native macOS codings agent orchestrator prowl.onev.cat
Something went wrong. Try again.
4.7 kB · 129 lines
Swift
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130import ComposableArchitectureimport Foundation
nonisolated struct ExternalDiffSnapshotPair: Equatable, Sendable { let leftURL: URL let rightURL: URL}
nonisolated struct ExternalDiffSnapshotClient: Sendable { var makeSnapshotPair: @Sendable (_ workingDirectory: URL) async throws -> ExternalDiffSnapshotPair}
extension ExternalDiffSnapshotClient: DependencyKey { static let liveValue = ExternalDiffSnapshotClient { workingDirectory in try await ExternalDiffSnapshotBuilder().makeSnapshotPair(at: workingDirectory) }
static let testValue = ExternalDiffSnapshotClient { _ in ExternalDiffSnapshotPair( leftURL: URL(fileURLWithPath: "/tmp/prowl-diff-left"), rightURL: URL(fileURLWithPath: "/tmp/prowl-diff-right") ) }}
extension DependencyValues { var externalDiffSnapshotClient: ExternalDiffSnapshotClient { get { self[ExternalDiffSnapshotClient.self] } set { self[ExternalDiffSnapshotClient.self] = newValue } }}
private nonisolated struct ExternalDiffSnapshotBuilder { func makeSnapshotPair(at workingDirectory: URL) async throws -> ExternalDiffSnapshotPair { let git = try await GitExecutableResolver.shared.resolve() let gitClient = GitClient() async let trackedOutput = gitClient.diffNameStatus(at: workingDirectory) async let untrackedPaths = gitClient.untrackedFilePaths(at: workingDirectory) let trackedFiles = DiffChangedFile.parseNameStatus(await trackedOutput) let untrackedFiles = await untrackedPaths.map { DiffChangedFile(status: .added, oldPath: nil, newPath: $0) } let files = trackedFiles + untrackedFiles
return try await Task.detached { let rootURL = FileManager.default.temporaryDirectory .appending(path: "ProwlDiffSnapshots") .appending(path: UUID().uuidString) let leftURL = rootURL.appending(path: "HEAD") let rightURL = rootURL.appending(path: "Worktree") try FileManager.default.createDirectory(at: leftURL, withIntermediateDirectories: true) try FileManager.default.createDirectory(at: rightURL, withIntermediateDirectories: true)
for file in files { try copySnapshotFile(file, from: workingDirectory, leftURL: leftURL, rightURL: rightURL, git: git) }
return ExternalDiffSnapshotPair(leftURL: leftURL, rightURL: rightURL) }.value }
private func copySnapshotFile( _ file: DiffChangedFile, from worktreeURL: URL, leftURL: URL, rightURL: URL, git: GitExecutable ) throws { if let oldPath = file.oldPath { try writeHeadFile(oldPath, worktreeURL: worktreeURL, destinationRoot: leftURL, git: git) } if let newPath = file.newPath { let sourceURL = worktreeURL.appending(path: newPath) guard FileManager.default.fileExists(atPath: sourceURL.path(percentEncoded: false)) else { return } let destinationURL = rightURL.appending(path: newPath) try createParentDirectory(for: destinationURL) if FileManager.default.fileExists(atPath: destinationURL.path(percentEncoded: false)) { try FileManager.default.removeItem(at: destinationURL) } try FileManager.default.copyItem(at: sourceURL, to: destinationURL) } }
private func writeHeadFile( _ relativePath: String, worktreeURL: URL, destinationRoot: URL, git: GitExecutable ) throws { let destinationURL = destinationRoot.appending(path: relativePath) try createParentDirectory(for: destinationURL) if FileManager.default.fileExists(atPath: destinationURL.path(percentEncoded: false)) { try FileManager.default.removeItem(at: destinationURL) } FileManager.default.createFile(atPath: destinationURL.path(percentEncoded: false), contents: nil) let outputHandle = try FileHandle(forWritingTo: destinationURL) defer { try? outputHandle.close() }
let process = Process() process.executableURL = git.url process.environment = ProcessInfo.processInfo.environment.merging(git.environment) { _, selected in selected } process.arguments = [ "-C", worktreeURL.path(percentEncoded: false), "show", "HEAD:\(relativePath)", ] process.standardOutput = outputHandle process.standardError = Pipe() try process.run() process.waitUntilExit() if process.terminationStatus != 0 { throw ExternalDiffSnapshotError.gitShowFailed(relativePath) } }
private func createParentDirectory(for fileURL: URL) throws { try FileManager.default.createDirectory( at: fileURL.deletingLastPathComponent(), withIntermediateDirectories: true ) }}
private nonisolated enum ExternalDiffSnapshotError: Error { case gitShowFailed(String)}