in plugin-bazel/src/main/kotlin/org/jetbrains/bazel/languages/starlark/globbing/StarlarkGlob.kt [466:575]
fun reallyGlob(
base: VirtualFile,
baseIsDirectory: Boolean,
patternParts: Array<String>,
idx: Int,
excludeDirectories: Boolean,
results: MutableCollection<VirtualFile>,
cache: Cache<String, Pattern>,
dirPred: Predicate<VirtualFile>,
) {
ProgressManager.checkCanceled()
if (baseIsDirectory && !dirPred.test(base)) {
return
}
if (idx == patternParts.size) { // Base case.
if (!(excludeDirectories && baseIsDirectory)) {
results.add(base)
}
return
}
if (!baseIsDirectory) {
// Nothing to find here.
return
}
val 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 ("**" == pattern) {
queueGlob(
base,
baseIsDirectory,
patternParts,
idx + 1,
excludeDirectories,
results,
cache,
dirPred,
)
}
if (!pattern.contains("*") && !pattern.contains("?")) {
val child = base.findChild(pattern)
if (child == null) return
val childIsDir = child.isDirectory
if (!childIsDir && !child.isFile) {
// The file is a dangling symlink, fifo, does not exist, etc.
return
}
queueGlob(
child,
childIsDir,
patternParts,
idx + 1,
excludeDirectories,
results,
cache,
dirPred,
)
return
}
val children = getChildren(base)
if (children == null) {
return
}
for (child in children) {
val childIsDir = child.isDirectory
if ("**" == pattern) {
// Recurse without shifting the pattern.
if (childIsDir) {
queueGlob(
child,
childIsDir,
patternParts,
idx,
excludeDirectories,
results,
cache,
dirPred,
)
}
}
if (matches(pattern, child.name, 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.size) {
results.add(child)
}
}
}
}
}