package org.jfrog.build.extractor.clientConfiguration.util;
import org.apache.commons.lang.StringUtils;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
/**
* Created by diman on 02/01/2017.
*/
public class FileCollectionUtil {
/**
* Return all files in the provided directory that can match the pattern.
* the number of files is limited to 1M files.
*
* @param baseDir the directory to get files from
* @param fixedPattern the pattern it can match
* @param isRecursive is the spec recursive
* @param regexp dose the spec regex
* @return all files in the base directory that can match the pattern.
*/
public static List<String> collectFiles(String baseDir, String fixedPattern, boolean isRecursive, boolean regexp) {
File[] filesToScan = new File(baseDir).listFiles();
List<String> results = new ArrayList<String>();
if (filesToScan != null) {
for (File file : filesToScan) {
if (file.isFile()) {
results.add(file.getAbsolutePath().replace("\\", "/"));
isPassedLimit(results.size());
} else if (isRecursive) {
results.addAll(collectFiles(file.getAbsolutePath(), -1, results.size()));
} else if (!regexp) {
// In case of not recursive wildcard pattern we can stop scanning in certain depth.
// this depth is when the number of slashes in the path and base directory with pattern are equals.
int numberOfSeparators = StringUtils.countMatches(fixedPattern, "/") + StringUtils.countMatches(baseDir, "/");
results.addAll(collectFiles(file.getAbsolutePath(), numberOfSeparators, results.size()));
}
}
}
return results;
}
/**
* Returns all files that exists in the provided directory and its subdirectories.
* scanning to max depth provided by the user.
* limited to 1m files minus provided by the user numberOfCandidates
* @param dir the directory to search in
* @param numberOfCandidates the number of already existing candidates
* @return all files that exists in the provided directory and its subdirectories till the provided depth.
*/
private static List<String> collectFiles(String dir, int depth, int numberOfCandidates) {
List<String> result = new ArrayList<String>();
List<String> foldersToScan = new LinkedList<String>();
foldersToScan.add(dir);
for (int i = 0; i < foldersToScan.size(); i++) {
String folderString = foldersToScan.get(i);
if (depth == -1 || StringUtils.countMatches(folderString, File.separator) <= depth) {
File file = new File(folderString);
List<File> folderContent = new ArrayList<File>();
if (file.listFiles() != null) {
folderContent.addAll(Arrays.asList(file.listFiles()));
}
if (!folderContent.isEmpty()) {
for (File entry : folderContent) {
if (entry.isDirectory()) {
foldersToScan.add(entry.getAbsolutePath());
} else {
// File can be candidate only if it in the correct depth or if the spec is recursive (depth == -1)
if (depth == -1 || StringUtils.countMatches(entry.getPath(), File.separator) == depth) {
result.add(entry.getAbsolutePath().replace("\\", "/"));
isPassedLimit(numberOfCandidates + result.size());
}
}
}
}
}
}
return result;
}
/**
* Throws exception if more than 1M candidate files provided by numberOfFiles
* @param numberOfFiles the number of found candidates
*/
private static void isPassedLimit(int numberOfFiles) {
int limit = 1000000;
if (numberOfFiles >= limit) {
throw new IllegalStateException("Too many candidate files found.");
}
}
}