Skip to content

Commit 4633b26

Browse files
authored
refactor workspace initializers (#3664)
motivation: nicer API to work with changes: * deprecate previous initializer * introduce new initializer with minimal signatures, and clearly defined argument names and API docs * make DependencyMirrors thread safe * adjust call sites
1 parent 7756de5 commit 4633b26

File tree

10 files changed

+483
-348
lines changed

10 files changed

+483
-348
lines changed

Sources/Commands/APIDigester.swift

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,6 @@ struct APIDigesterBaselineDumper {
3333
/// The input build parameters.
3434
let inputBuildParameters: BuildParameters
3535

36-
/// The manifest loader.
37-
let manifestLoader: ManifestLoaderProtocol
38-
39-
/// The repository manager.
40-
let repositoryManager: RepositoryManager
41-
4236
/// The API digester tool.
4337
let apiDigesterTool: SwiftAPIDigester
4438

@@ -49,16 +43,12 @@ struct APIDigesterBaselineDumper {
4943
baselineRevision: Revision,
5044
packageRoot: AbsolutePath,
5145
buildParameters: BuildParameters,
52-
manifestLoader: ManifestLoaderProtocol,
53-
repositoryManager: RepositoryManager,
5446
apiDigesterTool: SwiftAPIDigester,
5547
diags: DiagnosticsEngine
5648
) {
5749
self.baselineRevision = baselineRevision
5850
self.packageRoot = packageRoot
5951
self.inputBuildParameters = buildParameters
60-
self.manifestLoader = manifestLoader
61-
self.repositoryManager = repositoryManager
6252
self.apiDigesterTool = apiDigesterTool
6353
self.diags = diags
6454
}
@@ -93,8 +83,9 @@ struct APIDigesterBaselineDumper {
9383
}
9484

9585
// Clone the current package in a sandbox and checkout the baseline revision.
86+
let repositoryProvider = GitRepositoryProvider()
9687
let specifier = RepositorySpecifier(url: baselinePackageRoot.pathString)
97-
let workingCopy = try repositoryManager.provider.createWorkingCopy(
88+
let workingCopy = try repositoryProvider.createWorkingCopy(
9889
repository: specifier,
9990
sourcePath: packageRoot,
10091
at: baselinePackageRoot,
@@ -105,9 +96,7 @@ struct APIDigesterBaselineDumper {
10596

10697
// Create the workspace for this package.
10798
let workspace = try Workspace(
108-
forRootPackage: baselinePackageRoot,
109-
manifestLoader: manifestLoader,
110-
repositoryManager: repositoryManager
99+
forRootPackage: baselinePackageRoot
111100
)
112101

113102
let graph = try workspace.loadPackageGraph(
@@ -123,7 +112,7 @@ struct APIDigesterBaselineDumper {
123112

124113
// Update the data path input build parameters so it's built in the sandbox.
125114
var buildParameters = inputBuildParameters
126-
buildParameters.dataPath = workspace.dataPath
115+
buildParameters.dataPath = workspace.location.workingDirectory
127116

128117
// Build the baseline module.
129118
let buildOp = BuildOperation(

Sources/Commands/SwiftPackageTool.swift

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -364,13 +364,10 @@ extension SwiftPackageTool {
364364
try buildOp.build()
365365

366366
// Dump JSON for the baseline package.
367-
let workspace = try swiftTool.getActiveWorkspace()
368367
let baselineDumper = try APIDigesterBaselineDumper(
369368
baselineRevision: baselineRevision,
370369
packageRoot: swiftTool.getPackageRoot(),
371370
buildParameters: buildOp.buildParameters,
372-
manifestLoader: workspace.manifestLoader,
373-
repositoryManager: workspace.repositoryManager,
374371
apiDigesterTool: apiDigesterTool,
375372
diags: swiftTool.diagnostics
376373
)
@@ -886,7 +883,7 @@ extension SwiftPackageTool.Config {
886883
var mirrorURL: String
887884

888885
func run(_ swiftTool: SwiftTool) throws {
889-
let config = try swiftTool.getSwiftPMConfig()
886+
let config = try swiftTool.getMirrorsConfig()
890887

891888
if packageURL != nil {
892889
swiftTool.diagnostics.emit(
@@ -920,7 +917,7 @@ extension SwiftPackageTool.Config {
920917
var mirrorURL: String?
921918

922919
func run(_ swiftTool: SwiftTool) throws {
923-
let config = try swiftTool.getSwiftPMConfig()
920+
let config = try swiftTool.getMirrorsConfig()
924921

925922
if packageURL != nil {
926923
swiftTool.diagnostics.emit(
@@ -951,7 +948,7 @@ extension SwiftPackageTool.Config {
951948
var originalURL: String?
952949

953950
func run(_ swiftTool: SwiftTool) throws {
954-
let config = try swiftTool.getSwiftPMConfig()
951+
let config = try swiftTool.getMirrorsConfig()
955952

956953
if packageURL != nil {
957954
swiftTool.diagnostics.emit(

Sources/Commands/SwiftTool.swift

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -459,14 +459,14 @@ public class SwiftTool {
459459
return try getPackageRoot().appending(component: "Packages")
460460
}
461461

462-
func resolvedFilePath() throws -> AbsolutePath {
462+
func resolvedVersionsFilePath() throws -> AbsolutePath {
463463
if let multiRootPackageDataFile = options.multirootPackageDataFile {
464464
return multiRootPackageDataFile.appending(components: "xcshareddata", "swiftpm", "Package.resolved")
465465
}
466466
return try getPackageRoot().appending(component: "Package.resolved")
467467
}
468468

469-
func configFilePath() throws -> AbsolutePath {
469+
func mirrorsConfigFilePath() throws -> AbsolutePath {
470470
// Look for the override in the environment.
471471
if let envPath = ProcessEnv.vars["SWIFTPM_MIRROR_CONFIG"] {
472472
return try AbsolutePath(validating: envPath)
@@ -479,15 +479,15 @@ public class SwiftTool {
479479
return try getPackageRoot().appending(components: ".swiftpm", "config")
480480
}
481481

482-
func getSwiftPMConfig() throws -> Workspace.Configuration {
483-
return try _swiftpmConfig.get()
482+
func getMirrorsConfig() throws -> Workspace.Configuration {
483+
return try _mirrorsConfig.get()
484484
}
485485

486-
private lazy var _swiftpmConfig: Result<Workspace.Configuration, Swift.Error> = {
487-
return Result(catching: { try Workspace.Configuration(path: try configFilePath()) })
486+
private lazy var _mirrorsConfig: Result<Workspace.Configuration, Swift.Error> = {
487+
return Result(catching: { try Workspace.Configuration(path: try mirrorsConfigFilePath(), fileSystem: localFileSystem) })
488488
}()
489-
490-
func resolvedNetrcFilePath() throws -> AbsolutePath? {
489+
490+
func netrcFilePath() throws -> AbsolutePath? {
491491
guard options.netrc ||
492492
options.netrcFilePath != nil ||
493493
options.netrcOptional else { return nil }
@@ -551,21 +551,23 @@ public class SwiftTool {
551551
let cachePath = self.options.useRepositoriesCache ? try self.getCachePath() : .none
552552
_ = try self.getConfigPath() // TODO: actually use this in the workspace
553553
let isXcodeBuildSystemEnabled = self.options.buildSystem == .xcode
554-
let workspace = Workspace(
555-
dataPath: buildPath,
556-
editablesPath: try editablesPath(),
557-
pinsFile: try resolvedFilePath(),
558-
manifestLoader: try getManifestLoader(),
559-
toolsVersionLoader: ToolsVersionLoader(),
560-
delegate: delegate,
561-
config: try getSwiftPMConfig(),
562-
repositoryProvider: provider,
563-
netrcFilePath: try resolvedNetrcFilePath(),
554+
let workspace = try Workspace(
555+
fileSystem: localFileSystem,
556+
location: .init(
557+
workingDirectory: buildPath,
558+
editsDirectory: try editablesPath(),
559+
resolvedVersionsFilePath: try resolvedVersionsFilePath(),
560+
sharedCacheDirectory: cachePath
561+
),
562+
netrcFilePath: try netrcFilePath(),
563+
mirrors: self.getMirrorsConfig().mirrors,
564+
customManifestLoader: try getManifestLoader(), // FIXME: doe we really need to customize it?
565+
customRepositoryProvider: provider, // FIXME: doe we really need to customize it?
564566
additionalFileRules: isXcodeBuildSystemEnabled ? FileRuleDescription.xcbuildFileTypes : FileRuleDescription.swiftpmFileTypes,
565-
isResolverPrefetchingEnabled: options.shouldEnableResolverPrefetching,
566-
skipUpdate: options.skipDependencyUpdate,
567-
enableResolverTrace: options.enableResolverTrace,
568-
cachePath: cachePath
567+
resolverUpdateEnabled: !options.skipDependencyUpdate,
568+
resolverPrefetchingEnabled: options.shouldEnableResolverPrefetching,
569+
resolverTracingEnabled: options.enableResolverTrace,
570+
delegate: delegate
569571
)
570572
_workspace = workspace
571573
_workspaceDelegate = delegate
@@ -638,7 +640,7 @@ public class SwiftTool {
638640
// The `plugins` directory is inside the workspace's main data directory, and contains all temporary
639641
// files related to all plugins in the workspace.
640642
let buildEnvironment = try buildParameters().buildEnvironment
641-
let dataDir = try self.getActiveWorkspace().dataPath
643+
let dataDir = try self.getActiveWorkspace().location.workingDirectory
642644
let pluginsDir = dataDir.appending(component: "plugins")
643645

644646
// The `cache` directory is in the plugins directory and is where the plugin script runner caches

Sources/PackageGraph/DependencyMirrors.swift

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public final class DependencyMirrors {
2424

2525
private var index: [String: String]
2626
private var reverseIndex: [String: String]
27+
private let lock = Lock()
2728

2829
private init(_ mirrors: [Mirror]) {
2930
self.index = Dictionary(mirrors.map({ ($0.original, $0.mirror) }), uniquingKeysWith: { first, _ in first })
@@ -32,30 +33,36 @@ public final class DependencyMirrors {
3233

3334
/// Sets a mirror URL for the given URL.
3435
public func set(mirrorURL: String, forURL url: String) {
35-
self.index[url] = mirrorURL
36-
self.reverseIndex[mirrorURL] = url
36+
self.lock.withLock {
37+
self.index[url] = mirrorURL
38+
self.reverseIndex[mirrorURL] = url
39+
}
3740
}
3841

3942
/// Unsets a mirror for the given URL.
4043
/// - Parameter originalOrMirrorURL: The original URL or the mirrored URL
4144
/// - Throws: `Error.mirrorNotFound` if no mirror exists for the provided URL.
4245
public func unset(originalOrMirrorURL: String) throws {
43-
if let value = self.index[originalOrMirrorURL] {
44-
self.index[originalOrMirrorURL] = nil
45-
self.reverseIndex[value] = nil
46-
} else if let mirror = self.index.first(where: { $0.value == originalOrMirrorURL }) {
47-
self.index[mirror.key] = nil
48-
self.reverseIndex[originalOrMirrorURL] = nil
49-
} else {
50-
throw Error.mirrorNotFound
46+
try self.lock.withLock {
47+
if let value = self.index[originalOrMirrorURL] {
48+
self.index[originalOrMirrorURL] = nil
49+
self.reverseIndex[value] = nil
50+
} else if let mirror = self.index.first(where: { $0.value == originalOrMirrorURL }) {
51+
self.index[mirror.key] = nil
52+
self.reverseIndex[originalOrMirrorURL] = nil
53+
} else {
54+
throw Error.mirrorNotFound
55+
}
5156
}
5257
}
5358

5459
/// Returns the mirrored URL for a package dependency URL.
5560
/// - Parameter url: The original URL
5661
/// - Returns: The mirrored URL, if one exists.
5762
public func mirrorURL(for url: String) -> String? {
58-
return self.index[url]
63+
self.lock.withLock {
64+
return self.index[url]
65+
}
5966
}
6067

6168
/// Returns the effective URL for a package dependency URL.
@@ -69,29 +76,38 @@ public final class DependencyMirrors {
6976
/// - Parameter url: The mirror URL
7077
/// - Returns: The original URL, if one exists.
7178
public func originalURL(for url: String) -> String? {
72-
return self.reverseIndex[url]
79+
self.lock.withLock {
80+
return self.reverseIndex[url]
81+
}
7382
}
74-
7583
}
7684

7785
extension DependencyMirrors: Collection {
7886
public typealias Index = Dictionary<String, String>.Index
7987
public typealias Element = String
8088

8189
public var startIndex: Index {
82-
self.index.startIndex
90+
self.lock.withLock {
91+
self.index.startIndex
92+
}
8393
}
8494

8595
public var endIndex: Index {
86-
self.index.endIndex
96+
self.lock.withLock {
97+
self.index.endIndex
98+
}
8799
}
88100

89101
public subscript(index: Index) -> Element {
90-
self.index[index].value
102+
self.lock.withLock {
103+
self.index[index].value
104+
}
91105
}
92106

93107
public func index(after index: Index) -> Index {
94-
self.index.index(after: index)
108+
self.lock.withLock {
109+
self.index.index(after: index)
110+
}
95111
}
96112
}
97113

Sources/PackageGraph/Pubgrub/PubgrubDependencyResolver.swift

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -102,30 +102,30 @@ public struct PubgrubDependencyResolver {
102102
/// The container provider used to load package containers.
103103
private let provider: ContainerProvider
104104

105-
/// Skip updating containers while fetching them.
106-
private let skipUpdate: Bool
107-
108105
/// Reference to the package container provider.
109106
private let packageContainerProvider: PackageContainerProvider
110107

111108
/// Should resolver prefetch the containers.
112-
private let isPrefetchingEnabled: Bool
109+
private let prefetchingEnabled: Bool
110+
111+
/// Update containers while fetching them.
112+
private let updateEnabled: Bool
113113

114114
/// Resolver delegate
115115
private let delegate: DependencyResolverDelegate?
116116

117117
public init(
118118
provider: PackageContainerProvider,
119119
pinsMap: PinsStore.PinsMap = [:],
120-
isPrefetchingEnabled: Bool = false,
121-
skipUpdate: Bool = false,
120+
updateEnabled: Bool = true,
121+
prefetchingEnabled: Bool = false,
122122
delegate: DependencyResolverDelegate? = nil
123123
) {
124124
self.packageContainerProvider = provider
125125
self.pinsMap = pinsMap
126-
self.isPrefetchingEnabled = isPrefetchingEnabled
127-
self.skipUpdate = skipUpdate
128-
self.provider = ContainerProvider(provider: self.packageContainerProvider, skipUpdate: self.skipUpdate, pinsMap: self.pinsMap)
126+
self.updateEnabled = updateEnabled
127+
self.prefetchingEnabled = prefetchingEnabled
128+
self.provider = ContainerProvider(provider: self.packageContainerProvider, updateEnabled: self.updateEnabled, pinsMap: self.pinsMap)
129129
self.delegate = delegate
130130
}
131131

@@ -170,7 +170,7 @@ public struct PubgrubDependencyResolver {
170170
let inputs = try self.processInputs(root: root, with: constraints)
171171

172172
// Prefetch the containers if prefetching is enabled.
173-
if self.isPrefetchingEnabled {
173+
if self.prefetchingEnabled {
174174
// We avoid prefetching packages that are overridden since
175175
// otherwise we'll end up creating a repository container
176176
// for them.
@@ -1357,8 +1357,8 @@ private final class ContainerProvider {
13571357
/// The actual package container provider.
13581358
private let underlying: PackageContainerProvider
13591359

1360-
/// Wheather to perform update (git fetch) on existing cloned repositories or not.
1361-
private let skipUpdate: Bool
1360+
/// Whether to perform update (git fetch) on existing cloned repositories or not.
1361+
private let updateEnabled: Bool
13621362

13631363
/// Reference to the pins store.
13641364
private let pinsMap: PinsStore.PinsMap
@@ -1369,9 +1369,9 @@ private final class ContainerProvider {
13691369
//// Store prefetches synchronization
13701370
private var prefetches = ThreadSafeKeyValueStore<PackageReference, DispatchGroup>()
13711371

1372-
init(provider underlying: PackageContainerProvider, skipUpdate: Bool, pinsMap: PinsStore.PinsMap) {
1372+
init(provider underlying: PackageContainerProvider, updateEnabled: Bool, pinsMap: PinsStore.PinsMap) {
13731373
self.underlying = underlying
1374-
self.skipUpdate = skipUpdate
1374+
self.updateEnabled = updateEnabled
13751375
self.pinsMap = pinsMap
13761376
}
13771377

@@ -1404,7 +1404,7 @@ private final class ContainerProvider {
14041404
}
14051405
} else {
14061406
// Otherwise, fetch the container from the provider
1407-
self.underlying.getContainer(for: package, skipUpdate: skipUpdate, on: .sharedConcurrent) { result in
1407+
self.underlying.getContainer(for: package, skipUpdate: !self.updateEnabled, on: .sharedConcurrent) { result in
14081408
let result = result.tryMap { container -> PubGrubPackageContainer in
14091409
let pubGrubContainer = PubGrubPackageContainer(underlying: container, pinsMap: self.pinsMap)
14101410
// only cache positive results
@@ -1428,7 +1428,7 @@ private final class ContainerProvider {
14281428
return group
14291429
}
14301430
if needsFetching {
1431-
self.underlying.getContainer(for: identifier, skipUpdate: skipUpdate, on: .sharedConcurrent) { result in
1431+
self.underlying.getContainer(for: identifier, skipUpdate: !self.updateEnabled, on: .sharedConcurrent) { result in
14321432
defer { self.prefetches[identifier]?.leave() }
14331433
// only cache positive results
14341434
if case .success(let container) = result {

0 commit comments

Comments
 (0)