From 08f96cba497486b82c367559a4be0f698c55c753 Mon Sep 17 00:00:00 2001 From: tom doron Date: Tue, 14 Dec 2021 09:58:21 -0800 Subject: [PATCH 1/4] use idiomatic location for security directory and update location of configuration directory motivation: use idiomatic location for security directory on macOS changes: * allow users to customize security directory location with new --security-path CLI option * on macOS use /Library/org.swiftpm/security for security files and symlink from ~/.swiftpm/security * move configuration directory from /Library/org.swiftpm to /Library/org.swiftpm/configuration * add migration code from old configuraiton location to new one * add and adjust tests * update docker setup for new locationis --- Sources/Basics/FileSystem+Extensions.swift | 131 ++++++++++++++---- Sources/Commands/Options.swift | 3 + Sources/Commands/SwiftTool.swift | 28 ++-- .../JSONPackageCollectionProvider.swift | 2 +- ...FilePackageCollectionsSourcesStorage.swift | 2 +- Sources/SPMTestSupport/MockWorkspace.swift | 2 +- .../Workspace/WorkspaceConfiguration.swift | 2 +- .../FunctionalTests/MiscellaneousTests.swift | 52 ++++++- Utilities/Docker/docker-compose.2004.55.yaml | 1 - Utilities/Docker/docker-compose.yaml | 4 +- 10 files changed, 179 insertions(+), 48 deletions(-) diff --git a/Sources/Basics/FileSystem+Extensions.swift b/Sources/Basics/FileSystem+Extensions.swift index 53f3612b1bd..2cfaa01dc09 100644 --- a/Sources/Basics/FileSystem+Extensions.swift +++ b/Sources/Basics/FileSystem+Extensions.swift @@ -21,10 +21,9 @@ extension FileSystem { public var dotSwiftPM: AbsolutePath { self.homeDirectory.appending(component: ".swiftpm") } - - /// SwiftPM security directory - public var swiftPMSecurityDirectory: AbsolutePath { - self.dotSwiftPM.appending(component: "security") + + fileprivate var idiomaticSwiftPMDirectory: AbsolutePath? { + return FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first.flatMap { AbsolutePath($0.path) }?.appending(component: "org.swift.swiftpm") } } @@ -69,52 +68,126 @@ extension FileSystem { } } -// MARK: - config +// MARK: - configuration extension FileSystem { - private var idiomaticUserConfigDirectory: AbsolutePath? { - return FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first.flatMap { AbsolutePath($0.path) } - } - /// SwiftPM config directory under user's config directory (if exists) - public var swiftPMConfigDirectory: AbsolutePath { - if let path = self.idiomaticUserConfigDirectory { - return path.appending(component: "org.swift.swiftpm") + public var swiftPMConfigurationDirectory: AbsolutePath { + if let path = self.idiomaticSwiftPMDirectory { + return path.appending(component: "configuration") } else { - return self.dotSwiftPMConfigDirectory + return self.dotSwiftPMConfigurationDirectory } } - fileprivate var dotSwiftPMConfigDirectory: AbsolutePath { - return self.dotSwiftPM.appending(component: "config") + fileprivate var dotSwiftPMConfigurationDirectory: AbsolutePath { + return self.dotSwiftPM.appending(component: "configuration") + } +} + +extension FileSystem { + public func getOrCreateSwiftPMConfigurationDirectory(observabilityScope: ObservabilityScope?) throws -> AbsolutePath { + let idiomaticConfigurationDirectory = self.swiftPMConfigurationDirectory + + // temporary 5.6, remove on next version: transition from previous configuration location + if !self.exists(idiomaticConfigurationDirectory) { + try self.createDirectory(idiomaticConfigurationDirectory, recursive: true) + } + + // in the case where ~/.swiftpm/configuration is not the idiomatic location (eg on macOS where its /Users//Library/org.swift.swiftpm/configuration) + if idiomaticConfigurationDirectory != self.dotSwiftPMConfigurationDirectory { + // copy the configuration files from old location (eg /Users//Library/org.swift.swiftpm) to new one (eg /Users//Library/org.swift.swiftpm/configuration) + // but leave them there for backwards compatibility (eg older xcode) + let oldConfigDirectory = idiomaticConfigurationDirectory.parentDirectory + if self.exists(oldConfigDirectory, followSymlink: false) && self.isDirectory(oldConfigDirectory) { + let content = try self.getDirectoryContents(oldConfigDirectory).filter{ !$0.hasSuffix(".lock") } + for item in content { + if self.isFile(oldConfigDirectory.appending(component: item)) && + !self.isSymlink(oldConfigDirectory.appending(component: item)) && + !self.exists(idiomaticConfigurationDirectory.appending(component: item)) { + observabilityScope?.emit(warning: "Usage of \(oldConfigDirectory.appending(component: item)) has been deprecated. Please delete it and use the new \(idiomaticConfigurationDirectory.appending(component: item)) instead.") + try self.copy(from: oldConfigDirectory.appending(component: item), to: idiomaticConfigurationDirectory.appending(component: item)) + } + } + } + // in the case where ~/.swiftpm/configuration is the idiomatic location (eg on Linux) + } else { + // copy the configuration files from old location (~/.swiftpm/config) to new one (~/.swiftpm/configuration) + // but leave them there for backwards compatibility (eg older toolchain) + let oldConfigDirectory = self.dotSwiftPM.appending(component: "config") + if self.exists(oldConfigDirectory, followSymlink: false) && self.isDirectory(oldConfigDirectory) { + let content = try self.getDirectoryContents(oldConfigDirectory).filter{ !$0.hasSuffix(".lock") } + for item in content { + if self.isFile(oldConfigDirectory.appending(component: item)) && + !self.isSymlink(oldConfigDirectory.appending(component: item)) && + !self.exists(idiomaticConfigurationDirectory.appending(component: item)) { + observabilityScope?.emit(warning: "Usage of \(oldConfigDirectory.appending(component: item)) has been deprecated. Please delete it and use the new \(idiomaticConfigurationDirectory.appending(component: item)) instead.") + try self.copy(from: oldConfigDirectory.appending(component: item), to: idiomaticConfigurationDirectory.appending(component: item)) + } + } + } + } + // ~temporary 5.6 migration + + // Create idiomatic if necessary + if !self.exists(idiomaticConfigurationDirectory) { + try self.createDirectory(idiomaticConfigurationDirectory, recursive: true) + } + // Create ~/.swiftpm if necessary + if !self.exists(self.dotSwiftPM) { + try self.createDirectory(self.dotSwiftPM, recursive: true) + } + // Create ~/.swiftpm/configuration symlink if necessary + if !self.exists(self.dotSwiftPMConfigurationDirectory, followSymlink: false) { + try self.createSymbolicLink(dotSwiftPMConfigurationDirectory, pointingAt: idiomaticConfigurationDirectory, relative: false) + } + + return idiomaticConfigurationDirectory } } +// MARK: - security + extension FileSystem { - public func getOrCreateSwiftPMConfigDirectory() throws -> AbsolutePath { - let idiomaticConfigDirectory = self.swiftPMConfigDirectory + /// SwiftPM security directory under user's security directory (if exists) + public var swiftPMSecurityDirectory: AbsolutePath { + if let path = self.idiomaticSwiftPMDirectory { + return path.appending(component: "security") + } else { + return self.dotSwiftPMSecurityDirectory + } + } - // temporary 5.5, remove on next version: transition from ~/.swiftpm/config to idiomatic location + symbolic link - if idiomaticConfigDirectory != self.dotSwiftPMConfigDirectory && - self.exists(self.dotSwiftPMConfigDirectory) && self.isDirectory(self.dotSwiftPMConfigDirectory) && - !self.exists(idiomaticConfigDirectory) { - print("transitioning \(self.dotSwiftPMConfigDirectory) to \(idiomaticConfigDirectory)") - try self.move(from: self.dotSwiftPMConfigDirectory, to: idiomaticConfigDirectory) + fileprivate var dotSwiftPMSecurityDirectory: AbsolutePath { + return self.dotSwiftPM.appending(component: "security") + } +} + +extension FileSystem { + public func getOrCreateSwiftPMSecurityDirectory() throws -> AbsolutePath { + let idiomaticSecurityDirectory = self.swiftPMSecurityDirectory + + // temporary 5.6, remove on next version: transition from ~/.swiftpm/security to idiomatic location + symbolic link + if idiomaticSecurityDirectory != self.dotSwiftPMSecurityDirectory && + self.exists(self.dotSwiftPMSecurityDirectory) && + self.isDirectory(self.dotSwiftPMSecurityDirectory) { + try self.removeFileTree(self.dotSwiftPMSecurityDirectory) } + // ~temporary 5.6 migration // Create idiomatic if necessary - if !self.exists(idiomaticConfigDirectory) { - try self.createDirectory(idiomaticConfigDirectory, recursive: true) + if !self.exists(idiomaticSecurityDirectory) { + try self.createDirectory(idiomaticSecurityDirectory, recursive: true) } // Create ~/.swiftpm if necessary if !self.exists(self.dotSwiftPM) { try self.createDirectory(self.dotSwiftPM, recursive: true) } - // Create ~/.swiftpm/config symlink if necessary - if !self.exists(self.dotSwiftPMConfigDirectory, followSymlink: false) { - try self.createSymbolicLink(dotSwiftPMConfigDirectory, pointingAt: idiomaticConfigDirectory, relative: false) + // Create ~/.swiftpm/security symlink if necessary + if !self.exists(self.dotSwiftPMSecurityDirectory, followSymlink: false) { + try self.createSymbolicLink(dotSwiftPMSecurityDirectory, pointingAt: idiomaticSecurityDirectory, relative: false) } - return idiomaticConfigDirectory + return idiomaticSecurityDirectory } } diff --git a/Sources/Commands/Options.swift b/Sources/Commands/Options.swift index b98ee381bf0..efa61a09508 100644 --- a/Sources/Commands/Options.swift +++ b/Sources/Commands/Options.swift @@ -149,6 +149,9 @@ public struct SwiftToolOptions: ParsableArguments { @Option(help: "Specify the shared configuration directory") var configPath: AbsolutePath? + @Option(help: "Specify the shared security directory") + var securityPath: AbsolutePath? + /// Disables repository caching. @Flag(name: .customLong("repository-cache"), inversion: .prefixedEnableDisable, help: "Use a shared cache when fetching repositories") var useRepositoriesCache: Bool = true diff --git a/Sources/Commands/SwiftTool.swift b/Sources/Commands/SwiftTool.swift index fb69433c436..e893bde8d93 100644 --- a/Sources/Commands/SwiftTool.swift +++ b/Sources/Commands/SwiftTool.swift @@ -246,6 +246,8 @@ protocol SwiftCommand: ParsableCommand { extension SwiftCommand { public func run() throws { let swiftTool = try SwiftTool(options: swiftOptions) + // make sure common directories are created + try swiftTool.createSharedDirectories() try self.run(swiftTool) if swiftTool.observabilityScope.errorsReported || swiftTool.executionStatus == .failure { throw ExitCode.failure @@ -634,7 +636,7 @@ public class SwiftTool { } do { - return try localFileSystem.getOrCreateSwiftPMConfigDirectory() + return try localFileSystem.getOrCreateSwiftPMConfigurationDirectory(observabilityScope: self.observabilityScope) } catch { self.observabilityScope.emit(warning: "Failed creating default configuration location, \(error)") return .none @@ -642,21 +644,31 @@ public class SwiftTool { } private func getSharedSecurityDirectory() throws -> AbsolutePath? { - do { - let fileSystem = localFileSystem - let sharedSecurityDirectory = fileSystem.swiftPMSecurityDirectory - if !fileSystem.exists(sharedSecurityDirectory) { - try fileSystem.createDirectory(sharedSecurityDirectory, recursive: true) + if let explicitSecurityPath = options.securityPath { + // Create the explicit security path if necessary + if !localFileSystem.exists(explicitSecurityPath) { + try localFileSystem.createDirectory(explicitSecurityPath, recursive: true) } + return explicitSecurityPath + } + + do { + let sharedSecurityDirectory = try localFileSystem.getOrCreateSwiftPMSecurityDirectory() // And make sure we can write files (locking the directory writes a lock file) - try fileSystem.withLock(on: sharedSecurityDirectory, type: .exclusive) { } + try localFileSystem.withLock(on: sharedSecurityDirectory, type: .exclusive) { } return sharedSecurityDirectory } catch { - self.observabilityScope.emit(warning: "Failed creating shared security directory: \(error)") + self.observabilityScope.emit(warning: "Failed creating default security location, \(error)") return .none } } + fileprivate func createSharedDirectories() throws { + _ = try getSharedCacheDirectory() + _ = try getSharedConfigurationDirectory() + _ = try getSharedSecurityDirectory() + } + /// Returns the currently active workspace. func getActiveWorkspace() throws -> Workspace { if let workspace = _workspace { diff --git a/Sources/PackageCollections/Providers/JSONPackageCollectionProvider.swift b/Sources/PackageCollections/Providers/JSONPackageCollectionProvider.swift index 24c3bf9037f..f181f5753c2 100644 --- a/Sources/PackageCollections/Providers/JSONPackageCollectionProvider.swift +++ b/Sources/PackageCollections/Providers/JSONPackageCollectionProvider.swift @@ -55,7 +55,7 @@ struct JSONPackageCollectionProvider: PackageCollectionProvider { self.decoder = JSONDecoder.makeWithDefaults() self.validator = JSONModel.Validator(configuration: configuration.validator) self.signatureValidator = signatureValidator ?? PackageCollectionSigning( - trustedRootCertsDir: configuration.trustedRootCertsDir ?? fileSystem.swiftPMConfigDirectory.appending(component: "trust-root-certs").asURL, + trustedRootCertsDir: configuration.trustedRootCertsDir ?? fileSystem.swiftPMConfigurationDirectory.appending(component: "trust-root-certs").asURL, additionalTrustedRootCerts: sourceCertPolicy.allRootCerts.map { Array($0) }, observabilityScope: observabilityScope, callbackQueue: .sharedConcurrent diff --git a/Sources/PackageCollections/Storage/FilePackageCollectionsSourcesStorage.swift b/Sources/PackageCollections/Storage/FilePackageCollectionsSourcesStorage.swift index bfcb4af420e..e3122fd4813 100644 --- a/Sources/PackageCollections/Storage/FilePackageCollectionsSourcesStorage.swift +++ b/Sources/PackageCollections/Storage/FilePackageCollectionsSourcesStorage.swift @@ -26,7 +26,7 @@ struct FilePackageCollectionsSourcesStorage: PackageCollectionsSourcesStorage { init(fileSystem: FileSystem = localFileSystem, path: AbsolutePath? = nil) { self.fileSystem = fileSystem - self.path = path ?? fileSystem.swiftPMConfigDirectory.appending(component: "collections.json") + self.path = path ?? fileSystem.swiftPMConfigurationDirectory.appending(component: "collections.json") self.encoder = JSONEncoder.makeWithDefaults() self.decoder = JSONDecoder.makeWithDefaults() } diff --git a/Sources/SPMTestSupport/MockWorkspace.swift b/Sources/SPMTestSupport/MockWorkspace.swift index afd29ba67d0..c020affeb83 100644 --- a/Sources/SPMTestSupport/MockWorkspace.swift +++ b/Sources/SPMTestSupport/MockWorkspace.swift @@ -241,7 +241,7 @@ public final class MockWorkspace { resolvedVersionsFile: self.sandbox.appending(component: "Package.resolved"), sharedSecurityDirectory: self.fileSystem.swiftPMSecurityDirectory, sharedCacheDirectory: self.fileSystem.swiftPMCacheDirectory, - sharedConfigurationDirectory: self.fileSystem.swiftPMConfigDirectory + sharedConfigurationDirectory: self.fileSystem.swiftPMConfigurationDirectory ), mirrors: self.mirrors, customToolsVersion: self.toolsVersion, diff --git a/Sources/Workspace/WorkspaceConfiguration.swift b/Sources/Workspace/WorkspaceConfiguration.swift index a4bc3b9cce4..e717268be9e 100644 --- a/Sources/Workspace/WorkspaceConfiguration.swift +++ b/Sources/Workspace/WorkspaceConfiguration.swift @@ -126,7 +126,7 @@ extension Workspace { resolvedVersionsFile: DefaultLocations.resolvedVersionsFile(forRootPackage: rootPath), sharedSecurityDirectory: fileSystem.swiftPMSecurityDirectory, sharedCacheDirectory: fileSystem.swiftPMCacheDirectory, - sharedConfigurationDirectory: fileSystem.swiftPMConfigDirectory + sharedConfigurationDirectory: fileSystem.swiftPMConfigurationDirectory ) } } diff --git a/Tests/FunctionalTests/MiscellaneousTests.swift b/Tests/FunctionalTests/MiscellaneousTests.swift index e8ef4305b34..876347ecbc3 100644 --- a/Tests/FunctionalTests/MiscellaneousTests.swift +++ b/Tests/FunctionalTests/MiscellaneousTests.swift @@ -415,7 +415,7 @@ class MiscellaneousTestCase: XCTestCase { XCTAssert(output.contains("does not exist"), "Error from git was not propagated to process output: \(output)") } } - + func testLocalPackageUsedAsURL() throws { fixture(name: "Miscellaneous/LocalPackageAsURL", createGitRepo: false) { prefix in // This fixture has a setup that is trying to use a local package @@ -431,7 +431,7 @@ class MiscellaneousTestCase: XCTestCase { XCTAssert(output.contains("Cannot clone from local directory"), "Didn't find expected output: \(output)") } } - + func testUnicode() { #if !os(Linux) && !os(Android) // TODO: - Linux has trouble with this and needs investigation. fixture(name: "Miscellaneous/Unicode") { prefix in @@ -505,7 +505,7 @@ class MiscellaneousTestCase: XCTestCase { XCTAssertMatch(stderr, .contains("warning: '--generate-linuxmain' option is deprecated")) } } - + func testGenerateLinuxMain() { #if os(macOS) fixture(name: "Miscellaneous/TestDiscovery/Simple") { path in @@ -552,13 +552,13 @@ class MiscellaneousTestCase: XCTestCase { } #endif } - + func testTestsCanLinkAgainstExecutable() throws { // Check if the host compiler supports the '-entry-point-function-name' flag. #if swift(<5.5) try XCTSkipIf(true, "skipping because host compiler doesn't support '-entry-point-function-name'") #endif - + fixture(name: "Miscellaneous/TestableExe") { prefix in do { let (stdout, _) = try executeSwiftTest(prefix) @@ -648,6 +648,17 @@ class MiscellaneousTestCase: XCTestCase { try SwiftPMProduct.SwiftBuild.execute(["--cache-path", customCachePath.pathString], packagePath: path) XCTAssertDirectoryExists(customCachePath) } + + fixture(name: "Miscellaneous/Simple") { path in + try localFileSystem.chmod(.userUnWritable, path: path) + let customCachePath = path.appending(components: "custom", "cache") + XCTAssertNoSuchPath(customCachePath) + let result = try SwiftPMProduct.SwiftBuild.executeProcess(["--cache-path", customCachePath.pathString], packagePath: path) + XCTAssert(result.exitStatus != .terminated(code: 0)) + let output = try result.utf8stderrOutput() + XCTAssert(output.contains("error: You don’t have permission"), "expected permissions error") + XCTAssertNoSuchPath(customCachePath) + } } func testCustomConfigPath() { @@ -657,5 +668,36 @@ class MiscellaneousTestCase: XCTestCase { try SwiftPMProduct.SwiftBuild.execute(["--config-path", customConfigPath.pathString], packagePath: path) XCTAssertDirectoryExists(customConfigPath) } + + fixture(name: "Miscellaneous/Simple") { path in + try localFileSystem.chmod(.userUnWritable, path: path) + let customConfigPath = path.appending(components: "custom", "config") + XCTAssertNoSuchPath(customConfigPath) + let result = try SwiftPMProduct.SwiftBuild.executeProcess(["--config-path", customConfigPath.pathString], packagePath: path) + XCTAssert(result.exitStatus != .terminated(code: 0)) + let output = try result.utf8stderrOutput() + XCTAssert(output.contains("error: You don’t have permission"), "expected permissions error") + XCTAssertNoSuchPath(customConfigPath) + } + } + + func testCustomSecurityPath() { + fixture(name: "Miscellaneous/Simple") { path in + let customSecurityPath = path.appending(components: "custom", "security") + XCTAssertNoSuchPath(customSecurityPath) + try SwiftPMProduct.SwiftBuild.execute(["--security-path", customSecurityPath.pathString], packagePath: path) + XCTAssertDirectoryExists(customSecurityPath) + } + + fixture(name: "Miscellaneous/Simple") { path in + try localFileSystem.chmod(.userUnWritable, path: path) + let customSecurityPath = path.appending(components: "custom", "security") + XCTAssertNoSuchPath(customSecurityPath) + let result = try SwiftPMProduct.SwiftBuild.executeProcess(["--security-path", customSecurityPath.pathString], packagePath: path) + XCTAssert(result.exitStatus != .terminated(code: 0)) + let output = try result.utf8stderrOutput() + XCTAssert(output.contains("error: You don’t have permission"), "expected permissions error") + XCTAssertNoSuchPath(customSecurityPath) + } } } diff --git a/Utilities/Docker/docker-compose.2004.55.yaml b/Utilities/Docker/docker-compose.2004.55.yaml index 13be333b9b4..ed02fc5f485 100644 --- a/Utilities/Docker/docker-compose.2004.55.yaml +++ b/Utilities/Docker/docker-compose.2004.55.yaml @@ -16,7 +16,6 @@ services: args: ubuntu_version: "focal" swift_version: "5.5" - base_image: "swiftlang/swift:nightly-5.5-focal" build: image: swift-package-manager:20.04-5.5 diff --git a/Utilities/Docker/docker-compose.yaml b/Utilities/Docker/docker-compose.yaml index e70fb344767..201473a85eb 100644 --- a/Utilities/Docker/docker-compose.yaml +++ b/Utilities/Docker/docker-compose.yaml @@ -27,7 +27,9 @@ services: - ~/.ssh:/root/.ssh - ~/.cache:/root/.cache - ~/.swiftpm/cache:/root/.swiftpm/cache - - ~/.swiftpm/config:/root/.swiftpm/config + - ~/.swiftpm/configuration:/root/.swiftpm/config # old location, remove after 5.6 + - ~/.swiftpm/configuration:/root/.swiftpm/configuration + - ~/.swiftpm/security:/root/.swiftpm/security # swift-package-manager code - ../..:/code/swift-package-manager:z # bootstrap script requires dependencies to be pre-fetched and in a specific place From 90b95c660764b6669b8007615d6d3d00827d1419 Mon Sep 17 00:00:00 2001 From: tom doron Date: Tue, 14 Dec 2021 19:33:56 -0800 Subject: [PATCH 2/4] fixup --- Sources/Commands/SwiftTool.swift | 158 ++++++++++++++++--------------- 1 file changed, 81 insertions(+), 77 deletions(-) diff --git a/Sources/Commands/SwiftTool.swift b/Sources/Commands/SwiftTool.swift index e893bde8d93..20abd5400dc 100644 --- a/Sources/Commands/SwiftTool.swift +++ b/Sources/Commands/SwiftTool.swift @@ -246,8 +246,6 @@ protocol SwiftCommand: ParsableCommand { extension SwiftCommand { public func run() throws { let swiftTool = try SwiftTool(options: swiftOptions) - // make sure common directories are created - try swiftTool.createSharedDirectories() try self.run(swiftTool) if swiftTool.observabilityScope.errorsReported || swiftTool.executionStatus == .failure { throw ExitCode.failure @@ -296,6 +294,15 @@ public class SwiftTool { /// Path to the build directory. let buildPath: AbsolutePath + /// Path to the shared security directory + let sharedSecurityDirectory: AbsolutePath? + + /// Path to the shared cache directory + let sharedCacheDirectory: AbsolutePath? + + /// Path to the shared configuration directory + let sharedConfigurationDirectory: AbsolutePath? + /// The process set to hold the launched processes. These will be terminated on any signal /// received by the swift tools. let processSet: ProcessSet @@ -335,7 +342,7 @@ public class SwiftTool { self.observabilityScope.emit(error: "couldn't determine the current working directory") throw ExitCode.failure } - originalWorkingDirectory = cwd + self.originalWorkingDirectory = cwd do { try Self.postprocessArgParserResult(options: options, observabilityScope: self.observabilityScope) @@ -418,6 +425,11 @@ public class SwiftTool { customBuildPath ?? (packageRoot ?? cwd).appending(component: ".build") + // make sure common directories are created + self.sharedSecurityDirectory = try getSharedSecurityDirectory(options: self.options, observabilityScope: self.observabilityScope) + self.sharedConfigurationDirectory = try getSharedConfigurationDirectory(options: self.options, observabilityScope: self.observabilityScope) + self.sharedCacheDirectory = try getSharedCacheDirectory(options: self.options, observabilityScope: self.observabilityScope) + // set verbosity globals. // TODO: get rid of this global settings in TSC switch self.logLevel { @@ -494,7 +506,7 @@ public class SwiftTool { } func getMirrorsConfig(sharedConfigurationDirectory: AbsolutePath? = nil) throws -> Workspace.Configuration.Mirrors { - let sharedConfigurationDirectory = try sharedConfigurationDirectory ?? self.getSharedConfigurationDirectory() + let sharedConfigurationDirectory = sharedConfigurationDirectory ?? self.sharedConfigurationDirectory let sharedMirrorFile = sharedConfigurationDirectory.map { Workspace.DefaultLocations.mirrorsConfigurationFile(at: $0) } return try .init( localMirrorFile: self.mirrorsConfigFile(), @@ -539,7 +551,7 @@ public class SwiftTool { func getRegistriesConfig(sharedConfigurationDirectory: AbsolutePath? = nil) throws -> Workspace.Configuration.Registries { let localRegistriesFile = try Workspace.DefaultLocations.registriesConfigurationFile(forRootPackage: self.getPackageRoot()) - let sharedConfigurationDirectory = try sharedConfigurationDirectory ?? self.getSharedConfigurationDirectory() + let sharedConfigurationDirectory = sharedConfigurationDirectory ?? self.sharedConfigurationDirectory let sharedRegistriesFile = sharedConfigurationDirectory.map { Workspace.DefaultLocations.registriesConfigurationFile(at: $0) } @@ -609,66 +621,6 @@ public class SwiftTool { return providers } - private func getSharedCacheDirectory() throws -> AbsolutePath? { - if let explicitCachePath = options.cachePath { - // Create the explicit cache path if necessary - if !localFileSystem.exists(explicitCachePath) { - try localFileSystem.createDirectory(explicitCachePath, recursive: true) - } - return explicitCachePath - } - - do { - return try localFileSystem.getOrCreateSwiftPMCacheDirectory() - } catch { - self.observabilityScope.emit(warning: "Failed creating default cache location, \(error)") - return .none - } - } - - private func getSharedConfigurationDirectory() throws -> AbsolutePath? { - if let explicitConfigPath = options.configPath { - // Create the explicit config path if necessary - if !localFileSystem.exists(explicitConfigPath) { - try localFileSystem.createDirectory(explicitConfigPath, recursive: true) - } - return explicitConfigPath - } - - do { - return try localFileSystem.getOrCreateSwiftPMConfigurationDirectory(observabilityScope: self.observabilityScope) - } catch { - self.observabilityScope.emit(warning: "Failed creating default configuration location, \(error)") - return .none - } - } - - private func getSharedSecurityDirectory() throws -> AbsolutePath? { - if let explicitSecurityPath = options.securityPath { - // Create the explicit security path if necessary - if !localFileSystem.exists(explicitSecurityPath) { - try localFileSystem.createDirectory(explicitSecurityPath, recursive: true) - } - return explicitSecurityPath - } - - do { - let sharedSecurityDirectory = try localFileSystem.getOrCreateSwiftPMSecurityDirectory() - // And make sure we can write files (locking the directory writes a lock file) - try localFileSystem.withLock(on: sharedSecurityDirectory, type: .exclusive) { } - return sharedSecurityDirectory - } catch { - self.observabilityScope.emit(warning: "Failed creating default security location, \(error)") - return .none - } - } - - fileprivate func createSharedDirectories() throws { - _ = try getSharedCacheDirectory() - _ = try getSharedConfigurationDirectory() - _ = try getSharedSecurityDirectory() - } - /// Returns the currently active workspace. func getActiveWorkspace() throws -> Workspace { if let workspace = _workspace { @@ -677,28 +629,25 @@ public class SwiftTool { let delegate = ToolWorkspaceDelegate(self.outputStream, logLevel: self.logLevel, observabilityScope: self.observabilityScope) let provider = GitRepositoryProvider(processSet: processSet) - let sharedSecurityDirectory = try self.getSharedSecurityDirectory() - let sharedCacheDirectory = try self.getSharedCacheDirectory() - let sharedConfigurationDirectory = try self.getSharedConfigurationDirectory() let isXcodeBuildSystemEnabled = self.options.buildSystem == .xcode let workspace = try Workspace( fileSystem: localFileSystem, location: .init( - workingDirectory: buildPath, + workingDirectory: self.buildPath, editsDirectory: self.editsDirectory(), resolvedVersionsFile: self.resolvedVersionsFile(), - sharedSecurityDirectory: sharedSecurityDirectory, - sharedCacheDirectory: sharedCacheDirectory, - sharedConfigurationDirectory: sharedConfigurationDirectory + sharedSecurityDirectory: self.sharedSecurityDirectory, + sharedCacheDirectory: self.sharedCacheDirectory, + sharedConfigurationDirectory: self.sharedConfigurationDirectory ), - mirrors: self.getMirrorsConfig(sharedConfigurationDirectory: sharedConfigurationDirectory).mirrors, - registries: try self.getRegistriesConfig(sharedConfigurationDirectory: sharedConfigurationDirectory).configuration, + mirrors: self.getMirrorsConfig(sharedConfigurationDirectory: self.sharedConfigurationDirectory).mirrors, + registries: try self.getRegistriesConfig(sharedConfigurationDirectory: self.sharedConfigurationDirectory).configuration, authorizationProvider: self.getAuthorizationProvider(), customManifestLoader: self.getManifestLoader(), // FIXME: doe we really need to customize it? customRepositoryProvider: provider, // FIXME: doe we really need to customize it? additionalFileRules: isXcodeBuildSystemEnabled ? FileRuleDescription.xcbuildFileTypes : FileRuleDescription.swiftpmFileTypes, - resolverUpdateEnabled: !options.skipDependencyUpdate, - resolverPrefetchingEnabled: options.shouldEnableResolverPrefetching, + resolverUpdateEnabled: !self.options.skipDependencyUpdate, + resolverPrefetchingEnabled: self.options.shouldEnableResolverPrefetching, resolverFingerprintCheckingMode: self.options.resolverFingerprintCheckingMode, sharedRepositoriesCacheEnabled: self.options.useRepositoriesCache, delegate: delegate @@ -1023,7 +972,7 @@ public class SwiftTool { case (false, .local): cachePath = self.buildPath case (false, .shared): - cachePath = try self.getSharedCacheDirectory().map{ Workspace.DefaultLocations.manifestsDirectory(at: $0) } + cachePath = self.sharedCacheDirectory.map{ Workspace.DefaultLocations.manifestsDirectory(at: $0) } } var extraManifestFlags = self.options.manifestFlags @@ -1074,6 +1023,61 @@ private func getEnvBuildPath(workingDir: AbsolutePath) -> AbsolutePath? { return AbsolutePath(env, relativeTo: workingDir) } + +private func getSharedSecurityDirectory(options: SwiftToolOptions, observabilityScope: ObservabilityScope) throws -> AbsolutePath? { + if let explicitSecurityPath = options.securityPath { + // Create the explicit security path if necessary + if !localFileSystem.exists(explicitSecurityPath) { + try localFileSystem.createDirectory(explicitSecurityPath, recursive: true) + } + return explicitSecurityPath + } + + do { + let sharedSecurityDirectory = try localFileSystem.getOrCreateSwiftPMSecurityDirectory() + // And make sure we can write files (locking the directory writes a lock file) + try localFileSystem.withLock(on: sharedSecurityDirectory, type: .exclusive) { } + return sharedSecurityDirectory + } catch { + observabilityScope.emit(warning: "Failed creating default security location, \(error)") + return .none + } +} + +private func getSharedConfigurationDirectory(options: SwiftToolOptions, observabilityScope: ObservabilityScope) throws -> AbsolutePath? { + if let explicitConfigPath = options.configPath { + // Create the explicit config path if necessary + if !localFileSystem.exists(explicitConfigPath) { + try localFileSystem.createDirectory(explicitConfigPath, recursive: true) + } + return explicitConfigPath + } + + do { + return try localFileSystem.getOrCreateSwiftPMConfigurationDirectory(observabilityScope: observabilityScope) + } catch { + observabilityScope.emit(warning: "Failed creating default configuration location, \(error)") + return .none + } +} + +private func getSharedCacheDirectory(options: SwiftToolOptions, observabilityScope: ObservabilityScope) throws -> AbsolutePath? { + if let explicitCachePath = options.cachePath { + // Create the explicit cache path if necessary + if !localFileSystem.exists(explicitCachePath) { + try localFileSystem.createDirectory(explicitCachePath, recursive: true) + } + return explicitCachePath + } + + do { + return try localFileSystem.getOrCreateSwiftPMCacheDirectory() + } catch { + observabilityScope.emit(warning: "Failed creating default cache location, \(error)") + return .none + } +} + /// A wrapper to hold the build system so we can use it inside /// the int. handler without requiring to initialize it. final class BuildSystemRef { From 2e8f76fa445225afa3b76b8e62439bf8fb837fe2 Mon Sep 17 00:00:00 2001 From: tom doron Date: Tue, 14 Dec 2021 21:12:39 -0800 Subject: [PATCH 3/4] linux --- Tests/FunctionalTests/MiscellaneousTests.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Tests/FunctionalTests/MiscellaneousTests.swift b/Tests/FunctionalTests/MiscellaneousTests.swift index 876347ecbc3..644fb993d9c 100644 --- a/Tests/FunctionalTests/MiscellaneousTests.swift +++ b/Tests/FunctionalTests/MiscellaneousTests.swift @@ -649,6 +649,8 @@ class MiscellaneousTestCase: XCTestCase { XCTAssertDirectoryExists(customCachePath) } + // `FileSystem` does not support `chmod` on Linux + #if os(macOS) fixture(name: "Miscellaneous/Simple") { path in try localFileSystem.chmod(.userUnWritable, path: path) let customCachePath = path.appending(components: "custom", "cache") @@ -659,6 +661,7 @@ class MiscellaneousTestCase: XCTestCase { XCTAssert(output.contains("error: You don’t have permission"), "expected permissions error") XCTAssertNoSuchPath(customCachePath) } + #endif } func testCustomConfigPath() { @@ -669,6 +672,8 @@ class MiscellaneousTestCase: XCTestCase { XCTAssertDirectoryExists(customConfigPath) } + // `FileSystem` does not support `chmod` on Linux + #if os(macOS) fixture(name: "Miscellaneous/Simple") { path in try localFileSystem.chmod(.userUnWritable, path: path) let customConfigPath = path.appending(components: "custom", "config") @@ -679,6 +684,7 @@ class MiscellaneousTestCase: XCTestCase { XCTAssert(output.contains("error: You don’t have permission"), "expected permissions error") XCTAssertNoSuchPath(customConfigPath) } + #endif } func testCustomSecurityPath() { @@ -689,6 +695,8 @@ class MiscellaneousTestCase: XCTestCase { XCTAssertDirectoryExists(customSecurityPath) } + // `FileSystem` does not support `chmod` on Linux + #if os(macOS) fixture(name: "Miscellaneous/Simple") { path in try localFileSystem.chmod(.userUnWritable, path: path) let customSecurityPath = path.appending(components: "custom", "security") @@ -699,5 +707,6 @@ class MiscellaneousTestCase: XCTestCase { XCTAssert(output.contains("error: You don’t have permission"), "expected permissions error") XCTAssertNoSuchPath(customSecurityPath) } + #endif } } From 2ba88d3da7716a7ce816723343e82418f319d249 Mon Sep 17 00:00:00 2001 From: tom doron Date: Wed, 15 Dec 2021 12:37:55 -0800 Subject: [PATCH 4/4] be more noisy --- Sources/Basics/FileSystem+Extensions.swift | 30 ++++++++++++---------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/Sources/Basics/FileSystem+Extensions.swift b/Sources/Basics/FileSystem+Extensions.swift index 2cfaa01dc09..f421c09f78c 100644 --- a/Sources/Basics/FileSystem+Extensions.swift +++ b/Sources/Basics/FileSystem+Extensions.swift @@ -100,13 +100,14 @@ extension FileSystem { // but leave them there for backwards compatibility (eg older xcode) let oldConfigDirectory = idiomaticConfigurationDirectory.parentDirectory if self.exists(oldConfigDirectory, followSymlink: false) && self.isDirectory(oldConfigDirectory) { - let content = try self.getDirectoryContents(oldConfigDirectory).filter{ !$0.hasSuffix(".lock") } - for item in content { - if self.isFile(oldConfigDirectory.appending(component: item)) && - !self.isSymlink(oldConfigDirectory.appending(component: item)) && - !self.exists(idiomaticConfigurationDirectory.appending(component: item)) { - observabilityScope?.emit(warning: "Usage of \(oldConfigDirectory.appending(component: item)) has been deprecated. Please delete it and use the new \(idiomaticConfigurationDirectory.appending(component: item)) instead.") - try self.copy(from: oldConfigDirectory.appending(component: item), to: idiomaticConfigurationDirectory.appending(component: item)) + let configurationFiles = try self.getDirectoryContents(oldConfigDirectory) + .map{ oldConfigDirectory.appending(component: $0) } + .filter{ self.isFile($0) && !self.isSymlink($0) && $0.extension != "lock"} + for file in configurationFiles { + let destination = idiomaticConfigurationDirectory.appending(component: file.basename) + observabilityScope?.emit(warning: "Usage of \(file) has been deprecated. Please delete it and use the new \(destination) instead.") + if !self.exists(destination) { + try self.copy(from: file, to: destination) } } } @@ -116,13 +117,14 @@ extension FileSystem { // but leave them there for backwards compatibility (eg older toolchain) let oldConfigDirectory = self.dotSwiftPM.appending(component: "config") if self.exists(oldConfigDirectory, followSymlink: false) && self.isDirectory(oldConfigDirectory) { - let content = try self.getDirectoryContents(oldConfigDirectory).filter{ !$0.hasSuffix(".lock") } - for item in content { - if self.isFile(oldConfigDirectory.appending(component: item)) && - !self.isSymlink(oldConfigDirectory.appending(component: item)) && - !self.exists(idiomaticConfigurationDirectory.appending(component: item)) { - observabilityScope?.emit(warning: "Usage of \(oldConfigDirectory.appending(component: item)) has been deprecated. Please delete it and use the new \(idiomaticConfigurationDirectory.appending(component: item)) instead.") - try self.copy(from: oldConfigDirectory.appending(component: item), to: idiomaticConfigurationDirectory.appending(component: item)) + let configurationFiles = try self.getDirectoryContents(oldConfigDirectory) + .map{ oldConfigDirectory.appending(component: $0) } + .filter{ self.isFile($0) && !self.isSymlink($0) && $0.extension != "lock"} + for file in configurationFiles { + let destination = idiomaticConfigurationDirectory.appending(component: file.basename) + observabilityScope?.emit(warning: "Usage of \(file) has been deprecated. Please delete it and use the new \(destination) instead.") + if !self.exists(destination) { + try self.copy(from: file, to: destination) } } }