@@ -26,8 +26,6 @@ import struct TSCBasic.StringError
26
26
import struct TSCUtility. Version
27
27
28
28
enum ManifestJSONParser {
29
- private static let filePrefix = " file:// "
30
-
31
29
struct Input : Codable {
32
30
let package : Serialization . Package
33
31
let errors : [ String ]
@@ -56,6 +54,7 @@ enum ManifestJSONParser {
56
54
toolsVersion: ToolsVersion ,
57
55
packageKind: PackageReference . Kind ,
58
56
identityResolver: IdentityResolver ,
57
+ dependencyMapper: DependencyMapper ,
59
58
fileSystem: FileSystem
60
59
) throws -> ManifestJSONParser . Result {
61
60
let decoder = JSONDecoder . makeWithDefaults ( )
@@ -84,6 +83,7 @@ enum ManifestJSONParser {
84
83
toolsVersion: toolsVersion,
85
84
packageKind: packageKind,
86
85
identityResolver: identityResolver,
86
+ dependencyMapper: dependencyMapper,
87
87
fileSystem: fileSystem
88
88
)
89
89
}
@@ -148,180 +148,56 @@ enum ManifestJSONParser {
148
148
toolsVersion: ToolsVersion ,
149
149
packageKind: PackageReference . Kind ,
150
150
identityResolver: IdentityResolver ,
151
+ dependencyMapper: DependencyMapper ,
151
152
fileSystem: FileSystem
152
153
) throws -> PackageDependency {
153
154
switch dependency. kind {
154
155
case . registry( let identity, let requirement) :
155
- return try Self . parseRegistryDependency (
156
- identity: . plain( identity) ,
157
- requirement: . init( requirement) ,
158
- identityResolver: identityResolver
159
- )
160
- case . sourceControl( let name, let location, let requirement) :
161
- return try Self . parseSourceControlDependency (
162
- packageKind: packageKind,
163
- at: location,
164
- name: name,
165
- requirement: . init( requirement) ,
166
- identityResolver: identityResolver,
167
- fileSystem: fileSystem
168
- )
169
- case . fileSystem( let name, let path) :
170
- return try Self . parseFileSystemDependency (
171
- packageKind: packageKind,
172
- at: path,
173
- name: name,
174
- identityResolver: identityResolver,
175
- fileSystem: fileSystem
176
- )
177
- }
178
- }
179
-
180
- private static func parseFileSystemDependency(
181
- packageKind: PackageReference . Kind ,
182
- at location: String ,
183
- name: String ? ,
184
- identityResolver: IdentityResolver ,
185
- fileSystem: FileSystem
186
- ) throws -> PackageDependency {
187
- let location = try sanitizeDependencyLocation ( fileSystem: fileSystem, packageKind: packageKind, dependencyLocation: location)
188
- let path : AbsolutePath
189
- do {
190
- path = try AbsolutePath ( validating: location)
191
- } catch PathValidationError . invalidAbsolutePath( let path) {
192
- throw ManifestParseError . invalidManifestFormat ( " ' \( path) ' is not a valid path for path-based dependencies; use relative or absolute path instead. " , diagnosticFile: nil , compilerCommandLine: nil )
193
- }
194
- let identity = try identityResolver. resolveIdentity ( for: path)
195
- return . fileSystem( identity: identity,
196
- nameForTargetDependencyResolutionOnly: name,
197
- path: path,
198
- productFilter: . everything)
199
- }
200
-
201
- private static func parseSourceControlDependency(
202
- packageKind: PackageReference . Kind ,
203
- at location: String ,
204
- name: String ? ,
205
- requirement: PackageDependency . SourceControl . Requirement ,
206
- identityResolver: IdentityResolver ,
207
- fileSystem: FileSystem
208
- ) throws -> PackageDependency {
209
- // cleans up variants of path based location
210
- var location = try sanitizeDependencyLocation ( fileSystem: fileSystem, packageKind: packageKind, dependencyLocation: location)
211
- // location mapping (aka mirrors) if any
212
- location = identityResolver. mappedLocation ( for: location)
213
- if PackageIdentity . plain ( location) . isRegistry {
214
- // re-mapped to registry
215
- let identity = PackageIdentity . plain ( location)
216
- let registryRequirement : PackageDependency . Registry . Requirement
217
- switch requirement {
218
- case . branch, . revision:
219
- throw StringError ( " invalid mapping of source control to registry, requirement information mismatch: cannot map branch or revision based dependencies to registry. " )
220
- case . exact( let value) :
221
- registryRequirement = . exact( value)
222
- case . range( let value) :
223
- registryRequirement = . range( value)
224
- }
225
- return . registry(
226
- identity: identity,
227
- requirement: registryRequirement,
228
- productFilter: . everything
229
- )
230
- } else if let localPath = try ? AbsolutePath ( validating: location) {
231
- // a package in a git location, may be a remote URL or on disk
232
- // in the future this will check with the registries for the identity of the URL
233
- let identity = try identityResolver. resolveIdentity ( for: localPath)
234
- return . localSourceControl(
235
- identity: identity,
236
- nameForTargetDependencyResolutionOnly: name,
237
- path: localPath,
238
- requirement: requirement,
239
- productFilter: . everything
240
- )
241
- } else {
242
- let url = SourceControlURL ( location)
243
- // in the future this will check with the registries for the identity of the URL
244
- let identity = try identityResolver. resolveIdentity ( for: url)
245
- return . remoteSourceControl(
246
- identity: identity,
247
- nameForTargetDependencyResolutionOnly: name,
248
- url: url,
249
- requirement: requirement,
250
- productFilter: . everything
251
- )
252
- }
253
- }
254
-
255
- private static func parseRegistryDependency(
256
- identity: PackageIdentity ,
257
- requirement: PackageDependency . Registry . Requirement ,
258
- identityResolver: IdentityResolver
259
- ) throws -> PackageDependency {
260
- // location mapping (aka mirrors) if any
261
- let location = identityResolver. mappedLocation ( for: identity. description)
262
- if PackageIdentity . plain ( location) . isRegistry {
263
- // re-mapped to registry
264
- let identity = PackageIdentity . plain ( location)
265
- return . registry(
266
- identity: identity,
267
- requirement: requirement,
268
- productFilter: . everything
269
- )
270
- } else if let url = URL ( string: location) {
271
- let SourceControlURL = SourceControlURL ( url)
272
- // in the future this will check with the registries for the identity of the URL
273
- let identity = try identityResolver. resolveIdentity ( for: SourceControlURL)
274
- let sourceControlRequirement : PackageDependency . SourceControl . Requirement
275
- switch requirement {
276
- case . exact( let value) :
277
- sourceControlRequirement = . exact( value)
278
- case . range( let value) :
279
- sourceControlRequirement = . range( value)
156
+ do {
157
+ return try dependencyMapper. mappedDependency (
158
+ packageKind: . registry( . plain( identity) ) ,
159
+ at: identity,
160
+ nameForTargetDependencyResolutionOnly: nil ,
161
+ requirement: . init( requirement) ,
162
+ productFilter: . everything,
163
+ fileSystem: fileSystem
164
+ )
165
+ } catch let error as TSCBasic . PathValidationError {
166
+ throw error
167
+ } catch {
168
+ throw ManifestParseError . invalidManifestFormat ( " \( error. interpolationDescription) " , diagnosticFile: nil , compilerCommandLine: nil )
280
169
}
281
- return . remoteSourceControl(
282
- identity: identity,
283
- nameForTargetDependencyResolutionOnly: identity. description,
284
- url: SourceControlURL,
285
- requirement: sourceControlRequirement,
286
- productFilter: . everything
287
- )
288
- } else {
289
- throw StringError ( " invalid location: \( location) " )
290
- }
291
- }
292
-
293
- private static func sanitizeDependencyLocation( fileSystem: FileSystem , packageKind: PackageReference . Kind , dependencyLocation: String ) throws -> String {
294
- if dependencyLocation. hasPrefix ( " ~/ " ) {
295
- // If the dependency URL starts with '~/', try to expand it.
296
- return try AbsolutePath ( validating: String ( dependencyLocation. dropFirst ( 2 ) ) , relativeTo: fileSystem. homeDirectory) . pathString
297
- } else if dependencyLocation. hasPrefix ( filePrefix) {
298
- // FIXME: SwiftPM can't handle file locations with file:// scheme so we need to
299
- // strip that. We need to design a Location data structure for SwiftPM.
300
- let location = String ( dependencyLocation. dropFirst ( filePrefix. count) )
301
- let hostnameComponent = location. prefix ( while: { $0 != " / " } )
302
- guard hostnameComponent. isEmpty else {
303
- if hostnameComponent == " .. " {
304
- throw ManifestParseError . invalidManifestFormat (
305
- " file:// URLs cannot be relative, did you mean to use '.package(path:)'? " , diagnosticFile: nil , compilerCommandLine: nil
170
+ case . sourceControl( let name, let location, let requirement) :
171
+ do {
172
+ return try dependencyMapper. mappedDependency (
173
+ packageKind: packageKind,
174
+ at: location,
175
+ nameForTargetDependencyResolutionOnly: name,
176
+ requirement: . init( requirement) ,
177
+ productFilter: . everything,
178
+ fileSystem: fileSystem
306
179
)
307
- }
308
- throw ManifestParseError . invalidManifestFormat (
309
- " file:// URLs with hostnames are not supported, are you missing a '/'? " , diagnosticFile : nil , compilerCommandLine : nil
310
- )
180
+ } catch let error as TSCBasic . PathValidationError {
181
+ throw error
182
+ } catch {
183
+ throw ManifestParseError . invalidManifestFormat ( " \( error . interpolationDescription ) " , diagnosticFile : nil , compilerCommandLine : nil )
311
184
}
312
- return try AbsolutePath ( validating: location) . pathString
313
- } else if parseScheme ( dependencyLocation) == nil {
314
- // If the URL has no scheme, we treat it as a path (either absolute or relative to the base URL).
315
- switch packageKind {
316
- case . root( let packagePath) , . fileSystem( let packagePath) , . localSourceControl( let packagePath) :
317
- return try AbsolutePath ( validating: dependencyLocation, relativeTo: packagePath) . pathString
318
- case . remoteSourceControl, . registry:
319
- // nothing to "fix"
320
- return dependencyLocation
185
+ case . fileSystem( let name, let path) :
186
+ // FIXME: This case should really also be handled by `mappedDependency()` but that is currently impossible because `sanitizeDependencyLocation()` relies on the fact that we're calling it with an incorrect (file-system) `packageKind` for SCM-based dependencies, so we have no ability to distinguish between actual file-system dependencies and SCM-based ones without introducing some secondary package kind or other flag to pick the different behaviors. That seemed much worse than having this extra code path be here and `DefaultIdentityResolver.sanitizeDependencyLocation()` being public, but it should eventually be cleaned up. It seems to me as if that will mostly be a case of fixing the test suite to not rely on these fairly arbitrary behaviors.
187
+
188
+ // cleans up variants of path based location
189
+ let location = try DefaultDependencyMapper . sanitizeDependencyLocation ( fileSystem: fileSystem, packageKind: packageKind, dependencyLocation: path)
190
+ let path : AbsolutePath
191
+ do {
192
+ path = try AbsolutePath ( validating: location)
193
+ } catch PathValidationError . invalidAbsolutePath( let path) {
194
+ throw ManifestParseError . invalidManifestFormat ( " ' \( path) ' is not a valid path for path-based dependencies; use relative or absolute path instead. " , diagnosticFile: nil , compilerCommandLine: nil )
321
195
}
322
- } else {
323
- // nothing to "fix"
324
- return dependencyLocation
196
+ let identity = try identityResolver. resolveIdentity ( for: path)
197
+ return . fileSystem( identity: identity,
198
+ nameForTargetDependencyResolutionOnly: name,
199
+ path: path,
200
+ productFilter: . everything)
325
201
}
326
202
}
327
203
@@ -392,33 +268,6 @@ enum ManifestJSONParser {
392
268
return settings
393
269
}
394
270
395
- /// Parses the URL type of a git repository
396
- /// e.g. https://github.com/apple/swift returns "https"
397
- /// e.g. git@github.com:apple/swift returns "git"
398
- ///
399
- /// This is *not* a generic URI scheme parser!
400
- private static func parseScheme( _ location: String ) -> String ? {
401
- func prefixOfSplitBy( _ delimiter: String ) -> String ? {
402
- let ( head, tail) = location. spm_split ( around: delimiter)
403
- if tail == nil {
404
- //not found
405
- return nil
406
- } else {
407
- //found, return head
408
- //lowercase the "scheme", as specified by the URI RFC (just in case)
409
- return head. lowercased ( )
410
- }
411
- }
412
-
413
- for delim in [ " :// " , " @ " ] {
414
- if let found = prefixOfSplitBy ( delim) , !found. contains ( " / " ) {
415
- return found
416
- }
417
- }
418
-
419
- return nil
420
- }
421
-
422
271
/// Looks for Xcode-style build setting macros "$()".
423
272
fileprivate static let invalidValueRegex = try ! RegEx ( pattern: #"(\$\(.*?\))"# )
424
273
}
0 commit comments