I think you could make another executable target, and have the tool plugin call that, passing in everything you need (including the path to swiftlint?)
Your executable target can use Process to invoke swiftlint, and can capture the output and do what it wants with it.
Not sure what you mean with "Your executable target can use Process to invoke swiftlint".
SwiftLint is already a binary target in my spm lib. What is this Process thing you're referring to?
I mean that you need to create another target and write a small executable.
The plugin will invoke your executable, instead of invoking SwiftLintBinary.
Your executable can run SwiftLintBinary, and capture the output. It can then do whatever it wants with that output, including saving it to a json file.
Process is the Foundation class you use to run external processes and capture their input. Here's a basic example taken from the WWDC 2022 session:
let process = Process()
process.executableURL = URL(fileURLWithPath: "/usr/bin/git")
process.arguments = ["log", "--pretty=format:- %an <%ae>%n"]
let outputPipe = Pipe()
process.standardOutput = outputPipe
try process.run()
process.waitUntilExit()
let outputData = outputPipe.fileHandleForReading.readDataToEndOfFile()
let output = String(decoding: outputData, as: UTF8.self)
I needed to capture the output like samdeane mentioned (see the code).
I also asked the SwiftLint guys for an option to write reports to a file. They implemented that, so in a future release we can just specify an output file instead of having to capture the console log.
private func swiftlint(packageDir: String, executablePath: Path) async throws {
let process = Process()
let outputPipe = Pipe()
process.standardOutput = outputPipe
process.executableURL = URL(fileURLWithPath: executablePath.string)
process.arguments = [
"lint",
"--in-process-sourcekit",
"--config", "\(packageDir)/.swiftlint.yml",
"--reporter", "json"
]
try process.run()
process.waitUntilExit()
if process.terminationReason == .exit && process.terminationStatus == 0 {
print("Linting was successful.")
} else {
let problem = "\(process.terminationReason):\(process.terminationStatus)"
Diagnostics.error("Linting failed because: \(problem)")
throw SwiftLintCommandPluginErrors.swiftLintPluginError
}
do {
let path = "build/reports"
print("Creating directory structure '\(path)'.")
try FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: true)
let outputData = outputPipe.fileHandleForReading.readDataToEndOfFile()
let output = String(decoding: outputData, as: UTF8.self)
print("Creating swiftlint report at '\(packageDir)/build/reports/swiftlint.result.json'")
try output.write(
toFile: "\(packageDir)/build/reports/swiftlint.result.json",
atomically: true,
encoding: .utf8
)
} catch {
throw error
}
}