Skip to content

Commit 006713c

Browse files
authored
improve location of config directory (#3430)
motivation: use more idiomatic location for SwiftPM config changes: * on darwin platforms, use ~/Library/org.swift.swiftpm to store SwiftPM configs, which is more idiomatic * if idiomatic config directory is different from ~/.swift/config, create a symlink ~/.swift/config -> idiomatic * add temporary transition code for beta users of 5.5 that may already have ~/.swift/config in place * refactor and centralize the computation of config directory * refactor and centralize the computation of cache directory (no functional changes)
1 parent e3cefa5 commit 006713c

File tree

5 files changed

+111
-21
lines changed

5 files changed

+111
-21
lines changed

Sources/Basics/FileSystem+Extensions.swift

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
*/
1010

1111
import TSCBasic
12+
import class Foundation.FileManager
13+
14+
// MARK: - user level
1215

1316
extension FileSystem {
1417
/// SwiftPM directory under user's home directory (~/.swiftpm)
@@ -17,13 +20,93 @@ extension FileSystem {
1720
}
1821
}
1922

23+
24+
// MARK: - cache
25+
2026
extension FileSystem {
27+
private var idiomaticUserCacheDirectory: AbsolutePath? {
28+
// in TSC: FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)
29+
self.cachesDirectory
30+
}
31+
2132
/// SwiftPM cache directory under user's caches directory (if exists)
2233
public var swiftPMCacheDirectory: AbsolutePath {
23-
if let cachesDirectory = self.cachesDirectory {
24-
return cachesDirectory.appending(component: "org.swift.swiftpm")
34+
if let path = self.idiomaticUserCacheDirectory {
35+
return path.appending(component: "org.swift.swiftpm")
2536
} else {
26-
return self.dotSwiftPM.appending(component: "cache")
37+
return self.dotSwiftPMCachesDirectory
38+
}
39+
}
40+
41+
fileprivate var dotSwiftPMCachesDirectory: AbsolutePath {
42+
return self.dotSwiftPM.appending(component: "cache")
43+
}
44+
}
45+
46+
extension FileSystem {
47+
public func getOrCreateSwiftPMCacheDirectory() throws -> AbsolutePath {
48+
let idiomaticCacheDirectory = self.swiftPMCacheDirectory
49+
// Create idiomatic if necessary
50+
if !self.exists(idiomaticCacheDirectory) {
51+
try self.createDirectory(idiomaticCacheDirectory, recursive: true)
52+
}
53+
// Create ~/.swiftpm if necessary
54+
if !self.exists(self.dotSwiftPM) {
55+
try self.createDirectory(self.dotSwiftPM, recursive: true)
56+
}
57+
// Create ~/.swiftpm/cache symlink if necessary
58+
if !self.exists(self.dotSwiftPMCachesDirectory, followSymlink: false) {
59+
try self.createSymbolicLink(dotSwiftPMCachesDirectory, pointingAt: idiomaticCacheDirectory, relative: false)
60+
}
61+
return idiomaticCacheDirectory
62+
}
63+
}
64+
65+
// MARK: - config
66+
67+
extension FileSystem {
68+
private var idiomaticUserConfigDirectory: AbsolutePath? {
69+
return FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first.flatMap { AbsolutePath($0.path) }
70+
}
71+
72+
/// SwiftPM config directory under user's config directory (if exists)
73+
public var swiftPMConfigDirectory: AbsolutePath {
74+
if let path = self.idiomaticUserConfigDirectory {
75+
return path.appending(component: "org.swift.swiftpm")
76+
} else {
77+
return self.dotSwiftPMConfigDirectory
78+
}
79+
}
80+
81+
fileprivate var dotSwiftPMConfigDirectory: AbsolutePath {
82+
return self.dotSwiftPM.appending(component: "config")
83+
}
84+
}
85+
86+
extension FileSystem {
87+
public func getOrCreateSwiftPMConfigDirectory() throws -> AbsolutePath {
88+
let idiomaticConfigDirectory = self.swiftPMConfigDirectory
89+
90+
// temporary 5.5, remove on next version: transition from ~/.swiftpm/config to idiomatic location + symbolic link
91+
if idiomaticConfigDirectory != self.dotSwiftPMConfigDirectory &&
92+
self.exists(self.dotSwiftPMConfigDirectory) && self.isDirectory(self.dotSwiftPMConfigDirectory) &&
93+
!self.exists(idiomaticConfigDirectory) {
94+
print("transitioning \(self.dotSwiftPMConfigDirectory) to \(idiomaticConfigDirectory)")
95+
try self.move(from: self.dotSwiftPMConfigDirectory, to: idiomaticConfigDirectory)
96+
}
97+
98+
// Create idiomatic if necessary
99+
if !self.exists(idiomaticConfigDirectory) {
100+
try self.createDirectory(idiomaticConfigDirectory, recursive: true)
101+
}
102+
// Create ~/.swiftpm if necessary
103+
if !self.exists(self.dotSwiftPM) {
104+
try self.createDirectory(self.dotSwiftPM, recursive: true)
105+
}
106+
// Create ~/.swiftpm/config symlink if necessary
107+
if !self.exists(self.dotSwiftPMConfigDirectory, followSymlink: false) {
108+
try self.createSymbolicLink(dotSwiftPMConfigDirectory, pointingAt: idiomaticConfigDirectory, relative: false)
27109
}
110+
return idiomaticConfigDirectory
28111
}
29112
}

Sources/Commands/Options.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,10 @@ public struct SwiftToolOptions: ParsableArguments {
139139
@Option(help: "Specify the shared cache directory")
140140
var cachePath: AbsolutePath?
141141

142+
// TODO: add actual help when ready to be used
143+
@Option(help: .hidden)
144+
var configPath: AbsolutePath?
145+
142146
/// Disables repository caching.
143147
@Flag(name: .customLong("repository-cache"), inversion: .prefixedEnableDisable, help: "Use a shared cache when fetching repositories")
144148
var useRepositoriesCache: Bool = true

Sources/Commands/SwiftTool.swift

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -528,27 +528,30 @@ public class SwiftTool {
528528
}
529529

530530
do {
531-
// Create the default cache directory.
532-
let idiomaticCachePath = fileSystem.swiftPMCacheDirectory
533-
if !fileSystem.exists(idiomaticCachePath) {
534-
try fileSystem.createDirectory(idiomaticCachePath, recursive: true)
535-
}
536-
// Create ~/.swiftpm if necessary
537-
if !fileSystem.exists(fileSystem.dotSwiftPM) {
538-
try fileSystem.createDirectory(fileSystem.dotSwiftPM, recursive: true)
539-
}
540-
// Create ~/.swiftpm/cache symlink if necessary
541-
let dotSwiftPMCachesPath = fileSystem.dotSwiftPM.appending(component: "cache")
542-
if !fileSystem.exists(dotSwiftPMCachesPath, followSymlink: false) {
543-
try fileSystem.createSymbolicLink(dotSwiftPMCachesPath, pointingAt: idiomaticCachePath, relative: false)
544-
}
545-
return idiomaticCachePath
531+
return try fileSystem.getOrCreateSwiftPMCacheDirectory()
546532
} catch {
547533
self.diagnostics.emit(warning: "Failed creating default cache locations, \(error)")
548534
return nil
549535
}
550536
}
551537

538+
private func getConfigPath(fileSystem: FileSystem = localFileSystem) throws -> AbsolutePath? {
539+
if let explicitConfigPath = options.configPath {
540+
// Create the explicit config path if necessary
541+
if !fileSystem.exists(explicitConfigPath) {
542+
try fileSystem.createDirectory(explicitConfigPath, recursive: true)
543+
}
544+
return explicitConfigPath
545+
}
546+
547+
do {
548+
return try fileSystem.getOrCreateSwiftPMConfigDirectory()
549+
} catch {
550+
self.diagnostics.emit(warning: "Failed creating default config locations, \(error)")
551+
return nil
552+
}
553+
}
554+
552555
/// Returns the currently active workspace.
553556
func getActiveWorkspace() throws -> Workspace {
554557
if let workspace = _workspace {
@@ -559,6 +562,7 @@ public class SwiftTool {
559562
let delegate = ToolWorkspaceDelegate(self.stdoutStream, isVerbose: isVerbose, diagnostics: diagnostics)
560563
let provider = GitRepositoryProvider(processSet: processSet)
561564
let cachePath = self.options.useRepositoriesCache ? try self.getCachePath() : .none
565+
_ = try self.getConfigPath() // TODO: actually use this in the workspace
562566
let isXcodeBuildSystemEnabled = self.options.buildSystem == .xcode
563567
let workspace = Workspace(
564568
dataPath: buildPath,

Sources/PackageCollections/Providers/JSONPackageCollectionProvider.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ struct JSONPackageCollectionProvider: PackageCollectionProvider {
5353
self.decoder = JSONDecoder.makeWithDefaults()
5454
self.validator = JSONModel.Validator(configuration: configuration.validator)
5555
self.signatureValidator = signatureValidator ?? PackageCollectionSigning(
56-
trustedRootCertsDir: configuration.trustedRootCertsDir ?? fileSystem.dotSwiftPM.appending(components: "config", "trust-root-certs").asURL,
56+
trustedRootCertsDir: configuration.trustedRootCertsDir ?? fileSystem.swiftPMConfigDirectory.appending(component: "trust-root-certs").asURL,
5757
additionalTrustedRootCerts: sourceCertPolicy.allRootCerts,
5858
callbackQueue: .sharedConcurrent,
5959
diagnosticsEngine: diagnosticsEngine

Sources/PackageCollections/Storage/FilePackageCollectionsSourcesStorage.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ struct FilePackageCollectionsSourcesStorage: PackageCollectionsSourcesStorage {
2727
init(fileSystem: FileSystem = localFileSystem, path: AbsolutePath? = nil, diagnosticsEngine: DiagnosticsEngine? = nil) {
2828
self.fileSystem = fileSystem
2929

30-
let name = "collections"
31-
self.path = path ?? fileSystem.dotSwiftPM.appending(components: "config", "\(name).json")
30+
self.path = path ?? fileSystem.swiftPMConfigDirectory.appending(component: "collections.json")
3231
self.diagnosticsEngine = diagnosticsEngine
3332
self.encoder = JSONEncoder.makeWithDefaults()
3433
self.decoder = JSONDecoder.makeWithDefaults()

0 commit comments

Comments
 (0)