Skip to content

Commit 5b6ec8a

Browse files
committed
Converted SwiftBuildTool and SwiftTestTool
1 parent d2990e9 commit 5b6ec8a

File tree

2 files changed

+117
-129
lines changed

2 files changed

+117
-129
lines changed

Sources/Commands/SwiftBuildTool.swift

Lines changed: 52 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -8,89 +8,24 @@
88
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
99
*/
1010

11+
import ArgumentParser
1112
import TSCUtility
1213
import TSCBasic
1314
import PackageGraph
1415
import SPMBuildCore
1516
import Build
1617

17-
/// swift-build tool namespace
18-
public class SwiftBuildTool: SwiftTool<BuildToolOptions> {
18+
public struct BuildToolOptions: ParsableArguments {
19+
enum BuildToolMode {
20+
/// Build the package.
21+
case build
1922

20-
public convenience init(args: [String]) {
21-
self.init(
22-
toolName: "build",
23-
usage: "[options]",
24-
overview: "Build sources into binary products",
25-
args: args,
26-
seeAlso: type(of: self).otherToolNames()
27-
)
23+
/// Print the binary output path.
24+
case binPath
2825
}
29-
30-
override func runImpl() throws {
31-
switch try options.mode() {
32-
case .build:
33-
#if os(Linux)
34-
// Emit warning if clang is older than version 3.6 on Linux.
35-
// See: <rdar://problem/28108951> SR-2299 Swift isn't using Gold by default on stock 14.04.
36-
checkClangVersion()
37-
#endif
38-
39-
guard let subset = options.buildSubset(diagnostics: diagnostics) else { return }
40-
let buildSystem = try createBuildSystem()
41-
try buildSystem.build(subset: subset)
42-
43-
case .binPath:
44-
try print(buildParameters().buildPath.description)
45-
46-
case .version:
47-
print(Versioning.currentVersion.completeDisplayString)
48-
}
49-
}
50-
51-
override class func defineArguments(parser: ArgumentParser, binder: ArgumentBinder<BuildToolOptions>) {
52-
binder.bind(
53-
option: parser.add(option: buildTestsOptionName, kind: Bool.self,
54-
usage: "Build both source and test targets"),
55-
to: { $0.buildTests = $1 })
56-
57-
binder.bind(
58-
option: parser.add(option: productOptionName, kind: String.self,
59-
usage: "Build the specified product"),
60-
to: { $0.product = $1 })
61-
62-
binder.bind(
63-
option: parser.add(option: targetOptionName, kind: String.self,
64-
usage: "Build the specified target"),
65-
to: { $0.target = $1 })
66-
67-
binder.bind(
68-
option: parser.add(option: "--show-bin-path", kind: Bool.self,
69-
usage: "Print the binary output path"),
70-
to: { $0.shouldPrintBinPath = $1 })
71-
}
72-
73-
private func checkClangVersion() {
74-
// We only care about this on Ubuntu 14.04
75-
guard let uname = try? Process.checkNonZeroExit(args: "lsb_release", "-r").spm_chomp(),
76-
uname.hasSuffix("14.04"),
77-
let clangVersionOutput = try? Process.checkNonZeroExit(args: "clang", "--version").spm_chomp(),
78-
let clang = getClangVersion(versionOutput: clangVersionOutput) else {
79-
return
80-
}
81-
82-
if clang < Version(3, 6, 0) {
83-
print("warning: minimum recommended clang is version 3.6, otherwise you may encounter linker errors.")
84-
}
85-
}
86-
}
87-
88-
public class BuildToolOptions: ToolOptions {
26+
8927
/// Returns the mode in which the build tool should run.
9028
func mode() throws -> BuildToolMode {
91-
if shouldPrintVersion {
92-
return .version
93-
}
9429
if shouldPrintBinPath {
9530
return .binPath
9631
}
@@ -122,52 +57,67 @@ public class BuildToolOptions: ToolOptions {
12257
return allSubsets.first ?? .allExcludingTests
12358
}
12459

60+
@OptionGroup()
61+
var swiftOptions: SwiftToolOptions
62+
12563
/// If the test should be built.
126-
var buildTests = false
64+
@Flag(help: "Build both source and test targets")
65+
var buildTests: Bool
12766

12867
/// If the binary output path should be printed.
129-
var shouldPrintBinPath = false
68+
@Flag(name: .customLong("show-bin-path"), help: "Print the binary output path")
69+
var shouldPrintBinPath: Bool
13070

13171
/// Specific target to build.
72+
@Option(help: "Build the specified target")
13273
var target: String?
13374

13475
/// Specific product to build.
76+
@Option(help: "Build the specified product)
13577
var product: String?
13678
}
13779
138-
public enum BuildToolMode {
139-
/// Build the package.
140-
case build
80+
/// swift-build tool namespace
81+
public class SwiftBuildTool: SwiftTool<BuildToolOptions> {
82+
static let configuration = CommandConfiguration(
83+
commandName: "build",
84+
abstract: "Build sources into binary products")
14185

142-
/// Print the binary output path.
143-
case binPath
86+
@OptionGroup()
87+
var options: BuildToolOptions
14488

145-
/// Print the version.
146-
case version
147-
}
89+
func runImpl() throws {
90+
let swiftTool = try SwiftTool(options: options.swiftOptions)
91+
92+
switch try options.mode() {
93+
case .build:
94+
#if os(Linux)
95+
// Emit warning if clang is older than version 3.6 on Linux.
96+
// See: <rdar://problem/28108951> SR-2299 Swift isn't using Gold by default on stock 14.04.
97+
checkClangVersion()
98+
#endif
99+
100+
guard let subset = options.buildSubset(diagnostics: diagnostics) else { return }
101+
let buildSystem = try swiftTool.createBuildSystem()
102+
try buildSystem.build(subset: subset)
148103

149-
fileprivate let buildTestsOptionName = "--build-tests"
150-
fileprivate let productOptionName = "--product"
151-
fileprivate let targetOptionName = "--target"
152-
153-
fileprivate extension BuildSubset {
154-
var argumentName: String {
155-
switch self {
156-
case .allExcludingTests:
157-
fatalError("no corresponding argument")
158-
case .allIncludingTests:
159-
return buildTestsOptionName
160-
case .product:
161-
return productOptionName
162-
case .target:
163-
return targetOptionName
104+
case .binPath:
105+
try print(swiftTool.buildParameters().buildPath.description)
164106
}
165107
}
166-
}
167108

168-
extension SwiftBuildTool: ToolName {
169-
static var toolName: String {
170-
return "swift build"
109+
private func checkClangVersion() {
110+
// We only care about this on Ubuntu 14.04
111+
guard let uname = try? Process.checkNonZeroExit(args: "lsb_release", "-r").spm_chomp(),
112+
uname.hasSuffix("14.04"),
113+
let clangVersionOutput = try? Process.checkNonZeroExit(args: "clang", "--version").spm_chomp(),
114+
let clang = getClangVersion(versionOutput: clangVersionOutput) else {
115+
return
116+
}
117+
118+
if clang < Version(3, 6, 0) {
119+
print("warning: minimum recommended clang is version 3.6, otherwise you may encounter linker errors.")
120+
}
171121
}
172122
}
173123

Sources/Commands/SwiftTestTool.swift

Lines changed: 65 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ See http://swift.org/CONTRIBUTORS.txt for Swift project authors
1010

1111
import class Foundation.ProcessInfo
1212

13+
import ArgumentParser
1314
import TSCBasic
1415
import SPMBuildCore
1516
import Build
@@ -19,6 +20,14 @@ import Workspace
1920

2021
import func TSCLibc.exit
2122

23+
func parseAbsolutePath(_ argument: String) throws -> AbsolutePath {
24+
if let cwd = localFileSystem.currentWorkingDirectory {
25+
return AbsolutePath(argument, relativeTo: cwd)
26+
} else {
27+
return try AbsolutePath(validating: argument)
28+
}
29+
}
30+
2231
private enum TestError: Swift.Error {
2332
case invalidListTestJSONData
2433
case testsExecutableNotFound
@@ -38,7 +47,7 @@ extension TestError: CustomStringConvertible {
3847
}
3948
}
4049

41-
public class TestToolOptions: ToolOptions {
50+
public struct TestToolOptions: ParsableArguments {
4251
/// Returns the mode in with the tool command should run.
4352
var mode: TestMode {
4453
// If we got version option, just print the version and exit.
@@ -65,36 +74,72 @@ public class TestToolOptions: ToolOptions {
6574
return .runSerial
6675
}
6776

77+
@OptionGroup()
78+
var swiftOptions: SwiftToolOptions
79+
80+
@Flag(name: .customLong("skip-build"),
81+
help: "Skip building the test target")
82+
var shouldSkipBuilding: Bool
83+
6884
/// If the test target should be built before testing.
69-
var shouldBuildTests = true
85+
var shouldBuildTests: Bool {
86+
!shouldSkipBuilding
87+
}
7088

7189
/// If tests should run in parallel mode.
72-
var shouldRunInParallel = false
90+
@Flag(name: .customLong("parallel"),
91+
help: "Run the tests in parallel.")
92+
var shouldRunInParallel: Bool
7393

7494
/// Number of tests to execute in parallel
95+
@Option(name: .customLong("num-workers"),
96+
help: "Number of tests to execute in parallel.")
7597
var numberOfWorkers: Int?
7698

7799
/// List the tests and exit.
78-
var shouldListTests = false
100+
@Flag(name: [.customLong("list-tests"), .customShort("l")],
101+
help: "Lists test methods in specifier format")
102+
var shouldListTests: Bool
79103

80104
/// Generate LinuxMain entries and exit.
81-
var shouldGenerateLinuxMain = false
105+
@Flag(name: .customLong("generate-linuxmain"),
106+
help: "Generate LinuxMain.swift entries for the package")
107+
var shouldGenerateLinuxMain: Bool
82108

83109
/// If the path of the exported code coverage JSON should be printed.
84-
var shouldPrintCodeCovPath = false
110+
@Flag(name: .customLong("show-codecov-path"),
111+
help: "Print the path of the exported code coverage JSON file")
112+
var shouldPrintCodeCovPath: Bool
85113

86114
var testCaseSpecifier: TestCaseSpecifier {
87-
testCaseSpecifierOverride() ?? _testCaseSpecifier
115+
if let override = testCaseSpecifierOverride() {
116+
return override
117+
}
118+
119+
return filter.map { .regex($0) }
120+
?? specifier.map { .specific($0) }
121+
?? .none
88122
}
89123

90-
var _testCaseSpecifier: TestCaseSpecifier = .none
124+
@Option(name: .shortAndLong)
125+
var specifier: String?
126+
127+
@Option(help: """
128+
Run test cases matching regular expression, Format: <test-target>.<test-case> \
129+
or <test-target>.<test-case>/<test>
130+
""")
131+
var filter: String?
91132

92133
/// Path where the xUnit xml file should be generated.
134+
@Option(name: .customLong("xunit-output"),
135+
help: "Path where the xUnit xml file should be generated.",
136+
transform: parseAbsolutePath)
93137
var xUnitOutput: AbsolutePath?
94138

95139
/// The test product to use. This is useful when there are multiple test products
96140
/// to choose from (usually in multiroot packages).
97-
public var testProduct: String?
141+
@Option(help: "The test product to use.")
142+
var testProduct: String?
98143

99144
/// Returns the test case specifier if overridden in the env.
100145
private func testCaseSpecifierOverride() -> TestCaseSpecifier? {
@@ -135,7 +180,6 @@ public enum TestCaseSpecifier {
135180
}
136181

137182
public enum TestMode {
138-
case version
139183
case listTests
140184
case codeCovPath
141185
case generateLinuxMain
@@ -144,27 +188,21 @@ public enum TestMode {
144188
}
145189

146190
/// swift-test tool namespace
147-
public class SwiftTestTool: SwiftTool<TestToolOptions> {
148-
149-
public convenience init(args: [String]) {
150-
self.init(
151-
toolName: "test",
152-
usage: "[options]",
153-
overview: "Build and run tests",
154-
args: args,
155-
seeAlso: type(of: self).otherToolNames()
156-
)
157-
}
158-
159-
override func runImpl() throws {
160-
191+
public struct SwiftTestTool: ParsableCommand {
192+
static let configuration = CommandConfiguration(
193+
commandName: "swift test",
194+
abstract: "Build and run tests")
195+
196+
@OptionGroup()
197+
var options: TestToolOptions
198+
199+
func run() throws {
200+
let swiftTool = SwiftTool(options: options.swiftOptions)
201+
161202
// Validate commands arguments
162203
try validateArguments()
163204

164205
switch options.mode {
165-
case .version:
166-
print(Versioning.currentVersion.completeDisplayString)
167-
168206
case .listTests:
169207
let testProducts = try buildTestsIfNeeded()
170208
let testSuites = try getTestSuites(in: testProducts)

0 commit comments

Comments
 (0)