Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "version" argument to "installed" function, printing Xcode's installation path #220

Merged
merged 1 commit into from
Sep 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 15 additions & 0 deletions Sources/XcodesKit/XcodeInstaller.swift
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,21 @@ public final class XcodeInstaller {
}
}

public func printXcodePath(ofVersion versionString: String, searchingIn directory: Path) -> Promise<Void> {
return firstly { () -> Promise<Void> in
guard let version = Version(xcodeVersion: versionString) else {
throw Error.invalidVersion(versionString)
}
let installedXcodes = Current.files.installedXcodes(directory)
.sorted { $0.version < $1.version }
guard let installedXcode = installedXcodes.first(withVersion: version) else {
throw Error.versionNotInstalled(version)
}
Current.logging.log(installedXcode.path.string)
return Promise.value(())
}
}

func unarchiveAndMoveXIP(at source: URL, to destination: URL, experimentalUnxip: Bool) -> Promise<URL> {
return firstly { () -> Promise<Void> in
Current.logging.log(InstallationStep.unarchiving(experimentalUnxip: experimentalUnxip).description)
Expand Down
16 changes: 14 additions & 2 deletions Sources/xcodes/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,10 @@ struct Xcodes: ParsableCommand {
static var configuration = CommandConfiguration(
abstract: "List the versions of Xcode that are installed"
)

@Argument(help: "The version installed to which to print the path for",
completion: .custom { _ in Current.files.installedXcodes(getDirectory(possibleDirectory: nil)).sorted { $0.version < $1.version }.map { $0.version.appleDescription } })
var version: [String] = []

@OptionGroup
var globalDirectory: GlobalDirectoryOption
Expand All @@ -252,8 +256,16 @@ struct Xcodes: ParsableCommand {
Rainbow.enabled = Rainbow.enabled && globalColor.color

let directory = getDirectory(possibleDirectory: globalDirectory.directory)

installer.printInstalledXcodes(directory: directory)

installer.printXcodePath(ofVersion: version.joined(separator: " "), searchingIn: directory)
.recover { error -> Promise<Void> in
switch error {
case XcodeInstaller.Error.invalidVersion:
return installer.printInstalledXcodes(directory: directory)
default:
throw error
}
}
.done { Installed.exit() }
.catch { error in Installed.exit(withLegibleError: error) }

Expand Down
78 changes: 78 additions & 0 deletions Tests/XcodesKitTests/XcodesKitTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1212,6 +1212,84 @@ final class XcodesKitTests: XCTestCase {
"""
)
}

func test_Installed_WithValidVersion_PrintsXcodePath() {
var log = ""
XcodesKit.Current.logging.log = { log.append($0 + "\n") }

// There are installed Xcodes
Current.files.contentsAtPath = { path in
if path == "/Applications/Xcode-2.0.0.app/Contents/Info.plist" {
let url = Bundle.module.url(forResource: "Stub-2.0.0.Info", withExtension: "plist", subdirectory: "Fixtures")!
return try? Data(contentsOf: url)
}
else if path.contains("version.plist") {
let url = Bundle.module.url(forResource: "Stub.version", withExtension: "plist", subdirectory: "Fixtures")!
return try? Data(contentsOf: url)
}
else {
return nil
}
}
let installedXcodes = [
InstalledXcode(path: Path("/Applications/Xcode-2.0.0.app")!)!,
]
Current.files.installedXcodes = { _ in installedXcodes }

// One is selected
Current.shell.xcodeSelectPrintPath = {
Promise.value((status: 0, out: "/Applications/Xcode-2.0.0.app/Contents/Developer", err: ""))
}

// Standard output is not an interactive terminal
Current.shell.isatty = { false }

installer.printXcodePath(ofVersion: "2", searchingIn: Path.root/"Applications")
.cauterize()

XCTAssertEqual(
log,
"""
/Applications/Xcode-2.0.0.app

"""
)
}

func test_Installed_WithUninstalledVersion_ThrowsError() {
var log = ""
XcodesKit.Current.logging.log = { log.append($0 + "\n") }

// There are installed Xcodes
Current.files.contentsAtPath = { path in
if path == "/Applications/Xcode-2.0.0.app/Contents/Info.plist" {
let url = Bundle.module.url(forResource: "Stub-2.0.0.Info", withExtension: "plist", subdirectory: "Fixtures")!
return try? Data(contentsOf: url)
}
else if path.contains("version.plist") {
let url = Bundle.module.url(forResource: "Stub.version", withExtension: "plist", subdirectory: "Fixtures")!
return try? Data(contentsOf: url)
}
else {
return nil
}
}
let installedXcodes = [
InstalledXcode(path: Path("/Applications/Xcode-2.0.0.app")!)!,
]
Current.files.installedXcodes = { _ in installedXcodes }

// One is selected
Current.shell.xcodeSelectPrintPath = {
Promise.value((status: 0, out: "/Applications/Xcode-2.0.0.app/Contents/Developer", err: ""))
}

// Standard output is not an interactive terminal
Current.shell.isatty = { false }

installer.printXcodePath(ofVersion: "3", searchingIn: Path.root/"Applications")
.catch { error in XCTAssertEqual(error as! XcodeInstaller.Error, XcodeInstaller.Error.versionNotInstalled(Version(xcodeVersion: "3")!)) }
}

func test_Signout_WithExistingSession() {
var keychainDidRemove = false
Expand Down