Skip to content

Refactor --init mode for library package support, Adds test stubs to libs #141

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 8, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 123 additions & 31 deletions Sources/swift-build/initPackage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,59 +13,151 @@ import func libc.fclose
import PackageType
import POSIX

func initPackage() throws {
let rootd = try POSIX.getcwd()
let pkgname = rootd.basename
let manifest = Path.join(rootd, Manifest.filename)
let gitignore = Path.join(rootd, ".gitignore")
let sources = Path.join(rootd, "Sources")
let tests = Path.join(rootd, "Tests")
let main = Path.join(sources, "main.swift")

guard !manifest.exists else {
throw Error.ManifestAlreadyExists
final class InitPackage {

enum InitMode {
case Library
case Executable
}

let mode: InitMode
let pkgname: String
let rootd: String

init(mode: InitMode) throws {
self.mode = mode
rootd = try POSIX.getcwd()
pkgname = rootd.basename
}

let packageFP = try fopen(manifest, mode: .Write)
defer {
fclose(packageFP)
func writePackageStructure() throws {
print("Creating \(mode) package: \(pkgname)")

try writeManifestFile()
try writeGitIgnore()
try writeSources()
try writeTests()
}

print("Creating \(Manifest.filename)")
// print the manifest file
try fputs("import PackageDescription\n", packageFP)
try fputs("\n", packageFP)
try fputs("let package = Package(\n", packageFP)
try fputs(" name: \"\(pkgname)\"\n", packageFP)
try fputs(")\n", packageFP)
private func writeManifestFile() throws {
let manifest = Path.join(rootd, Manifest.filename)
guard manifest.exists == false else {
throw Error.ManifestAlreadyExists
}

let packageFP = try fopen(manifest, mode: .Write)
defer {
fclose(packageFP)
}
print("Creating \(Manifest.filename)")
// print the manifest file
try fputs("import PackageDescription\n", packageFP)
try fputs("\n", packageFP)
try fputs("let package = Package(\n", packageFP)
try fputs(" name: \"\(pkgname)\"\n", packageFP)
try fputs(")\n", packageFP)
}

if !gitignore.exists {
private func writeGitIgnore() throws {
let gitignore = Path.join(rootd, ".gitignore")
guard gitignore.exists == false else {
return
}
let gitignoreFP = try fopen(gitignore, mode: .Write)
defer {
fclose(gitignoreFP)
}

print("Creating .gitignore")
// print the .gitignore
try fputs(".DS_Store\n", gitignoreFP)
try fputs("/.build\n", gitignoreFP)
try fputs("/Packages\n", gitignoreFP)
}

if !sources.exists {
private func writeSources() throws {
let sources = Path.join(rootd, "Sources")
guard sources.exists == false else {
return
}
print("Creating Sources/")
try mkdir(sources)

let mainFP = try fopen(main, mode: .Write)

let sourceFileName = (mode == .Executable) ? "main.swift" : "\(pkgname).swift"
let sourceFile = Path.join(sources, sourceFileName)
let sourceFileFP = try fopen(sourceFile, mode: .Write)
defer {
fclose(mainFP)
fclose(sourceFileFP)
}
print("Creating Sources/\(sourceFileName)")
switch mode {
case .Library:
try fputs("struct \(pkgname) {\n\n", sourceFileFP)
try fputs("}\n", sourceFileFP)
case .Executable:
try fputs("print(\"Hello, world!\")\n", sourceFileFP)
}
print("Creating Sources/main.swift")
try fputs("print(\"Hello, world!\")\n", mainFP)
}

if !tests.exists {
private func writeTests() throws {
let tests = Path.join(rootd, "Tests")
guard tests.exists == false else {
return
}
print("Creating Tests/")
try mkdir(tests)
///Only libraries are testable for now
if mode == .Library {
try writeLinuxMain(testsPath: tests)
try writeTestFileStubs(testsPath: tests)
}
}

private func writeLinuxMain(testsPath testsPath: String) throws {
let linuxMain = Path.join(testsPath, "LinuxMain.swift")
let linuxMainFP = try fopen(linuxMain, mode: .Write)
defer {
fclose(linuxMainFP)
}
print("Creating Tests/LinuxMain.swift")
try fputs("import XCTest\n", linuxMainFP)
try fputs("@testable import \(pkgname)test\n\n", linuxMainFP)
try fputs("XCTMain([\n", linuxMainFP)
try fputs("\t\(pkgname)(),\n", linuxMainFP)
try fputs("])\n", linuxMainFP)
}

private func writeTestFileStubs(testsPath testsPath: String) throws {
let testModule = Path.join(testsPath, pkgname)
print("Creating Tests/\(pkgname)/")
try mkdir(testModule)

let testsFile = Path.join(testModule, "\(pkgname).swift")
print("Creating Tests/\(pkgname)/\(pkgname).swift")
let testsFileFP = try fopen(testsFile, mode: .Write)
defer {
fclose(testsFileFP)
}
try fputs("import XCTest\n", testsFileFP)
try fputs("@testable import \(pkgname)\n\n", testsFileFP)

try fputs("class \(pkgname): XCTestCase {\n\n", testsFileFP)

try fputs("\tfunc testExample() {\n", testsFileFP)
try fputs("\t\t// This is an example of a functional test case.\n", testsFileFP)
try fputs("\t\t// Use XCTAssert and related functions to verify your tests produce the correct results.\n", testsFileFP)
try fputs("\t}\n\n", testsFileFP)

try fputs("}\n", testsFileFP)

try fputs("\n#if os(Linux)\n", testsFileFP)
try fputs("extension \(pkgname): XCTestCaseProvider {\n", testsFileFP)
try fputs("\tvar allTests : [(String, () throws -> Void)] {\n", testsFileFP)
try fputs("\t\treturn [\n", testsFileFP)
try fputs("\t\t\t(\"testExample\", testExample),\n", testsFileFP)
try fputs("\t\t]\n", testsFileFP)
try fputs("\t}\n", testsFileFP)
try fputs("}\n", testsFileFP)
try fputs("#endif\n", testsFileFP)
}
}
}
7 changes: 4 additions & 3 deletions Sources/swift-build/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@ do {
let yaml = try describe(dirs.build, conf, modules, products, Xcc: opts.Xcc, Xld: opts.Xld, Xswiftc: opts.Xswiftc)
try build(YAMLPath: yaml, target: "default")

case .Init:
try initPackage()

case .Init(let initMode):
let initPackage = try InitPackage(mode: initMode)
try initPackage.writePackageStructure()

case .Fetch:
try fetch(try directories().root)

Expand Down
17 changes: 14 additions & 3 deletions Sources/swift-build/usage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func usage(print: (String) -> Void = { print($0) }) {
print("MODES:")
print(" --configuration <value> Build with configuration (debug|release) [-c]")
print(" --clean[=<mode>] Delete artefacts (build|dist) [-k]")
print(" --init Creates a new Swift project")
print(" --init <mode> Creates a new Swift package (executable|library)")
print(" --fetch Fetch package dependencies")
print("")
print("OPTIONS:")
Expand All @@ -40,7 +40,7 @@ enum Mode {
case Build(Configuration)
case Clean(CleanMode)
case Fetch
case Init
case Init(InitPackage.InitMode)
case Usage
case Version
}
Expand Down Expand Up @@ -116,7 +116,18 @@ func parse(commandLineArguments args: [String]) throws -> (Mode, Options) {
case (nil, .Usage):
mode = .Usage
case (nil, .Init):
mode = .Init
mode = .Init(.Executable)
switch try cruncher.peek() {
case .Name("executable")?:
cruncher.postPeekPop()
case .Name("library")?:
mode = .Init(.Library)
cruncher.postPeekPop()
case .Name(let name)?:
throw CommandLineError.InvalidUsage("Unknown init mode: \(name)", .Imply)
default:
break
}
case (nil, .Clean):
mode = .Clean(.Build)
switch try cruncher.peek() {
Expand Down