Skip to content

Commit

Permalink
Add select and update options to install
Browse files Browse the repository at this point in the history
  • Loading branch information
tahirmt committed Mar 17, 2022
1 parent fbe2b25 commit 8061e41
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 15 deletions.
5 changes: 5 additions & 0 deletions Sources/XcodesKit/XcodeInstaller.swift
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,11 @@ public final class XcodeInstaller {
Current.shell.exit(0)
}
}

/// Perform the install but don't exit out but return the installed xcode version as output instead
public func installWithoutLogging(_ installationType: InstallationType, dataSource: DataSource, downloader: Downloader, destination: Path, experimentalUnxip: Bool) -> Promise<InstalledXcode> {
self.install(installationType, dataSource: dataSource, downloader: downloader, destination: destination, attemptNumber: 0, experimentalUnxip: experimentalUnxip)
}

private func install(_ installationType: InstallationType, dataSource: DataSource, downloader: Downloader, destination: Path, attemptNumber: Int, experimentalUnxip: Bool) -> Promise<InstalledXcode> {
return firstly { () -> Promise<(Xcode, URL)> in
Expand Down
23 changes: 14 additions & 9 deletions Sources/XcodesKit/XcodeSelect.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Path
import Version
import Rainbow

public func selectXcode(shouldPrint: Bool, pathOrVersion: String, directory: Path) -> Promise<Void> {
public func selectXcode(shouldPrint: Bool, pathOrVersion: String, directory: Path, fallbackToInteractive: Bool = true) -> Promise<Void> {
firstly { () -> Promise<ProcessOutput> in
Current.shell.xcodeSelectPrintPath()
}
Expand Down Expand Up @@ -49,18 +49,23 @@ public func selectXcode(shouldPrint: Bool, pathOrVersion: String, directory: Pat
return Promise.value(())
}

return selectXcodeAtPath(pathToSelect)
let selectPromise = selectXcodeAtPath(pathToSelect)
.done { output in
Current.logging.log("Selected \(output.out)".green)
Current.shell.exit(0)
}
.recover { _ in
selectXcodeInteractively(currentPath: output.out, directory: directory)
.done { output in
Current.logging.log("Selected \(output.out)".green)
Current.shell.exit(0)
}
}
if fallbackToInteractive {
return selectPromise
.recover { _ in
selectXcodeInteractively(currentPath: output.out, directory: directory)
.done { output in
Current.logging.log("Selected \(output.out)".green)
Current.shell.exit(0)
}
}
} else {
return selectPromise
}
}
}
}
Expand Down
67 changes: 61 additions & 6 deletions Sources/xcodes/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ struct Xcodes: ParsableCommand {
}

struct Install: ParsableCommand {
enum InstallError: Error {
case notAlreadyInstalled
}
static var configuration = CommandConfiguration(
abstract: "Download and install a specific version of Xcode",
discussion: """
Expand Down Expand Up @@ -182,6 +185,15 @@ struct Xcodes: ParsableCommand {

@Flag(help: "Don't use aria2 to download Xcode, even if its available.")
var noAria2: Bool = false

@Flag(help: "Select the installed xcode version after installation.")
var select: Bool = false

@Flag(help: "Whether to update the list before installing")
var update: Bool = false

@ArgumentParser.Flag(name: [.customShort("p"), .customLong("print-path")], help: "Print the path of the selected Xcode")
var print: Bool = false

@Flag(help: "Use the experimental unxip functionality. May speed up unarchiving by up to 2-3x.")
var experimentalUnxip: Bool = false
Expand Down Expand Up @@ -220,17 +232,60 @@ struct Xcodes: ParsableCommand {
}

let destination = getDirectory(possibleDirectory: directory)

installer.install(installation, dataSource: globalDataSource.dataSource, downloader: downloader, destination: destination, experimentalUnxip: experimentalUnxip)
.done { Install.exit() }

if select == false {
// install normally
installer.install(installation, dataSource: globalDataSource.dataSource, downloader: downloader, destination: destination, experimentalUnxip: experimentalUnxip)
.done { Install.exit() }
.catch { error in
Install.processDownloadOrInstall(error: error)
}
} else {
// check if the version is already installed and try to select it
firstly { () -> Promise<Void> in
if case .version(let version) = installation {
return selectXcode(shouldPrint: print, pathOrVersion: version, directory: destination, fallbackToInteractive: false)
} else {
return Promise { _ in
throw InstallError.notAlreadyInstalled
}
}
}
.done { Install.exit() } // successfully selected
.catch { error in
Install.processDownloadOrInstall(error: error)
// select failed. Xcode must not be installed.
firstly { () -> Promise<InstalledXcode> in
// update the list before installing only for version type because the other types already update internally
if update, case .version = installation {
Current.logging.log("Updating...")
return xcodeList.update(dataSource: globalDataSource.dataSource)
.then { _ -> Promise<InstalledXcode> in
installer.installWithoutLogging(installation, dataSource: globalDataSource.dataSource, downloader: downloader, destination: destination, experimentalUnxip: experimentalUnxip)
}
} else {
// install
return installer.installWithoutLogging(installation, dataSource: globalDataSource.dataSource, downloader: downloader, destination: destination, experimentalUnxip: experimentalUnxip)
}
}
.then { xcode -> Promise<Void> in
Current.logging.log("\nXcode \(xcode.version.descriptionWithoutBuildMetadata) has been installed to \(xcode.path.string)".green)

// Install was successful, now select it
return selectXcode(shouldPrint: print, pathOrVersion: xcode.path.string, directory: destination, fallbackToInteractive: false)
}
.done {
Install.exit()
}
.catch { error in
Install.processDownloadOrInstall(error: error)
}
}

}

RunLoop.current.run()
}
}

struct Installed: ParsableCommand {
static var configuration = CommandConfiguration(
abstract: "List the versions of Xcode that are installed"
Expand Down

0 comments on commit 8061e41

Please sign in to comment.