Skip to content

Commit bb10f18

Browse files
authored
Merge pull request #99 from DougGregor/no-locals-for-old-file-systems
Thread a filesystem throughout the Swift driver.
2 parents 3696f04 + 2774216 commit bb10f18

16 files changed

+99
-59
lines changed

Sources/SwiftDriver/Driver/Driver.swift

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ public struct Driver {
7777
/// it should be identical to the real environment.
7878
public let env: [String: String]
7979

80+
/// The file system which we should interact with.
81+
public let fileSystem: FileSystem
82+
8083
/// Diagnostic engine for emitting warnings, errors, etc.
8184
public let diagnosticEngine: DiagnosticsEngine
8285

@@ -226,17 +229,19 @@ public struct Driver {
226229
public init(
227230
args: [String],
228231
env: [String: String] = ProcessEnv.vars,
229-
diagnosticsEngine: DiagnosticsEngine = DiagnosticsEngine(handlers: [Driver.stderrDiagnosticsHandler])
232+
diagnosticsEngine: DiagnosticsEngine = DiagnosticsEngine(handlers: [Driver.stderrDiagnosticsHandler]),
233+
fileSystem: FileSystem = localFileSystem
230234
) throws {
231235
self.env = env
236+
self.fileSystem = fileSystem
232237

233238
self.diagnosticEngine = diagnosticsEngine
234239

235240
if case .subcommand = try Self.invocationRunMode(forArgs: args).mode {
236241
throw Error.subcommandPassedToDriver
237242
}
238243

239-
var args = try Self.expandResponseFiles(args, diagnosticsEngine: self.diagnosticEngine)[...]
244+
var args = try Self.expandResponseFiles(args, fileSystem: fileSystem, diagnosticsEngine: self.diagnosticEngine)[...]
240245

241246
self.driverKind = try Self.determineDriverKind(args: &args)
242247
self.optionTable = OptionTable()
@@ -246,7 +251,7 @@ public struct Driver {
246251
.map {
247252
Triple($0, normalizing: true)
248253
}
249-
(self.toolchain, self.targetTriple) = try Self.computeToolchain(explicitTarget, diagnosticsEngine: diagnosticEngine, env: env)
254+
(self.toolchain, self.targetTriple) = try Self.computeToolchain(explicitTarget, diagnosticsEngine: diagnosticEngine, env: env, fileSystem: fileSystem)
250255
self.targetVariantTriple = self.parsedOptions.getLastArgument(.targetVariant).map { Triple($0.asSingle, normalizing: true) }
251256

252257
// Find the Swift compiler executable.
@@ -266,7 +271,7 @@ public struct Driver {
266271

267272
// Compute the working directory.
268273
workingDirectory = try parsedOptions.getLastArgument(.workingDirectory).map { workingDirectoryArg in
269-
let cwd = localFileSystem.currentWorkingDirectory
274+
let cwd = fileSystem.currentWorkingDirectory
270275
return try cwd.map{ AbsolutePath(workingDirectoryArg.asSingle, relativeTo: $0) } ?? AbsolutePath(validating: workingDirectoryArg.asSingle)
271276
}
272277

@@ -280,7 +285,7 @@ public struct Driver {
280285
self.inputFiles = inputFiles
281286
self.recordedInputModificationDates = .init(uniqueKeysWithValues:
282287
Set(inputFiles).compactMap {
283-
guard let modTime = try? localFileSystem
288+
guard let modTime = try? fileSystem
284289
.getFileInfo($0.file).modTime else { return nil }
285290
return ($0, modTime)
286291
})
@@ -289,7 +294,7 @@ public struct Driver {
289294
// Initialize an empty output file map, which will be populated when we start creating jobs.
290295
if let outputFileMapArg = parsedOptions.getLastArgument(.outputFileMap)?.asSingle {
291296
let path = try VirtualPath(path: outputFileMapArg)
292-
outputFileMap = try .load(file: path, diagnosticEngine: diagnosticEngine)
297+
outputFileMap = try .load(fileSystem: fileSystem, file: path, diagnosticEngine: diagnosticEngine)
293298
} else {
294299
outputFileMap = nil
295300
}
@@ -327,13 +332,14 @@ public struct Driver {
327332
compilerMode: compilerMode,
328333
outputFileMap: self.outputFileMap,
329334
compilerOutputType: self.compilerOutputType,
330-
moduleOutput: self.moduleOutput,
335+
moduleOutput: self.moduleOutput,
336+
fileSystem: fileSystem,
331337
inputFiles: inputFiles,
332338
diagnosticEngine: diagnosticEngine,
333339
actualSwiftVersion: try? toolchain.swiftCompilerVersion()
334340
)
335341

336-
self.sdkPath = Self.computeSDKPath(&parsedOptions, compilerMode: compilerMode, toolchain: toolchain, diagnosticsEngine: diagnosticEngine, env: env)
342+
self.sdkPath = Self.computeSDKPath(&parsedOptions, compilerMode: compilerMode, toolchain: toolchain, fileSystem: fileSystem, diagnosticsEngine: diagnosticEngine, env: env)
337343

338344
self.importedObjCHeader = try Self.computeImportedObjCHeader(&parsedOptions, compilerMode: compilerMode, diagnosticEngine: diagnosticEngine)
339345
self.bridgingPrecompiledHeader = try Self.computeBridgingPrecompiledHeader(&parsedOptions,
@@ -531,6 +537,7 @@ extension Driver {
531537
/// - Parameter visitedResponseFiles: Set containing visited response files to detect recursive parsing.
532538
private static func expandResponseFiles(
533539
_ args: [String],
540+
fileSystem: FileSystem,
534541
diagnosticsEngine: DiagnosticsEngine,
535542
visitedResponseFiles: inout Set<AbsolutePath>
536543
) throws -> [String] {
@@ -548,9 +555,9 @@ extension Driver {
548555
visitedResponseFiles.remove(responseFile)
549556
}
550557

551-
let contents = try localFileSystem.readFileContents(responseFile).cString
558+
let contents = try fileSystem.readFileContents(responseFile).cString
552559
let lines = tokenizeResponseFile(contents)
553-
result.append(contentsOf: try expandResponseFiles(lines, diagnosticsEngine: diagnosticsEngine, visitedResponseFiles: &visitedResponseFiles))
560+
result.append(contentsOf: try expandResponseFiles(lines, fileSystem: fileSystem, diagnosticsEngine: diagnosticsEngine, visitedResponseFiles: &visitedResponseFiles))
554561
} else {
555562
result.append(arg)
556563
}
@@ -562,24 +569,23 @@ extension Driver {
562569
/// Expand response files in the input arguments and return a new argument list.
563570
public static func expandResponseFiles(
564571
_ args: [String],
572+
fileSystem: FileSystem,
565573
diagnosticsEngine: DiagnosticsEngine
566574
) throws -> [String] {
567575
var visitedResponseFiles = Set<AbsolutePath>()
568-
return try expandResponseFiles(args, diagnosticsEngine: diagnosticsEngine, visitedResponseFiles: &visitedResponseFiles)
576+
return try expandResponseFiles(args, fileSystem: fileSystem, diagnosticsEngine: diagnosticsEngine, visitedResponseFiles: &visitedResponseFiles)
569577
}
570578
}
571579

572580
extension Driver {
573581
/// Determine the driver kind based on the command-line arguments, consuming the arguments
574582
/// conveying this information.
575583
public static func determineDriverKind(
576-
args: inout ArraySlice<String>,
577-
cwd: AbsolutePath? = localFileSystem.currentWorkingDirectory
584+
args: inout ArraySlice<String>
578585
) throws -> DriverKind {
579586
// Get the basename of the driver executable.
580587
let execRelPath = args.removeFirst()
581-
let execPath = try cwd.map{ AbsolutePath(execRelPath, relativeTo: $0) } ?? AbsolutePath(validating: execRelPath)
582-
var driverName = execPath.basename
588+
var driverName = try VirtualPath(path: execRelPath).basenameWithoutExt
583589

584590
// Determine driver kind based on the first argument.
585591
let driverModeOption = "--driver-mode="
@@ -670,7 +676,7 @@ extension Driver {
670676
forceResponseFiles: forceResponseFiles,
671677
recordedInputModificationDates: recordedInputModificationDates
672678
)
673-
try jobExecutor.execute(env: env)
679+
try jobExecutor.execute(env: env, fileSystem: fileSystem)
674680
}
675681

676682
public mutating func createToolExecutionDelegate() -> ToolExecutionDelegate {
@@ -694,7 +700,7 @@ extension Driver {
694700
try ProcessEnv.setVar(envVar, value: value)
695701
}
696702

697-
try job.verifyInputsNotModified(since: self.recordedInputModificationDates)
703+
try job.verifyInputsNotModified(since: self.recordedInputModificationDates, fileSystem: fileSystem)
698704

699705
return try exec(path: arguments[0], args: arguments)
700706
}
@@ -1357,6 +1363,7 @@ extension Driver {
13571363
_ parsedOptions: inout ParsedOptions,
13581364
compilerMode: CompilerMode,
13591365
toolchain: Toolchain,
1366+
fileSystem: FileSystem,
13601367
diagnosticsEngine: DiagnosticsEngine,
13611368
env: [String: String]
13621369
) -> String? {
@@ -1392,14 +1399,14 @@ extension Driver {
13921399
// FIXME: TSC should provide a better utility for this.
13931400
if let absPath = try? AbsolutePath(validating: sdkPath) {
13941401
path = absPath
1395-
} else if let cwd = localFileSystem.currentWorkingDirectory {
1402+
} else if let cwd = fileSystem.currentWorkingDirectory {
13961403
path = AbsolutePath(sdkPath, relativeTo: cwd)
13971404
} else {
13981405
diagnosticsEngine.emit(.warning_no_such_sdk(sdkPath))
13991406
return sdkPath
14001407
}
14011408

1402-
if !localFileSystem.exists(path) {
1409+
if !fileSystem.exists(path) {
14031410
diagnosticsEngine.emit(.warning_no_such_sdk(sdkPath))
14041411
}
14051412
// .. else check if SDK is too old (we need target triple to diagnose that).
@@ -1505,11 +1512,12 @@ extension Driver {
15051512
static func computeToolchain(
15061513
_ explicitTarget: Triple?,
15071514
diagnosticsEngine: DiagnosticsEngine,
1508-
env: [String: String]
1515+
env: [String: String],
1516+
fileSystem: FileSystem
15091517
) throws -> (Toolchain, Triple) {
15101518
let toolchainType = try explicitTarget?.toolchainType(diagnosticsEngine) ??
15111519
defaultToolchainType
1512-
let toolchain = toolchainType.init(env: env)
1520+
let toolchain = toolchainType.init(env: env, fileSystem: fileSystem)
15131521
return (toolchain, try explicitTarget ?? toolchain.hostTargetTriple())
15141522
}
15151523
}

Sources/SwiftDriver/Driver/OutputFileMap.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
import TSCBasic
1313
import Foundation
1414

15+
public typealias FileSystem = TSCBasic.FileSystem
16+
1517
/// Mapping of input file paths to specific output files.
1618
public struct OutputFileMap: Equatable {
1719
/// The known mapping from input file to specific output files.
@@ -68,11 +70,12 @@ public struct OutputFileMap: Equatable {
6870

6971
/// Load the output file map at the given path.
7072
public static func load(
73+
fileSystem: FileSystem,
7174
file: VirtualPath,
7275
diagnosticEngine: DiagnosticsEngine
7376
) throws -> OutputFileMap {
7477
// Load and decode the file.
75-
let contents = try localFileSystem.readFileContents(file)
78+
let contents = try fileSystem.readFileContents(file)
7679
let result = try JSONDecoder().decode(OutputFileMapJSON.self, from: Data(contents.contents))
7780

7881
// Convert the loaded entries into virual output file map.
@@ -84,6 +87,7 @@ public struct OutputFileMap: Equatable {
8487

8588
/// Store the output file map at the given path.
8689
public func store(
90+
fileSystem: FileSystem,
8791
file: AbsolutePath,
8892
diagnosticEngine: DiagnosticsEngine
8993
) throws {
@@ -98,7 +102,7 @@ public struct OutputFileMap: Equatable {
98102
#endif
99103

100104
let contents = try encoder.encode(OutputFileMapJSON.fromVirtualOutputFileMap(entries).entries)
101-
try localFileSystem.writeFileContents(file, bytes: ByteString(contents))
105+
try fileSystem.writeFileContents(file, bytes: ByteString(contents))
102106
}
103107
}
104108

Sources/SwiftDriver/Execution/JobExecutor.swift

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,18 @@ public struct ArgsResolver {
2020
/// The map of virtual path to the actual path.
2121
public var pathMapping: [VirtualPath: AbsolutePath]
2222

23+
/// The file system used by the resolver.
24+
private let fileSystem: FileSystem
25+
2326
/// Path to the directory that will contain the temporary files.
2427
private let temporaryDirectory: AbsolutePath
2528

26-
public init() throws {
29+
public init(fileSystem: FileSystem = localFileSystem) throws {
2730
self.pathMapping = [:]
31+
self.fileSystem = fileSystem
2832
self.temporaryDirectory = try withTemporaryDirectory(removeTreeOnDeinit: false) { path in
2933
// FIXME: TSC removes empty directories even when removeTreeOnDeinit is false. This seems like a bug.
30-
try localFileSystem.writeFileContents(path.appending(component: ".keep-directory")) { $0 <<< "" }
34+
try fileSystem.writeFileContents(path.appending(component: ".keep-directory")) { $0 <<< "" }
3135
return path
3236
}
3337
}
@@ -75,7 +79,7 @@ public struct ArgsResolver {
7579
"Platform does not support response files for job: \(job)")
7680
// Match the integrated driver's behavior, which uses response file names of the form "arguments-[0-9a-zA-Z].resp".
7781
let responseFilePath = temporaryDirectory.appending(component: "arguments-\(abs(job.hashValue)).resp")
78-
try localFileSystem.writeFileContents(responseFilePath) {
82+
try fileSystem.writeFileContents(responseFilePath) {
7983
$0 <<< resolvedArguments[1...].map{ $0.spm_shellEscaped() }.joined(separator: "\n")
8084
}
8185
resolvedArguments = [resolvedArguments[0], "@\(responseFilePath.pathString)"]
@@ -123,6 +127,9 @@ public final class JobExecutor {
123127
/// The environment variables.
124128
let env: [String: String]
125129

130+
/// The file system.
131+
let fileSystem: FileSystem
132+
126133
/// The job executor delegate.
127134
let executorDelegate: JobExecutorDelegate
128135

@@ -144,6 +151,7 @@ public final class JobExecutor {
144151
init(
145152
argsResolver: ArgsResolver,
146153
env: [String: String],
154+
fileSystem: FileSystem,
147155
producerMap: [VirtualPath: Job],
148156
executorDelegate: JobExecutorDelegate,
149157
jobQueue: OperationQueue,
@@ -154,6 +162,7 @@ public final class JobExecutor {
154162
self.producerMap = producerMap
155163
self.argsResolver = argsResolver
156164
self.env = env
165+
self.fileSystem = fileSystem
157166
self.executorDelegate = executorDelegate
158167
self.jobQueue = jobQueue
159168
self.processSet = processSet
@@ -202,8 +211,8 @@ public final class JobExecutor {
202211
}
203212

204213
/// Execute all jobs.
205-
public func execute(env: [String: String]) throws {
206-
let context = createContext(jobs, env: env)
214+
public func execute(env: [String: String], fileSystem: FileSystem) throws {
215+
let context = createContext(jobs, env: env, fileSystem: fileSystem)
207216

208217
let delegate = JobExecutorBuildDelegate(context)
209218
let engine = LLBuildEngine(delegate: delegate)
@@ -217,7 +226,7 @@ public final class JobExecutor {
217226
}
218227

219228
/// Create the context required during the execution.
220-
func createContext(_ jobs: [Job], env: [String: String]) -> Context {
229+
func createContext(_ jobs: [Job], env: [String: String], fileSystem: FileSystem) -> Context {
221230
var producerMap: [VirtualPath: Job] = [:]
222231
for job in jobs {
223232
for output in job.outputs {
@@ -233,6 +242,7 @@ public final class JobExecutor {
233242
return Context(
234243
argsResolver: argsResolver,
235244
env: env,
245+
fileSystem: fileSystem,
236246
producerMap: producerMap,
237247
executorDelegate: executorDelegate,
238248
jobQueue: jobQueue,
@@ -254,7 +264,7 @@ struct JobExecutorBuildDelegate: LLBuildEngineDelegate {
254264
func lookupRule(rule: String, key: Key) -> Rule {
255265
switch rule {
256266
case ExecuteAllJobsRule.ruleName:
257-
return ExecuteAllJobsRule(key)
267+
return ExecuteAllJobsRule(key, fileSystem: context.fileSystem)
258268
case ExecuteJobRule.ruleName:
259269
return ExecuteJobRule(key, context: context)
260270
default:
@@ -295,9 +305,9 @@ class ExecuteAllJobsRule: LLBuildRule {
295305
/// True if any of the inputs had any error.
296306
private var allInputsSucceeded: Bool = true
297307

298-
init(_ key: Key) {
308+
init(_ key: Key, fileSystem: FileSystem) {
299309
self.key = RuleKey(key)
300-
super.init()
310+
super.init(fileSystem: fileSystem)
301311
}
302312

303313
override func start(_ engine: LLTaskBuildEngine) {
@@ -344,7 +354,7 @@ class ExecuteJobRule: LLBuildRule {
344354
init(_ key: Key, context: JobExecutor.Context) {
345355
self.key = RuleKey(key)
346356
self.context = context
347-
super.init()
357+
super.init(fileSystem: context.fileSystem)
348358
}
349359

350360
override func start(_ engine: LLTaskBuildEngine) {
@@ -392,7 +402,7 @@ class ExecuteJobRule: LLBuildRule {
392402
let arguments: [String] = try resolver.resolveArgumentList(for: job,
393403
forceResponseFiles: context.forceResponseFiles)
394404

395-
try job.verifyInputsNotModified(since: context.recordedInputModificationDates)
405+
try job.verifyInputsNotModified(since: context.recordedInputModificationDates, fileSystem: engine.fileSystem)
396406

397407
let process = try context.executorDelegate.launchProcess(
398408
for: job, arguments: arguments, env: env

Sources/SwiftDriver/Execution/llbuild.swift

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,11 @@ public final class LLBuildEngine {
106106
public class LLTaskBuildEngine {
107107

108108
let engine: TaskBuildEngine
109+
let fileSystem: FileSystem
109110

110-
init(_ engine: TaskBuildEngine) {
111+
init(_ engine: TaskBuildEngine, fileSystem: FileSystem) {
111112
self.engine = engine
113+
self.fileSystem = fileSystem
112114
}
113115

114116
public func taskNeedsInput<T: LLBuildKey>(_ key: T, inputID: Int) {
@@ -132,23 +134,26 @@ open class LLBuildRule: Rule, Task {
132134
fatalError("subclass responsibility")
133135
}
134136

135-
public init() {
137+
let fileSystem: FileSystem
138+
139+
public init(fileSystem: FileSystem) {
140+
self.fileSystem = fileSystem
136141
}
137142

138143
public func createTask() -> Task {
139144
return self
140145
}
141146

142147
public func start(_ engine: TaskBuildEngine) {
143-
self.start(LLTaskBuildEngine(engine))
148+
self.start(LLTaskBuildEngine(engine, fileSystem: fileSystem))
144149
}
145150

146151
public func provideValue(_ engine: TaskBuildEngine, inputID: Int, value: Value) {
147-
self.provideValue(LLTaskBuildEngine(engine), inputID: inputID, value: value)
152+
self.provideValue(LLTaskBuildEngine(engine, fileSystem: fileSystem), inputID: inputID, value: value)
148153
}
149154

150155
public func inputsAvailable(_ engine: TaskBuildEngine) {
151-
self.inputsAvailable(LLTaskBuildEngine(engine))
156+
self.inputsAvailable(LLTaskBuildEngine(engine, fileSystem: fileSystem))
152157
}
153158

154159
// MARK:-

0 commit comments

Comments
 (0)