Skip to content

Allow relative paths in output file map #63

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions Sources/SwiftDriver/Driver/Driver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -247,13 +247,19 @@ public struct Driver {
let inputFiles = try Self.collectInputFiles(&self.parsedOptions)
self.inputFiles = inputFiles

let outputFileMap: OutputFileMap?
// Initialize an empty output file map, which will be populated when we start creating jobs.
if let outputFileMapArg = parsedOptions.getLastArgument(.outputFileMap)?.asSingle {
let path = try AbsolutePath(validating: outputFileMapArg)
self.outputFileMap = try .load(file: path, diagnosticEngine: diagnosticEngine)
outputFileMap = try .load(file: path, diagnosticEngine: diagnosticEngine)
} else {
outputFileMap = nil
}
else {
self.outputFileMap = nil

if let workingDirectory = self.workingDirectory {
self.outputFileMap = outputFileMap?.resolveRelativePaths(relativeTo: workingDirectory)
} else {
self.outputFileMap = outputFileMap
}

// Determine the compilation mode.
Expand Down
30 changes: 28 additions & 2 deletions Sources/SwiftDriver/Driver/OutputFileMap.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,25 @@ public struct OutputFileMap: Equatable {
try! existingOutput(inputFile: VirtualPath(path: ""), outputType: outputType)
}

public func resolveRelativePaths(relativeTo absPath: AbsolutePath) -> OutputFileMap {
let resolvedKeyValues: [(VirtualPath, [FileType : VirtualPath])] = entries.map {
let resolvedKey: VirtualPath
// Special case for single dependency record, leave it as is
if ($0.key == .relative(.init(""))) {
resolvedKey = $0.key
} else {
resolvedKey = $0.key.resolvedRelativePath(base: absPath)
}
let resolvedValue = $0.value.mapValues {
$0.resolvedRelativePath(base: absPath)
}
return (resolvedKey, resolvedValue)
}
return OutputFileMap(entries: .init(resolvedKeyValues, uniquingKeysWith: { _,_ in
fatalError("Paths collided after resolving")
}))
}

/// Load the output file map at the given path.
public static func load(
file: AbsolutePath,
Expand Down Expand Up @@ -156,9 +175,9 @@ fileprivate struct OutputFileMapJSON: Codable {

/// Converts into virtual path entries.
func toVirtualOutputFileMap() throws -> [VirtualPath : [FileType : VirtualPath]] {
Dictionary(uniqueKeysWithValues: try entries.map { input, entry in
Dictionary(try entries.map { input, entry in
(try VirtualPath(path: input), try entry.paths.mapValues(VirtualPath.init(path:)))
})
}, uniquingKeysWith: { $1 })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This behavior looks good to me, and I think it's consistent with the C++ driver

}

/// Converts from virtual path entries
Expand Down Expand Up @@ -186,3 +205,10 @@ extension String {
return self + "." + ext
}
}

extension VirtualPath {
fileprivate func resolvedRelativePath(base: AbsolutePath) -> VirtualPath {
guard case let .relative(relPath) = self else { return self }
return .absolute(.init(base, relPath))
}
}
38 changes: 38 additions & 0 deletions Tests/SwiftDriverTests/SwiftDriverTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,44 @@ final class SwiftDriverTests: XCTestCase {
}
}

func testOutputFileMapResolving() throws {
// Create sample OutputFileMap:

let stringyEntries: [String: [FileType: String]] = [
"": [.swiftDeps: "foo.build/master.swiftdeps"],
"foo.swift" : [
.dependencies: "foo.build/foo.d",
.object: "foo.build/foo.swift.o",
.swiftModule: "foo.build/foo~partial.swiftmodule",
.swiftDeps: "foo.build/foo.swiftdeps"
]
]
let resolvedStringyEntries: [String: [FileType: String]] = [
"": [.swiftDeps: "/foo_root/foo.build/master.swiftdeps"],
"/foo_root/foo.swift" : [
.dependencies: "/foo_root/foo.build/foo.d",
.object: "/foo_root/foo.build/foo.swift.o",
.swiftModule: "/foo_root/foo.build/foo~partial.swiftmodule",
.swiftDeps: "/foo_root/foo.build/foo.swiftdeps"
]
]
func outputFileMapFromStringyEntries(
_ entries: [String: [FileType: String]]
) throws -> OutputFileMap {
.init(entries: Dictionary(uniqueKeysWithValues: try entries.map { try (
VirtualPath(path: $0.key),
$0.value.mapValues(VirtualPath.init(path:))
)}))
}
let sampleOutputFileMap =
try outputFileMapFromStringyEntries(stringyEntries)
let resolvedOutputFileMap = sampleOutputFileMap
.resolveRelativePaths(relativeTo: .init("/foo_root"))
let expectedOutputFileMap =
try outputFileMapFromStringyEntries(resolvedStringyEntries)
XCTAssertEqual(expectedOutputFileMap, resolvedOutputFileMap)
}

func testResponseFileExpansion() throws {
try withTemporaryDirectory { path in
let diags = DiagnosticsEngine()
Expand Down