Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Sources/XToolSupport/SDKBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ struct SDKBuilder {
}

private func installToolset(in output: URL) async throws {
// tag from https://github.com/kabiroberai/darwin-tools-linux-llvm
// tag from https://github.com/xtool-org/darwin-tools-linux-llvm
let darwinToolsVersion = "1.0.1"

let toolsetDir = output.appendingPathComponent("toolset")
Expand All @@ -169,7 +169,7 @@ struct SDKBuilder {

@Dependency(\.httpClient) var httpClient
let url = URL(string: """
https://github.com/kabiroberai/darwin-tools-linux-llvm/releases/download/\
https://github.com/xtool-org/darwin-tools-linux-llvm/releases/download/\
v\(darwinToolsVersion)/toolset-\(arch.rawValue).tar.gz
""")!
let (response, body) = try await httpClient.send(HTTPRequest(url: url))
Expand Down
95 changes: 62 additions & 33 deletions Sources/XToolSupport/SDKCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ struct SDKCommand: AsyncParsableCommand {
DevSDKInstallCommand.self,
DevSDKRemoveCommand.self,
DevSDKBuildCommand.self,
DevSDKStatusCommand.self,
],
defaultSubcommand: DevSDKInstallCommand.self
)
Expand Down Expand Up @@ -98,19 +99,30 @@ struct DevSDKRemoveCommand: AsyncParsableCommand {
)

func run() async throws {
guard let sdk = try DarwinSDK.current() else {
guard let sdk = try await DarwinSDK.current() else {
throw Console.Error("Cannot remove SDK: no Darwin SDK installed")
}
try sdk.remove()
print("Uninstalled SDK")
}
}

struct DarwinSDK {
private static let sdksDir = URL(fileURLWithPath: NSHomeDirectory())
.appendingPathComponent(".swiftpm/swift-sdks")
.resolvingSymlinksInPath()
struct DevSDKStatusCommand: AsyncParsableCommand {
static let configuration = CommandConfiguration(
commandName: "status",
abstract: "Get the status of the Darwin Swift SDK"
)

func run() async throws {
if let sdk = try await DarwinSDK.current() {
print("Installed at \(sdk.bundle.path)")
} else {
print("Not installed")
}
}
}

struct DarwinSDK {
let bundle: URL
let version: String

Expand All @@ -126,36 +138,55 @@ struct DarwinSDK {
}
}

@discardableResult
static func install(movingFrom path: String) throws -> DarwinSDK {
static func install(from path: String) async throws {
// we can't just move into ~/.swiftpm/swift-sdks because the swiftpm directory
// location depends on factors like $XDG_CONFIG_HOME. Rather than replicating
// SwiftPM's logic, which may change, it's more reliable to directly invoke
// `swift sdk install`. See: https://github.com/xtool-org/xtool/pull/40

let url = URL(fileURLWithPath: path)
guard DarwinSDK(bundle: url) != nil else { throw Console.Error("Invalid Darwin SDK at '\(path)'")}
let targetURL = sdksDir.appendingPathComponent("darwin.artifactbundle")
if targetURL.exists {
throw Console.Error("Darwin SDK is already installed at '\(targetURL.path)'. Please remove it first.")
}
try? FileManager.default.createDirectory(at: sdksDir, withIntermediateDirectories: true)
try FileManager.default.moveItem(at: url, to: targetURL)
guard let sdk = DarwinSDK(bundle: targetURL) else {
throw Console.Error("Darwin SDK failed to install")
}
return sdk

let process = Process()
process.executableURL = try await ToolRegistry.locate("swift")
process.arguments = ["sdk", "install", url.path]
try await process.runUntilExit()
}

static func current() throws -> DarwinSDK? {
let sdks = (try? FileManager.default.contentsOfDirectory(at: sdksDir, includingPropertiesForKeys: nil)) ?? []
let darwinSDKs = sdks.compactMap { DarwinSDK(bundle: $0) }
switch darwinSDKs.count {
case 0:
static func current() async throws -> DarwinSDK? {
let output = Pipe()

let process = Process()
process.executableURL = try await ToolRegistry.locate("swift")
process.arguments = ["sdk", "configure", "darwin", "arm64-apple-ios", "--show-configuration"]
process.standardOutput = output
process.standardError = FileHandle.nullDevice

async let outputData = Data(reading: output.fileHandleForReading)

do {
try await process.runUntilExit()
} catch Process.Failure.exit {
return nil
case 1:
return darwinSDKs[0]
default:
throw Console.Error("""
You have multiple copies of the Darwin SDK installed. Please delete all but one to continue.
\(darwinSDKs.map { "- \($0.bundle.path) (version '\($0.version)')" }.joined(separator: "\n"))
""")
}

// should be something like
// swiftResourcesPath: /home/user/.swiftpm/swift-sdks/darwin.artifactbundle/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift
let resourcesPathPrefix = "swiftResourcesPath: "
let outputString = String(decoding: try await outputData, as: UTF8.self)

guard let resourcesPath = outputString
.split(separator: "\n")
.first(where: { $0.hasPrefix(resourcesPathPrefix) })?
.dropFirst(resourcesPathPrefix.count)
else { return nil }

var resourcesURL = URL(fileURLWithPath: String(resourcesPath))
for _ in 0..<6 {
resourcesURL = resourcesURL.deletingLastPathComponent()
}

return DarwinSDK(bundle: resourcesURL)
}

func isUpToDate() -> Bool {
Expand Down Expand Up @@ -210,7 +241,7 @@ struct InstallSDKOperation {
#if os(macOS)
print("Skipping SDK install; the iOS SDK ships with Xcode on macOS")
#else
if let sdk = try DarwinSDK.current() {
if let sdk = try await DarwinSDK.current() {
print("Removing existing SDK...")
try sdk.remove()
}
Expand All @@ -222,12 +253,10 @@ struct InstallSDKOperation {
let builder = SDKBuilder(input: input, outputPath: tempDir.url.path, arch: arch)
let sdkPath = try await builder.buildSDK()

try DarwinSDK.install(movingFrom: sdkPath)
try await DarwinSDK.install(from: sdkPath)

// don't destroy tempDir before this point
withExtendedLifetime(tempDir) {}

print("Installed darwin.artifactbundle")
#endif
}
}
2 changes: 1 addition & 1 deletion Sources/XToolSupport/SetupCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ struct SetupOperation {
print("Skipping Darwin SDK setup since we're on macOS.")
}
#else
switch try DarwinSDK.current()?.isUpToDate() {
switch try await DarwinSDK.current()?.isUpToDate() {
case true?:
if !quiet {
print("Darwin SDK is up to date.")
Expand Down
Loading