Skip to content

Instantly share code, notes, and snippets.

@iby
Created September 5, 2021 09:22
Show Gist options
  • Save iby/3bf0f18170ee900bad059df945fc9fb2 to your computer and use it in GitHub Desktop.
Save iby/3bf0f18170ee900bad059df945fc9fb2 to your computer and use it in GitHub Desktop.
Create a list of excluded paths at the base location keeping the specified paths.
private func exclude(paths: [String], at basePath: String) -> [String] {
let slash = CharacterSet(charactersIn: "/")
let baseURL = URL(fileURLWithPath: basePath, isDirectory: true)
var exclusions = try! FileManager.default.contentsOfDirectory(atPath: basePath).sorted()
var inclusions = paths
// Cleanup paths removing and expanding `/.`, `/..`, etc.
inclusions = inclusions.reduce(into: [], { inclusions, inclusion in
let path = URL(fileURLWithPath: inclusion, relativeTo: baseURL).standardized.relativePath.trimmingCharacters(in: slash)
if !path.isEmpty { inclusions.append(path) }
})
// Remove child inclusions, i.e., `["foo/bar", "foo"]` becomes `["foo"]`.
inclusions = Set(inclusions).reduce(into: [], { inclusions, inclusion in
inclusions.removeAll(where: { $0.starts(with: "\(inclusion)/") })
if !inclusions.contains(where: { inclusion.starts(with: "\($0)/") }) { inclusions.append(inclusion) }
})
while let inclusion = inclusions.popLast()?.trimmingCharacters(in: slash) {
exclusions = exclusions.reduce(into: [], { (exclusions, exclusion) in
// If the inclusion is fully matched then we simply not reduce (add back) it into exclusions
// list, but examine it deeper if it starts with exclusions.
if inclusion.starts(with: "\(exclusion)/") {
exclusions.append(contentsOf: exclude(paths: [String(inclusion.dropFirst(exclusion.count + 1))], at: baseURL.appendingPathComponent(exclusion).path).map({ "\(exclusion)/\($0)" }))
} else if inclusion != exclusion {
exclusions.append(exclusion)
}
})
}
return exclusions
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment