Skip to content

Commit f6c8f03

Browse files
committed
Merge pull request #141 from aciidb0mb3r/init_pkg_enhancements
Refactor --init mode for library package support, Adds test stubs to libs
2 parents 2d70e5a + f10727c commit f6c8f03

File tree

3 files changed

+141
-37
lines changed

3 files changed

+141
-37
lines changed

Sources/swift-build/initPackage.swift

Lines changed: 123 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,59 +13,151 @@ import func libc.fclose
1313
import PackageType
1414
import POSIX
1515

16-
func initPackage() throws {
17-
let rootd = try POSIX.getcwd()
18-
let pkgname = rootd.basename
19-
let manifest = Path.join(rootd, Manifest.filename)
20-
let gitignore = Path.join(rootd, ".gitignore")
21-
let sources = Path.join(rootd, "Sources")
22-
let tests = Path.join(rootd, "Tests")
23-
let main = Path.join(sources, "main.swift")
24-
25-
guard !manifest.exists else {
26-
throw Error.ManifestAlreadyExists
16+
final class InitPackage {
17+
18+
enum InitMode {
19+
case Library
20+
case Executable
21+
}
22+
23+
let mode: InitMode
24+
let pkgname: String
25+
let rootd: String
26+
27+
init(mode: InitMode) throws {
28+
self.mode = mode
29+
rootd = try POSIX.getcwd()
30+
pkgname = rootd.basename
2731
}
2832

29-
let packageFP = try fopen(manifest, mode: .Write)
30-
defer {
31-
fclose(packageFP)
33+
func writePackageStructure() throws {
34+
print("Creating \(mode) package: \(pkgname)")
35+
36+
try writeManifestFile()
37+
try writeGitIgnore()
38+
try writeSources()
39+
try writeTests()
3240
}
3341

34-
print("Creating \(Manifest.filename)")
35-
// print the manifest file
36-
try fputs("import PackageDescription\n", packageFP)
37-
try fputs("\n", packageFP)
38-
try fputs("let package = Package(\n", packageFP)
39-
try fputs(" name: \"\(pkgname)\"\n", packageFP)
40-
try fputs(")\n", packageFP)
42+
private func writeManifestFile() throws {
43+
let manifest = Path.join(rootd, Manifest.filename)
44+
guard manifest.exists == false else {
45+
throw Error.ManifestAlreadyExists
46+
}
47+
48+
let packageFP = try fopen(manifest, mode: .Write)
49+
defer {
50+
fclose(packageFP)
51+
}
52+
print("Creating \(Manifest.filename)")
53+
// print the manifest file
54+
try fputs("import PackageDescription\n", packageFP)
55+
try fputs("\n", packageFP)
56+
try fputs("let package = Package(\n", packageFP)
57+
try fputs(" name: \"\(pkgname)\"\n", packageFP)
58+
try fputs(")\n", packageFP)
59+
}
4160

42-
if !gitignore.exists {
61+
private func writeGitIgnore() throws {
62+
let gitignore = Path.join(rootd, ".gitignore")
63+
guard gitignore.exists == false else {
64+
return
65+
}
4366
let gitignoreFP = try fopen(gitignore, mode: .Write)
4467
defer {
4568
fclose(gitignoreFP)
4669
}
47-
70+
4871
print("Creating .gitignore")
4972
// print the .gitignore
5073
try fputs(".DS_Store\n", gitignoreFP)
5174
try fputs("/.build\n", gitignoreFP)
5275
try fputs("/Packages\n", gitignoreFP)
5376
}
5477

55-
if !sources.exists {
78+
private func writeSources() throws {
79+
let sources = Path.join(rootd, "Sources")
80+
guard sources.exists == false else {
81+
return
82+
}
5683
print("Creating Sources/")
5784
try mkdir(sources)
58-
59-
let mainFP = try fopen(main, mode: .Write)
85+
86+
let sourceFileName = (mode == .Executable) ? "main.swift" : "\(pkgname).swift"
87+
let sourceFile = Path.join(sources, sourceFileName)
88+
let sourceFileFP = try fopen(sourceFile, mode: .Write)
6089
defer {
61-
fclose(mainFP)
90+
fclose(sourceFileFP)
91+
}
92+
print("Creating Sources/\(sourceFileName)")
93+
switch mode {
94+
case .Library:
95+
try fputs("struct \(pkgname) {\n\n", sourceFileFP)
96+
try fputs("}\n", sourceFileFP)
97+
case .Executable:
98+
try fputs("print(\"Hello, world!\")\n", sourceFileFP)
6299
}
63-
print("Creating Sources/main.swift")
64-
try fputs("print(\"Hello, world!\")\n", mainFP)
65100
}
66101

67-
if !tests.exists {
102+
private func writeTests() throws {
103+
let tests = Path.join(rootd, "Tests")
104+
guard tests.exists == false else {
105+
return
106+
}
68107
print("Creating Tests/")
69108
try mkdir(tests)
109+
///Only libraries are testable for now
110+
if mode == .Library {
111+
try writeLinuxMain(testsPath: tests)
112+
try writeTestFileStubs(testsPath: tests)
113+
}
114+
}
115+
116+
private func writeLinuxMain(testsPath testsPath: String) throws {
117+
let linuxMain = Path.join(testsPath, "LinuxMain.swift")
118+
let linuxMainFP = try fopen(linuxMain, mode: .Write)
119+
defer {
120+
fclose(linuxMainFP)
121+
}
122+
print("Creating Tests/LinuxMain.swift")
123+
try fputs("import XCTest\n", linuxMainFP)
124+
try fputs("@testable import \(pkgname)test\n\n", linuxMainFP)
125+
try fputs("XCTMain([\n", linuxMainFP)
126+
try fputs("\t\(pkgname)(),\n", linuxMainFP)
127+
try fputs("])\n", linuxMainFP)
128+
}
129+
130+
private func writeTestFileStubs(testsPath testsPath: String) throws {
131+
let testModule = Path.join(testsPath, pkgname)
132+
print("Creating Tests/\(pkgname)/")
133+
try mkdir(testModule)
134+
135+
let testsFile = Path.join(testModule, "\(pkgname).swift")
136+
print("Creating Tests/\(pkgname)/\(pkgname).swift")
137+
let testsFileFP = try fopen(testsFile, mode: .Write)
138+
defer {
139+
fclose(testsFileFP)
140+
}
141+
try fputs("import XCTest\n", testsFileFP)
142+
try fputs("@testable import \(pkgname)\n\n", testsFileFP)
143+
144+
try fputs("class \(pkgname): XCTestCase {\n\n", testsFileFP)
145+
146+
try fputs("\tfunc testExample() {\n", testsFileFP)
147+
try fputs("\t\t// This is an example of a functional test case.\n", testsFileFP)
148+
try fputs("\t\t// Use XCTAssert and related functions to verify your tests produce the correct results.\n", testsFileFP)
149+
try fputs("\t}\n\n", testsFileFP)
150+
151+
try fputs("}\n", testsFileFP)
152+
153+
try fputs("\n#if os(Linux)\n", testsFileFP)
154+
try fputs("extension \(pkgname): XCTestCaseProvider {\n", testsFileFP)
155+
try fputs("\tvar allTests : [(String, () throws -> Void)] {\n", testsFileFP)
156+
try fputs("\t\treturn [\n", testsFileFP)
157+
try fputs("\t\t\t(\"testExample\", testExample),\n", testsFileFP)
158+
try fputs("\t\t]\n", testsFileFP)
159+
try fputs("\t}\n", testsFileFP)
160+
try fputs("}\n", testsFileFP)
161+
try fputs("#endif\n", testsFileFP)
70162
}
71-
}
163+
}

Sources/swift-build/main.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,10 @@ do {
4848
let yaml = try describe(dirs.build, conf, modules, products, Xcc: opts.Xcc, Xld: opts.Xld, Xswiftc: opts.Xswiftc)
4949
try build(YAMLPath: yaml, target: "default")
5050

51-
case .Init:
52-
try initPackage()
53-
51+
case .Init(let initMode):
52+
let initPackage = try InitPackage(mode: initMode)
53+
try initPackage.writePackageStructure()
54+
5455
case .Fetch:
5556
try fetch(try directories().root)
5657

Sources/swift-build/usage.swift

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ func usage(print: (String) -> Void = { print($0) }) {
2020
print("MODES:")
2121
print(" --configuration <value> Build with configuration (debug|release) [-c]")
2222
print(" --clean[=<mode>] Delete artefacts (build|dist) [-k]")
23-
print(" --init Creates a new Swift project")
23+
print(" --init <mode> Creates a new Swift package (executable|library)")
2424
print(" --fetch Fetch package dependencies")
2525
print("")
2626
print("OPTIONS:")
@@ -40,7 +40,7 @@ enum Mode {
4040
case Build(Configuration)
4141
case Clean(CleanMode)
4242
case Fetch
43-
case Init
43+
case Init(InitPackage.InitMode)
4444
case Usage
4545
case Version
4646
}
@@ -116,7 +116,18 @@ func parse(commandLineArguments args: [String]) throws -> (Mode, Options) {
116116
case (nil, .Usage):
117117
mode = .Usage
118118
case (nil, .Init):
119-
mode = .Init
119+
mode = .Init(.Executable)
120+
switch try cruncher.peek() {
121+
case .Name("executable")?:
122+
cruncher.postPeekPop()
123+
case .Name("library")?:
124+
mode = .Init(.Library)
125+
cruncher.postPeekPop()
126+
case .Name(let name)?:
127+
throw CommandLineError.InvalidUsage("Unknown init mode: \(name)", .Imply)
128+
default:
129+
break
130+
}
120131
case (nil, .Clean):
121132
mode = .Clean(.Build)
122133
switch try cruncher.peek() {

0 commit comments

Comments
 (0)