Skip to content

Commit aac81f1

Browse files
authored
Merge pull request #2350 from Matejkob/refactor-dev-utils
Refactor swift-syntax-dev-utils package
2 parents 296e24d + 5cf467d commit aac81f1

File tree

10 files changed

+316
-184
lines changed

10 files changed

+316
-184
lines changed

SwiftSyntaxDevUtils/Sources/swift-syntax-dev-utils/SwiftSyntaxDevUtils.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import ArgumentParser
1515
@main
1616
struct SwiftSyntaxDevUtils: ParsableCommand {
1717

18-
static var configuration: CommandConfiguration = CommandConfiguration(
18+
static let configuration = CommandConfiguration(
1919
abstract: """
2020
Build and test script for SwiftSyntax.
2121

SwiftSyntaxDevUtils/Sources/swift-syntax-dev-utils/commands/Build.swift

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,42 @@
1313
import ArgumentParser
1414
import Foundation
1515

16-
struct Build: ParsableCommand, BuildCommand {
17-
static var configuration: CommandConfiguration {
18-
return CommandConfiguration(
19-
abstract: "Build swift-syntax."
20-
)
21-
}
16+
struct Build: ParsableCommand {
17+
static let configuration = CommandConfiguration(
18+
abstract: "Build swift-syntax."
19+
)
2220

2321
@OptionGroup
2422
var arguments: BuildArguments
2523

2624
func run() throws {
27-
try buildTarget(packageDir: Paths.packageDir, targetName: "SwiftSyntax-all")
28-
try buildTarget(packageDir: Paths.examplesDir, targetName: "Examples-all")
29-
try buildTarget(packageDir: Paths.swiftParserCliDir, targetName: "swift-parser-cli")
25+
let executor = BuildExecutor(
26+
swiftPMBuilder: SwiftPMBuilder(
27+
toolchain: arguments.toolchain,
28+
buildDir: arguments.buildDir,
29+
multirootDataFile: arguments.multirootDataFile,
30+
release: arguments.release,
31+
enableRawSyntaxValidation: arguments.enableRawSyntaxValidation,
32+
enableTestFuzzing: arguments.enableTestFuzzing,
33+
warningsAsErrors: arguments.warningsAsErrors,
34+
verbose: arguments.verbose
35+
)
36+
)
37+
try executor.run()
38+
}
39+
}
40+
41+
struct BuildExecutor {
42+
private let swiftPMBuilder: SwiftPMBuilder
43+
44+
init(swiftPMBuilder: SwiftPMBuilder) {
45+
self.swiftPMBuilder = swiftPMBuilder
46+
}
47+
48+
func run() throws {
49+
try swiftPMBuilder.buildTarget(packageDir: Paths.packageDir, targetName: "SwiftSyntax-all")
50+
try swiftPMBuilder.buildTarget(packageDir: Paths.examplesDir, targetName: "Examples-all")
51+
try swiftPMBuilder.buildTarget(packageDir: Paths.swiftParserCliDir, targetName: "swift-parser-cli")
3052
try buildEditorExtension()
3153
}
3254

@@ -36,4 +58,23 @@ struct Build: ParsableCommand, BuildCommand {
3658
try invokeXcodeBuild(projectPath: Paths.editorExtensionProjectPath, scheme: "SwiftRefactorExtension")
3759
#endif
3860
}
61+
62+
@discardableResult
63+
private func invokeXcodeBuild(projectPath: URL, scheme: String) throws -> ProcessResult {
64+
try withTemporaryDirectory { tempDir in
65+
let processRunner = ProcessRunner(
66+
executableURL: try Paths.xcodebuildExec,
67+
arguments: [
68+
"-project", projectPath.path,
69+
"-scheme", scheme,
70+
"-derivedDataPath", tempDir.path,
71+
],
72+
additionalEnvironment: [:]
73+
)
74+
75+
let result = try processRunner.run(verbose: swiftPMBuilder.verbose)
76+
77+
return result
78+
}
79+
}
3980
}

SwiftSyntaxDevUtils/Sources/swift-syntax-dev-utils/commands/Format.swift

Lines changed: 68 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,25 @@ fileprivate let directoriesToExclude = [
2424
]
2525

2626
struct Format: ParsableCommand {
27-
static var configuration: CommandConfiguration {
28-
return CommandConfiguration(
29-
abstract: "Format files in SwiftSyntax using swift-format.",
30-
discussion: """
31-
This command automatically builds the '\(Self.swiftFormatBranch)' branch \
32-
of swift-format in the '\(Paths.swiftFormatBuildDir.lastPathComponent)' \
33-
directory of this repository and uses the build to format the swift-syntax \
34-
sources.
35-
"""
36-
)
37-
}
27+
static let configuration = CommandConfiguration(
28+
abstract: "Format files in SwiftSyntax using swift-format.",
29+
discussion: """
30+
This command automatically builds the '\(FormatExecutor.swiftFormatBranch)' branch \
31+
of swift-format in the '\(Paths.swiftFormatBuildDir.lastPathComponent)' \
32+
directory of this repository and uses the build to format the swift-syntax \
33+
sources.
34+
"""
35+
)
3836

3937
@Flag(help: "Update the sources of swift-format and rebuild swift-format")
4038
var update: Bool = false
4139

42-
@Flag(help: "Instead of formatting in-place, verify that the files are correctly formatted. Exit with 1 if files are not correctly formatted.")
40+
@Flag(
41+
help: """
42+
Instead of formatting in-place, verify that the files are correctly formatted. \
43+
Exit with 1 if files are not correctly formatted.
44+
"""
45+
)
4346
var lint: Bool = false
4447

4548
@Option(
@@ -53,12 +56,18 @@ struct Format: ParsableCommand {
5356
@Flag(help: "Enable verbose logging.")
5457
var verbose: Bool = false
5558

56-
/// The configuration to build swift-format in.
57-
private static let swiftFormatBuildConfiguration: String = "release"
58-
59-
/// The branch of swift-format to build.
60-
private static let swiftFormatBranch: String = "main"
59+
func run() throws {
60+
let executor = FormatExecutor(
61+
update: update,
62+
lint: lint,
63+
swiftFormat: swiftFormat,
64+
verbose: verbose
65+
)
66+
try executor.run()
67+
}
68+
}
6169

70+
struct FormatExecutor {
6271
private enum Error: Swift.Error, CustomStringConvertible {
6372
case swiftFormatNotFound
6473
case lintFailed
@@ -87,6 +96,46 @@ struct Format: ParsableCommand {
8796
}
8897
}
8998

99+
/// Update the sources of swift-format and rebuild swift-format
100+
private let update: Bool
101+
102+
/// Instead of formatting in-place, verify that the files are correctly formatted.
103+
///
104+
/// Exit with 1 if files are not correctly formatted.
105+
private let lint: Bool
106+
107+
/// Instead of building a local swift-format, use this swift-format executable.
108+
///
109+
/// Should primarily be used for CI, which has already built swift-format.
110+
private let swiftFormat: String?
111+
112+
/// Enable verbose logging.
113+
private let verbose: Bool
114+
115+
/// The branch of swift-format to build.
116+
static let swiftFormatBranch: String = "main"
117+
118+
/// The configuration to build swift-format in.
119+
private static let swiftFormatBuildConfiguration: String = "release"
120+
121+
/// Creates an Executor
122+
/// - Parameters:
123+
/// - update: Update the sources of swift-format and rebuild swift-format
124+
/// - lint: Instead of formatting in-place, verify that the files are correctly formatted.
125+
/// - swiftFormat: Instead of building a local swift-format, use this swift-format executable.
126+
/// - verbose: Enable verbose logging.
127+
init(
128+
update: Bool,
129+
lint: Bool = false,
130+
swiftFormat: String? = nil,
131+
verbose: Bool = false
132+
) {
133+
self.update = update
134+
self.lint = lint
135+
self.swiftFormat = swiftFormat
136+
self.verbose = verbose
137+
}
138+
90139
/// Run `git` in the .swift-format-build directory with the provided arguments.
91140
private func runGitCommand(_ arguments: String...) throws {
92141
try ProcessRunner(
@@ -219,12 +268,12 @@ struct Format: ParsableCommand {
219268
print("💡 You are building running the format script with Swift 5.9 or lower. Running it with SwiftPM 5.10 is about 10s faster.")
220269
#endif
221270

222-
try run(updateAndBuild: self.update)
271+
try run(updateAndBuild: update)
223272
}
224273

225274
/// - Parameter updateAndBuild: Whether to update the locally checked out
226275
/// swift-format sources and rebuild swift-format.
227-
func run(updateAndBuild: Bool) throws {
276+
private func run(updateAndBuild: Bool) throws {
228277
if updateAndBuild {
229278
try cloneOrUpdateSwiftFormat()
230279
try buildSwiftFormat()

SwiftSyntaxDevUtils/Sources/swift-syntax-dev-utils/commands/GenerateSourceCode.swift

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,64 @@
1313
import ArgumentParser
1414
import Foundation
1515

16-
struct GenerateSourceCode: ParsableCommand, SourceCodeGeneratorCommand {
17-
static var configuration: CommandConfiguration {
18-
return CommandConfiguration(
19-
abstract: "Generate swift-syntax sources."
20-
)
21-
}
16+
struct GenerateSourceCode: ParsableCommand {
17+
static let configuration = CommandConfiguration(
18+
abstract: "Generate swift-syntax sources."
19+
)
2220

2321
@OptionGroup
2422
var arguments: SourceCodeGeneratorArguments
2523

2624
func run() throws {
27-
try self.runCodeGeneration(sourceDir: Paths.sourcesDir)
25+
let executor = GenerateSourceCodeExecutor(
26+
toolchain: arguments.toolchain,
27+
verbose: arguments.verbose
28+
)
29+
try executor.run(sourceDir: Paths.sourcesDir)
30+
}
31+
}
32+
33+
struct GenerateSourceCodeExecutor {
34+
/// The path to the toolchain that shall be used to build SwiftSyntax.
35+
private let toolchain: URL
36+
37+
/// Enable verbose logging.
38+
private let verbose: Bool
39+
40+
/// Creates an executor
41+
/// - Parameters:
42+
/// - toolchain: The path to the toolchain that shall be used to build SwiftSyntax.
43+
/// - verbose: Enable verbose logging.
44+
init(toolchain: URL, verbose: Bool = false) {
45+
self.toolchain = toolchain
46+
self.verbose = verbose
47+
}
48+
49+
func run(sourceDir: URL) throws {
50+
logSection("Running code generation")
51+
52+
var args = [
53+
"run",
54+
"--package-path", Paths.codeGenerationDir.relativePath,
55+
"generate-swift-syntax", sourceDir.relativePath,
56+
]
57+
58+
if verbose {
59+
args += ["--verbose"]
60+
}
61+
62+
let additionalEnvironment = [
63+
"SWIFT_BUILD_SCRIPT_ENVIRONMENT": "1",
64+
"SWIFTSYNTAX_ENABLE_RAWSYNTAX_VALIDATION": "1",
65+
"SWIFTCI_USE_LOCAL_DEPS": nil,
66+
]
67+
68+
let process = ProcessRunner(
69+
executableURL: toolchain.appendingPathComponent("bin").appendingPathComponent("swift"),
70+
arguments: args,
71+
additionalEnvironment: additionalEnvironment
72+
)
73+
74+
try process.run(verbose: verbose)
2875
}
2976
}

SwiftSyntaxDevUtils/Sources/swift-syntax-dev-utils/commands/Test.swift

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,38 @@
1313
import ArgumentParser
1414
import Foundation
1515

16-
struct Test: ParsableCommand, BuildCommand {
17-
static var configuration: CommandConfiguration {
18-
return CommandConfiguration(
19-
abstract: "Run swift-syntax tests."
20-
)
21-
}
16+
struct Test: ParsableCommand {
17+
static let configuration = CommandConfiguration(
18+
abstract: "Run swift-syntax tests."
19+
)
2220

2321
@OptionGroup
2422
var arguments: BuildArguments
2523

24+
func run() throws {
25+
let executor = TestExecutor(
26+
swiftPMBuilder: SwiftPMBuilder(
27+
toolchain: arguments.toolchain,
28+
buildDir: arguments.buildDir,
29+
multirootDataFile: arguments.multirootDataFile,
30+
release: arguments.release,
31+
enableRawSyntaxValidation: arguments.enableRawSyntaxValidation,
32+
enableTestFuzzing: arguments.enableTestFuzzing,
33+
warningsAsErrors: arguments.warningsAsErrors,
34+
verbose: arguments.verbose
35+
)
36+
)
37+
try executor.run()
38+
}
39+
}
40+
41+
struct TestExecutor {
42+
private let swiftPMBuilder: SwiftPMBuilder
43+
44+
init(swiftPMBuilder: SwiftPMBuilder) {
45+
self.swiftPMBuilder = swiftPMBuilder
46+
}
47+
2648
func run() throws {
2749
try runTests()
2850
try runCodeGenerationTests()
@@ -34,53 +56,46 @@ struct Test: ParsableCommand, BuildCommand {
3456
private func runTests() throws {
3557
logSection("Running SwiftSyntax Tests")
3658

37-
try invokeSwiftPM(
59+
try swiftPMBuilder.invokeSwiftPM(
3860
action: "test",
3961
packageDir: Paths.packageDir,
4062
additionalArguments: ["--test-product", "swift-syntaxPackageTests"],
41-
additionalEnvironment: swiftPMEnvironmentVariables,
63+
additionalEnvironment: swiftPMBuilder.swiftPMEnvironmentVariables,
4264
captureStdout: false,
4365
captureStderr: false
4466
)
4567
}
4668

4769
private func runCodeGenerationTests() throws {
4870
logSection("Running CodeGeneration Tests")
49-
try invokeSwiftPM(
71+
try swiftPMBuilder.invokeSwiftPM(
5072
action: "test",
5173
packageDir: Paths.codeGenerationDir,
5274
additionalArguments: ["--test-product", "CodeGenerationPackageTests"],
53-
additionalEnvironment: swiftPMEnvironmentVariables,
75+
additionalEnvironment: swiftPMBuilder.swiftPMEnvironmentVariables,
5476
captureStdout: false,
5577
captureStderr: false
5678
)
5779
}
5880

5981
private func runExamplesTests() throws {
6082
logSection("Running Examples Tests")
61-
try invokeSwiftPM(
83+
try swiftPMBuilder.invokeSwiftPM(
6284
action: "test",
6385
packageDir: Paths.examplesDir,
6486
additionalArguments: ["--test-product", "ExamplesPackageTests"],
65-
additionalEnvironment: swiftPMEnvironmentVariables,
87+
additionalEnvironment: swiftPMBuilder.swiftPMEnvironmentVariables,
6688
captureStdout: false,
6789
captureStderr: false
6890
)
6991
}
7092

7193
private func findSwiftpmBinPath(packageDir: URL) throws -> String {
72-
return try invokeSwiftPM(
94+
return try swiftPMBuilder.invokeSwiftPM(
7395
action: "build",
7496
packageDir: packageDir,
7597
additionalArguments: ["--show-bin-path"],
7698
additionalEnvironment: [:]
7799
).stdout
78100
}
79-
80-
/// This returns a path to the build examples folder.
81-
/// Example: '<workingDir>/swift-syntax/Examples/.build/arm64-apple-macosx/debug
82-
private func findExamplesBinPath() throws -> URL {
83-
let stdOut = try findSwiftpmBinPath(packageDir: Paths.examplesDir)
84-
return URL(fileURLWithPath: stdOut.trimmingCharacters(in: .whitespacesAndNewlines))
85-
}
86101
}

0 commit comments

Comments
 (0)