Skip to content

Commit 7e6e3bd

Browse files
committed
Unskip tests blocked by requireThreadSafeWorkingDirectory
Now that llbuild has fork/exec support, the tests can be enabled on Amazon Linux 2, OpenBSD, etc.
1 parent b82337a commit 7e6e3bd

File tree

67 files changed

+237
-168
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+237
-168
lines changed

Sources/SWBApplePlatform/AssetCatalogCompiler.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public final class ActoolCompilerSpec : GenericCompilerSpec, SpecIdentifierType,
5555
}
5656

5757
private func assetTagCombinations(catalogInputs inputs: [FileToBuild], _ cbc: CommandBuildContext, _ delegate: any TaskGenerationDelegate) async throws -> Set<Set<String>> {
58-
return try await executeExternalTool(cbc, delegate, commandLine: [resolveExecutablePath(cbc, cbc.scope.actoolExecutablePath()).str, "--print-asset-tag-combinations", "--output-format", "xml1"] + inputs.map { $0.absolutePath.str }, workingDirectory: cbc.producer.defaultWorkingDirectory.str, environment: environmentFromSpec(cbc, delegate).bindingsDictionary, executionDescription: "Compute asset tag combinations") { output in
58+
return try await executeExternalTool(cbc, delegate, commandLine: [resolveExecutablePath(cbc, cbc.scope.actoolExecutablePath()).str, "--print-asset-tag-combinations", "--output-format", "xml1"] + inputs.map { $0.absolutePath.str }, workingDirectory: cbc.producer.defaultWorkingDirectory, environment: environmentFromSpec(cbc, delegate).bindingsDictionary, executionDescription: "Compute asset tag combinations") { output in
5959
struct AssetCatalogToolOutput: Decodable {
6060
struct Diagnostic: Decodable {
6161
let description: String

Sources/SWBApplePlatform/CoreDataCompiler.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public final class CoreDataModelCompilerSpec : GenericCompilerSpec, SpecIdentifi
6767
// Mark the entire directory structure as being watched by the build system.
6868
delegate.access(path: input.absolutePath)
6969

70-
generatedFiles = try await generatedFilePaths(cbc, delegate, commandLine: [commandLine[0]] + ["--dry-run"] + commandLine[1...], workingDirectory: cbc.producer.defaultWorkingDirectory.str, environment: self.environmentFromSpec(cbc, delegate).bindingsDictionary, executionDescription: "Compute data model \(input.absolutePath.basename) code generation output paths") { output in
70+
generatedFiles = try await generatedFilePaths(cbc, delegate, commandLine: [commandLine[0]] + ["--dry-run"] + commandLine[1...], workingDirectory: cbc.producer.defaultWorkingDirectory, environment: self.environmentFromSpec(cbc, delegate).bindingsDictionary, executionDescription: "Compute data model \(input.absolutePath.basename) code generation output paths") { output in
7171
return output.unsafeStringValue.split(separator: "\n").map(Path.init).map { $0.prependingPrivatePrefixIfNeeded(otherPath: outputDir) }
7272
}
7373
guard !generatedFiles.isEmpty else {

Sources/SWBApplePlatform/CoreMLCompiler.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ public final class CoreMLCompilerSpec : GenericCompilerSpec, SpecIdentifierType,
241241
// Mark the file as being watched by the build system to invalidate the build description.
242242
delegate.access(path: input.absolutePath)
243243

244-
generatedFiles = try await generatedFilePaths(cbc, delegate, commandLine: commandLine[0...3] + ["--dry-run", "yes"] + commandLine[4...], workingDirectory: cbc.producer.defaultWorkingDirectory.str, environment: self.environmentFromSpec(cbc, delegate).bindingsDictionary, executionDescription: "Compute CoreML model \(input.absolutePath.basename) code generation output paths") { output in
244+
generatedFiles = try await generatedFilePaths(cbc, delegate, commandLine: commandLine[0...3] + ["--dry-run", "yes"] + commandLine[4...], workingDirectory: cbc.producer.defaultWorkingDirectory, environment: self.environmentFromSpec(cbc, delegate).bindingsDictionary, executionDescription: "Compute CoreML model \(input.absolutePath.basename) code generation output paths") { output in
245245
return output.unsafeStringValue.split(separator: "\n").map(Path.init)
246246
}
247247
guard !generatedFiles.isEmpty else {

Sources/SWBApplePlatform/IntentsCompiler.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ public final class IntentsCompilerSpec : GenericCompilerSpec, SpecIdentifierType
194194
// Mark the file as being watched by the build system to invalidate the build description.
195195
delegate.access(path: input.absolutePath)
196196

197-
generatedFiles = try await generatedFilePaths(cbc, delegate, commandLine: commandLine[0...1] + ["-dryRun"] + commandLine[2...], workingDirectory: cbc.producer.defaultWorkingDirectory.str, environment: self.environmentFromSpec(cbc, delegate).bindingsDictionary, executionDescription: "Compute Intent Definition \(input.absolutePath.basename) code generation output paths") { output in
197+
generatedFiles = try await generatedFilePaths(cbc, delegate, commandLine: commandLine[0...1] + ["-dryRun"] + commandLine[2...], workingDirectory: cbc.producer.defaultWorkingDirectory, environment: self.environmentFromSpec(cbc, delegate).bindingsDictionary, executionDescription: "Compute Intent Definition \(input.absolutePath.basename) code generation output paths") { output in
198198
return output.unsafeStringValue.split(separator: "\n").map(Path.init).map { $0.prependingPrivatePrefixIfNeeded(otherPath: outputDir) }
199199
}
200200
guard !generatedFiles.isEmpty else {

Sources/SWBApplePlatform/XCStringsCompiler.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public final class XCStringsCompilerSpec: GenericCompilerSpec, SpecIdentifierTyp
6262
// xcstringstool compile --dry-run
6363
dryRunCommandLine.insert("--dry-run", at: 2)
6464

65-
outputs = try await generatedFilePaths(cbc, delegate, commandLine: dryRunCommandLine, workingDirectory: cbc.producer.defaultWorkingDirectory.str, environment: environmentFromSpec(cbc, delegate).bindingsDictionary, executionDescription: "Compute XCStrings \(cbc.input.absolutePath.basename) output paths") { output in
65+
outputs = try await generatedFilePaths(cbc, delegate, commandLine: dryRunCommandLine, workingDirectory: cbc.producer.defaultWorkingDirectory, environment: environmentFromSpec(cbc, delegate).bindingsDictionary, executionDescription: "Compute XCStrings \(cbc.input.absolutePath.basename) output paths") { output in
6666
return output.unsafeStringValue.split(separator: "\n").map(Path.init)
6767
}
6868
} catch {

Sources/SWBBuildService/BuildDependencyInfo.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ extension BuildDependencyInfo {
469469

470470
/// Special `CoreClientDelegate`-conforming struct because our use of `GlobalProductPlan` here should never be running external tools.
471471
fileprivate struct UnsupportedCoreClientDelegate: CoreClientDelegate {
472-
func executeExternalTool(commandLine: [String], workingDirectory: String?, environment: [String : String]) async throws -> ExternalToolResult {
472+
func executeExternalTool(commandLine: [String], workingDirectory: Path?, environment: [String : String]) async throws -> ExternalToolResult {
473473
throw StubError.error("Running external tools is not supported when computing build dependency target info.")
474474
}
475475
}

Sources/SWBBuildService/ClientExchangeDelegate.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ final class ClientExchangeDelegate: ClientDelegate {
3333
self.session = session
3434
}
3535

36-
func executeExternalTool(commandLine: [String], workingDirectory: String?, environment: [String : String]) async throws -> ExternalToolResult {
36+
func executeExternalTool(commandLine: [String], workingDirectory: Path?, environment: [String : String]) async throws -> ExternalToolResult {
3737
// Create a synchronous client exchange which the session uses to handle the response from the client, to make the communication synchronous from the point of view of our caller.
3838
let exchange = SynchronousClientExchange<ExternalToolExecutionResponse>(session)
3939

Sources/SWBBuildSystem/BuildOperation.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,14 +1122,14 @@ private struct OperatorSystemAdaptorDynamicContext: DynamicTaskExecutionDelegate
11221122
}
11231123

11241124
@discardableResult
1125-
func spawn(commandLine: [String], environment: [String: String], workingDirectory: String, processDelegate: any ProcessDelegate) async throws -> Bool {
1125+
func spawn(commandLine: [String], environment: [String: String], workingDirectory: Path, processDelegate: any ProcessDelegate) async throws -> Bool {
11261126
guard let jobContext else {
11271127
throw StubError.error("API misuse. Spawning processes is only allowed from `performTaskAction`.")
11281128
}
11291129

11301130
// This calls into llb_buildsystem_command_interface_spawn, which can block, so ensure it's shunted to a new thread so as not to block the Swift Concurrency thread pool. This shouldn't risk thread explosion because this function is only allowed to be called from performTaskAction, which in turn should be bounded to ncores based on the number of active llbuild lane threads.
11311131
return await _Concurrency.Task.detachNewThread(name: "llb_buildsystem_command_interface_spawn") { [commandInterface, jobContext, processDelegate] in
1132-
commandInterface.spawn(jobContext, commandLine: commandLine, environment: environment, workingDirectory: workingDirectory, processDelegate: processDelegate)
1132+
commandInterface.spawn(jobContext, commandLine: commandLine, environment: environment, workingDirectory: workingDirectory.str, processDelegate: processDelegate)
11331133
}
11341134
}
11351135

Sources/SWBCore/ProcessExecutionCache.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,20 @@ public import SWBUtil
1414

1515
public final class ProcessExecutionCache: Sendable {
1616
private let cache = AsyncCache<[String], Processes.ExecutionResult>()
17+
private let workingDirectory: Path?
1718

18-
public init() { }
19+
public init(workingDirectory: Path? = .root) {
20+
// FIXME: Work around lack of thread-safe working directory support in Foundation (Amazon Linux 2, OpenBSD). Executing processes in the current working directory is less deterministic, but all of the clients which use this class are generally not expected to be sensitive to the working directory anyways. This workaround can be removed once we drop support for Amazon Linux 2 and/or adopt swift-subprocess and/or Foundation.Process's working directory support is made thread safe.
21+
if try! Process.hasUnsafeWorkingDirectorySupport {
22+
self.workingDirectory = nil
23+
return
24+
}
25+
self.workingDirectory = workingDirectory
26+
}
1927

2028
public func run(_ delegate: any CoreClientTargetDiagnosticProducingDelegate, _ commandLine: [String], executionDescription: String?) async throws -> Processes.ExecutionResult {
2129
try await cache.value(forKey: commandLine) {
22-
try await delegate.executeExternalTool(commandLine: commandLine, workingDirectory: "/", environment: [:], executionDescription: executionDescription)
30+
try await delegate.executeExternalTool(commandLine: commandLine, workingDirectory: workingDirectory, environment: [:], executionDescription: executionDescription)
2331
}
2432
}
2533
}

Sources/SWBCore/SpecImplementations/CommandLineToolSpec.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1393,15 +1393,15 @@ open class CommandLineToolSpec : PropertyDomainSpec, SpecType, TaskTypeDescripti
13931393
return Base.instance.shouldStart(task, buildCommand: buildCommand)
13941394
}
13951395

1396-
public func executeExternalTool<T>(_ cbc: CommandBuildContext, _ delegate: any TaskGenerationDelegate, commandLine: [String], workingDirectory: String?, environment: [String: String], executionDescription: String?, _ parse: @escaping (ByteString) throws -> T) async throws -> T {
1396+
public func executeExternalTool<T>(_ cbc: CommandBuildContext, _ delegate: any TaskGenerationDelegate, commandLine: [String], workingDirectory: Path?, environment: [String: String], executionDescription: String?, _ parse: @escaping (ByteString) throws -> T) async throws -> T {
13971397
let executionResult = try await delegate.executeExternalTool(commandLine: commandLine, workingDirectory: workingDirectory, environment: environment, executionDescription: executionDescription)
13981398
guard executionResult.exitStatus.isSuccess else {
13991399
throw RunProcessNonZeroExitError(args: commandLine, workingDirectory: workingDirectory, environment: .init(environment), status: executionResult.exitStatus, stdout: ByteString(executionResult.stdout), stderr: ByteString(executionResult.stderr))
14001400
}
14011401
return try parse(ByteString(executionResult.stdout))
14021402
}
14031403

1404-
public func generatedFilePaths(_ cbc: CommandBuildContext, _ delegate: any TaskGenerationDelegate, commandLine: [String], workingDirectory: String?, environment: [String: String], executionDescription: String?, _ parse: @escaping (ByteString) throws -> [Path]) async throws -> [Path] {
1404+
public func generatedFilePaths(_ cbc: CommandBuildContext, _ delegate: any TaskGenerationDelegate, commandLine: [String], workingDirectory: Path?, environment: [String: String], executionDescription: String?, _ parse: @escaping (ByteString) throws -> [Path]) async throws -> [Path] {
14051405
return try await executeExternalTool(cbc, delegate, commandLine: commandLine, workingDirectory: workingDirectory, environment: environment, executionDescription: executionDescription, parse)
14061406
}
14071407
}

Sources/SWBCore/TaskGeneration.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,7 @@ public struct PlannedTaskBuilder {
647647

648648
/// Interface by which core classes can request information from the client.
649649
public protocol CoreClientDelegate {
650-
func executeExternalTool(commandLine: [String], workingDirectory: String?, environment: [String: String]) async throws -> ExternalToolResult
650+
func executeExternalTool(commandLine: [String], workingDirectory: Path?, environment: [String: String]) async throws -> ExternalToolResult
651651
}
652652

653653
public protocol CoreClientTargetDiagnosticProducingDelegate: AnyObject, TargetDiagnosticProducingDelegate, ActivityReporter {
@@ -757,7 +757,7 @@ extension TaskGenerationDelegate {
757757
}
758758

759759
extension CoreClientTargetDiagnosticProducingDelegate {
760-
public func executeExternalTool(commandLine: [String], workingDirectory: String? = nil, environment: [String: String] = [:], executionDescription: String?) async throws -> Processes.ExecutionResult {
760+
public func executeExternalTool(commandLine: [String], workingDirectory: Path? = nil, environment: [String: String] = [:], executionDescription: String?) async throws -> Processes.ExecutionResult {
761761
try await withActivity(ruleInfo: "ExecuteExternalTool " + commandLine.joined(separator: " "), executionDescription: executionDescription ?? CommandLineToolSpec.fallbackExecutionDescription, signature: ByteString(encodingAsUTF8: "\(commandLine) \(String(describing: workingDirectory)) \(environment)"), target: nil, parentActivity: ActivityID.buildDescriptionActivity) { activity in
762762
try await coreClientDelegate.executeExternalTool(commandLine: commandLine, workingDirectory: workingDirectory, environment: environment)
763763
}
@@ -768,15 +768,15 @@ extension CoreClientTargetDiagnosticProducingDelegate {
768768
private let externalToolExecutionQueue = AsyncOperationQueue(concurrentTasks: ProcessInfo.processInfo.activeProcessorCount)
769769

770770
extension CoreClientDelegate {
771-
package func executeExternalTool(commandLine: [String], workingDirectory: String? = nil, environment: [String: String] = [:]) async throws -> Processes.ExecutionResult {
771+
package func executeExternalTool(commandLine: [String], workingDirectory: Path? = nil, environment: [String: String] = [:]) async throws -> Processes.ExecutionResult {
772772
switch try await executeExternalTool(commandLine: commandLine, workingDirectory: workingDirectory, environment: environment) {
773773
case .deferred:
774774
guard let url = commandLine.first.map(URL.init(fileURLWithPath:)) else {
775775
throw StubError.error("Cannot execute empty command line.")
776776
}
777777

778778
return try await externalToolExecutionQueue.withOperation {
779-
try await Process.getOutput(url: url, arguments: Array(commandLine.dropFirst()), currentDirectoryURL: workingDirectory.map(URL.init(fileURLWithPath:)), environment: Environment.current.addingContents(of: .init(environment)))
779+
try await Process.getOutput(url: url, arguments: Array(commandLine.dropFirst()), currentDirectoryURL: workingDirectory.map { URL(fileURLWithPath: $0.str) }, environment: Environment.current.addingContents(of: .init(environment)))
780780
}
781781
case let .result(status, stdout, stderr):
782782
return Processes.ExecutionResult(exitStatus: status, stdout: stdout, stderr: stderr)

Sources/SWBProtocol/ClientExchangeMessages.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ public struct ExternalToolExecutionRequest: ClientExchangeMessage, Equatable {
2121
public let exchangeHandle: String
2222

2323
public let commandLine: [String]
24-
public let workingDirectory: String?
24+
public let workingDirectory: Path?
2525
public let environment: [String: String]
2626

27-
public init(sessionHandle: String, exchangeHandle: String, commandLine: [String], workingDirectory: String?, environment: [String: String]) {
27+
public init(sessionHandle: String, exchangeHandle: String, commandLine: [String], workingDirectory: Path?, environment: [String: String]) {
2828
self.sessionHandle = sessionHandle
2929
self.exchangeHandle = exchangeHandle
3030
self.commandLine = commandLine

Sources/SWBTaskExecution/TaskActions/ClangCompileTaskAction.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ public final class ClangCompileTaskAction: TaskAction, BuildValueValidatingTaskA
266266
let commandLine = command.arguments
267267
let delegate = TaskProcessDelegate(outputDelegate: outputDelegate)
268268
// The frontend invocations should be unaffected by the environment, pass an empty one.
269-
try await spawn(commandLine: commandLine, environment: [:], workingDirectory: task.workingDirectory.str, dynamicExecutionDelegate: dynamicExecutionDelegate, clientDelegate: clientDelegate, processDelegate: delegate)
269+
try await spawn(commandLine: commandLine, environment: [:], workingDirectory: task.workingDirectory, dynamicExecutionDelegate: dynamicExecutionDelegate, clientDelegate: clientDelegate, processDelegate: delegate)
270270
lastResult = delegate.commandResult
271271

272272
if lastResult == .succeeded {

Sources/SWBTaskExecution/TaskActions/CodeSignTaskAction.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public final class CodeSignTaskAction: TaskAction {
3737
commandLine.insert(preEncryptHashesFlag, at: 1)
3838
}
3939

40-
try await spawn(commandLine: commandLine, environment: task.environment.bindingsDictionary, workingDirectory: task.workingDirectory.str, dynamicExecutionDelegate: dynamicExecutionDelegate, clientDelegate: clientDelegate, processDelegate: processDelegate)
40+
try await spawn(commandLine: commandLine, environment: task.environment.bindingsDictionary, workingDirectory: task.workingDirectory, dynamicExecutionDelegate: dynamicExecutionDelegate, clientDelegate: clientDelegate, processDelegate: processDelegate)
4141
} catch {
4242
outputDelegate.error(error.localizedDescription)
4343
return .failed

Sources/SWBTaskExecution/TaskActions/CopyTiffTaskAction.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ public final class CopyTiffTaskAction: TaskAction {
145145

146146
let processDelegate = TaskProcessDelegate(outputDelegate: outputDelegate)
147147
do {
148-
try await spawn(commandLine: tiffutilCommand, environment: task.environment.bindingsDictionary, workingDirectory: task.workingDirectory.str, dynamicExecutionDelegate: dynamicExecutionDelegate, clientDelegate: clientDelegate, processDelegate: processDelegate)
148+
try await spawn(commandLine: tiffutilCommand, environment: task.environment.bindingsDictionary, workingDirectory: task.workingDirectory, dynamicExecutionDelegate: dynamicExecutionDelegate, clientDelegate: clientDelegate, processDelegate: processDelegate)
149149
} catch {
150150
outputDelegate.error(error.localizedDescription)
151151
return .failed

0 commit comments

Comments
 (0)