in base/src/com/google/idea/blaze/base/lang/buildfile/globbing/UnixGlob.java [515:606]
private void reallyGlob(
File base,
boolean baseIsDirectory,
String[] patternParts,
int idx,
boolean excludeDirectories,
Collection<File> results,
Cache<String, Pattern> cache,
Predicate<File> dirPred)
throws IOException {
ProgressManager.checkCanceled();
if (baseIsDirectory && !dirPred.test(base)) {
return;
}
if (idx == patternParts.length) { // Base case.
if (!(excludeDirectories && baseIsDirectory)) {
results.add(base);
}
return;
}
if (!baseIsDirectory) {
// Nothing to find here.
return;
}
final String pattern = patternParts[idx];
// ** is special: it can match nothing at all.
// For example, x/** matches x, **/y matches y, and x/**/y matches x/y.
if ("**".equals(pattern)) {
queueGlob(
base,
baseIsDirectory,
patternParts,
idx + 1,
excludeDirectories,
results,
cache,
dirPred);
}
if (!pattern.contains("*") && !pattern.contains("?")) {
// We do not need to do a readdir in this case, just a stat.
File child = new File(base, pattern);
boolean childIsDir = fileOperationProvider.isDirectory(child);
if (!childIsDir && !fileOperationProvider.isFile(child)) {
// The file is a dangling symlink, fifo, does not exist, etc.
return;
}
queueGlob(
child, childIsDir, patternParts, idx + 1, excludeDirectories, results, cache, dirPred);
return;
}
File[] children = getChildren(base);
if (children == null) {
return;
}
for (File child : children) {
boolean childIsDir = fileOperationProvider.isDirectory(child);
if ("**".equals(pattern)) {
// Recurse without shifting the pattern.
if (childIsDir) {
queueGlob(
child, childIsDir, patternParts, idx, excludeDirectories, results, cache, dirPred);
}
}
if (matches(pattern, child.getName(), cache)) {
// Recurse and consume one segment of the pattern.
if (childIsDir) {
queueGlob(
child,
childIsDir,
patternParts,
idx + 1,
excludeDirectories,
results,
cache,
dirPred);
} else {
// Instead of using an async call, just repeat the base case above.
if (idx + 1 == patternParts.length) {
results.add(child);
}
}
}
}
}