Skip to content

Commit b53aead

Browse files
authored
Merge pull request #2928 from abertelrud/eng/add-workspace-callbacks
Add Workspace callbacks for when each package is loaded
2 parents 96da0ba + e8d26cb commit b53aead

File tree

3 files changed

+65
-8
lines changed

3 files changed

+65
-8
lines changed

Sources/SPMTestSupport/TestWorkspace.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,4 +750,12 @@ public final class TestWorkspaceDelegate: WorkspaceDelegate {
750750
public func willResolveDependencies(reason: WorkspaceResolveReason) {
751751
events.append("will resolve dependencies")
752752
}
753+
754+
public func willLoadManifest(packagePath: AbsolutePath, url: String, version: Version?, packageKind: PackageReference.Kind) {
755+
events.append("will load manifest for \(packageKind) package: \(url)")
756+
}
757+
758+
public func didLoadManifest(packagePath: AbsolutePath, url: String, version: Version?, packageKind: PackageReference.Kind, manifest: Manifest?, diagnostics: [Diagnostic]) {
759+
events.append("did load manifest for \(packageKind) package: \(url)")
760+
}
753761
}

Sources/Workspace/Workspace.swift

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This source file is part of the Swift.org open source project
33

4-
Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
4+
Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
55
Licensed under Apache License v2.0 with Runtime Library Exception
66

77
See http://swift.org/LICENSE.txt for license information
@@ -38,6 +38,12 @@ public enum WorkspaceResolveReason: Equatable {
3838
/// The delegate interface used by the workspace to report status information.
3939
public protocol WorkspaceDelegate: class {
4040

41+
/// The workspace is about to load a package manifest (which might be in the cache, or might need to be parsed). Note that this does not include speculative loading of manifests that may occr during dependency resolution; rather, it includes only the final manifest loading that happens after a particular package version has been checked out into a working directory.
42+
func willLoadManifest(packagePath: AbsolutePath, url: String, version: Version?, packageKind: PackageReference.Kind)
43+
44+
/// The workspace has loaded a package manifest, either successfully or not. The manifest is nil if an error occurs, in which case there will also be at least one error in the list of diagnostics (there may be warnings even if a manifest is loaded successfully).
45+
func didLoadManifest(packagePath: AbsolutePath, url: String, version: Version?, packageKind: PackageReference.Kind, manifest: Manifest?, diagnostics: [Diagnostic])
46+
4147
/// The workspace has started fetching this repository.
4248
func fetchingWillBegin(repository: String)
4349

@@ -53,10 +59,22 @@ public protocol WorkspaceDelegate: class {
5359
/// The workspace has finished updating and all the dependencies are already up-to-date.
5460
func dependenciesUpToDate()
5561

56-
/// The workspace has started cloning this repository.
62+
/// The workspace is about to clone a repository from the local cache to a working directory.
63+
func willClone(repository url: String, to path: AbsolutePath)
64+
65+
/// The workspace has cloned a repository from the local cache to a working directory. The error indicates whether the operation failed or succeeded.
66+
func didClone(repository url: String, to path: AbsolutePath, error: Diagnostic?)
67+
68+
/// The workspace has started cloning this repository. This callback is marginally deprecated in favor of the willClone/didClone pair.
5769
func cloning(repository: String)
5870

59-
/// The workspace is checking out a repository.
71+
/// The workspace is about to check out a particular revision of a working directory.
72+
func willCheckOut(repository url: String, revision: String, at path: AbsolutePath)
73+
74+
/// The workspace has checked out a particular revision of a working directory. The error indicates whether the operation failed or succeeded.
75+
func didCheckOut(repository url: String, revision: String, at path: AbsolutePath, error: Diagnostic?)
76+
77+
/// The workspace is checking out a repository. This callback is marginally deprecated in favor of the willCheckOut/didCheckOut pair.
6078
func checkingOut(repository: String, atReference reference: String, to path: AbsolutePath)
6179

6280
/// The workspace is removing this repository because it is no longer needed.
@@ -78,6 +96,17 @@ public protocol WorkspaceDelegate: class {
7896
}
7997

8098
public extension WorkspaceDelegate {
99+
func willLoadManifest(packagePath: AbsolutePath, url: String, version: Version?, packageKind: PackageReference.Kind) {}
100+
func didLoadManifest(packagePath: AbsolutePath, url: String, version: Version?, packageKind: PackageReference.Kind, manifest: Manifest?, diagnostics: [Diagnostic]) {}
101+
func willClone(repository url: String, to path: AbsolutePath) {
102+
cloning(repository: url)
103+
}
104+
func didClone(repository url: String, to path: AbsolutePath, error: Diagnostic?) {}
105+
func cloning(repository: String) {}
106+
func willCheckOut(repository url: String, revision: String, at path: AbsolutePath) {
107+
checkingOut(repository: url, atReference: revision, to: path)
108+
}
109+
func didCheckOut(repository url: String, revision: String, at path: AbsolutePath, error: Diagnostic?) {}
81110
func checkingOut(repository: String, atReference: String, to path: AbsolutePath) {}
82111
func repositoryWillUpdate(_ repository: String) {}
83112
func repositoryDidUpdate(_ repository: String) {}
@@ -1255,7 +1284,10 @@ extension Workspace {
12551284
packageKind: PackageReference.Kind,
12561285
diagnostics: DiagnosticsEngine
12571286
) -> Manifest? {
1258-
return diagnostics.with(location: PackageLocation.Local(packagePath: packagePath)) { diagnostics in
1287+
// Load the manifest, bracketed by the calls to the delegate callbacks. The delegate callback is only passed any diagnostics emited during the parsing of the manifest, but they are also forwarded up to the caller.
1288+
delegate?.willLoadManifest(packagePath: packagePath, url: url, version: version, packageKind: packageKind)
1289+
let manifestDiagnostics = DiagnosticsEngine(handlers: [{diagnostics.emit($0)}])
1290+
let manifest: Manifest? = diagnostics.with(location: PackageLocation.Local(packagePath: packagePath)) { diagnostics in
12591291
return diagnostics.wrap {
12601292
// Load the tools version for the package.
12611293
let toolsVersion = try toolsVersionLoader.load(
@@ -1277,6 +1309,8 @@ extension Workspace {
12771309
)
12781310
}
12791311
}
1312+
delegate?.didLoadManifest(packagePath: packagePath, url: url, version: version, packageKind: packageKind, manifest: manifest, diagnostics: manifestDiagnostics.diagnostics)
1313+
return manifest
12801314
}
12811315

12821316
fileprivate func updateBinaryArtifacts(
@@ -2220,8 +2254,9 @@ extension Workspace {
22202254
try fileSystem.removeFileTree(path)
22212255

22222256
// Inform the delegate that we're starting cloning.
2223-
delegate?.cloning(repository: handle.repository.url)
2257+
delegate?.willClone(repository: handle.repository.url, to: path)
22242258
try handle.cloneCheckout(to: path, editable: false)
2259+
delegate?.didClone(repository: handle.repository.url, to: path, error: nil)
22252260

22262261
return path
22272262
}
@@ -2247,7 +2282,7 @@ extension Workspace {
22472282
let workingRepo = try repositoryManager.provider.openCheckout(at: path)
22482283

22492284
// Inform the delegate.
2250-
delegate?.checkingOut(repository: package.repository.url, atReference: checkoutState.description, to: path)
2285+
delegate?.willCheckOut(repository: package.repository.url, revision: checkoutState.description, at: path)
22512286

22522287
// Do mutable-immutable dance because checkout operation modifies the disk state.
22532288
try fileSystem.chmod(.userWritable, path: path, options: [.recursive, .onlyFiles])
@@ -2261,6 +2296,8 @@ extension Workspace {
22612296
checkoutState: checkoutState))
22622297
try state.saveState()
22632298

2299+
delegate?.didCheckOut(repository: package.repository.url, revision: checkoutState.description, at: path, error: nil)
2300+
22642301
return path
22652302
}
22662303

Tests/WorkspaceTests/WorkspaceTests.swift

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This source file is part of the Swift.org open source project
33

4-
Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
4+
Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
55
Licensed under Apache License v2.0 with Runtime Library Exception
66

77
See http://swift.org/LICENSE.txt for license information
@@ -90,6 +90,18 @@ final class WorkspaceTests: XCTestCase {
9090
result.check(dependency: "quix", at: .checkout(.version("1.2.0")))
9191
}
9292

93+
// Check the load-package callbacks.
94+
XCTAssertMatch(workspace.delegate.events, [
95+
.equal("will load manifest for root package: /tmp/ws/roots/Foo"),
96+
.equal("did load manifest for root package: /tmp/ws/roots/Foo"),
97+
])
98+
XCTAssertMatch(workspace.delegate.events, [
99+
.equal("will load manifest for remote package: /tmp/ws/pkgs/Quix"),
100+
.equal("did load manifest for remote package: /tmp/ws/pkgs/Quix"),
101+
.equal("will load manifest for remote package: /tmp/ws/pkgs/Baz"),
102+
.equal("did load manifest for remote package: /tmp/ws/pkgs/Baz")
103+
])
104+
93105
// Close and reopen workspace.
94106
workspace.closeWorkspace()
95107
workspace.checkManagedDependencies() { result in
@@ -2720,7 +2732,7 @@ final class WorkspaceTests: XCTestCase {
27202732
// Check we don't have updating Foo event.
27212733
workspace.checkUpdate(roots: ["Root"]) { diagnostics in
27222734
XCTAssertNoDiagnostics(diagnostics)
2723-
XCTAssertEqual(workspace.delegate.events, ["Everything is already up-to-date"])
2735+
XCTAssertMatch(workspace.delegate.events, ["Everything is already up-to-date"])
27242736
}
27252737
}
27262738

0 commit comments

Comments
 (0)