Skip to content

Commit 0bc0a71

Browse files
authored
improve output when resolving packages (#3427) (#3446)
1 parent 070dd07 commit 0bc0a71

File tree

11 files changed

+233
-111
lines changed

11 files changed

+233
-111
lines changed

Sources/Basics/DispatchTimeInterval+Extensions.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,13 @@ extension DispatchTimeInterval {
5757
}
5858
}
5959
}
60+
61+
// remove when available to all platforms
62+
#if os(Linux) || os(Windows) || os(Android)
63+
extension DispatchTime {
64+
public func distance(to: DispatchTime) -> DispatchTimeInterval {
65+
let duration = to.uptimeNanoseconds - self.uptimeNanoseconds
66+
return .nanoseconds(duration >= Int.max ? Int.max : Int(duration))
67+
}
68+
}
69+
#endif

Sources/Commands/SwiftTool.swift

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ import Basics
3030
typealias Diagnostic = TSCBasic.Diagnostic
3131

3232
private class ToolWorkspaceDelegate: WorkspaceDelegate {
33-
3433
/// The stream to use for reporting progress.
3534
private let stdoutStream: ThreadSafeOutputByteStream
3635

@@ -73,7 +72,12 @@ private class ToolWorkspaceDelegate: WorkspaceDelegate {
7372
}
7473
}
7574

76-
func fetchingDidFinish(repository: String, fetchDetails: RepositoryManager.FetchDetails?, diagnostic: Diagnostic?) {
75+
func fetchingDidFinish(repository: String, fetchDetails: RepositoryManager.FetchDetails?, diagnostic: Diagnostic?, duration: DispatchTimeInterval) {
76+
queue.async {
77+
self.stdoutStream <<< "Fetched \(repository) (\(duration.descriptionInSeconds))"
78+
self.stdoutStream <<< "\n"
79+
self.stdoutStream.flush()
80+
}
7781
}
7882

7983
func repositoryWillUpdate(_ repository: String) {
@@ -84,7 +88,12 @@ private class ToolWorkspaceDelegate: WorkspaceDelegate {
8488
}
8589
}
8690

87-
func repositoryDidUpdate(_ repository: String) {
91+
func repositoryDidUpdate(_ repository: String, duration: DispatchTimeInterval) {
92+
queue.async {
93+
self.stdoutStream <<< "Updated \(repository) (\(duration.descriptionInSeconds))"
94+
self.stdoutStream <<< "\n"
95+
self.stdoutStream.flush()
96+
}
8897
}
8998

9099
func dependenciesUpToDate() {
@@ -104,8 +113,15 @@ private class ToolWorkspaceDelegate: WorkspaceDelegate {
104113
}
105114

106115
func willCheckOut(repository: String, revision: String, at path: AbsolutePath) {
116+
// noop
117+
}
118+
119+
func didCheckOut(repository: String, revision: String, at path: AbsolutePath, error: Diagnostic?) {
120+
guard case .none = error else {
121+
return // error will be printed before hand
122+
}
107123
queue.async {
108-
self.stdoutStream <<< "Resolving \(repository) at \(revision)"
124+
self.stdoutStream <<< "Working copy of \(repository) resolved at \(revision)"
109125
self.stdoutStream <<< "\n"
110126
self.stdoutStream.flush()
111127
}
@@ -185,6 +201,22 @@ private class ToolWorkspaceDelegate: WorkspaceDelegate {
185201
}
186202
}
187203

204+
func willComputeVersion(package: PackageIdentity, location: String) {
205+
queue.async {
206+
self.stdoutStream <<< "Computing version for \(location)"
207+
self.stdoutStream <<< "\n"
208+
self.stdoutStream.flush()
209+
}
210+
}
211+
212+
func didComputeVersion(package: PackageIdentity, location: String, version: String, duration: DispatchTimeInterval) {
213+
queue.async {
214+
self.stdoutStream <<< "Computed \(location) at \(version) (\(duration.descriptionInSeconds))"
215+
self.stdoutStream <<< "\n"
216+
self.stdoutStream.flush()
217+
}
218+
}
219+
188220
func downloadingBinaryArtifact(from url: String, bytesDownloaded: Int64, totalBytesToDownload: Int64?) {
189221
queue.async {
190222
if let totalBytesToDownload = totalBytesToDownload {
@@ -209,6 +241,13 @@ private class ToolWorkspaceDelegate: WorkspaceDelegate {
209241
self.downloadProgress.removeAll()
210242
}
211243
}
244+
245+
// noop
246+
247+
func willLoadManifest(packagePath: AbsolutePath, url: String, version: Version?, packageKind: PackageReference.Kind) {}
248+
func didLoadManifest(packagePath: AbsolutePath, url: String, version: Version?, packageKind: PackageReference.Kind, manifest: Manifest?, diagnostics: [Diagnostic]) {}
249+
func didCreateWorkingCopy(repository url: String, at path: AbsolutePath, error: Diagnostic?) {}
250+
func resolvedFileChanged() {}
212251
}
213252

214253
/// Handler for the main DiagnosticsEngine used by the SwiftTool class.
@@ -920,3 +959,24 @@ extension Diagnostic.Message {
920959
.warning("\(flag) is an *unsupported* option which can be removed at any time; do not rely on it")
921960
}
922961
}
962+
963+
extension DispatchTimeInterval {
964+
var descriptionInSeconds: String {
965+
switch self {
966+
case .seconds(let value):
967+
return "\(value)s"
968+
case .milliseconds(let value):
969+
return String(format: "%.2f", Double(value)/Double(1000)) + "s"
970+
case .microseconds(let value):
971+
return String(format: "%.2f", Double(value)/Double(1_000_000)) + "s"
972+
case .nanoseconds(let value):
973+
return String(format: "%.2f", Double(value)/Double(1_000_000_000)) + "s"
974+
case .never:
975+
return "n/a"
976+
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
977+
@unknown default:
978+
return "n/a"
979+
#endif
980+
}
981+
}
982+
}

Sources/PackageGraph/DependencyResolver.swift

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
99
*/
1010

11-
import TSCBasic
11+
import Dispatch
1212
import PackageModel
13+
import TSCBasic
1314

1415
public protocol DependencyResolver {
1516
typealias Binding = (package: PackageReference, binding: BoundVersion, products: ProductFilter)
@@ -32,14 +33,14 @@ extension DependencyResolverError: CustomStringConvertible {
3233

3334
public protocol DependencyResolverDelegate {
3435
func willResolve(term: Term)
35-
func didResolve(term: Term, version: Version)
36+
func didResolve(term: Term, version: Version, duration: DispatchTimeInterval)
3637

3738
func derived(term: Term)
3839
func conflict(conflict: Incompatibility)
39-
func satisfied(term: Term, by: Assignment, incompatibility: Incompatibility)
40-
func partiallySatisfied(term: Term, by: Assignment, incompatibility: Incompatibility, difference: Term)
40+
func satisfied(term: Term, by assignment: Assignment, incompatibility: Incompatibility)
41+
func partiallySatisfied(term: Term, by assignment: Assignment, incompatibility: Incompatibility, difference: Term)
4142
func failedToResolve(incompatibility: Incompatibility)
42-
func computed(bindings: [DependencyResolver.Binding])
43+
func solved(result: [DependencyResolver.Binding])
4344
}
4445

4546
public struct TracingDependencyResolverDelegate: DependencyResolverDelegate {
@@ -57,7 +58,7 @@ public struct TracingDependencyResolverDelegate: DependencyResolverDelegate {
5758
self.log("resolving: \(term.node.package.location)")
5859
}
5960

60-
public func didResolve(term: Term, version: Version) {
61+
public func didResolve(term: Term, version: Version, duration: DispatchTimeInterval) {
6162
self.log("resolved: \(term.node.package.location) @ \(version)")
6263
}
6364

@@ -85,10 +86,10 @@ public struct TracingDependencyResolverDelegate: DependencyResolverDelegate {
8586
log("CR: new incompatibility \(incompatibility)")
8687
}
8788

88-
public func computed(bindings: [DependencyResolver.Binding]) {
89+
public func solved(result: [DependencyResolver.Binding]) {
8990
self.log("solved:")
90-
for (container, binding, _) in bindings {
91-
self.log("\(container) \(binding)")
91+
for (package, binding, _) in result {
92+
self.log("\(package) \(binding)")
9293
}
9394
}
9495

@@ -97,3 +98,44 @@ public struct TracingDependencyResolverDelegate: DependencyResolverDelegate {
9798
self.stream.flush()
9899
}
99100
}
101+
102+
public struct MultiplexResolverDelegate: DependencyResolverDelegate {
103+
private let underlying: [DependencyResolverDelegate]
104+
105+
public init (_ underlying: [DependencyResolverDelegate]) {
106+
self.underlying = underlying
107+
}
108+
109+
public func willResolve(term: Term) {
110+
underlying.forEach { $0.willResolve(term: term) }
111+
}
112+
113+
public func didResolve(term: Term, version: Version, duration: DispatchTimeInterval) {
114+
underlying.forEach { $0.didResolve(term: term, version: version, duration: duration) }
115+
}
116+
117+
public func derived(term: Term) {
118+
underlying.forEach { $0.derived(term: term) }
119+
}
120+
121+
public func conflict(conflict: Incompatibility) {
122+
underlying.forEach { $0.conflict(conflict: conflict) }
123+
}
124+
125+
public func satisfied(term: Term, by assignment: Assignment, incompatibility: Incompatibility) {
126+
underlying.forEach { $0.satisfied(term: term, by: assignment, incompatibility: incompatibility) }
127+
}
128+
129+
public func partiallySatisfied(term: Term, by assignment: Assignment, incompatibility: Incompatibility, difference: Term) {
130+
underlying.forEach { $0.partiallySatisfied(term: term, by: assignment, incompatibility: incompatibility, difference: difference) }
131+
}
132+
133+
public func failedToResolve(incompatibility: Incompatibility) {
134+
underlying.forEach { $0.failedToResolve(incompatibility: incompatibility) }
135+
}
136+
137+
public func solved(result: [(package: PackageReference, binding: BoundVersion, products: ProductFilter)]) {
138+
underlying.forEach { $0.solved(result: result) }
139+
}
140+
141+
}

Sources/PackageGraph/Pubgrub/PubgrubDependencyResolver.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ public struct PubgrubDependencyResolver {
238238
finalAssignments.append((identifier, override.version, override.products))
239239
}
240240

241-
self.delegate?.computed(bindings: finalAssignments)
241+
self.delegate?.solved(result: finalAssignments)
242242

243243
return (finalAssignments, state)
244244
}
@@ -632,6 +632,7 @@ public struct PubgrubDependencyResolver {
632632
// get conflicts (if any) sooner.
633633
self.computeCounts(for: undecided) { result in
634634
do {
635+
let start = DispatchTime.now()
635636
let counts = try result.get()
636637
// forced unwraps safe since we are testing for count and errors above
637638
let pkgTerm = undecided.min { counts[$0]! < counts[$1]! }!
@@ -670,7 +671,7 @@ public struct PubgrubDependencyResolver {
670671

671672
// Decide this version if there was no conflict with its dependencies.
672673
if !haveConflict {
673-
self.delegate?.didResolve(term: pkgTerm, version: version)
674+
self.delegate?.didResolve(term: pkgTerm, version: version, duration: start.distance(to: .now()))
674675
state.decide(pkgTerm.node, at: version)
675676
}
676677

Sources/SPMTestSupport/MockWorkspace.swift

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,10 @@ public final class MockWorkspaceDelegate: WorkspaceDelegate {
592592
self.append("updating repo: \(repository)")
593593
}
594594

595+
public func repositoryDidUpdate(_ repository: String, duration: DispatchTimeInterval) {
596+
self.append("finished updating repo: \(repository)")
597+
}
598+
595599
public func dependenciesUpToDate() {
596600
self.append("Everything is already up-to-date")
597601
}
@@ -600,18 +604,26 @@ public final class MockWorkspaceDelegate: WorkspaceDelegate {
600604
self.append("fetching repo: \(repository)")
601605
}
602606

603-
public func fetchingDidFinish(repository: String, fetchDetails: RepositoryManager.FetchDetails?, diagnostic: Diagnostic?) {
607+
public func fetchingDidFinish(repository: String, fetchDetails: RepositoryManager.FetchDetails?, diagnostic: Diagnostic?, duration: DispatchTimeInterval) {
604608
self.append("finished fetching repo: \(repository)")
605609
}
606610

607611
public func willCreateWorkingCopy(repository url: String, at path: AbsolutePath) {
608612
self.append("creating working copy for: \(url)")
609613
}
610614

615+
public func didCreateWorkingCopy(repository url: String, at path: AbsolutePath, error: Diagnostic?) {
616+
self.append("finished creating working copy for: \(url)")
617+
}
618+
611619
public func willCheckOut(repository url: String, revision: String, at path: AbsolutePath) {
612620
self.append("checking out repo: \(url)")
613621
}
614622

623+
public func didCheckOut(repository url: String, revision: String, at path: AbsolutePath, error: Diagnostic?) {
624+
self.append("finsihed checking out repo: \(url)")
625+
}
626+
615627
public func removing(repository: String) {
616628
self.append("removing repo: \(repository)")
617629
}
@@ -628,6 +640,26 @@ public final class MockWorkspaceDelegate: WorkspaceDelegate {
628640
self.append("did load manifest for \(packageKind) package: \(url)")
629641
}
630642

643+
public func willComputeVersion(package: PackageIdentity, location: String) {
644+
// noop
645+
}
646+
647+
public func didComputeVersion(package: PackageIdentity, location: String, version: String, duration: DispatchTimeInterval) {
648+
// noop
649+
}
650+
651+
public func resolvedFileChanged() {
652+
// noop
653+
}
654+
655+
public func downloadingBinaryArtifact(from url: String, bytesDownloaded: Int64, totalBytesToDownload: Int64?) {
656+
// noop
657+
}
658+
659+
public func didDownloadBinaryArtifacts() {
660+
// noop
661+
}
662+
631663
private func append(_ event: String) {
632664
self.lock.withLock {
633665
self._events.append(event)

0 commit comments

Comments
 (0)