diff --git a/Sources/Commands/Error.swift b/Sources/Commands/Error.swift index c6d6973f391..e6006d17054 100644 --- a/Sources/Commands/Error.swift +++ b/Sources/Commands/Error.swift @@ -23,6 +23,7 @@ public enum Error: ErrorProtocol { case invalidInstallation(String) case invalidSwiftExec(String) case buildYAMLNotFound(String) + case repositoryHasChanges(String) } extension Error: CustomStringConvertible { @@ -38,6 +39,8 @@ extension Error: CustomStringConvertible { return "invalid SWIFT_EXEC value: \(value)" case .buildYAMLNotFound(let value): return "no build YAML found: \(value)" + case .repositoryHasChanges(let value): + return "repository has changes: \(value)" } } } diff --git a/Sources/Commands/SwiftPackageTool.swift b/Sources/Commands/SwiftPackageTool.swift index ad95045869a..e138ca2ecb3 100644 --- a/Sources/Commands/SwiftPackageTool.swift +++ b/Sources/Commands/SwiftPackageTool.swift @@ -179,6 +179,22 @@ public struct SwiftPackageTool { try initPackage.writePackageStructure() case .update: + // Attempt to ensure that none of the repositories are modified. + for item in walk(opts.path.Packages, recursively: false) { + // Only look at repositories. + guard Path.join(item, ".git").exists else { continue } + + // If there is a staged or unstaged diff, don't remove the + // tree. This won't detect new untracked files, but it is + // just a safety measure for now. + let diffArgs = ["--no-ext-diff", "--quiet", "--exit-code"] + do { + _ = try Git.runPopen([Git.tool, "-C", item, "diff"] + diffArgs) + _ = try Git.runPopen([Git.tool, "-C", item, "diff", "--cached"] + diffArgs) + } catch { + throw Error.repositoryHasChanges(item) + } + } try Utility.removeFileTree(opts.path.Packages) fallthrough