Files
wehub-resource-sync 1d1286fadb
Build / Build and test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:18:38 +08:00

92 lines
3.0 KiB
Swift

import Foundation
protocol XcodeCleanExecuting: Sendable {
func clean(
candidates: [XcodeCleanCandidate],
selectedCandidateIDs: Set<XcodeCleanCandidate.ID>
) async throws -> XcodeCleanExecutionResult
}
struct XcodeCleanExecutor: XcodeCleanExecuting {
let fileSystem: XcodeCleanFileSystemProviding
let allowedRoots: [String]
init(
fileSystem: XcodeCleanFileSystemProviding = LocalXcodeCleanFileSystem(),
allowedRoots: [String]? = nil
) {
self.fileSystem = fileSystem
self.allowedRoots = (allowedRoots ?? Self.defaultAllowedRoots()).map { Self.ensureTrailingSlash($0) }
}
func clean(
candidates: [XcodeCleanCandidate],
selectedCandidateIDs: Set<XcodeCleanCandidate.ID>
) async throws -> XcodeCleanExecutionResult {
var itemResults: [XcodeCleanExecutionItemResult] = []
for candidate in candidates where selectedCandidateIDs.contains(candidate.id) {
try Task.checkCancellation()
itemResults.append(clean(candidate))
}
return XcodeCleanExecutionResult(itemResults: itemResults)
}
private func clean(_ candidate: XcodeCleanCandidate) -> XcodeCleanExecutionItemResult {
guard candidate.safety.isCleanable else {
return XcodeCleanExecutionItemResult(
candidateID: candidate.id,
path: candidate.path,
outcome: .skipped(candidate.safety)
)
}
if !isPathAllowed(candidate.path) {
return XcodeCleanExecutionItemResult(
candidateID: candidate.id,
path: candidate.path,
outcome: .skipped(.outsideAllowedRoot)
)
}
guard fileSystem.itemExists(at: candidate.path) else {
return XcodeCleanExecutionItemResult(
candidateID: candidate.id,
path: candidate.path,
outcome: .skipped(.missing)
)
}
do {
try fileSystem.removeItem(at: candidate.path)
return XcodeCleanExecutionItemResult(
candidateID: candidate.id,
path: candidate.path,
outcome: .removed(reclaimedBytes: candidate.sizeBytes)
)
} catch {
return XcodeCleanExecutionItemResult(
candidateID: candidate.id,
path: candidate.path,
outcome: .failed(message: error.localizedDescription)
)
}
}
private func isPathAllowed(_ path: String) -> Bool {
allowedRoots.contains { path.hasPrefix($0) }
}
private static func defaultAllowedRoots() -> [String] {
let home = NSHomeDirectory()
return XcodeCleanRuleCatalog.allowedRootPrefixes.map { prefix in
prefix.hasPrefix("~/") ? home + String(prefix.dropFirst()) : prefix
}
}
private static func ensureTrailingSlash(_ path: String) -> String {
path.hasSuffix("/") ? path : path + "/"
}
}