-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Paralellize retrieving resolved packages #8220
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
Changes from all commits
e507854
f326ad8
0cf2d7c
3d99328
7bdd76e
798bdc3
e996177
7f7c672
60f8942
5b1c7e2
3cda975
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -172,12 +172,18 @@ extension Workspace.ManagedDependency: CustomStringConvertible { | |
|
||
extension Workspace { | ||
/// A collection of managed dependencies. | ||
final public class ManagedDependencies { | ||
public struct ManagedDependencies { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Turning There are only two methods of |
||
private var dependencies: [PackageIdentity: ManagedDependency] | ||
|
||
init() { | ||
self.dependencies = [:] | ||
} | ||
|
||
private init( | ||
_ dependencies: [PackageIdentity: ManagedDependency] | ||
) { | ||
self.dependencies = dependencies | ||
} | ||
|
||
init(_ dependencies: [ManagedDependency]) throws { | ||
// rdar://86857825 do not use Dictionary(uniqueKeysWithValues:) as it can crash the process when input is incorrect such as in older versions of SwiftPM | ||
|
@@ -204,12 +210,16 @@ extension Workspace { | |
return .none | ||
} | ||
|
||
public func add(_ dependency: ManagedDependency) { | ||
self.dependencies[dependency.packageRef.identity] = dependency | ||
public func add(_ dependency: ManagedDependency) -> Self { | ||
var dependencies = dependencies | ||
dependencies[dependency.packageRef.identity] = dependency | ||
return ManagedDependencies(dependencies) | ||
} | ||
|
||
public func remove(_ identity: PackageIdentity) { | ||
self.dependencies[identity] = nil | ||
public func remove(_ identity: PackageIdentity) -> Self { | ||
var dependencies = dependencies | ||
dependencies[identity] = nil | ||
return ManagedDependencies(dependencies) | ||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -169,7 +169,7 @@ extension Workspace { | |
} | ||
|
||
// Update the resolved file. | ||
try self.saveResolvedFile( | ||
try await self.saveResolvedFile( | ||
resolvedPackagesStore: resolvedPackagesStore, | ||
dependencyManifests: updatedDependencyManifests, | ||
originHash: resolvedFileOriginHash, | ||
|
@@ -219,7 +219,7 @@ extension Workspace { | |
case .update(let forceResolution): | ||
return try await resolveAndUpdateResolvedFile(forceResolution: forceResolution) | ||
case .bestEffort: | ||
guard !self.state.dependencies.hasEditedDependencies() else { | ||
guard await !self.state.dependencies.hasEditedDependencies() else { | ||
return try await resolveAndUpdateResolvedFile(forceResolution: false) | ||
} | ||
guard self.fileSystem.exists(self.location.resolvedVersionsFile) else { | ||
|
@@ -410,9 +410,10 @@ extension Workspace { | |
// | ||
// We require cloning if there is no checkout or if the checkout doesn't | ||
// match with the pin. | ||
let dependencies = await state.dependencies | ||
let requiredResolvedPackages = resolvedPackagesStore.resolvedPackages.values.filter { pin in | ||
// also compare the location in case it has changed | ||
guard let dependency = state.dependencies[comparingLocation: pin.packageRef] else { | ||
guard let dependency = dependencies[comparingLocation: pin.packageRef] else { | ||
return true | ||
} | ||
switch dependency.state { | ||
|
@@ -426,26 +427,31 @@ extension Workspace { | |
} | ||
|
||
// Retrieve the required resolved packages. | ||
for resolvedPackage in requiredResolvedPackages { | ||
await observabilityScope.makeChildScope( | ||
description: "retrieving resolved package versions for dependencies", | ||
metadata: resolvedPackage.packageRef.diagnosticsMetadata | ||
).trap { | ||
switch resolvedPackage.packageRef.kind { | ||
case .localSourceControl, .remoteSourceControl: | ||
_ = try await self.checkoutRepository( | ||
package: resolvedPackage.packageRef, | ||
at: resolvedPackage.state, | ||
observabilityScope: observabilityScope | ||
) | ||
case .registry: | ||
_ = try await self.downloadRegistryArchive( | ||
package: resolvedPackage.packageRef, | ||
at: resolvedPackage.state, | ||
observabilityScope: observabilityScope | ||
) | ||
default: | ||
throw InternalError("invalid resolved package type \(resolvedPackage.packageRef.kind)") | ||
await withThrowingTaskGroup(of: Void.self) { taskGroup in | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Returning back the parallelization of retrieving resolved packages |
||
for resolvedPackage in requiredResolvedPackages { | ||
let observabilityScope = observabilityScope.makeChildScope( | ||
description: "retrieving resolved package versions for dependencies", | ||
metadata: resolvedPackage.packageRef.diagnosticsMetadata | ||
) | ||
taskGroup.addTask { | ||
await observabilityScope.trap { | ||
switch resolvedPackage.packageRef.kind { | ||
case .localSourceControl, .remoteSourceControl: | ||
_ = try await self.checkoutRepository( | ||
package: resolvedPackage.packageRef, | ||
at: resolvedPackage.state, | ||
observabilityScope: observabilityScope | ||
) | ||
case .registry: | ||
_ = try await self.downloadRegistryArchive( | ||
package: resolvedPackage.packageRef, | ||
at: resolvedPackage.state, | ||
observabilityScope: observabilityScope | ||
) | ||
default: | ||
throw InternalError("invalid resolved package type \(resolvedPackage.packageRef.kind)") | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
@@ -523,7 +529,7 @@ extension Workspace { | |
} | ||
|
||
// load and update the `Package.resolved` store with any changes from loading the top level dependencies | ||
guard let resolvedPackagesStore = self.loadAndUpdateResolvedPackagesStore( | ||
guard let resolvedPackagesStore = await self.loadAndUpdateResolvedPackagesStore( | ||
dependencyManifests: currentManifests, | ||
rootManifestsMinimumToolsVersion: rootManifestsMinimumToolsVersion, | ||
observabilityScope: observabilityScope | ||
|
@@ -554,7 +560,7 @@ extension Workspace { | |
case .notRequired: | ||
// since nothing changed we can exit early, | ||
// but need update resolved file and download an missing binary artifact | ||
try self.saveResolvedFile( | ||
try await self.saveResolvedFile( | ||
resolvedPackagesStore: resolvedPackagesStore, | ||
dependencyManifests: currentManifests, | ||
originHash: resolvedFileOriginHash, | ||
|
@@ -625,7 +631,7 @@ extension Workspace { | |
} | ||
|
||
// Update the resolved file. | ||
try self.saveResolvedFile( | ||
try await self.saveResolvedFile( | ||
resolvedPackagesStore: resolvedPackagesStore, | ||
dependencyManifests: updatedDependencyManifests, | ||
originHash: resolvedFileOriginHash, | ||
|
@@ -679,15 +685,15 @@ extension Workspace { | |
|
||
// First remove the checkouts that are no longer required. | ||
for (packageRef, state) in packageStateChanges { | ||
observabilityScope.makeChildScope( | ||
await observabilityScope.makeChildScope( | ||
description: "removing unneeded checkouts", | ||
metadata: packageRef.diagnosticsMetadata | ||
).trap { | ||
switch state { | ||
case .added, .updated, .unchanged: | ||
break | ||
case .removed: | ||
try self.remove(package: packageRef) | ||
try await self.remove(package: packageRef) | ||
} | ||
} | ||
} | ||
|
@@ -772,8 +778,8 @@ extension Workspace { | |
state: .custom(version: version, path: path), | ||
subpath: RelativePath(validating: "") | ||
) | ||
self.state.dependencies.add(dependency) | ||
try self.state.save() | ||
await self.state.add(dependency: dependency) | ||
try await self.state.save() | ||
return path | ||
} else { | ||
throw InternalError("invalid container for \(package.identity) of type \(package.kind)") | ||
|
@@ -800,8 +806,8 @@ extension Workspace { | |
throw InternalError("invalid package type: \(package.kind)") | ||
} | ||
|
||
self.state.dependencies.add(dependency) | ||
try self.state.save() | ||
await self.state.add(dependency: dependency) | ||
try await self.state.save() | ||
return path | ||
} | ||
} | ||
|
@@ -889,7 +895,7 @@ extension Workspace { | |
dependencyManifests: DependencyManifests, | ||
rootManifestsMinimumToolsVersion: ToolsVersion, | ||
observabilityScope: ObservabilityScope | ||
) -> ResolvedPackagesStore? { | ||
) async -> ResolvedPackagesStore? { | ||
guard let resolvedPackagesStore = observabilityScope.trap({ try self.resolvedPackagesStore.load() }) else { | ||
return nil | ||
} | ||
|
@@ -899,7 +905,7 @@ extension Workspace { | |
else { | ||
return nil | ||
} | ||
for dependency in self.state.dependencies.filter(\.packageRef.kind.isResolvable) { | ||
for dependency in await self.state.dependencies.filter(\.packageRef.kind.isResolvable) { | ||
// a required dependency that is already loaded (managed) should be represented in the `Package.resolved` store. | ||
// also comparing location as it may have changed at this point | ||
if requiredDependencies.contains(where: { $0.equalsIncludingLocation(dependency.packageRef) }) { | ||
|
@@ -1011,13 +1017,13 @@ extension Workspace { | |
// Get the existing managed dependency for this package ref, if any. | ||
|
||
// first find by identity only since edit location may be different by design | ||
var currentDependency = self.state.dependencies[binding.package.identity] | ||
var currentDependency = await self.state.dependencies[binding.package.identity] | ||
// Check if this is an edited dependency. | ||
if case .edited(let basedOn, _) = currentDependency?.state, let originalReference = basedOn?.packageRef { | ||
packageStateChanges[originalReference.identity] = (originalReference, .unchanged) | ||
} else { | ||
// if not edited, also compare by location since it may have changed | ||
currentDependency = self.state.dependencies[comparingLocation: binding.package] | ||
currentDependency = await self.state.dependencies[comparingLocation: binding.package] | ||
} | ||
|
||
switch binding.boundVersion { | ||
|
@@ -1119,7 +1125,7 @@ extension Workspace { | |
} | ||
} | ||
// Set the state of any old package that might have been removed. | ||
for packageRef in self.state.dependencies.lazy.map(\.packageRef) | ||
for packageRef in await self.state.dependencies.lazy.map(\.packageRef) | ||
where packageStateChanges[packageRef.identity] == nil | ||
{ | ||
packageStateChanges[packageRef.identity] = (packageRef, .removed) | ||
|
Uh oh!
There was an error while loading. Please reload this page.