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

org.kuali.common.util.FileSystemUtils Maven / Gradle / Ivy

There is a newer version: 4.4.17
Show newest version
/**
 * Copyright 2010-2013 The Kuali Foundation
 *
 * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
 *
 * 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 org.kuali.common.util;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.kuali.common.util.execute.CopyFilePatternsExecutable;
import org.kuali.common.util.execute.CopyFileRequest;
import org.kuali.common.util.execute.CopyFileResult;
import org.kuali.common.util.file.DirDiff;
import org.kuali.common.util.file.DirRequest;
import org.kuali.common.util.file.MD5Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FileSystemUtils {

	private static final Logger logger = LoggerFactory.getLogger(FileSystemUtils.class);

	public static final String RECURSIVE_FILE_INCLUDE_PATTERN = "**/**";
	public static final List DEFAULT_RECURSIVE_INCLUDES = Arrays.asList(RECURSIVE_FILE_INCLUDE_PATTERN);

	private static final String SVN_PATTERN = "**/.svn/**";
	private static final String GIT_PATTERN = "**/.git/**";
	public static final List DEFAULT_SCM_IGNORE_PATTERNS = Arrays.asList(SVN_PATTERN, GIT_PATTERN);

	/**
	 * Return a recursive listing of all files in the directory ignoring ++/.svn/++ and ++/.git/++
	 */
	public static List getAllNonScmFiles(File dir) {
		return getAllNonScmFiles(dir, DEFAULT_SCM_IGNORE_PATTERNS);
	}

	/**
	 * Return a recursive listing of all files in the directory ignoring files that match scmIgnorePatterns
	 */
	public static List getAllNonScmFiles(File dir, List scmIgnorePatterns) {
		SimpleScanner scanner = new SimpleScanner(dir, DEFAULT_RECURSIVE_INCLUDES, scmIgnorePatterns);
		return scanner.getFiles();
	}

	/**
	 * This method recursively copies one file system directory to another directory under the control of SCM. Before doing so, it records 3 types of files:
	 * 
	 * 
	 *  1 - both     - files that exist in both directories 
	 *  2 - dir1Only - files that exist in the source directory but not the SCM directory
	 *  3 - dir2Only - files that exist in the SCM directory but not the source directory
	 * 
* * This provides enough information for SCM tooling to then complete the work of making the SCM directory exactly match the file system directory and commit any changes to the * SCM system. */ @Deprecated public static DirectoryDiff prepareScmDir(PrepareScmDirRequest request) { return prepareScmDir(request, null, false); } /** * This method recursively copies one file system directory to another directory under the control of SCM. Before doing so, it records 3 types of files: * *
	 *  1 - both     - files that exist in both directories 
	 *  2 - dir1Only - files that exist in the source directory but not the SCM directory
	 *  3 - dir2Only - files that exist in the SCM directory but not the source directory
	 * 
* * This provides enough information for SCM tooling to then complete the work of making the SCM directory exactly match the file system directory and commit any changes to the * SCM system. */ @Deprecated public static DirectoryDiff prepareScmDir(PrepareScmDirRequest request, File relativeDir, boolean diffOnly) { // Make sure we are configured correctly Assert.notNull(request, "request is null"); Assert.notNull(request.getSrcDir(), "srcDir is null"); Assert.notNull(request.getScmDir(), "scmDir is null"); // Both must already exist and must be directories (can't be a regular file) Assert.isExistingDir(request.getSrcDir(), "srcDir is not an existing directory"); Assert.isExistingDir(request.getScmDir(), "scmDir is not an existing directory"); // Setup a diff request DirectoryDiffRequest diffRequest = new DirectoryDiffRequest(); diffRequest.setDir1(request.getSrcDir()); diffRequest.setDir2(request.getScmDir()); diffRequest.setExcludes(request.getScmIgnorePatterns()); // Record the differences between the two directories DirectoryDiff diff = getDiff(diffRequest); // Copy files from the source directory to the SCM directory if (!diffOnly) { CopyFilePatternsExecutable exec = new CopyFilePatternsExecutable(); exec.setSrcDir(request.getSrcDir()); exec.setDstDir(request.getScmDir()); exec.setExcludes(request.getScmIgnorePatterns()); exec.setRelativeDir(relativeDir); exec.execute(); } // Return the diff so we'll know what SCM needs to add/delete from its directory return diff; } public static List getFiles(File dir, List includes, List excludes) { SimpleScanner scanner = new SimpleScanner(dir, includes, excludes); return scanner.getFiles(); } @Deprecated public static DirectoryDiff getDiff(File dir1, File dir2, List includes, List excludes) { DirectoryDiffRequest request = new DirectoryDiffRequest(); request.setDir1(dir1); request.setDir2(dir2); request.setIncludes(includes); request.setExcludes(excludes); return getDiff(request); } /** * Compare 2 directories on the file system and return an object containing the results. All of the files contained in either of the 2 directories get aggregated into 5 * categories. * *
	 * 1 - Both            - Files that exist in both directories
	 * 2 - Different       - Files that exist in both directories but who's MD5 checksums do not match 
	 * 3 - Identical       - Files that exist in both directories with matching MD5 checksums 
	 * 4 - Source Dir Only - Files that exist only in the source directory
	 * 5 - Target Dir Only - Files that exist only in the target directory
	 * 
* * The 5 lists in DirDiff contain the relative paths to files for each category. */ public static DirDiff getMD5Diff(DirRequest request) { // Do a quick diff (just figures out what files are unique to each directory vs files that are in both) DirDiff diff = getQuickDiff(request); // Do a deep diff // This computes MD5 checksums for any files present in both directories fillInMD5Results(diff); // return the diff result return diff; } public static List getMD5Results(List sources, List targets) { Assert.isTrue(sources.size() == targets.size(), "lists are not the same size"); List results = new ArrayList(); for (int i = 0; i < sources.size(); i++) { File source = sources.get(i); File target = targets.get(i); MD5Result md5Result = getMD5Result(source, target); results.add(md5Result); } return results; } protected static void fillInMD5Results(DirDiff diff) { List sources = getFullPaths(diff.getSourceDir(), diff.getBoth()); List targets = getFullPaths(diff.getTargetDir(), diff.getBoth()); List results = getMD5Results(sources, targets); List different = new ArrayList(); List identical = new ArrayList(); for (MD5Result md5Result : results) { String sourceChecksum = md5Result.getSourceChecksum(); String targetChecksum = md5Result.getTargetChecksum(); Assert.notNull(sourceChecksum, "sourceChecksum is null"); Assert.notNull(targetChecksum, "targetChecksum is null"); if (StringUtils.equals(sourceChecksum, targetChecksum)) { identical.add(md5Result); } else { different.add(md5Result); } } // diff.setDifferent(different); diff.setIdentical(identical); } public static MD5Result getMD5Result(File source, File target) { String sourceChecksum = LocationUtils.getMD5Checksum(source); String targetChecksum = LocationUtils.getMD5Checksum(target); MD5Result result = new MD5Result(); result.setSource(source); result.setTarget(target); result.setSourceChecksum(sourceChecksum); result.setTargetChecksum(targetChecksum); return result; } /** * Compare 2 directories on the file system and return an object containing the results. All of the files contained in either of the 2 directories get placed into one of 3 * categories. * *
	 * 1 - Both       - Files that exist in both directories
	 * 2 - Dir 1 Only - Files that exist only in directory 1
	 * 3 - Dir 2 Only - Files that exist only in directory 2
	 * 
* * The 3 lists in DirectoryDiff contain the relative paths to files for each category. */ @Deprecated public static DirectoryDiff getDiff(DirectoryDiffRequest request) { DirRequest newRequest = new DirRequest(); newRequest.setExcludes(request.getExcludes()); newRequest.setIncludes(request.getIncludes()); newRequest.setSourceDir(request.getDir1()); newRequest.setTargetDir(request.getDir2()); DirDiff diff = getQuickDiff(newRequest); DirectoryDiff dd = new DirectoryDiff(diff.getSourceDir(), diff.getTargetDir()); dd.setBoth(diff.getBoth()); dd.setDir1Only(diff.getSourceDirOnly()); dd.setDir2Only(diff.getTargetDirOnly()); return dd; } public static DirDiff getQuickDiff(DirRequest request) { // Get a listing of files from both directories using the exact same includes/excludes List sourceFiles = getFiles(request.getSourceDir(), request.getIncludes(), request.getExcludes()); List targetFiles = getFiles(request.getTargetDir(), request.getIncludes(), request.getExcludes()); // Get the unique set of paths for each file relative to their parent directory Set sourcePaths = new HashSet(getRelativePaths(request.getSourceDir(), sourceFiles)); Set targetPaths = new HashSet(getRelativePaths(request.getTargetDir(), targetFiles)); // Paths that exist in both directories Set both = SetUtils.intersection(sourcePaths, targetPaths); // Paths that exist in source but not target Set sourceOnly = SetUtils.difference(sourcePaths, targetPaths); // Paths that exist in target but not source Set targetOnly = SetUtils.difference(targetPaths, sourcePaths); logger.debug("source={}, sourceOnly.size()={}", request.getSourceDir(), sourceOnly.size()); logger.debug("target={}, targetOnly.size()={}", request.getTargetDir(), targetOnly.size()); // Store the information we've collected into a result object DirDiff result = new DirDiff(request.getSourceDir(), request.getTargetDir()); // Store the relative paths on the diff object result.setBoth(new ArrayList(both)); result.setSourceDirOnly(new ArrayList(sourceOnly)); result.setTargetDirOnly(new ArrayList(targetOnly)); // Sort the relative paths Collections.sort(result.getBoth()); Collections.sort(result.getSourceDirOnly()); Collections.sort(result.getTargetDirOnly()); // return the diff return result; } /** * Examine the contents of a text file, stopping as soon as it contains token, or timeout is exceeded, whichever comes first. */ public static MonitorTextFileResult monitorTextFile(File file, String token, int intervalMillis, int timeoutMillis, String encoding) { // Make sure we are configured correctly Assert.notNull(file, "file is null"); Assert.hasText(token, "token has no text"); Assert.hasText(encoding, "encoding has no text"); Assert.isTrue(intervalMillis > 0, "interval must be a positive integer"); Assert.isTrue(timeoutMillis > 0, "timeout must be a positive integer"); // Setup some member variables to record what happens long start = System.currentTimeMillis(); long stop = start + timeoutMillis; boolean exists = false; boolean contains = false; boolean timeoutExceeded = false; long now = -1; String content = null; // loop until timeout is exceeded or we find the token inside the file for (;;) { // Always pause (unless this is the first iteration) if (now != -1) { ThreadUtils.sleep(intervalMillis); } // Check to make sure we haven't exceeded our timeout limit now = System.currentTimeMillis(); if (now > stop) { timeoutExceeded = true; break; } // If the file does not exist, no point in going any further exists = LocationUtils.exists(file); if (!exists) { continue; } // The file exists, check to see if the token we are looking for is present in the file content = LocationUtils.toString(file, encoding); contains = StringUtils.contains(content, token); if (contains) { // We found what we are looking for, we are done break; } } // Record how long the overall process took long elapsed = now - start; // Fill in a pojo detailing what happened MonitorTextFileResult mtfr = new MonitorTextFileResult(exists, contains, timeoutExceeded, elapsed); mtfr.setAbsolutePath(LocationUtils.getCanonicalPath(file)); mtfr.setContent(content); return mtfr; } public static List syncFiles(List requests) throws IOException { List results = new ArrayList(); for (SyncRequest request : requests) { SyncResult result = syncFiles(request); results.add(result); } return results; } public static SyncResult syncFilesQuietly(SyncRequest request) { try { return syncFiles(request); } catch (IOException e) { throw new IllegalStateException("Unexpected IO error"); } } public static SyncResult syncFiles(SyncRequest request) throws IOException { logger.info("Sync [{}] -> [{}]", request.getSrcDir(), request.getDstDir()); List dstFiles = getAllNonScmFiles(request.getDstDir()); List srcFiles = request.getSrcFiles(); List dstPaths = getRelativePaths(request.getDstDir(), dstFiles); List srcPaths = getRelativePaths(request.getSrcDir(), srcFiles); List adds = new ArrayList(); List updates = new ArrayList(); List deletes = new ArrayList(); for (String srcPath : srcPaths) { boolean existing = dstPaths.contains(srcPath); if (existing) { updates.add(srcPath); } else { adds.add(srcPath); } } for (String dstPath : dstPaths) { boolean extra = !srcPaths.contains(dstPath); if (extra) { deletes.add(dstPath); } } copyFiles(request.getSrcDir(), request.getSrcFiles(), request.getDstDir()); SyncResult result = new SyncResult(); result.setAdds(getFullPaths(request.getDstDir(), adds)); result.setUpdates(getFullPaths(request.getDstDir(), updates)); result.setDeletes(getFullPaths(request.getDstDir(), deletes)); return result; } protected static void copyFiles(File srcDir, List files, File dstDir) throws IOException { for (File file : files) { String relativePath = getRelativePath(srcDir, file); File dstFile = new File(dstDir, relativePath); FileUtils.copyFile(file, dstFile); } } public static List getFullPaths(File dir, Set relativePaths) { return getFullPaths(dir, new ArrayList(relativePaths)); } public static List getSortedFullPaths(File dir, List relativePaths) { List files = getFullPaths(dir, relativePaths); Collections.sort(files); return files; } public static List getFullPaths(File dir, List relativePaths) { List files = new ArrayList(); for (String relativePath : relativePaths) { File file = new File(dir, relativePath); File canonical = new File(LocationUtils.getCanonicalPath(file)); files.add(canonical); } return files; } protected static List getRelativePaths(File dir, List files) { List relativePaths = new ArrayList(); for (File file : files) { String relativePath = getRelativePath(dir, file); relativePaths.add(relativePath); } return relativePaths; } /** * Return true if child lives on the file system somewhere underneath parent, false otherwise. */ public static boolean isParent(File parent, File child) { if (parent == null || child == null) { return false; } String parentPath = LocationUtils.getCanonicalPath(parent); String childPath = LocationUtils.getCanonicalPath(child); if (StringUtils.equals(parentPath, childPath)) { return false; } else { return StringUtils.contains(childPath, parentPath); } } /** * Return the relative path to file from parentDir. parentDir is optional and can be null. If parentDir is not * supplied (or is not a parent directory to file the canonical path to file is returned. */ public static String getRelativePathQuietly(File parentDir, File file) { Assert.notNull(file, "file is null"); if (isParent(parentDir, file)) { return getRelativePath(parentDir, file); } else { return LocationUtils.getCanonicalPath(file); } } public static String getRelativePath(File dir, File file) { String dirPath = LocationUtils.getCanonicalPath(dir); String filePath = LocationUtils.getCanonicalPath(file); if (!StringUtils.contains(filePath, dirPath)) { throw new IllegalArgumentException(file + " does not reside under " + dir); } return StringUtils.remove(filePath, dirPath); } public static List getCopyFileRequests(File srcDir, List includes, List excludes, File dstDir) { SimpleScanner scanner = new SimpleScanner(srcDir, includes, excludes); List srcFiles = scanner.getFiles(); List requests = new ArrayList(); for (File srcFile : srcFiles) { String relativePath = FileSystemUtils.getRelativePath(srcDir, srcFile); File dstFile = new File(dstDir, relativePath); CopyFileRequest request = new CopyFileRequest(srcFile, dstFile); requests.add(request); } return requests; } public static CopyFileResult copyFile(File src, File dst) { try { long start = System.currentTimeMillis(); boolean overwritten = dst.exists(); FileUtils.copyFile(src, dst); return new CopyFileResult(src, dst, overwritten, System.currentTimeMillis() - start); } catch (IOException e) { throw new IllegalStateException("Unexpected IO error", e); } } public static List copyFiles(List requests) { List results = new ArrayList(); for (CopyFileRequest request : requests) { CopyFileResult result = copyFile(request.getSource(), request.getDestination()); results.add(result); } return results; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy