Skip to content

Commit 9eb51f4

Browse files
authored
refactor dependency mapping (#7055)
motivation: address broken validation when using relative path in remote depednencies changes: * simply to have a single API that encapsulated all the mapping use cases * introduce intermediate MappablePackageDependency model to converge the various implementations * simplify the mapping logic to better address realtive paths * add and adjust tests rdar://100823575
1 parent 97ef9ed commit 9eb51f4

File tree

4 files changed

+325
-169
lines changed

4 files changed

+325
-169
lines changed

Sources/PackageGraph/PackageGraphRoot.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,13 @@ public struct PackageGraphRoot {
5656

5757
return self._dependencies.map { dependency in
5858
do {
59-
return try dependencyMapper.mappedDependency(for: dependency, fileSystem: localFileSystem)
59+
return try dependencyMapper.mappedDependency(
60+
MappablePackageDependency(
61+
dependency,
62+
parentPackagePath: localFileSystem.currentWorkingDirectory ?? .root
63+
),
64+
fileSystem: localFileSystem
65+
)
6066
} catch {
6167
observabilityScope.emit(warning: "could not map dependency \(dependency.identity): \(error.interpolationDescription)")
6268
return dependency

Sources/PackageLoading/ManifestJSONParser.swift

Lines changed: 54 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ enum ManifestJSONParser {
5353
v4 jsonString: String,
5454
toolsVersion: ToolsVersion,
5555
packageKind: PackageReference.Kind,
56+
packagePath: AbsolutePath,
5657
identityResolver: IdentityResolver,
5758
dependencyMapper: DependencyMapper,
5859
fileSystem: FileSystem
@@ -77,11 +78,26 @@ enum ManifestJSONParser {
7778
throw ManifestParseError.runtimeManifestErrors(input.errors)
7879
}
7980

81+
var packagePath = packagePath
82+
switch packageKind {
83+
case .localSourceControl(let _packagePath):
84+
// we have a more accurate path than the virtual one
85+
packagePath = _packagePath
86+
case .root(let _packagePath), .fileSystem(let _packagePath):
87+
// we dont have a more accurate path, and they should be the same
88+
// asserting (debug only) to make sure refactoring is correct 11/2023
89+
assert(packagePath == _packagePath, "expecting package path '\(packagePath)' to be the same as '\(_packagePath)'")
90+
break
91+
case .remoteSourceControl, .registry:
92+
// we dont have a more accurate path
93+
break
94+
}
95+
8096
let dependencies = try input.package.dependencies.map {
8197
try Self.parseDependency(
8298
dependency: $0,
8399
toolsVersion: toolsVersion,
84-
packageKind: packageKind,
100+
parentPackagePath: packagePath,
85101
identityResolver: identityResolver,
86102
dependencyMapper: dependencyMapper,
87103
fileSystem: fileSystem
@@ -146,58 +162,24 @@ enum ManifestJSONParser {
146162
private static func parseDependency(
147163
dependency: Serialization.PackageDependency,
148164
toolsVersion: ToolsVersion,
149-
packageKind: PackageReference.Kind,
165+
parentPackagePath: AbsolutePath,
150166
identityResolver: IdentityResolver,
151167
dependencyMapper: DependencyMapper,
152168
fileSystem: FileSystem
153169
) throws -> PackageDependency {
154-
switch dependency.kind {
155-
case .registry(let identity, let requirement):
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)
169-
}
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
179-
)
180-
} catch let error as TSCBasic.PathValidationError {
181-
throw error
182-
} catch {
183-
throw ManifestParseError.invalidManifestFormat("\(error.interpolationDescription)", diagnosticFile: nil, compilerCommandLine: nil)
184-
}
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) {
170+
do {
171+
return try dependencyMapper.mappedDependency(
172+
MappablePackageDependency(dependency, parentPackagePath: parentPackagePath),
173+
fileSystem: fileSystem
174+
)
175+
} catch let error as TSCBasic.PathValidationError {
176+
if case .fileSystem(_, let path) = dependency.kind {
194177
throw ManifestParseError.invalidManifestFormat("'\(path)' is not a valid path for path-based dependencies; use relative or absolute path instead.", diagnosticFile: nil, compilerCommandLine: nil)
178+
} else {
179+
throw error
195180
}
196-
let identity = try identityResolver.resolveIdentity(for: path)
197-
return .fileSystem(identity: identity,
198-
nameForTargetDependencyResolutionOnly: name,
199-
path: path,
200-
productFilter: .everything)
181+
} catch {
182+
throw ManifestParseError.invalidManifestFormat("\(error.interpolationDescription)", diagnosticFile: nil, compilerCommandLine: nil)
201183
}
202184
}
203185

@@ -596,3 +578,28 @@ extension TargetBuildSettingDescription.Setting {
596578
)
597579
}
598580
}
581+
582+
extension MappablePackageDependency {
583+
fileprivate init(_ seed: Serialization.PackageDependency, parentPackagePath: AbsolutePath) {
584+
switch seed.kind {
585+
case .fileSystem(let name, let path):
586+
self.init(
587+
parentPackagePath: parentPackagePath,
588+
kind: .fileSystem(name: name, path: path),
589+
productFilter: .everything
590+
)
591+
case .sourceControl(let name, let location, let requirement):
592+
self.init(
593+
parentPackagePath: parentPackagePath,
594+
kind: .sourceControl(name: name, location: location, requirement: .init(requirement)),
595+
productFilter: .everything
596+
)
597+
case .registry(let id, let requirement):
598+
self.init(
599+
parentPackagePath: parentPackagePath,
600+
kind: .registry(id: id, requirement: .init(requirement)),
601+
productFilter: .everything
602+
)
603+
}
604+
}
605+
}

Sources/PackageLoading/ManifestLoader.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ public final class ManifestLoader: ManifestLoaderProtocol {
409409
_ result: EvaluationResult,
410410
packageIdentity: PackageIdentity,
411411
packageKind: PackageReference.Kind,
412+
packagePath: AbsolutePath,
412413
packageLocation: String,
413414
toolsVersion: ToolsVersion,
414415
identityResolver: IdentityResolver,
@@ -453,6 +454,7 @@ public final class ManifestLoader: ManifestLoaderProtocol {
453454
v4: manifestJSON,
454455
toolsVersion: toolsVersion,
455456
packageKind: packageKind,
457+
packagePath: packagePath,
456458
identityResolver: identityResolver,
457459
dependencyMapper: dependencyMapper,
458460
fileSystem: fileSystem
@@ -560,6 +562,7 @@ public final class ManifestLoader: ManifestLoaderProtocol {
560562
evaluationResult,
561563
packageIdentity: packageIdentity,
562564
packageKind: packageKind,
565+
packagePath: path.parentDirectory,
563566
packageLocation: packageLocation,
564567
toolsVersion: toolsVersion,
565568
identityResolver: identityResolver,
@@ -602,6 +605,7 @@ public final class ManifestLoader: ManifestLoaderProtocol {
602605
evaluationResult,
603606
packageIdentity: packageIdentity,
604607
packageKind: packageKind,
608+
packagePath: path.parentDirectory,
605609
packageLocation: packageLocation,
606610
toolsVersion: toolsVersion,
607611
identityResolver: identityResolver,

0 commit comments

Comments
 (0)