From 937ef2b0d59c22388fd109c93124f29aef357adb Mon Sep 17 00:00:00 2001 From: Sam Deane Date: Tue, 16 Jul 2019 15:11:54 +0100 Subject: [PATCH] look up explicit version number when installing --- .../xcshareddata/xcschemes/xpkg.xcscheme | 6 +- Sources/XPkgCore/Engine.swift | 74 ++++++++++--------- Sources/XPkgCore/InstallCommand.swift | 6 +- Sources/XPkgCore/Package.swift | 32 +++++--- Sources/XPkgCore/ReinstallCommand.swift | 8 +- Tests/XPkgTests/XPkgTests.swift | 6 +- 6 files changed, 75 insertions(+), 57 deletions(-) diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/xpkg.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/xpkg.xcscheme index 25ecd69..7477fcd 100644 --- a/.swiftpm/xcode/xcshareddata/xcschemes/xpkg.xcscheme +++ b/.swiftpm/xcode/xcshareddata/xcschemes/xpkg.xcscheme @@ -78,7 +78,7 @@ + isEnabled = "YES"> + isEnabled = "NO"> + isEnabled = "YES"> Bool { + internal func latestVersion(_ url: URL) -> String? { let runner = Runner(for: gitURL) - if let result = try? runner.sync(arguments: ["ls-remote", remote, "--exit-code"]) { - return result.status == 0 + guard let result = try? runner.sync(arguments: ["ls-remote", "--tags", "--refs", "--sort=v:refname", "--exit-code", url.absoluteString ]), result.status == 0 else { + return nil } - return false + + guard let version = result.stdout.split(separator: "v").last else { + return "" + } + + return String(version.trimmingCharacters(in: .whitespacesAndNewlines)) } - internal func remotePackageURL(_ package: String, skipValidation: Bool = false) -> URL { - let remote : URL? - if package.contains("git@") { - remote = URL(string: package) - } else { - let local = URL(fileURLWithPath: package) - if fileManager.fileExists(at: local) { - remote = local - } else if package.contains("/") { - remote = URL(string: "git@github.com:\(package)") + internal func remotePackageURL(_ package: String, skipValidation: Bool = false) -> (URL, String?) { + func validate(_ remote: URL) -> String? { + if skipValidation { + return nil } else { - // iterate default orgs, looking for a repo that exists - // if we don't find any, we just default to the unqualified package - knowing that it's probably wrong - var found: URL? = nil - for org in defaultOrgs { - let repo = "git@github.com:\(org)/\(package)" - if skipValidation || remoteExists(repo) { - found = URL(string: repo) - output.log("Found remote package \(org)/\(package).") - break - } - } - remote = found ?? URL(string: "git@github.com:\(package)") + return latestVersion(remote) } } - - return remote! // assertion is that this can't fail for a properly formed package name... + + if let remote = URL(string: package), let version = validate(remote) { + return (remote, version) + } + + if let remote = URL(string: "git@github.com:\(package)"), let version = validate(remote) { + return (remote, version) + } + + for org in defaultOrgs { + if let remote = URL(string: "git@github.com:\(org)/\(package)"), let version = validate(remote) { + return (remote, version) + } + } + + return (URL(string: "git@github.com:\(package)")!, nil) } internal var vaultURL: URL { @@ -261,7 +263,7 @@ let package = Package( try manifestText.write(to: url, atomically: true, encoding: .utf8) removeManifestCache() } catch { - print(error) + verbose.log(error) } } @@ -294,10 +296,11 @@ let package = Package( for package in after { if !beforeSet.contains(package) { do { - try package.run(action: "install", engine: self) - print("Added \(package.name)") + if try package.run(action: "install", engine: self) { + output.log("Added \(package.name)") + } } catch { - print("Install action for \(package.name) failed.") + output.log("Install action for \(package.name) failed.") } } } @@ -306,10 +309,11 @@ let package = Package( for package in before { if !afterSet.contains(package) { do { - try package.run(action:"remove", engine: self) - print("Removed \(package.name).") + if try package.run(action:"remove", engine: self) { + output.log("Removed \(package.name).") + } } catch { - print("Remove action for \(package.name) failed.") + output.log("Remove action for \(package.name) failed.") } } } diff --git a/Sources/XPkgCore/InstallCommand.swift b/Sources/XPkgCore/InstallCommand.swift index 3fa5383..5fde406 100644 --- a/Sources/XPkgCore/InstallCommand.swift +++ b/Sources/XPkgCore/InstallCommand.swift @@ -26,14 +26,14 @@ struct InstallCommand: Command { return } - // resolve the spec to a full url + // resolve the spec to a full url and a version output.log("Searching for package \(packageSpec)...") - let url = engine.remotePackageURL(packageSpec) + let (url, version) = engine.remotePackageURL(packageSpec) var updatedManifest = manifest // add the package to the manifest engine.verbose.log("Adding package to manifest.") - let newPackage = Package(url: url, version: "1.0.0") + let newPackage = Package(url: url, version: version ?? "") updatedManifest = manifest updatedManifest.add(package: newPackage) diff --git a/Sources/XPkgCore/Package.swift b/Sources/XPkgCore/Package.swift index 4b32b6d..4b19d0e 100644 --- a/Sources/XPkgCore/Package.swift +++ b/Sources/XPkgCore/Package.swift @@ -337,27 +337,37 @@ struct Package: Decodable { // self.name = newName } - func run(action: String, engine: Engine) throws { + func run(action: String, engine: Engine) throws -> Bool { do { + // run as a new-style package let runner = Runner(for: engine.swiftURL, cwd: engine.vaultURL) let result = try runner.sync(arguments: ["run", "\(name)-xpkg-hooks", name, path, action]) - engine.verbose.log(result.stdout) - if result.status != 0 { + if result.status == 0 { + return true + } + + if !result.stdout.contains("no exexcutable product") { + engine.verbose.log("Failed to run \(action) hooks for \(name).") + engine.verbose.log(result.stdout) engine.verbose.log(result.stderr) - engine.verbose.log("Couldn't run action \(action) - trying fallback.") - - // fallback to old method? - let configURL = local.appendingPathComponent(".xpkg.json") - if engine.fileManager.fileExists(atPath: configURL.path) { - let installed = InstalledPackage(local: local, output: engine.output, verbose: engine.verbose) - try installed.run(legacyAction: action, config: configURL) - } } + + // fallback to old method? + let configURL = local.appendingPathComponent(".xpkg.json") + if engine.fileManager.fileExists(atPath: configURL.path) { + let installed = InstalledPackage(local: local, output: engine.output, verbose: engine.verbose) + try installed.run(legacyAction: action, config: configURL) + return true + } + } catch { engine.output.log("Couldn't run action \(action).") engine.verbose.log(error) throw error } + + engine.verbose.log("Ignoring \(name) as it isn't an xpkg package.") + return false } } diff --git a/Sources/XPkgCore/ReinstallCommand.swift b/Sources/XPkgCore/ReinstallCommand.swift index cb501dd..76820e3 100644 --- a/Sources/XPkgCore/ReinstallCommand.swift +++ b/Sources/XPkgCore/ReinstallCommand.swift @@ -15,9 +15,13 @@ struct ReinstallCommand: Command { engine.attempt(action: "Reinstalling \(package.name).") { do { engine.verbose.log("Uninstalling \(package.name)") - try package.run(action: "remove", engine: engine) + if try package.run(action: "remove", engine: engine) { + engine.output.log("Removed \(package.name).") + } engine.verbose.log("Installing \(package.name)") - try package.run(action: "install", engine: engine) + if try package.run(action: "install", engine: engine) { + engine.output.log("Reinstalled \(package.name).") + } } catch { engine.output.log("Reinstall of \(package.name) failed.") engine.verbose.log(error) diff --git a/Tests/XPkgTests/XPkgTests.swift b/Tests/XPkgTests/XPkgTests.swift index facc631..88ed9c4 100644 --- a/Tests/XPkgTests/XPkgTests.swift +++ b/Tests/XPkgTests/XPkgTests.swift @@ -15,21 +15,21 @@ class XPkgTests: XCTestCase { let arguments = Arguments(program: "xpkg") let engine = Engine(arguments: arguments) engine.defaultOrgs = ["testorg"] - let remote = engine.remotePackageURL("test", skipValidation: true) + let (remote, _) = engine.remotePackageURL("test", skipValidation: true) XCTAssertEqual(remote, URL(string: "git@github.com:testorg/test")) } func testNameOrg() { let arguments = Arguments(program: "xpkg") let engine = Engine(arguments: arguments) - let remote = engine.remotePackageURL("someorg/someproj") + let (remote, _) = engine.remotePackageURL("someorg/someproj") XCTAssertEqual(remote, URL(string: "git@github.com:someorg/someproj")) } func testRepo() { let arguments = Arguments(program: "xpkg") let engine = Engine(arguments: arguments) - let remote = engine.remotePackageURL("git@mygit.com:someorg/someproj") + let (remote, _) = engine.remotePackageURL("git@mygit.com:someorg/someproj") XCTAssertEqual(remote, URL(string: "git@mygit.com:someorg/someproj")) }