From 7a5dfd2ccdf38bb38b3709aef00da79b6ed2284a Mon Sep 17 00:00:00 2001 From: Kabir Oberai Date: Sun, 4 Jan 2026 21:55:35 -0500 Subject: [PATCH] Validate SDK before overwriting (#192) Running an invalid `sdk` subcommand like `xtool sdk list` (there's no `list` subcommand) is interpreted as "install the sdk at path `./list`". We previously unconditionally removed the existing SDK during installation. By switching the order so that we validate the path first, we avoid performing a potentially destructive action unless we have clear intent. See #186. Before: ```bash $ xtool sdk list Removing existing SDK... # destructive! Error: Could not read file or directory at path 'list'. ``` After: ```bash $ xtool sdk list Error: Could not read file or directory at path 'list'. See 'xtool help sdk' for usage. ``` --- Sources/XToolSupport/SDKBuilder.swift | 5 ++++- Sources/XToolSupport/SDKCommand.swift | 7 ++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Sources/XToolSupport/SDKBuilder.swift b/Sources/XToolSupport/SDKBuilder.swift index c940fbc..ef3bc6c 100644 --- a/Sources/XToolSupport/SDKBuilder.swift +++ b/Sources/XToolSupport/SDKBuilder.swift @@ -18,7 +18,10 @@ struct SDKBuilder { init(path: String) throws { var isDir: ObjCBool = false guard FileManager.default.fileExists(atPath: path, isDirectory: &isDir) else { - throw Console.Error("Could not read file or directory at path '\(path)'") + throw Console.Error(""" + Could not read file or directory at path '\(path)'. + See 'xtool help sdk' for usage. + """) } let url = URL(fileURLWithPath: path) diff --git a/Sources/XToolSupport/SDKCommand.swift b/Sources/XToolSupport/SDKCommand.swift index d587ec8..18f550d 100644 --- a/Sources/XToolSupport/SDKCommand.swift +++ b/Sources/XToolSupport/SDKCommand.swift @@ -243,14 +243,15 @@ struct InstallSDKOperation { #if os(macOS) print("Skipping SDK install; the iOS SDK ships with Xcode on macOS") #else + // validate input before removing existing SDK + let input = try SDKBuilder.Input(path: path) + let arch = try ArchSelection.auto.sdkBuilderArch + if let sdk = try await DarwinSDK.current() { print("Removing existing SDK...") try sdk.remove() } - let input = try SDKBuilder.Input(path: path) - let arch = try ArchSelection.auto.sdkBuilderArch - let tempDir = try TemporaryDirectory(name: "DarwinSDKBuild") let builder = SDKBuilder(input: input, outputPath: tempDir.url.path, arch: arch) let sdkPath = try await builder.buildSDK()