Skip to content

Commit da998bc

Browse files
committed
Add -supplementary-output-file-map
1 parent d95da61 commit da998bc

File tree

6 files changed

+98
-26
lines changed

6 files changed

+98
-26
lines changed

Sources/XCRemoteCache/Commands/SwiftFrontend/SwiftFrontendArgInput.swift

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ public struct SwiftFrontendArgInput {
6363
// .swiftsourceinfo and .swiftdoc will be placed next to the .swiftmodule
6464
let sourceInfoPath: String?
6565
let docPath: String?
66+
let supplementaryOutputFileMap: String?
6667

6768
/// Manual initializer implementation required to be public
6869
public init(
@@ -77,7 +78,8 @@ public struct SwiftFrontendArgInput {
7778
dependenciesPaths: [String],
7879
diagnosticsPaths: [String],
7980
sourceInfoPath: String?,
80-
docPath: String?
81+
docPath: String?,
82+
supplementaryOutputFileMap: String?
8183
) {
8284
self.compile = compile
8385
self.emitModule = emitModule
@@ -91,6 +93,7 @@ public struct SwiftFrontendArgInput {
9193
self.diagnosticsPaths = diagnosticsPaths
9294
self.sourceInfoPath = sourceInfoPath
9395
self.docPath = docPath
96+
self.supplementaryOutputFileMap = supplementaryOutputFileMap
9497
}
9598

9699
// swiftlint:disable:next cyclomatic_complexity function_body_length
@@ -139,23 +142,28 @@ public struct SwiftFrontendArgInput {
139142
emitModule: nil
140143
)
141144

142-
let compilationFileMap = (0..<primaryInputsCount).reduce([String: SwiftFileCompilationInfo]()) { prev, i in
143-
var new = prev
144-
new[primaryInputPaths[i]] = SwiftFileCompilationInfo(
145-
file: primaryInputFilesURLs[i],
146-
dependencies: dependenciesPaths.get(i).map(URL.init(fileURLWithPath:)),
147-
object: outputPaths.get(i).map(URL.init(fileURLWithPath:)),
148-
// for now - swift-dependencies are not requested in the driver compilation mode
149-
swiftDependencies: nil
150-
)
151-
return new
145+
let compilationFilesOutputs: SwiftcContext.CompilationFilesOutputs
146+
if let compimentaryFileMa = supplementaryOutputFileMap {
147+
compilationFilesOutputs = .supplementaryFileMap(compimentaryFileMa)
148+
} else {
149+
compilationFilesOutputs = .map((0..<primaryInputsCount).reduce([String: SwiftFileCompilationInfo]()) { prev, i in
150+
var new = prev
151+
new[primaryInputPaths[i]] = SwiftFileCompilationInfo(
152+
file: primaryInputFilesURLs[i],
153+
dependencies: dependenciesPaths.get(i).map(URL.init(fileURLWithPath:)),
154+
object: outputPaths.get(i).map(URL.init(fileURLWithPath:)),
155+
// for now - swift-dependencies are not requested in the driver compilation mode
156+
swiftDependencies: nil
157+
)
158+
return new
159+
})
152160
}
153161

154162
return try .init(
155163
config: config,
156164
moduleName: moduleName,
157165
steps: steps,
158-
outputs: .map(compilationFileMap),
166+
outputs: compilationFilesOutputs,
159167
target: target,
160168
inputs: .list(inputPaths),
161169
exampleWorkspaceFilePath: outputPaths[0]

Sources/XCRemoteCache/Commands/Swiftc/SwiftcContext.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ public struct SwiftcContext {
4848
public enum CompilationFilesOutputs {
4949
/// defined in a separate file (via -output-file-map)
5050
case fileMap(String)
51+
/// defined in a separate file (via -supplementary-output-file-map)
52+
case supplementaryFileMap(String)
5153
/// explicitly passed in the invocation
5254
case map([String: SwiftFileCompilationInfo])
5355
}

Sources/XCRemoteCache/Commands/Swiftc/SwiftcFilemapInputEditor.swift

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@
1818
// under the License.
1919

2020
import Foundation
21+
import Yams
2122

2223
/// Errors with reading swiftc inputs
2324
enum SwiftcInputReaderError: Error {
2425
case readingFailed
2526
case invalidFormat
27+
case invalidYamlFormat
2628
case missingField(String)
2729
}
2830

@@ -61,19 +63,26 @@ public struct SwiftFileCompilationInfo: Encodable, Equatable {
6163

6264
class SwiftcFilemapInputEditor: SwiftcInputReader, SwiftcInputWriter {
6365

66+
enum Format {
67+
case json
68+
case yaml
69+
}
70+
6471
private let file: URL
72+
private let fileFormat: Format
6573
private let fileManager: FileManager
6674

67-
init(_ file: URL, fileManager: FileManager) {
75+
init(_ file: URL, fileFormat: Format, fileManager: FileManager) {
6876
self.file = file
77+
self.fileFormat = fileFormat
6978
self.fileManager = fileManager
7079
}
7180

7281
func read() throws -> SwiftCompilationInfo {
7382
guard let content = fileManager.contents(atPath: file.path) else {
7483
throw SwiftcInputReaderError.readingFailed
7584
}
76-
guard let representation = try JSONSerialization.jsonObject(with: content, options: []) as? [String: Any] else {
85+
guard let representation = try decodeFile(content: content) else {
7786
throw SwiftcInputReaderError.invalidFormat
7887
}
7988
return try SwiftCompilationInfo(from: representation)
@@ -83,11 +92,20 @@ class SwiftcFilemapInputEditor: SwiftcInputReader, SwiftcInputWriter {
8392
let data = try JSONSerialization.data(withJSONObject: info.dump(), options: [.prettyPrinted])
8493
fileManager.createFile(atPath: file.path, contents: data, attributes: nil)
8594
}
95+
96+
private func decodeFile(content: Data) throws -> [String: Any]? {
97+
switch fileFormat {
98+
case .json:
99+
return try JSONSerialization.jsonObject(with: content, options: []) as? [String: Any]
100+
case .yaml:
101+
return try Yams.load(yaml: String(data: content, encoding: .utf8)!) as? [String: Any]
102+
}
103+
}
86104
}
87105

88106
extension SwiftCompilationInfo {
89107
init(from object: [String: Any]) throws {
90-
info = try SwiftModuleCompilationInfo(from: object[""])
108+
info = try SwiftModuleCompilationInfo(from: object["", default: [:]])
91109
files = try object.reduce([]) { prev, new in
92110
let (key, value) = new
93111
if key.isEmpty {

Sources/XCRemoteCache/Commands/Swiftc/XCSwiftc.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,9 @@ public class XCSwiftAbstract<InputArgs> {
8383
// and the file/list is named "output"
8484
switch context.outputs {
8585
case .fileMap(let path):
86-
inputReader = SwiftcFilemapInputEditor(URL(fileURLWithPath: path), fileManager: fileManager)
86+
inputReader = SwiftcFilemapInputEditor(URL(fileURLWithPath: path), fileFormat: .json, fileManager: fileManager)
87+
case .supplementaryFileMap(let path):
88+
inputReader = SwiftcFilemapInputEditor(URL(fileURLWithPath: path), fileFormat: .yaml, fileManager: fileManager)
8789
case .map(let map):
8890
// static - passed via the arguments list
8991
// TODO: check if first 2 ars can always be `nil`

Sources/xcswift-frontend/XCSwiftcFrontendMain.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public class XCSwiftcFrontendMain {
4242
var diagnosticsPaths: [String] = []
4343
var sourceInfoPath: String?
4444
var docPath: String?
45+
var supplementaryOutputFileMap: String?
4546

4647
for i in 0..<args.count {
4748
let arg = args[i]
@@ -73,6 +74,8 @@ public class XCSwiftcFrontendMain {
7374
case "-primary-file":
7475
// .swift
7576
primaryInputPaths.append(args[i + 1])
77+
case "-supplementary-output-file-map":
78+
supplementaryOutputFileMap = args[i + 1]
7679
default:
7780
if arg.hasSuffix(".swift") {
7881
inputPaths.append(arg)
@@ -94,7 +97,8 @@ public class XCSwiftcFrontendMain {
9497
dependenciesPaths: dependenciesPaths,
9598
diagnosticsPaths: diagnosticsPaths,
9699
sourceInfoPath: sourceInfoPath,
97-
docPath: docPath
100+
docPath: docPath,
101+
supplementaryOutputFileMap: supplementaryOutputFileMap
98102
)
99103
// swift-frontened is first invoked with some "probing" args like
100104
// -print-target-info

Tests/XCRemoteCacheTests/Commands/SwiftcFilemapInputEditorTests.swift

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,21 @@ class SwiftcFilemapInputEditorTests: FileXCTestCase {
3434
)
3535
private let sampleInfoContentData = #"{"":{"swift-dependencies":"/"}}"#.data(using: .utf8)!
3636
private var inputFile: URL!
37-
private var editor: SwiftcFilemapInputEditor!
37+
private var editorJson: SwiftcFilemapInputEditor!
38+
private var editorYaml: SwiftcFilemapInputEditor!
3839

3940
override func setUpWithError() throws {
4041
try super.setUpWithError()
4142
try prepareTempDir()
4243
inputFile = workingDirectory!.appendingPathComponent("swift.json")
43-
editor = SwiftcFilemapInputEditor(inputFile, fileManager: fileManager)
44+
editorJson = SwiftcFilemapInputEditor(inputFile, fileFormat: .json, fileManager: fileManager)
45+
editorYaml = SwiftcFilemapInputEditor(inputFile, fileFormat: .yaml, fileManager: fileManager)
4446
}
4547

4648
func testReading() throws {
4749
try fileManager.spt_writeToFile(atPath: inputFile.path, contents: sampleInfoContentData)
4850

49-
let readInfo = try editor.read()
51+
let readInfo = try editorJson.read()
5052

5153
XCTAssertEqual(readInfo, sampleInfo)
5254
}
@@ -80,13 +82,13 @@ class SwiftcFilemapInputEditorTests: FileXCTestCase {
8082
])
8183
try fileManager.spt_writeToFile(atPath: inputFile.path, contents: infoContentData)
8284

83-
let readInfo = try editor.read()
85+
let readInfo = try editorJson.read()
8486

8587
XCTAssertEqual(readInfo, expectedInfo)
8688
}
8789

8890
func testWritingSavesContent() throws {
89-
try editor.write(sampleInfo)
91+
try editorJson.write(sampleInfo)
9092

9193
let savedContent = try Data(contentsOf: inputFile)
9294
let content = try JSONSerialization.jsonObject(with: savedContent, options: []) as? [String: Any]
@@ -108,7 +110,7 @@ class SwiftcFilemapInputEditorTests: FileXCTestCase {
108110
),
109111
])
110112

111-
try editor.write(extendedInfo)
113+
try editorJson.write(extendedInfo)
112114

113115
let savedContent = try Data(contentsOf: inputFile)
114116
let content = try JSONSerialization.jsonObject(with: savedContent, options: []) as? [String: Any]
@@ -119,12 +121,48 @@ class SwiftcFilemapInputEditorTests: FileXCTestCase {
119121
func testModifyingFileCompilationInfo() throws {
120122
try fileManager.spt_writeToFile(atPath: inputFile.path, contents: sampleInfoContentData)
121123

122-
let originalInfo = try editor.read()
124+
let originalInfo = try editorJson.read()
123125
var modifiedInfo = originalInfo
124126
modifiedInfo.files = [file]
125-
try editor.write(modifiedInfo)
126-
let finalInfo = try editor.read()
127+
try editorJson.write(modifiedInfo)
128+
let finalInfo = try editorJson.read()
127129

128130
XCTAssertEqual(finalInfo, modifiedInfo)
129131
}
132+
133+
func testReadingSupplementaryInfoWithOptionalProperties() throws {
134+
let infoContentData = #"""
135+
"/file1.swift":
136+
swift-dependencies: "/file1.swiftdeps"
137+
dependencies: "/file1.d"
138+
"/file2.swift":
139+
dependencies: "/file2.d"
140+
object: "/file2.o"
141+
swift-dependencies: "/file2.swiftdeps"
142+
"""#.data(using: .utf8)!
143+
let expectedInfo = SwiftCompilationInfo(
144+
info: SwiftModuleCompilationInfo(
145+
dependencies: nil,
146+
swiftDependencies: nil
147+
),
148+
files: [
149+
SwiftFileCompilationInfo(
150+
file: "/file1.swift",
151+
dependencies: "/file1.d",
152+
object: nil,
153+
swiftDependencies: "/file1.swiftdeps"
154+
),
155+
SwiftFileCompilationInfo(
156+
file: "/file2.swift",
157+
dependencies: "/file2.d",
158+
object: "/file2.o",
159+
swiftDependencies: "/file2.swiftdeps"
160+
),
161+
])
162+
try fileManager.spt_writeToFile(atPath: inputFile.path, contents: infoContentData)
163+
164+
let readInfo = try editorYaml.read()
165+
166+
XCTAssertEqual(readInfo, expectedInfo)
167+
}
130168
}

0 commit comments

Comments
 (0)