Skip to content

Commit d3ed7e4

Browse files
committed
Migrate build script to Swift
1 parent e340af4 commit d3ed7e4

16 files changed

+894
-721
lines changed

SwiftSyntaxDevUtils/Package.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// swift-tools-version:5.7
2+
3+
import PackageDescription
4+
import Foundation
5+
6+
let package = Package(
7+
name: "swift-syntax-dev-utils",
8+
platforms: [
9+
.macOS(.v10_15)
10+
],
11+
products: [
12+
.executable(name: "swift-syntax-dev-utils", targets: ["swift-syntax-dev-utils"])
13+
],
14+
targets: [
15+
.executableTarget(
16+
name: "swift-syntax-dev-utils",
17+
dependencies: [
18+
.product(name: "ArgumentParser", package: "swift-argument-parser")
19+
]
20+
)
21+
]
22+
)
23+
24+
if ProcessInfo.processInfo.environment["SWIFTCI_USE_LOCAL_DEPS"] == nil {
25+
// Building standalone.
26+
package.dependencies += [
27+
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.2.2")
28+
]
29+
} else {
30+
package.dependencies += [
31+
.package(path: "../../swift-argument-parser")
32+
]
33+
}

SwiftSyntaxDevUtils/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# swift-syntax-dev-utils
2+
3+
Scripts to help build swift-syntax in CI. In most cases, you should not need to run these scripts yourself. The [Contributing Guide](../Contributing.md) contains information of how to build swift-syntax locally.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import ArgumentParser
14+
15+
@main
16+
struct SwiftSyntaxCLI: ParsableCommand {
17+
18+
static var configuration: CommandConfiguration = CommandConfiguration(
19+
abstract: """
20+
Build and test script for SwiftSyntax.
21+
22+
The build script can also drive the test suite included in the SwiftSyntax
23+
repo. This requires a custom build of the compiler project since it accesses
24+
test utilities that are not shipped as part of the toolchains. See the Testing
25+
section for arguments that need to be specified for this.
26+
""",
27+
subcommands: [
28+
Build.self,
29+
GenerateSourceCode.self,
30+
Test.self,
31+
VerifySourceCode.self,
32+
]
33+
)
34+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import ArgumentParser
14+
import Foundation
15+
16+
struct Build: ParsableCommand, BuildCommand {
17+
@OptionGroup
18+
var arguments: BuildArguments
19+
20+
func run() throws {
21+
try buildTarget(packageDir: Paths.packageDir, targetName: "SwiftSyntax-all")
22+
try buildTarget(packageDir: Paths.examplesDir, targetName: "Examples-all")
23+
}
24+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import ArgumentParser
14+
import Foundation
15+
16+
struct GenerateSourceCode: ParsableCommand, SourceCodeGeneratorCommand {
17+
@OptionGroup
18+
var arguments: SourceCodeGeneratorArguments
19+
20+
func run() throws {
21+
try self.runCodeGeneration(sourceDir: Paths.sourcesDir)
22+
}
23+
}
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import ArgumentParser
14+
import Foundation
15+
16+
struct Test: ParsableCommand, BuildCommand {
17+
@OptionGroup
18+
var arguments: BuildArguments
19+
20+
@Flag(help: "Don't run lit-based tests")
21+
var skipLitTests: Bool = false
22+
23+
@Option(
24+
help: """
25+
Path to the FileCheck executable that was built as part of the LLVM repository.
26+
If not specified, it will be looked up from PATH.
27+
"""
28+
)
29+
var filecheckExec: String?
30+
31+
func run() throws {
32+
try buildExample(exampleName: "ExamplePlugin")
33+
34+
try runTests()
35+
36+
logSection("All tests passed")
37+
}
38+
39+
private func runTests() throws {
40+
logSection("Running SwiftSyntax Tests")
41+
42+
if !skipLitTests {
43+
try runLitTests()
44+
}
45+
46+
try runXCTests()
47+
}
48+
49+
private func runLitTests() throws {
50+
logSection("Running lit-based tests")
51+
52+
guard FileManager.default.fileExists(atPath: Paths.litExec.path) else {
53+
throw ScriptExectutionError(
54+
message: """
55+
Error: Could not find lit.py.
56+
Looking at '\(Paths.litExec.path)'.
57+
58+
Make sure you have the llvm repo checked out next to the swift-syntax repo.
59+
Refer to README.md for more information.
60+
"""
61+
)
62+
}
63+
64+
let productBinPath = try findProductBinPath()
65+
let examplesBinPath = try findExamplesBinPath()
66+
67+
var litCall = [
68+
Paths.litExec.path,
69+
Paths.packageDir.path,
70+
"lit_tests",
71+
]
72+
73+
if let filecheckExec {
74+
litCall += ["--param", "FILECHECK=" + filecheckExec]
75+
}
76+
77+
litCall += ["--param", "EXAMPLES_BIN_PATH=" + examplesBinPath.path]
78+
litCall += ["--param", "TOOLCHAIN=" + arguments.toolchain.path]
79+
80+
// Print all failures
81+
litCall += ["--verbose"]
82+
// Don't show all commands if verbose is not enabled
83+
if !arguments.verbose {
84+
litCall += ["--succinct"]
85+
}
86+
87+
guard let pythonExec = Paths.python3Exec else {
88+
throw ScriptExectutionError(message: "Didn't find python3 executable")
89+
}
90+
91+
let process = ProcessRunner(
92+
executableURL: pythonExec,
93+
arguments: litCall
94+
)
95+
96+
try process.run(verbose: arguments.verbose)
97+
}
98+
99+
private func runXCTests() throws {
100+
logSection("Running XCTests")
101+
var swiftpmCallArguments: [String] = []
102+
103+
if arguments.verbose {
104+
swiftpmCallArguments += ["--verbose"]
105+
}
106+
107+
swiftpmCallArguments += ["--test-product", "SwiftSyntaxPackageTests"]
108+
109+
var additionalEnvironment: [String: String] = [:]
110+
additionalEnvironment["SWIFT_BUILD_SCRIPT_ENVIRONMENT"] = "1"
111+
112+
if arguments.enableRawSyntaxValidation {
113+
additionalEnvironment["SWIFTSYNTAX_ENABLE_RAWSYNTAX_VALIDATION"] = "1"
114+
}
115+
116+
if arguments.enableTestFuzzing {
117+
additionalEnvironment["SWIFTPARSER_ENABLE_ALTERNATE_TOKEN_INTROSPECTION"] = "1"
118+
}
119+
120+
// Tell other projects in the unified build to use local dependencies
121+
additionalEnvironment["SWIFTCI_USE_LOCAL_DEPS"] = "1"
122+
additionalEnvironment["SWIFT_SYNTAX_PARSER_LIB_SEARCH_PATH"] =
123+
arguments.toolchain
124+
.appendingPathComponent("lib")
125+
.appendingPathComponent("swift")
126+
.appendingPathComponent("macosx")
127+
.path
128+
129+
try invokeSwiftPM(
130+
action: "test",
131+
packageDir: Paths.packageDir,
132+
additionalArguments: swiftpmCallArguments,
133+
additionalEnvironment: additionalEnvironment
134+
)
135+
}
136+
137+
private func findSwiftpmBinPath(packageDir: URL) throws -> String {
138+
return try invokeSwiftPM(
139+
action: "build",
140+
packageDir: packageDir,
141+
additionalArguments: ["--show-bin-path"],
142+
additionalEnvironment: [:]
143+
)
144+
}
145+
146+
/// This returns a path to the build product folder.
147+
/// Example: '<workingDir>/swift-syntax/.build/arm64-apple-macosx/debug/'
148+
private func findProductBinPath() throws -> URL {
149+
let stdOut = try findSwiftpmBinPath(packageDir: Paths.packageDir)
150+
return URL(fileURLWithPath: stdOut.trimmingCharacters(in: .whitespacesAndNewlines))
151+
}
152+
153+
/// This returns a path to the build examples folder.
154+
/// Example: '<workingDir>/swift-syntax/Examples/.build/arm64-apple-macosx/debug
155+
private func findExamplesBinPath() throws -> URL {
156+
let stdOut = try findSwiftpmBinPath(packageDir: Paths.examplesDir)
157+
return URL(fileURLWithPath: stdOut.trimmingCharacters(in: .whitespacesAndNewlines))
158+
}
159+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import ArgumentParser
14+
import Foundation
15+
16+
fileprivate var modules: [String] {
17+
["SwiftParser", "SwiftParserDiagnostics", "SwiftSyntax", "SwiftSyntaxBuilder"]
18+
}
19+
20+
struct VerifySourceCode: ParsableCommand, SourceCodeGeneratorCommand {
21+
@OptionGroup
22+
var arguments: SourceCodeGeneratorArguments
23+
24+
func run() throws {
25+
let tempDir = FileManager.default.temporaryDirectory
26+
27+
try self.runCodeGeneration(sourceDir: tempDir)
28+
29+
logSection("Verifing code generated files")
30+
31+
guard let diffExec = Paths.diffExec else {
32+
throw ScriptExectutionError(message: "Didn't find a diff execution path")
33+
}
34+
35+
for module in modules {
36+
let selfGeneratedDir = tempDir.appendingPathComponent(module).appendingPathComponent("generated")
37+
let userGeneratedDir = Paths.sourcesDir.appendingPathComponent(module).appendingPathComponent("generated")
38+
39+
let process = ProcessRunner(
40+
executableURL: diffExec,
41+
arguments: [
42+
"--recursive",
43+
"--exclude",
44+
".*", // Exclude dot files like .DS_Store
45+
"--context=0",
46+
selfGeneratedDir.path,
47+
userGeneratedDir.path,
48+
]
49+
)
50+
51+
let result = try process.run(verbose: arguments.verbose)
52+
53+
if !result.stderr.isEmpty {
54+
throw ScriptExectutionError(
55+
message: """
56+
FAIL: code-generated files committed to repository do
57+
not match generated ones. Please re-generate the
58+
code-generated-files using the following command, open a PR to the
59+
SwiftSyntax project and merge it alongside the main PR.
60+
$ swift run swift-syntax-dev-utils generate-source-code
61+
/path/to/toolchain.xctoolchain/usr
62+
"""
63+
)
64+
}
65+
}
66+
}
67+
}

0 commit comments

Comments
 (0)