Major update for stability
This commit is contained in:
@@ -14,17 +14,16 @@ final class RsyncRunner: ObservableObject {
|
||||
let wasCancelled: Bool
|
||||
}
|
||||
|
||||
func run(job: SyncJob, dryRun: Bool) async throws -> Result {
|
||||
func run(job: SyncJob, dryRun: Bool, trigger: SyncRunTrigger = .manual) async throws -> Result {
|
||||
guard !isRunning else { throw RunnerError.alreadyRunning }
|
||||
guard !job.sourcePath.isEmpty, !job.destinationPath.isEmpty else { throw RunnerError.invalidPaths }
|
||||
if job.isRemote && job.remoteHost.isEmpty { throw RunnerError.missingRemoteHost }
|
||||
if job.isRemote && remoteDestinationLooksLikeHost(job) { throw RunnerError.invalidRemoteDestination }
|
||||
if job.isRemote && job.sshKeyPath.trimmingCharacters(in: .whitespacesAndNewlines).hasSuffix(".pub") {
|
||||
let privatePath = RsyncCommandBuilder.normalizedPrivateKeyPath(job.sshKeyPath)
|
||||
if privatePath.hasSuffix(".pub") { throw RunnerError.publicSSHKeySelected }
|
||||
if let message = RsyncSecurityValidator.validationMessage(for: job, trigger: trigger) {
|
||||
throw RunnerError.securityValidation(message)
|
||||
}
|
||||
|
||||
let executable = RsyncLocator.locate()
|
||||
guard RsyncLocator.isTrustedExecutableCandidate(executable) else {
|
||||
throw RunnerError.invalidExecutable(executable)
|
||||
}
|
||||
let arguments = RsyncCommandBuilder.build(job: job, dryRun: dryRun, executable: executable)
|
||||
|
||||
isRunning = true
|
||||
@@ -106,15 +105,18 @@ final class RsyncRunner: ObservableObject {
|
||||
}
|
||||
|
||||
enum RunnerError: LocalizedError {
|
||||
case alreadyRunning, invalidPaths, missingRemoteHost, invalidRemoteDestination, publicSSHKeySelected
|
||||
case alreadyRunning
|
||||
case securityValidation(String)
|
||||
case invalidExecutable(String)
|
||||
|
||||
var errorDescription: String? {
|
||||
switch self {
|
||||
case .alreadyRunning: return "Another rsync job is already running."
|
||||
case .invalidPaths: return "Source and destination are required."
|
||||
case .missingRemoteHost: return "Remote host is required for an SSH job."
|
||||
case .invalidRemoteDestination: return "Remote destination must be a path on the remote machine, for example /home/mag/backup or ~/backup — not the host address."
|
||||
case .publicSSHKeySelected: return "The SSH key must be the private key (for example ~/.ssh/id_rsa or ~/.ssh/id_ed25519), not the .pub file."
|
||||
case .alreadyRunning:
|
||||
return "Another rsync job is already running."
|
||||
case .securityValidation(let message):
|
||||
return message
|
||||
case .invalidExecutable(let path):
|
||||
return "The rsync executable at \(path) is unavailable or is not a trusted regular executable file."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user