Skip to content

Commit 1491d34

Browse files
authored
refine location comparison when pre-loading package state from local state (#7002)
1 parent d4a961b commit 1491d34

File tree

7 files changed

+502
-29
lines changed

7 files changed

+502
-29
lines changed

Sources/PackageGraph/PubGrub/ContainerProvider.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,14 @@ final class ContainerProvider {
6262
completion: @escaping (Result<PubGrubPackageContainer, Error>) -> Void
6363
) {
6464
// Return the cached container, if available.
65-
if let container = self.containersCache[package], package.equalsIncludingLocation(container.package) {
65+
if let container = self.containersCache[comparingLocation: package] {
6666
return completion(.success(container))
6767
}
6868

6969
if let prefetchSync = self.prefetches[package] {
7070
// If this container is already being prefetched, wait for that to complete
7171
prefetchSync.notify(queue: .sharedConcurrent) {
72-
if let container = self.containersCache[package], package.equalsIncludingLocation(container.package) {
72+
if let container = self.containersCache[comparingLocation: package] {
7373
// should be in the cache once prefetch completed
7474
return completion(.success(container))
7575
} else {
@@ -125,3 +125,12 @@ final class ContainerProvider {
125125
}
126126
}
127127
}
128+
129+
extension ThreadSafeKeyValueStore where Key == PackageReference, Value == PubGrubPackageContainer {
130+
subscript(comparingLocation package: PackageReference) -> PubGrubPackageContainer? {
131+
if let container = self[package], container.package.equalsIncludingLocation(package) {
132+
return container
133+
}
134+
return .none
135+
}
136+
}

Sources/PackageModel/PackageIdentity.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,7 @@ public struct CanonicalPackageLocation: Equatable, CustomStringConvertible {
424424
}
425425

426426
/// Similar to `CanonicalPackageLocation` but differentiates based on the scheme.
427-
public struct CanonicalPackageURL: CustomStringConvertible {
427+
public struct CanonicalPackageURL: Equatable, CustomStringConvertible {
428428
public let description: String
429429
public let scheme: String?
430430

Sources/PackageModel/PackageReference.swift

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,24 @@ extension PackageReference: Equatable {
161161

162162
// TODO: consider rolling into Equatable
163163
public func equalsIncludingLocation(_ other: PackageReference) -> Bool {
164-
return self.identity == other.identity && self.canonicalLocation == other.canonicalLocation
164+
if self.identity != other.identity {
165+
return false
166+
}
167+
if self.canonicalLocation != other.canonicalLocation {
168+
return false
169+
}
170+
switch (self.kind, other.kind) {
171+
case (.remoteSourceControl(let lurl), .remoteSourceControl(let rurl)):
172+
return lurl.canonicalURL == rurl.canonicalURL
173+
default:
174+
return true
175+
}
176+
}
177+
}
178+
179+
extension SourceControlURL {
180+
var canonicalURL: CanonicalPackageURL {
181+
CanonicalPackageURL(self.absoluteString)
165182
}
166183
}
167184

Sources/Workspace/ManagedDependency.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ extension Workspace {
196196

197197
// When loading manifests in Workspace, there are cases where we must also compare the location
198198
// as it may attempt to load manifests for dependencies that have the same identity but from a different location
199-
// (e.g. dependency is changed to a fork with the same identity)
199+
// (e.g. dependency is changed to a fork with the same identity)
200200
public subscript(comparingLocation package: PackageReference) -> ManagedDependency? {
201201
if let dependency = self.dependencies[package.identity], dependency.packageRef.equalsIncludingLocation(package) {
202202
return dependency

Sources/Workspace/Workspace+Manifests.swift

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -198,9 +198,11 @@ extension Workspace {
198198
}
199199
}
200200

201+
let topLevelDependencies = root.packages.flatMap { $1.manifest.dependencies.map { $0.packageRef } }
202+
201203
var requiredIdentities: OrderedCollections.OrderedSet<PackageReference> = []
202204
_ = transitiveClosure(inputNodes) { node in
203-
node.manifest.dependenciesRequired(for: node.productFilter).compactMap { dependency in
205+
return node.manifest.dependenciesRequired(for: node.productFilter).compactMap{ dependency in
204206
let package = dependency.packageRef
205207
let (inserted, index) = requiredIdentities.append(package)
206208
if !inserted {
@@ -209,17 +211,26 @@ extension Workspace {
209211
if existing.canonicalLocation == package.canonicalLocation {
210212
// same literal location is fine
211213
if existing.locationString != package.locationString {
212-
let preferred = [existing, package].sorted(by: {
213-
$0.locationString > $1.locationString
214-
}).first! // safe
215-
observabilityScope.emit(debug: """
216-
similar variants of package '\(package.identity)' \
217-
found at '\(package.locationString)' and '\(existing.locationString)'. \
218-
using preferred variant '\(preferred.locationString)'
219-
""")
220-
if preferred.locationString != existing.locationString {
221-
requiredIdentities.remove(existing)
222-
requiredIdentities.insert(preferred, at: index)
214+
// we prefer the top level dependencies
215+
if topLevelDependencies.contains(where: { $0.locationString == existing.locationString }) {
216+
observabilityScope.emit(debug: """
217+
similar variants of package '\(package.identity)' \
218+
found at '\(package.locationString)' and '\(existing.locationString)'. \
219+
using preferred root variant '\(existing.locationString)'
220+
""")
221+
} else {
222+
let preferred = [existing, package].sorted(by: {
223+
$0.locationString > $1.locationString
224+
}).first! // safe
225+
observabilityScope.emit(debug: """
226+
similar variants of package '\(package.identity)' \
227+
found at '\(package.locationString)' and '\(existing.locationString)'. \
228+
using preferred variant '\(preferred.locationString)'
229+
""")
230+
if preferred.locationString != existing.locationString {
231+
requiredIdentities.remove(existing)
232+
requiredIdentities.insert(preferred, at: index)
233+
}
223234
}
224235
}
225236
} else {

Sources/Workspace/Workspace.swift

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1723,8 +1723,8 @@ extension Workspace {
17231723
needsUpdate = true
17241724
} else {
17251725
for dependency in dependenciesToPin {
1726-
if let pin = storedPinStore.pins.first(where: { $0.value.packageRef.equalsIncludingLocation(dependency.packageRef) }) {
1727-
if pin.value.state != PinsStore.Pin(dependency)?.state {
1726+
if let pin = storedPinStore.pins[comparingLocation: dependency.packageRef] {
1727+
if pin.state != PinsStore.Pin(dependency)?.state {
17281728
needsUpdate = true
17291729
break
17301730
}
@@ -2531,9 +2531,8 @@ extension Workspace {
25312531
// a required dependency that is already loaded (managed) should be represented in the pins store.
25322532
// also comparing location as it may have changed at this point
25332533
if requiredDependencies.contains(where: { $0.equalsIncludingLocation(dependency.packageRef) }) {
2534-
let pin = pinsStore.pins[dependency.packageRef.identity]
25352534
// if pin not found, or location is different (it may have changed at this point) pin it
2536-
if !(pin?.packageRef.equalsIncludingLocation(dependency.packageRef) ?? false) {
2535+
if pinsStore.pins[comparingLocation: dependency.packageRef] == .none {
25372536
pinsStore.pin(dependency)
25382537
}
25392538
} else if let pin = pinsStore.pins[dependency.packageRef.identity] {
@@ -3099,7 +3098,7 @@ extension Workspace {
30993098

31003099
// only update if necessary
31013100
if !workingCopy.exists(revision: revision) {
3102-
// The fetch operation may update contents of the checkout,
3101+
// The fetch operation may update contents of the checkout,
31033102
// so we need to do mutable-immutable dance.
31043103
try self.fileSystem.chmod(.userWritable, path: checkoutPath, options: [.recursive, .onlyFiles])
31053104
try workingCopy.fetch()
@@ -3951,3 +3950,12 @@ extension Workspace.ManagedDependencies {
39513950
})
39523951
}
39533952
}
3953+
3954+
extension PinsStore.Pins {
3955+
subscript(comparingLocation package: PackageReference) -> PinsStore.Pin? {
3956+
if let pin = self[package.identity], pin.packageRef.equalsIncludingLocation(package) {
3957+
return pin
3958+
}
3959+
return .none
3960+
}
3961+
}

0 commit comments

Comments
 (0)