Skip to content

Commit 949c36d

Browse files
authored
Merge pull request #449 from zunda-pixel/main
Support CommandPlugin
2 parents ec43b60 + 05aa376 commit 949c36d

File tree

3 files changed

+178
-1
lines changed

3 files changed

+178
-1
lines changed

Package.swift

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ let package = Package(
3333
name: "SwiftFormatConfiguration",
3434
targets: ["SwiftFormatConfiguration"]
3535
),
36+
.plugin(
37+
name: "FormatPlugin",
38+
targets: ["Format Source Code"]
39+
),
40+
.plugin(
41+
name: "LintPlugin",
42+
targets: ["Lint Source Code"]
43+
),
3644
],
3745
dependencies: [
3846
// See the "Dependencies" section below.
@@ -91,7 +99,32 @@ let package = Package(
9199
.product(name: "SwiftSyntax", package: "swift-syntax"),
92100
]
93101
),
94-
102+
.plugin(
103+
name: "Format Source Code",
104+
capability: .command(
105+
intent: .sourceCodeFormatting(),
106+
permissions: [
107+
.writeToPackageDirectory(reason: "This command formats the Swift source files")
108+
]
109+
),
110+
dependencies: [
111+
.target(name: "swift-format")
112+
],
113+
path: "Plugins/FormatPlugin"
114+
),
115+
.plugin(
116+
name: "Lint Source Code",
117+
capability: .command(
118+
intent: .custom(
119+
verb: "lint-source-code",
120+
description: "Lint source code for a specified target."
121+
)
122+
),
123+
dependencies: [
124+
.target(name: "swift-format")
125+
],
126+
path: "Plugins/LintPlugin"
127+
),
95128
.executableTarget(
96129
name: "generate-pipeline",
97130
dependencies: [

Plugins/FormatPlugin/plugin.swift

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import PackagePlugin
2+
import Foundation
3+
4+
@main
5+
struct FormatPlugin {
6+
func format(tool: PluginContext.Tool, targetDirectories: [String], configurationFilePath: String?) throws {
7+
let swiftFormatExec = URL(fileURLWithPath: tool.path.string)
8+
9+
var arguments: [String] = ["format"]
10+
11+
arguments.append(contentsOf: targetDirectories)
12+
13+
arguments.append(contentsOf: ["--recursive", "--parallel", "--in-place"])
14+
15+
if let configurationFilePath = configurationFilePath {
16+
arguments.append(contentsOf: ["--configuration", configurationFilePath])
17+
}
18+
19+
let process = try Process.run(swiftFormatExec, arguments: arguments)
20+
process.waitUntilExit()
21+
22+
if process.terminationReason == .exit && process.terminationStatus == 0 {
23+
print("Formatted the source code.")
24+
}
25+
else {
26+
let problem = "\(process.terminationReason):\(process.terminationStatus)"
27+
Diagnostics.error("swift-format invocation failed: \(problem)")
28+
}
29+
}
30+
}
31+
32+
extension FormatPlugin: CommandPlugin {
33+
func performCommand(
34+
context: PluginContext,
35+
arguments: [String]
36+
) async throws {
37+
let swiftFormatTool = try context.tool(named: "swift-format")
38+
39+
var argExtractor = ArgumentExtractor(arguments)
40+
let targetNames = argExtractor.extractOption(named: "target")
41+
let targetsToFormat = try context.package.targets(named: targetNames)
42+
43+
let configurationFilePath = argExtractor.extractOption(named: "configuration").first
44+
45+
let sourceCodeTargets = targetsToFormat.compactMap{ $0 as? SourceModuleTarget }
46+
47+
try format(
48+
tool: swiftFormatTool,
49+
targetDirectories: sourceCodeTargets.map(\.directory.string),
50+
configurationFilePath: configurationFilePath
51+
)
52+
}
53+
}
54+
55+
#if canImport(XcodeProjectPlugin)
56+
import XcodeProjectPlugin
57+
58+
extension FormatPlugin: XcodeCommandPlugin {
59+
func performCommand(context: XcodeProjectPlugin.XcodePluginContext, arguments: [String]) throws {
60+
let swiftFormatTool = try context.tool(named: "swift-format")
61+
62+
var argExtractor = ArgumentExtractor(arguments)
63+
let configurationFilePath = argExtractor.extractOption(named: "configuration").first
64+
65+
try format(
66+
tool: swiftFormatTool,
67+
targetDirectories: [context.xcodeProject.directory.string],
68+
configurationFilePath: configurationFilePath
69+
)
70+
}
71+
}
72+
#endif

Plugins/LintPlugin/plugin.swift

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import PackagePlugin
2+
import Foundation
3+
4+
@main
5+
struct LintPlugin {
6+
func lint(tool: PluginContext.Tool, targetDirectories: [String], configurationFilePath: String?) throws {
7+
let swiftFormatExec = URL(fileURLWithPath: tool.path.string)
8+
9+
var arguments: [String] = ["lint"]
10+
11+
arguments.append(contentsOf: targetDirectories)
12+
13+
arguments.append(contentsOf: ["--recursive", "--parallel", "--strict"])
14+
15+
if let configurationFilePath = configurationFilePath {
16+
arguments.append(contentsOf: ["--configuration", configurationFilePath])
17+
}
18+
19+
let process = try Process.run(swiftFormatExec, arguments: arguments)
20+
process.waitUntilExit()
21+
22+
if process.terminationReason == .exit && process.terminationStatus == 0 {
23+
print("Lintted the source code.")
24+
}
25+
else {
26+
let problem = "\(process.terminationReason):\(process.terminationStatus)"
27+
Diagnostics.error("swift-format invocation failed: \(problem)")
28+
}
29+
}
30+
}
31+
32+
extension LintPlugin: CommandPlugin {
33+
func performCommand(
34+
context: PluginContext,
35+
arguments: [String]
36+
) async throws {
37+
let swiftFormatTool = try context.tool(named: "swift-format")
38+
39+
// Extract the arguments that specify what targets to format.
40+
var argExtractor = ArgumentExtractor(arguments)
41+
let targetNames = argExtractor.extractOption(named: "target")
42+
let targetsToFormat = try context.package.targets(named: targetNames)
43+
44+
let configurationFilePath = argExtractor.extractOption(named: "configuration").first
45+
46+
let sourceCodeTargets = targetsToFormat.compactMap { $0 as? SourceModuleTarget }
47+
48+
try lint(
49+
tool: swiftFormatTool,
50+
targetDirectories: sourceCodeTargets.map(\.directory.string),
51+
configurationFilePath: configurationFilePath
52+
)
53+
}
54+
}
55+
56+
#if canImport(XcodeProjectPlugin)
57+
import XcodeProjectPlugin
58+
59+
extension LintPlugin: XcodeCommandPlugin {
60+
func performCommand(context: XcodeProjectPlugin.XcodePluginContext, arguments: [String]) throws {
61+
let swiftFormatTool = try context.tool(named: "swift-format")
62+
var argExtractor = ArgumentExtractor(arguments)
63+
let configurationFilePath = argExtractor.extractOption(named: "configuration").first
64+
65+
try lint(
66+
tool: swiftFormatTool,
67+
targetDirectories: [context.xcodeProject.directory.string],
68+
configurationFilePath: configurationFilePath
69+
)
70+
}
71+
}
72+
#endif

0 commit comments

Comments
 (0)