Skip to content

Commit a9cbf5c

Browse files
authored
Support additional dependencies in forced resolution mode (#7023)
rdar://115630439
1 parent 8281211 commit a9cbf5c

File tree

2 files changed

+59
-15
lines changed

2 files changed

+59
-15
lines changed

Sources/Workspace/Workspace+Manifests.swift

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,24 @@ extension Workspace {
410410
automaticallyAddManagedDependencies: Bool = false,
411411
observabilityScope: ObservabilityScope
412412
) throws -> DependencyManifests {
413+
let prepopulateManagedDependencies: ([PackageReference]) throws -> Void = { refs in
414+
// pre-populate managed dependencies if we are asked to do so (this happens when resolving to a resolved
415+
// file)
416+
if automaticallyAddManagedDependencies {
417+
try refs.forEach { ref in
418+
// Since we are creating managed dependencies based on the resolved file in this mode, but local
419+
// packages aren't part of that file, they will be missing from it. So we're eagerly adding them
420+
// here, but explicitly don't add any that are overridden by a root with the same identity since
421+
// that would lead to loading the given package twice, once as a root and once as a dependency
422+
// which violates various assumptions.
423+
if case .fileSystem = ref.kind, !root.manifests.keys.contains(ref.identity) {
424+
try self.state.dependencies.add(.fileSystem(packageRef: ref))
425+
}
426+
}
427+
observabilityScope.trap { try self.state.save() }
428+
}
429+
}
430+
413431
// Utility Just because a raw tuple cannot be hashable.
414432
struct Key: Hashable {
415433
let identity: PackageIdentity
@@ -444,6 +462,7 @@ extension Workspace {
444462

445463
// Load root dependencies manifests (in parallel)
446464
let rootDependencies = root.dependencies.map(\.packageRef)
465+
try prepopulateManagedDependencies(rootDependencies)
447466
let rootDependenciesManifests = try temp_await { self.loadManagedManifests(
448467
for: rootDependencies,
449468
observabilityScope: observabilityScope,
@@ -475,21 +494,7 @@ extension Workspace {
475494
let dependenciesRequired = pair.item.dependenciesRequired(for: pair.key.productFilter)
476495
let dependenciesToLoad = dependenciesRequired.map(\.packageRef)
477496
.filter { !loadedManifests.keys.contains($0.identity) }
478-
// pre-populate managed dependencies if we are asked to do so (this happens when resolving to a resolved
479-
// file)
480-
if automaticallyAddManagedDependencies {
481-
try dependenciesToLoad.forEach { ref in
482-
// Since we are creating managed dependencies based on the resolved file in this mode, but local
483-
// packages aren't part of that file, they will be missing from it. So we're eagerly adding them
484-
// here, but explicitly don't add any that are overridden by a root with the same identity since
485-
// that would lead to loading the given package twice, once as a root and once as a dependency
486-
// which violates various assumptions.
487-
if case .fileSystem = ref.kind, !root.manifests.keys.contains(ref.identity) {
488-
try self.state.dependencies.add(.fileSystem(packageRef: ref))
489-
}
490-
}
491-
observabilityScope.trap { try self.state.save() }
492-
}
497+
try prepopulateManagedDependencies(dependenciesToLoad)
493498
let dependenciesManifests = try temp_await { self.loadManagedManifests(
494499
for: dependenciesToLoad,
495500
observabilityScope: observabilityScope,

Tests/WorkspaceTests/WorkspaceTests.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5225,6 +5225,45 @@ final class WorkspaceTests: XCTestCase {
52255225
}
52265226
}
52275227

5228+
func testForceResolveToResolvedVersionsLocalPackageInAdditionalDependencies() throws {
5229+
let sandbox = AbsolutePath("/tmp/ws/")
5230+
let fs = InMemoryFileSystem()
5231+
5232+
let workspace = try MockWorkspace(
5233+
sandbox: sandbox,
5234+
fileSystem: fs,
5235+
roots: [
5236+
MockPackage(
5237+
name: "Root",
5238+
targets: [
5239+
MockTarget(name: "Root"),
5240+
],
5241+
products: [],
5242+
dependencies: []
5243+
),
5244+
],
5245+
packages: [
5246+
MockPackage(
5247+
name: "Foo",
5248+
targets: [
5249+
MockTarget(name: "Foo"),
5250+
],
5251+
products: [
5252+
MockProduct(name: "Foo", targets: ["Foo"]),
5253+
],
5254+
versions: [nil]
5255+
),
5256+
]
5257+
)
5258+
5259+
try workspace.checkPackageGraph(roots: ["Root"], dependencies: [.fileSystem(path: workspace.packagesDir.appending(component: "Foo"))], forceResolvedVersions: true) { _, diagnostics in
5260+
XCTAssertNoDiagnostics(diagnostics)
5261+
}
5262+
workspace.checkManagedDependencies { result in
5263+
result.check(dependency: "foo", at: .local)
5264+
}
5265+
}
5266+
52285267
// This verifies that the simplest possible loading APIs are available for package clients.
52295268
func testSimpleAPI() throws {
52305269
try testWithTemporaryDirectory { path in

0 commit comments

Comments
 (0)