All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.metaeffekt.artifact.analysis.utils.FileUtils Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2021-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.metaeffekt.artifact.analysis.utils;

import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Delete;
import org.apache.tools.ant.taskdefs.Tar;
import org.apache.tools.ant.taskdefs.Zip;
import org.mozilla.universalchardet.UniversalDetector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StreamUtils;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

public class FileUtils extends org.metaeffekt.core.util.FileUtils {

    private static final Logger LOG = LoggerFactory.getLogger(FileUtils.class);

    public static final AntPathMatcher ANT_PATH_MATCHER = new AntPathMatcher();

    public static final void deleteDir(File dir) {
        if (dir.exists()) {
            Delete delete = new Delete();
            Project project = new Project();
            project.setBaseDir(dir);
            delete.setProject(project);
            delete.setDir(dir);
            delete.execute();
        }
    }

    public static String[] scanDirectoryForFiles(File targetDir, boolean addDefaultExcludes, String... includes) {
        DirectoryScanner scanner = new DirectoryScanner();
        scanner.setBasedir(targetDir);
        scanner.setIncludes(includes);
        scanner.setCaseSensitive(false);
        if (addDefaultExcludes) {
            scanner.addDefaultExcludes();
        }
        scanner.scan();
        return scanner.getIncludedFiles();
    }

    public static boolean compareFolders(File sourceDir, File targetDir) {
        validateExists(sourceDir);
        validateExists(targetDir);

        HashSet sourceFileSet = fileToSet(sourceDir);
        HashSet targetFileSet = fileToSet(targetDir);

        List messages = new ArrayList<>();

        // compare from source to target
        for (String file : sourceFileSet) {
            if (!targetFileSet.contains(file)) {
                messages.add(String.format("Target folder does not contain file %s", file));
            }
        }

        // compare from target to source
        for (String file : targetFileSet) {
            if (!sourceFileSet.contains(file)) {
                messages.add(String.format("Source folder does not contain file %s", file));
            }
        }

        // compare file content by comparing checksums
        for (String file : sourceFileSet) {
            String sourceCS = computeChecksum(new File(sourceDir, file));
            String targetCS = computeChecksum(new File(targetDir, file));

            if (!sourceCS.equals(targetCS)) {
                messages.add(String.format("Content of file %s differs.", file));
            }
        }

        // print report (full diff)
        for (String message : messages) {
            LOG.info(message);
        }

        return !messages.isEmpty();
    }


    public static HashSet fileToSet(File dir) {
        String[] files = scanDirectoryForFiles(dir, true, "**/*");
        HashSet fileSet = new HashSet<>();
        for (String file : files) {
            fileSet.add(file);
        }
        return fileSet;
    }

    /**
     * Uses the native zip command to zip the file. Uses the -X attribute to create files with deterministic checksum.
     *
     * @param sourceDir     The directory to zip (recursively).
     * @param targetZipFile The target zip file name.
     * @throws IOException If the commands could not be executed.
     */
    public static void zipNative(File sourceDir, File targetZipFile) throws IOException {
        // FIXME: touch all files in source dir to normalize timestamp
        String[] touchArray = {"find", ".", "-type", "f", "-exec", "touch", "-t", "202001010000", "{}", "+"};
        Process touch = Runtime.getRuntime().exec(touchArray, new String[]{}, sourceDir);

        // block until touch is completed
        waitForProcess(touch);

        // run native zip process
        String[] zip = {"zip", "-X", "-r", targetZipFile.getAbsolutePath(), "."};
        Process p = Runtime.getRuntime().exec(zip, new String[]{}, sourceDir);

        // block until zip is completed
        waitForProcess(p);

        // check exit value and write error to System.err in case exit code is not 0
        if (p.exitValue() != 0) {
            StreamUtils.copy(p.getErrorStream(), System.err);
        }
    }

    /**
     * Uses the native zip command to zip the file. Uses the -X attribute to create files with deterministic checksum.
     *
     * @param sourceDir     The directory to zip (recursively).
     * @param targetZipFile The target zip file name.
     */
    public static void zipAnt(File sourceDir, File targetZipFile) {
        Zip zip = new Zip();
        Project project = new Project();
        project.setBaseDir(sourceDir);
        zip.setProject(project);
        zip.setBasedir(sourceDir);
        zip.setCompress(true);
        zip.setDestFile(targetZipFile);
        zip.setFollowSymlinks(false);
        zip.execute();
    }

    public static void gzip(File sourceDir, File targetZipFile) throws IOException {
        Tar zip = new Tar();
        Project project = new Project();
        project.setBaseDir(sourceDir);
        zip.setBasedir(sourceDir);
        zip.setProject(project);
        zip.setDestFile(targetZipFile);
        zip.setDescription("");
        zip.execute();
    }

    public static boolean matches(String absolutePath, String[] patterns) {
        for (String pattern : patterns) {
            pattern = pattern.trim();

            // Springs AntPatternMatcher requires a trailing "/" to match an absolute path
            pattern = "/" + pattern;
            if (ANT_PATH_MATCHER.match(pattern, absolutePath)) {
                return true;
            }
        }

        // none of the patterns matched
        return false;
    }

    public static File findSingleFile(File baseFile, String pattern) {
        final String[] files = scanDirectoryForFiles(baseFile, pattern);
        if (files.length == 1) {
            return new File(baseFile, files[0]);
        }
        return null;
    }

    public static File findSingleDir(File baseFile, String pattern) {
        final String[] dirs = FileUtils.scanDirectoryForFolders(baseFile, pattern);
        if (dirs.length == 1) {
            return new File(baseFile, dirs[0]);
        }
        return null;
    }

    public static String computeContentChecksum(File file, File tmpFolder) throws IOException {
        final File contentChecksumFile = new File(tmpFolder, file.getName() + ".content.md5");
        createDirectoryContentChecksumFile(file, contentChecksumFile);
        try {
            return FileUtils.computeChecksum(contentChecksumFile);
        } finally {
            deleteQuietly(contentChecksumFile);
        }
    }

    public static void forceMkDirQuietly(File file) {
        try {
            FileUtils.forceMkdir(file);
        } catch (IOException exception) {
            throw new IllegalStateException("Cannot create folder [" + file + "].");
        }
    }

    public static boolean exists(String filePath) {
        if (filePath == null) return false;
        return new File(filePath).exists();
    }

    public static String detectEncoding(File file) throws IOException {
        String encoding = UniversalDetector.detectCharset(file);
        if (encoding == null) {
            // fallback to UTF-8
            encoding = FileUtils.ENCODING_UTF_8;
        }
        return encoding;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy