Skip to content

Commit bfa5ae9

Browse files
committed
deprecate static APIs with inefficient defaults
motivation: configuration work has pointed out that some of the static APIs (which are questionable to begin with) use inefficient defaults changes: * deprecate Workspace.create, Workspace.loadRootGraph, PackageBuilder.loadRootPackage, ManifestLoader.loadRootManifest and replace them with instance methods on workspace * add a simple constructor to workspace, that uses the host toolchain by default * adjust call-sites, test and examples
1 parent a9e3527 commit bfa5ae9

File tree

8 files changed

+185
-96
lines changed

8 files changed

+185
-96
lines changed

Examples/package-info/Package.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1-
// swift-tools-version:4.2
1+
// swift-tools-version:5.1
2+
23
import PackageDescription
34

45
let package = Package(
56
name: "package-info",
7+
platforms: [
8+
.macOS(.v10_15),
9+
.iOS(.v13)
10+
],
611
dependencies: [
712
// This just points to the SwiftPM at the root of this repository.
813
.package(path: "../../"),

Examples/package-info/Sources/package-info/main.swift

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,29 @@ import Workspace
66
// PREREQUISITES
77
// ============
88

9-
// We will need to know where the Swift compiler is.
10-
let swiftCompiler: AbsolutePath = {
11-
let string: String
12-
#if os(macOS)
13-
string = try! Process.checkNonZeroExit(args: "xcrun", "--sdk", "macosx", "-f", "swiftc").spm_chomp()
14-
#else
15-
string = try! Process.checkNonZeroExit(args: "which", "swiftc").spm_chomp()
16-
#endif
17-
return AbsolutePath(string)
18-
}()
19-
209
// We need a package to work with.
21-
// This assumes there is one in the current working directory:
22-
let packagePath = localFileSystem.currentWorkingDirectory!
10+
// This computes the path of this package root based on the file location
11+
let packagePath = AbsolutePath(#file).parentDirectory.parentDirectory.parentDirectory
2312

2413
// LOADING
2514
// =======
2615

27-
// Note:
28-
// This simplified API has been added since 0.4.0 was released.
29-
// See older revisions for examples that work with 0.4.0.
30-
3116
// There are several levels of information available.
3217
// Each takes longer to load than the level above it, but provides more detail.
3318
let diagnostics = DiagnosticsEngine()
34-
let identityResolver = DefaultIdentityResolver()
35-
let manifest = try tsc_await { ManifestLoader.loadRootManifest(at: packagePath, swiftCompiler: swiftCompiler, swiftCompilerFlags: [], identityResolver: identityResolver, on: .global(), completion: $0) }
36-
let loadedPackage = try tsc_await { PackageBuilder.loadRootPackage(at: packagePath, swiftCompiler: swiftCompiler, swiftCompilerFlags: [], identityResolver: identityResolver, diagnostics: diagnostics, on: .global(), completion: $0) }
37-
let graph = try Workspace.loadRootGraph(at: packagePath, swiftCompiler: swiftCompiler, swiftCompilerFlags: [], identityResolver: identityResolver, diagnostics: diagnostics)
19+
let workspace = try Workspace(forRootPackage: packagePath)
20+
let manifest = try tsc_await { workspace.loadRootManifest(at: packagePath, diagnostics: diagnostics, completion: $0) }
21+
22+
let package = try tsc_await { workspace.loadRootPackage(at: packagePath, diagnostics: diagnostics, completion: $0) }
23+
guard !diagnostics.hasErrors else {
24+
fatalError("error package manifest: \(diagnostics)")
25+
}
26+
27+
let graph = try workspace.loadPackageGraph(rootPath: packagePath, diagnostics: diagnostics)
28+
guard !diagnostics.hasErrors else {
29+
fatalError("error loading package dependencies: \(diagnostics)")
30+
}
31+
3832

3933
// EXAMPLES
4034
// ========
@@ -46,7 +40,7 @@ let targets = manifest.targets.map({ $0.name }).joined(separator: ", ")
4640
print("Targets:", targets)
4741

4842
// Package
49-
let executables = loadedPackage.targets.filter({ $0.type == .executable }).map({ $0.name })
43+
let executables = package.targets.filter({ $0.type == .executable }).map({ $0.name })
5044
print("Executable targets:", executables)
5145

5246
// PackageGraph

Sources/Commands/APIDigester.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ struct APIDigesterBaselineDumper {
104104
try workingCopy.checkout(revision: baselineRevision)
105105

106106
// Create the workspace for this package.
107-
let workspace = Workspace.create(
107+
let workspace = try Workspace(
108108
forRootPackage: baselinePackageRoot,
109109
manifestLoader: manifestLoader,
110110
repositoryManager: repositoryManager

Sources/PackageLoading/ManifestLoader.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ public final class ManifestLoader: ManifestLoaderProtocol {
140140
/// - diagnostics: Optional. The diagnostics engine.
141141
/// - on: The dispatch queue to perform asynchronous operations on.
142142
/// - completion: The completion handler .
143+
// deprecated 8/2021
144+
@available(*, deprecated, message: "use workspace API instead")
143145
public static func loadRootManifest(
144146
at path: AbsolutePath,
145147
swiftCompiler: AbsolutePath,
@@ -151,7 +153,7 @@ public final class ManifestLoader: ManifestLoaderProtocol {
151153
completion: @escaping (Result<Manifest, Error>) -> Void
152154
) {
153155
do {
154-
let toolchain = try ToolchainConfiguration(swiftCompiler: swiftCompiler, swiftCompilerFlags: swiftCompilerFlags)
156+
let toolchain = ToolchainConfiguration(swiftCompiler: swiftCompiler, swiftCompilerFlags: swiftCompilerFlags)
155157
let loader = ManifestLoader(toolchain: toolchain)
156158
let toolsVersion = try ToolsVersionLoader().load(at: path, fileSystem: fileSystem)
157159
let packageLocation = fileSystem.isFile(path) ? path.parentDirectory : path

Sources/PackageLoading/PackageBuilder.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ public final class PackageBuilder {
242242
/// Create the special REPL product for this package.
243243
private let createREPLProduct: Bool
244244

245-
/// The additionla file detection rules.
245+
/// The additional file detection rules.
246246
private let additionalFileRules: [FileRuleDescription]
247247

248248
/// Minimum deployment target of XCTest per platform.
@@ -296,6 +296,8 @@ public final class PackageBuilder {
296296
/// - diagnostics: Optional. The diagnostics engine.
297297
/// - on: The dispatch queue to perform asynchronous operations on.
298298
/// - completion: The completion handler .
299+
// deprecated 8/2021
300+
@available(*, deprecated, message: "use workspace API instead")
299301
public static func loadRootPackage(
300302
at path: AbsolutePath,
301303
swiftCompiler: AbsolutePath,

Sources/PackageModel/ToolchainConfiguration.swift

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,35 +35,31 @@ public struct ToolchainConfiguration {
3535
/// XCTest Location
3636
public let xctestLocation: AbsolutePath?
3737

38+
/// Creates the set of manifest resources associated with a `swiftc` executable.
39+
///
40+
/// - Parameters:
41+
/// - swiftCompiler: The absolute path of the associated `swiftc` executable.
42+
/// - swiftCompilerFlags: Extra flags to pass the Swift compiler.: Extra flags to pass the Swift compiler.
43+
/// - libDir: The path of the library resources.
44+
/// - binDir: The bin directory.
45+
/// - sdkRoot: The path to SDK root.
46+
/// - xctestLocation: XCTest Location
3847
public init(
3948
swiftCompiler: AbsolutePath,
40-
swiftCompilerFlags: [String],
41-
libDir: AbsolutePath,
49+
swiftCompilerFlags: [String] = [],
50+
libDir: AbsolutePath? = nil,
4251
binDir: AbsolutePath? = nil,
4352
sdkRoot: AbsolutePath? = nil,
4453
xctestLocation: AbsolutePath? = nil
4554
) {
4655
self.swiftCompiler = swiftCompiler
4756
self.swiftCompilerFlags = swiftCompilerFlags
48-
self.libDir = libDir
57+
self.libDir = libDir ?? Self.libDir(forBinDir: swiftCompiler.parentDirectory)
4958
self.binDir = binDir
5059
self.sdkRoot = sdkRoot
5160
self.xctestLocation = xctestLocation
5261
}
5362

54-
/// Creates the set of manifest resources associated with a `swiftc` executable.
55-
///
56-
/// - Parameters:
57-
/// - swiftCompiler: The absolute path of the associated `swiftc` executable.
58-
public init(swiftCompiler: AbsolutePath, swiftCompilerFlags: [String]) throws {
59-
let binDir = swiftCompiler.parentDirectory
60-
self.init(
61-
swiftCompiler: swiftCompiler,
62-
swiftCompilerFlags: swiftCompilerFlags,
63-
libDir: Self.libDir(forBinDir: binDir)
64-
)
65-
}
66-
6763
public static func libDir(forBinDir binDir: AbsolutePath) -> AbsolutePath {
6864
return binDir.parentDirectory.appending(components: "lib", "swift", "pm")
6965
}

Sources/Workspace/Workspace.swift

Lines changed: 131 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -252,24 +252,44 @@ public class Workspace {
252252
pinsFile: AbsolutePath,
253253
manifestLoader: ManifestLoaderProtocol,
254254
repositoryManager: RepositoryManager? = nil,
255-
currentToolsVersion: ToolsVersion = ToolsVersion.currentToolsVersion,
256-
toolsVersionLoader: ToolsVersionLoaderProtocol = ToolsVersionLoader(),
255+
currentToolsVersion: ToolsVersion? = nil,
256+
toolsVersionLoader: ToolsVersionLoaderProtocol? = nil,
257257
delegate: WorkspaceDelegate? = nil,
258-
config: Workspace.Configuration = Workspace.Configuration(),
259-
fileSystem: FileSystem = localFileSystem,
260-
repositoryProvider: RepositoryProvider = GitRepositoryProvider(),
258+
config: Workspace.Configuration? = nil,
259+
fileSystem: FileSystem? = nil,
260+
repositoryProvider: RepositoryProvider? = nil,
261261
identityResolver: IdentityResolver? = nil,
262-
httpClient: HTTPClient = HTTPClient(),
262+
httpClient: HTTPClient? = nil,
263263
netrcFilePath: AbsolutePath? = nil,
264-
archiver: Archiver = ZipArchiver(),
265-
checksumAlgorithm: HashAlgorithm = SHA256(),
266-
additionalFileRules: [FileRuleDescription] = [],
267-
isResolverPrefetchingEnabled: Bool = false,
268-
enablePubgrubResolver: Bool = false,
269-
skipUpdate: Bool = false,
270-
enableResolverTrace: Bool = false,
264+
archiver: Archiver? = nil,
265+
checksumAlgorithm: HashAlgorithm? = nil,
266+
additionalFileRules: [FileRuleDescription]? = nil,
267+
isResolverPrefetchingEnabled: Bool? = nil,
268+
enablePubgrubResolver: Bool? = nil,
269+
skipUpdate: Bool? = nil,
270+
enableResolverTrace: Bool? = nil,
271271
cachePath: AbsolutePath? = nil
272272
) {
273+
// defaults
274+
let currentToolsVersion = currentToolsVersion ?? ToolsVersion.currentToolsVersion
275+
let toolsVersionLoader = toolsVersionLoader ?? ToolsVersionLoader()
276+
let config = config ?? Workspace.Configuration()
277+
let fileSystem = fileSystem ?? localFileSystem
278+
let repositoryProvider = repositoryProvider ?? GitRepositoryProvider()
279+
let httpClient = httpClient ?? HTTPClient()
280+
let archiver = archiver ?? ZipArchiver()
281+
var checksumAlgorithm = checksumAlgorithm ?? SHA256()
282+
#if canImport(CryptoKit)
283+
if checksumAlgorithm is SHA256, #available(macOS 10.15, *) {
284+
checksumAlgorithm = CryptoKitSHA256()
285+
}
286+
#endif
287+
let additionalFileRules = additionalFileRules ?? []
288+
let isResolverPrefetchingEnabled = isResolverPrefetchingEnabled ?? false
289+
let skipUpdate = skipUpdate ?? false
290+
let enableResolverTrace = enableResolverTrace ?? false
291+
292+
// initialize
273293
self.delegate = delegate
274294
self.dataPath = dataPath
275295
self.config = config
@@ -281,12 +301,6 @@ public class Workspace {
281301
self.netrcFilePath = netrcFilePath
282302
self.archiver = archiver
283303

284-
var checksumAlgorithm = checksumAlgorithm
285-
#if canImport(CryptoKit)
286-
if checksumAlgorithm is SHA256, #available(macOS 10.15, *) {
287-
checksumAlgorithm = CryptoKitSHA256()
288-
}
289-
#endif
290304
self.checksumAlgorithm = checksumAlgorithm
291305
self.isResolverPrefetchingEnabled = isResolverPrefetchingEnabled
292306
self.skipUpdate = skipUpdate
@@ -329,21 +343,66 @@ public class Workspace {
329343
///
330344
/// The root package path is used to compute the build directory and other
331345
/// default paths.
332-
public static func create(
346+
public convenience init(
347+
forRootPackage packagePath: AbsolutePath,
348+
toolchain: UserToolchain? = nil,
349+
repositoryManager: RepositoryManager? = nil,
350+
delegate: WorkspaceDelegate? = nil
351+
) throws {
352+
// 👀 is this correct (default toolchain)
353+
let toolchain = try toolchain ?? UserToolchain(destination: .hostDestination())
354+
let manifestLoader = ManifestLoader(toolchain: toolchain.configuration)
355+
356+
try self.init(
357+
forRootPackage: packagePath,
358+
manifestLoader: manifestLoader,
359+
repositoryManager: repositoryManager,
360+
delegate: delegate
361+
)
362+
}
363+
364+
/// A convenience method for creating a workspace for the given root
365+
/// package path.
366+
///
367+
/// The root package path is used to compute the build directory and other
368+
/// default paths.
369+
public convenience init(
333370
forRootPackage packagePath: AbsolutePath,
334371
manifestLoader: ManifestLoaderProtocol,
335372
repositoryManager: RepositoryManager? = nil,
336-
delegate: WorkspaceDelegate? = nil,
337-
identityResolver: IdentityResolver? = nil
338-
) -> Workspace {
339-
return Workspace(
373+
delegate: WorkspaceDelegate? = nil
374+
) throws {
375+
376+
self .init(
340377
dataPath: packagePath.appending(component: ".build"),
341378
editablesPath: packagePath.appending(component: "Packages"),
342379
pinsFile: packagePath.appending(component: "Package.resolved"),
343380
manifestLoader: manifestLoader,
344381
repositoryManager: repositoryManager,
345-
delegate: delegate,
346-
identityResolver: identityResolver
382+
delegate: delegate
383+
)
384+
}
385+
386+
/// A convenience method for creating a workspace for the given root
387+
/// package path.
388+
///
389+
/// The root package path is used to compute the build directory and other
390+
/// default paths.
391+
// FIXME: this one is kind of messy to backwards support, hopefully we can remove quickly
392+
// deprecated 8/2021
393+
@available(*, deprecated, message: "use constructor instead")
394+
public static func create(
395+
forRootPackage packagePath: AbsolutePath,
396+
manifestLoader: ManifestLoaderProtocol,
397+
repositoryManager: RepositoryManager? = nil,
398+
delegate: WorkspaceDelegate? = nil,
399+
identityResolver: IdentityResolver? = nil
400+
) -> Workspace {
401+
return try! .init(forRootPackage: packagePath,
402+
manifestLoader: manifestLoader,
403+
repositoryManager: repositoryManager,
404+
delegate: delegate//,
405+
//identityResolver: identityResolver
347406
)
348407
}
349408
}
@@ -628,14 +687,16 @@ extension Workspace {
628687
/// - diagnostics: Optional. The diagnostics engine.
629688
/// - on: The dispatch queue to perform asynchronous operations on.
630689
/// - completion: The completion handler .
690+
// deprecated 8/2021
691+
@available(*, deprecated, message: "use workspace instance API instead")
631692
public static func loadRootGraph(
632693
at packagePath: AbsolutePath,
633694
swiftCompiler: AbsolutePath,
634695
swiftCompilerFlags: [String],
635696
identityResolver: IdentityResolver? = nil,
636697
diagnostics: DiagnosticsEngine
637698
) throws -> PackageGraph {
638-
let toolchain = try ToolchainConfiguration(swiftCompiler: swiftCompiler, swiftCompilerFlags: swiftCompilerFlags)
699+
let toolchain = ToolchainConfiguration(swiftCompiler: swiftCompiler, swiftCompilerFlags: swiftCompilerFlags)
639700
let loader = ManifestLoader(toolchain: toolchain)
640701
let workspace = Workspace.create(forRootPackage: packagePath, manifestLoader: loader, identityResolver: identityResolver)
641702
return try workspace.loadPackageGraph(rootPath: packagePath, diagnostics: diagnostics)
@@ -752,6 +813,49 @@ extension Workspace {
752813
}
753814
}
754815

816+
/// Loads and returns manifest at the given path.
817+
public func loadRootManifest(
818+
at path: AbsolutePath,
819+
diagnostics: DiagnosticsEngine,
820+
completion: @escaping(Result<Manifest, Error>) -> Void
821+
) {
822+
self.loadRootManifests(packages: [path], diagnostics: diagnostics) { result in
823+
completion(result.tryMap{
824+
// normally, we call loadRootManifests which attempts to load any manifest it can and report errors via diagnostics
825+
// in this case, we want to load a specific manifest, so if the diagnostics contains an error we want to throw
826+
guard !diagnostics.hasErrors else {
827+
// not sure about this one
828+
throw StringError("\(diagnostics)")
829+
}
830+
guard let manifest = $0[path] else {
831+
throw InternalError("Unknown manifest for '\(path)'")
832+
}
833+
return manifest
834+
})
835+
}
836+
}
837+
838+
public func loadRootPackage(
839+
at path: AbsolutePath,
840+
diagnostics: DiagnosticsEngine,
841+
completion: @escaping(Result<Package, Error>) -> Void
842+
) {
843+
self.loadRootManifest(at: path, diagnostics: diagnostics) { result in
844+
let result = result.tryMap { manifest -> Package in
845+
let identity = self.identityResolver.resolveIdentity(for: manifest.packageLocation)
846+
let builder = PackageBuilder(
847+
identity: identity,
848+
manifest: manifest,
849+
productFilter: .everything,
850+
path: path,
851+
xcTestMinimumDeploymentTargets: MinimumDeploymentTarget.default.xcTestMinimumDeploymentTargets,
852+
diagnostics: diagnostics)
853+
return try builder.construct()
854+
}
855+
completion(result)
856+
}
857+
}
858+
755859
/// Generates the checksum
756860
public func checksum(
757861
forBinaryArtifactAt path: AbsolutePath,

0 commit comments

Comments
 (0)