Skip to content

Commit 2b9a29f

Browse files
authored
[Collections] Better handling of spaces in collection file path (#3412)
Motivation: Try adding a local package collection file with space(s) in the filename and it would result in error "Error: Invalid argument 'collectionUrl'". Modifications: In case `URL(string:)` fails, try `URL(fileURLWithPath:)` if the path starts with `file://`. This initializer escapes whitespaces appropriately. rdar://76732268
1 parent 8ee8d40 commit 2b9a29f

File tree

1 file changed

+23
-17
lines changed

1 file changed

+23
-17
lines changed

Sources/Commands/SwiftPackageCollectionsTool.swift

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ public struct SwiftPackageCollectionsTool: ParsableCommand {
108108
static let configuration = CommandConfiguration(abstract: "Add a new collection")
109109

110110
@Argument(help: "URL of the collection to add")
111-
var collectionUrl: String
111+
var collectionURL: String
112112

113113
@Option(name: .long, help: "Sort order for the added collection")
114114
var order: Int?
@@ -120,11 +120,9 @@ public struct SwiftPackageCollectionsTool: ParsableCommand {
120120
var skipSignatureCheck: Bool = false
121121

122122
mutating func run() throws {
123-
guard let collectionUrl = URL(string: collectionUrl) else {
124-
throw CollectionsError.invalidArgument("collectionUrl")
125-
}
123+
let collectionURL = try url(self.collectionURL)
126124

127-
let source = PackageCollectionsModel.CollectionSource(type: .json, url: collectionUrl, skipSignatureCheck: self.skipSignatureCheck)
125+
let source = PackageCollectionsModel.CollectionSource(type: .json, url: collectionURL, skipSignatureCheck: self.skipSignatureCheck)
128126
let collection: PackageCollectionsModel.Collection = try with { collections in
129127
do {
130128
let userTrusted = self.trustUnsigned
@@ -155,14 +153,12 @@ public struct SwiftPackageCollectionsTool: ParsableCommand {
155153
static let configuration = CommandConfiguration(abstract: "Remove a configured collection")
156154

157155
@Argument(help: "URL of the collection to remove")
158-
var collectionUrl: String
156+
var collectionURL: String
159157

160158
mutating func run() throws {
161-
guard let collectionUrl = URL(string: collectionUrl) else {
162-
throw CollectionsError.invalidArgument("collectionUrl")
163-
}
159+
let collectionURL = try url(self.collectionURL)
164160

165-
let source = PackageCollectionsModel.CollectionSource(type: .json, url: collectionUrl)
161+
let source = PackageCollectionsModel.CollectionSource(type: .json, url: collectionURL)
166162
try with { collections in
167163
let collection = try tsc_await { collections.getCollection(source, callback: $0) }
168164
_ = try tsc_await { collections.removeCollection(source, callback: $0) }
@@ -229,7 +225,7 @@ public struct SwiftPackageCollectionsTool: ParsableCommand {
229225
var jsonOptions: JSONOptions
230226

231227
@Argument(help: "URL of the package or collection to get information for")
232-
var packageUrl: String
228+
var packageURL: String
233229

234230
@Option(name: .long, help: "Version of the package to get information for")
235231
var version: String?
@@ -268,8 +264,8 @@ public struct SwiftPackageCollectionsTool: ParsableCommand {
268264

269265
mutating func run() throws {
270266
try with { collections in
271-
let identity = PackageIdentity(url: packageUrl)
272-
let reference = PackageReference.remote(identity: identity, location: packageUrl)
267+
let identity = PackageIdentity(url: packageURL)
268+
let reference = PackageReference.remote(identity: identity, location: packageURL)
273269

274270
do { // assume URL is for a package in an imported collection
275271
let result = try tsc_await { collections.getPackageMetadata(reference, callback: $0) }
@@ -307,12 +303,10 @@ public struct SwiftPackageCollectionsTool: ParsableCommand {
307303
throw error
308304
}
309305

310-
guard let collectionUrl = URL(string: packageUrl) else {
311-
throw CollectionsError.invalidArgument("collectionUrl")
312-
}
306+
let collectionURL = try url(self.packageURL)
313307

314308
do {
315-
let source = PackageCollectionsModel.CollectionSource(type: .json, url: collectionUrl)
309+
let source = PackageCollectionsModel.CollectionSource(type: .json, url: collectionURL)
316310
let collection = try tsc_await { collections.getCollection(source, callback: $0) }
317311

318312
let description = optionalRow("Description", collection.overview)
@@ -374,4 +368,16 @@ private extension ParsableCommand {
374368

375369
return try handler(collections)
376370
}
371+
372+
func url(_ urlString: String) throws -> Foundation.URL {
373+
guard let url = URL(string: urlString) else {
374+
let filePrefix = "file://"
375+
guard urlString.hasPrefix(filePrefix) else {
376+
throw CollectionsError.invalidArgument("collectionURL")
377+
}
378+
// URL(fileURLWithPath:) can handle whitespaces in path
379+
return URL(fileURLWithPath: String(urlString.dropFirst(filePrefix.count)))
380+
}
381+
return url
382+
}
377383
}

0 commit comments

Comments
 (0)