Skip to content

Support additional dependencies in forced resolution mode #7023

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 20 additions & 15 deletions Sources/Workspace/Workspace+Manifests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,24 @@ extension Workspace {
automaticallyAddManagedDependencies: Bool = false,
observabilityScope: ObservabilityScope
) throws -> DependencyManifests {
let prepopulateManagedDependencies: ([PackageReference]) throws -> Void = { refs in
// pre-populate managed dependencies if we are asked to do so (this happens when resolving to a resolved
// file)
if automaticallyAddManagedDependencies {
try refs.forEach { ref in
// Since we are creating managed dependencies based on the resolved file in this mode, but local
// packages aren't part of that file, they will be missing from it. So we're eagerly adding them
// here, but explicitly don't add any that are overridden by a root with the same identity since
// that would lead to loading the given package twice, once as a root and once as a dependency
// which violates various assumptions.
if case .fileSystem = ref.kind, !root.manifests.keys.contains(ref.identity) {
try self.state.dependencies.add(.fileSystem(packageRef: ref))
}
}
observabilityScope.trap { try self.state.save() }
}
}

// Utility Just because a raw tuple cannot be hashable.
struct Key: Hashable {
let identity: PackageIdentity
Expand Down Expand Up @@ -444,6 +462,7 @@ extension Workspace {

// Load root dependencies manifests (in parallel)
let rootDependencies = root.dependencies.map(\.packageRef)
try prepopulateManagedDependencies(rootDependencies)
let rootDependenciesManifests = try temp_await { self.loadManagedManifests(
for: rootDependencies,
observabilityScope: observabilityScope,
Expand Down Expand Up @@ -475,21 +494,7 @@ extension Workspace {
let dependenciesRequired = pair.item.dependenciesRequired(for: pair.key.productFilter)
let dependenciesToLoad = dependenciesRequired.map(\.packageRef)
.filter { !loadedManifests.keys.contains($0.identity) }
// pre-populate managed dependencies if we are asked to do so (this happens when resolving to a resolved
// file)
if automaticallyAddManagedDependencies {
try dependenciesToLoad.forEach { ref in
// Since we are creating managed dependencies based on the resolved file in this mode, but local
// packages aren't part of that file, they will be missing from it. So we're eagerly adding them
// here, but explicitly don't add any that are overridden by a root with the same identity since
// that would lead to loading the given package twice, once as a root and once as a dependency
// which violates various assumptions.
if case .fileSystem = ref.kind, !root.manifests.keys.contains(ref.identity) {
try self.state.dependencies.add(.fileSystem(packageRef: ref))
}
}
observabilityScope.trap { try self.state.save() }
}
try prepopulateManagedDependencies(dependenciesToLoad)
let dependenciesManifests = try temp_await { self.loadManagedManifests(
for: dependenciesToLoad,
observabilityScope: observabilityScope,
Expand Down
39 changes: 39 additions & 0 deletions Tests/WorkspaceTests/WorkspaceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5225,6 +5225,45 @@ final class WorkspaceTests: XCTestCase {
}
}

func testForceResolveToResolvedVersionsLocalPackageInAdditionalDependencies() throws {
let sandbox = AbsolutePath("/tmp/ws/")
let fs = InMemoryFileSystem()

let workspace = try MockWorkspace(
sandbox: sandbox,
fileSystem: fs,
roots: [
MockPackage(
name: "Root",
targets: [
MockTarget(name: "Root"),
],
products: [],
dependencies: []
),
],
packages: [
MockPackage(
name: "Foo",
targets: [
MockTarget(name: "Foo"),
],
products: [
MockProduct(name: "Foo", targets: ["Foo"]),
],
versions: [nil]
),
]
)

try workspace.checkPackageGraph(roots: ["Root"], dependencies: [.fileSystem(path: workspace.packagesDir.appending(component: "Foo"))], forceResolvedVersions: true) { _, diagnostics in
XCTAssertNoDiagnostics(diagnostics)
}
workspace.checkManagedDependencies { result in
result.check(dependency: "foo", at: .local)
}
}

// This verifies that the simplest possible loading APIs are available for package clients.
func testSimpleAPI() throws {
try testWithTemporaryDirectory { path in
Expand Down