Commit 0476fc3c authored by David Owens II's avatar David Owens II

Significant refactoring to support the new atpkg format.

The bootstrap scripts were also updated to build the entire product properly into libs; no more compiler flags.
Project structure simplified to at* for each of our targets.
The YAML parser completely removed.
parent 67cdcee2
Pipeline #681 passed with stage
bin/
*xcuserdata*
.atllbuild/
atbuild
build.db
.built/
*xcuserdata*
.DS_Store
\ No newline at end of file
......@@ -5,7 +5,7 @@ osx:
stage: build
script:
- export PATH=/Library/Developer/Toolchains/swift-latest.xctoolchain/usr/bin:"${PATH}"
- ./bootstrap.sh
- ./bootstrap/build.sh
tags:
- openswift
artifacts:
......
;; Copyright (c) 2016 Anarchy Tools Contributors.
;;
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http:;;www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
;; The build file for all of the targets of the Anarchy Tools build tool.
(package
:name "atbuild"
:tasks {:hellworld {:tool "shell"
:script "echo \"Hello world\"" }
:default {:dependencies ["yaml"]
:tool "atllbuild"
:source ["cli/src/**.swift"]
:name "atbuild"
:outputType "executable"
:linkWithProduct: ["yaml.a"]}
:bootstrap-osx {:dependencies ["bootstrap-yaml-osx"]
:tool "atllbuild"
:source ["cli/src/**.swift"]
:name "atbuild"
:bootstrapOnly true
:llbuildyaml: "llbuild-osx.yaml"
:outputType "executable"
:linkWithProduct ["yaml.a"]}
:bootstrap-linux {:dependencies ["bootstrap-yaml-linux"]
:tool "atllbuild"
:source ["cli/src/**.swift"]
:name "atbuild"
:bootstrapOnly true
:llbuildyaml: "llbuild-linux.yaml"
:linkSDK false
:compileOptions ["-D" "CORELIBS_FOUNDATION"]
:outputType "executable"
:linkWithProduct ["yaml.a"]}
:bootstrap {:dependencies ["bootstrap-osx", "bootstrap-linux"]
:tool "nop"}
:yaml {:tool "atllbuild"
:source ["parsers/yaml/**.swift"]
:name "yaml"
:outputType "static-library"}
:atpkg-model {:tool "atllbuild"
:source ["model/src/**.swift"]
:name "atpkgmodel"
:outputType "static-library"}
:atpkg-parser {:dependencies ["atpkg-model"]
:tool "atllbuild"
:source ["parsers/atpkg/src/**.swift"]
:name "atpkgparser"
:outputType "static-library"
:linkWithProduct ["atpkgmodel.a"]}
:atpkg-tests {:dependencies ["atpkg-parser", "atpkg-model"]
:tool "atllbuild"
:source ["parsers/atpkg/tests/**.swift"]
:name "atpkgtests"
:outputType "executable"
:linkWithProduct ["atpkparser.a", "atpkgmodel.a"]}
:run-atpkg-tests {:dependencies ["atpkg-tests"]
:tool "shell"
:script "./.atllbuild/products/atpkgtests"}
:run-tests {:dependencies ["run-atpkg-tests"]
:tool "nop" }
)
package:
name: "atbuild"
tasks:
helloworld:
tool: "shell"
script: "echo \"Hello world\""
default:
dependency: ["yaml"]
tool: "atllbuild"
source: ["cli/src/**.swift"]
name: "atbuild"
outputType: "executable"
linkWithProduct: ["yaml.a"]
bootstrap-yaml-osx:
tool: "atllbuild"
source: ["parsers/yaml/**.swift"]
name: "yaml"
llbuildyaml: "yaml-osx-llbuild.yaml"
outputType: "static-library"
bootstrapOnly: true
bootstrap-yaml-linux:
tool: "atllbuild"
source: ["parsers/yaml/**.swift"]
name: "yaml"
llbuildyaml: "yaml-linux-llbuild.yaml"
outputType: "static-library"
linkSDK: false
compileOptions: ["-D","CORELIBS_FOUNDATION"]
bootstrapOnly: true
bootstrap-osx:
tool: "atllbuild"
source: ["cli/src/**.swift"]
name: "atbuild"
bootstrapOnly: true
llbuildyaml: "llbuild-osx.yaml"
outputType: "executable"
linkWithProduct: ["yaml.a"]
dependency: ["bootstrap-yaml-osx"]
bootstrap-linux:
tool: "atllbuild"
source: ["cli/src/**.swift"]
name: "atbuild"
bootstrapOnly: true
llbuildyaml: "llbuild-linux.yaml"
linkSDK: false
compileOptions: ["-D","CORELIBS_FOUNDATION"]
outputType: "executable"
linkWithProduct: ["yaml.a"]
dependency: ["bootstrap-yaml-linux"]
bootstrap:
tool: "nop"
dependency: ["bootstrap-osx", "bootstrap-linux"]
yaml:
tool: "atllbuild"
source: ["parsers/yaml/**.swift"]
name: "yaml"
outputType: "static-library"
atpkg:
tool: "atllbuild"
source: ["atpkg/src/**.swift"]
name: "atpkg"
outputType: "static-library"
atpkg-tests:
dependency: ["atpkg"]
tool: "atllbuild"
source: ["atpkg/tests/**.swift"]
name: "atpkgtests"
outputType: "executable"
linkWithProduct: ["atpkg.a"]
run-atpkg-tests:
dependency: ["atpkg-tests"]
tool: "shell"
script: "./.atllbuild/products/atpkgtests"
run-tests:
tool: "nop"
dependency: ["run-atpkg-tests"]
// main.swift
// © 2016 Anarchy Tools Contributors.
// This file is part of atbuild. It is subject to the license terms in the LICENSE
// file found in the top level of this distribution
// No part of atbuild, including this file, may be copied, modified,
// propagated, or distributed except according to the terms contained
// in the LICENSE file.
// Copyright (c) 2016 Anarchy Tools Contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
let version = "0.2.0-dev"
import Foundation
import atpkg
import attools
#if ATBUILD
import yaml
#endif
let defaultBuildFile = "build.atpkg"
func loadPackageFile() -> Package {
guard let package = Package(filepath: defaultBuildFile) else {
print("Unable to load build file: \(defaultBuildFile)")
exit(1)
}
return package
}
//usage message
if Process.arguments.count > 1 && Process.arguments[1] == "--help" {
......@@ -23,26 +37,22 @@ if Process.arguments.count > 1 && Process.arguments[1] == "--help" {
print("")
print("Usage:")
print("atbuild [task]")
if let yaml = try? loadyaml() {
if let taskNames = yaml["tasks"]?.dictionary?.keys.map({$0.string!}) {
print(" task: \(Array(taskNames)) ")
}
let package = loadPackageFile()
print("tasks:")
for (key, task) in package.tasks {
print(" \(key)")
}
exit(1)
}
//load configuration
let yaml = try! loadyaml()
guard let package = yaml["package"]?.dictionary else { fatalError("No package in YAML") }
guard let name = package["name"]?.string else { fatalError("No package name") }
print("Building package \(name)...")
let package = loadPackageFile()
print("Building package \(package.name)...")
func runtask(taskName: String) {
guard let task = yaml["tasks"]?.dictionary else { fatalError("No tasks in YAML") }
guard let defaultTask = task[Yaml(stringLiteral: taskName)]?.dictionary else { fatalError("No \(taskName) task in YAML") }
let t = try! Task(yaml: defaultTask, name: taskName, entireConfig: yaml)
try! t.run()
guard let task = package.tasks[taskName] else { fatalError("No \(taskName) task in build configuration.") }
TaskRunner.runTask(task, package: package)
}
//choose which task to run
......@@ -54,4 +64,4 @@ else {
}
//success message
print("Built package \(name).")
\ No newline at end of file
print("Built package \(package.name).")
\ No newline at end of file
......@@ -12,117 +12,33 @@
// See the License for the specific language governing permissions and
// limitations under the License.
public enum OutputType {
case Executable
case StaticLibrary
case DynamicLibrary
}
public class FilePath {
public var path: String
public init(path: String) {
self.path = path
}
init?(value: ParseValue) {
guard let str = value.stringLiteral else { return nil }
self.path = str
}
}
public class Dependency {
public var name: String
public init(name: String) {
self.name = name
}
init?(value: ParseValue) {
guard let str = value.stringLiteral else { return nil }
self.name = str
}
}
public class Task {
// The required properties.
public var name: String
// The optional properties. All optional properties must have a default value.
public var dependencies: [Dependency] = []
final public class Task {
public var key: String = ""
public var dependencies: [String] = []
public var tool: String = "atllbuild"
public var sources: [FilePath] = []
public var bootstrapOnly: Bool = false
public var llbuildyaml: String = ""
public var linkSDK: Bool = false
public var compilerOptions: [String] = []
public var outputType: OutputType = OutputType.StaticLibrary
public var linkWithProduct: [String] = []
public init(name: String) {
self.name = name
}
private var kvp: [String:ParseValue]
init?(value: ParseValue, name: String) {
guard let kvp = value.map else { return nil }
if let value = kvp["name"]?.stringLiteral { self.name = value }
else {
print("ERROR: Name is a required property on task.")
return nil
}
if let value = kvp["tool"]?.stringLiteral { self.tool = value }
if let value = kvp["bootstrapOnly"]?.boolLiteral { self.bootstrapOnly = value }
if let value = kvp["llbuildyaml"]?.stringLiteral { self.llbuildyaml = value }
if let value = kvp["linkSDK"]?.boolLiteral { self.linkSDK = value }
if let value = kvp["outputType"]?.stringLiteral {
switch value {
case "lib": self.outputType = .StaticLibrary
case "static-library": self.outputType = .StaticLibrary
case "dylib": self.outputType = .DynamicLibrary
case "dynamic-library": self.outputType = .DynamicLibrary
case "exe": self.outputType = .Executable
case "executable": self.outputType = .Executable
default: print("ERROR: unsupported outputType: \(value), defaulting to: \(self.outputType)")
}
}
self.kvp = kvp
self.key = name
self.tool = kvp["tool"]?.string ?? self.tool
if let values = kvp["dependencies"]?.vector {
for value in values {
if let dep = Dependency(value: value) { self.dependencies.append(dep) }
}
}
if let values = kvp["sources"]?.vector {
for value in values {
if let filepath = FilePath(value: value) { self.sources.append(filepath) }
}
}
if let values = kvp["source"]?.vector {
for value in values {
if let filepath = FilePath(value: value) { self.sources.append(filepath) }
}
}
if let values = kvp["compilerOptions"]?.vector {
for value in values {
if let value = value.stringLiteral { self.compilerOptions.append(value) }
}
}
if let values = kvp["linkWithProduct"]?.vector {
for value in values {
if let value = value.stringLiteral { self.linkWithProduct.append(value) }
if let dep = value.string { self.dependencies.append(dep) }
}
}
}
public subscript(key: String) -> ParseValue? {
return kvp[key]
}
}
public class Package {
final public class Package {
// The required properties.
public var name: String
......@@ -134,15 +50,28 @@ public class Package {
self.name = name
}
public convenience init?(filepath: String) {
guard let parser = Parser(filepath: filepath) else { return nil }
do {
let result = try parser.parse()
self.init(type: result)
}
catch {
print("error: \(error)")
return nil
}
}
public init?(type: ParseType) {
if type.name != "package" { return nil }
if let value = type.properties["name"]?.stringLiteral { self.name = value }
if let value = type.properties["name"]?.string { self.name = value }
else {
print("ERROR: No name specified for the package.")
return nil
}
if let value = type.properties["version"]?.stringLiteral { self.version = value }
if let value = type.properties["version"]?.string { self.version = value }
if let parsedTasks = type.properties["tasks"]?.map {
for (key, value) in parsedTasks {
......
......@@ -31,22 +31,22 @@ public enum ParseValue {
}
extension ParseValue {
public var stringLiteral: String? {
public var string: String? {
if case let .StringLiteral(value) = self { return value }
return nil
}
public var integerLiteral: Int? {
public var integer: Int? {
if case let .IntegerLiteral(value) = self { return value }
return nil
}
public var floatLiteral: Double? {
public var float: Double? {
if case let .FloatLiteral(value) = self { return value }
return nil
}
public var boolLiteral: Bool? {
public var bool: Bool? {
if case let .BoolLiteral(value) = self { return value }
return nil
}
......@@ -63,12 +63,12 @@ extension ParseValue {
}
public class ParseType {
final public class ParseType {
public var name: String = ""
public var properties: [String:ParseValue] = [:]
}
public class Parser {
final public class Parser {
let lexer: Lexer
private func next() -> Token? {
......
......@@ -18,7 +18,7 @@ public struct ScannerInfo {
public let column: Int
}
public class Scanner {
final public class Scanner {
var content: String
var index: String.Index
......
......@@ -75,8 +75,7 @@ func isWhitespace(c: Character?) -> Bool {
return isCharacterPartOfSet(c, set: NSCharacterSet.whitespaceCharacterSet())
}
public class Lexer {
final public class Lexer {
var scanner: Scanner
var current: Token? = nil
......
......@@ -7,7 +7,7 @@
:tasks {:build {:tool "lldb-build"
:name "json-swift"
:output-type "lib"
:source [ "src/**.swift" ]}}
:source [ "src/**.swift" "lib/**.swift" ]}}
)
; End of the sample.
\ No newline at end of file
......@@ -41,23 +41,11 @@ class PackageTests: Test {
for (key, task) in package.tasks {
try test.assert(key == "build")
try test.assert(task.tool == "lldb-build")
try test.assert(task.name == "json-swift")
try test.assert(task.outputType == .StaticLibrary)
try test.assert(task.sources.count == 1)
try test.assert(task.sources[0].path == "src/**.swift")
try test.assert(task["name"]?.string == "json-swift")
try test.assert(task["output-type"]?.string == "lib")
try test.assert(task["source"]?.vector?.count == 2)
try test.assert(task["source"]?.vector?[0].string == "src/**.swift")
try test.assert(task["source"]?.vector?[1].string == "lib/**.swift")
}
// (package
// :name "basic"
// :version "0.1.0-dev"
// :tasks {:build {:tool "lldb-build"
// :name "json-swift"
// :output-type "lib"
// :source [ "src/**.swift" ]}}
// )
// ; End of the sample.
}
}
This diff is collapsed.
......@@ -34,11 +34,11 @@ class ParserTests: Test {
let name = result.properties["name"]
try test.assert(name != nil)
try test.assert(name?.stringLiteral == "basic")
try test.assert(name?.string == "basic")
let version = result.properties["version"]
try test.assert(version != nil)
try test.assert(version?.stringLiteral == "0.1.0-dev")
try test.assert(version?.string == "0.1.0-dev")
let tasks = result.properties["tasks"]
try test.assert(tasks != nil)
......@@ -48,19 +48,20 @@ class ParserTests: Test {
let tool = build?.map?["tool"]
try test.assert(tool != nil)
try test.assert(tool?.stringLiteral == "lldb-build")
try test.assert(tool?.string == "lldb-build")
let buildName = build?.map?["name"]
try test.assert(buildName != nil)
try test.assert(buildName?.stringLiteral == "json-swift")
try test.assert(buildName?.string == "json-swift")
let outputType = build?.map?["output-type"]
try test.assert(outputType != nil)
try test.assert(outputType?.stringLiteral == "lib")
try test.assert(outputType?.string == "lib")
let source = build?.map?["source"]
try test.assert(source != nil)
try test.assert(source?.vector != nil)
try test.assert(source?.vector?[0].stringLiteral == "src/**.swift")
try test.assert(source?.vector?[0].string == "src/**.swift")
try test.assert(source?.vector?[1].string == "lib/**.swift")
}
}
\ No newline at end of file
......@@ -299,6 +299,21 @@ class ScannerTests: Test {
try test.assert(scanner.next()?.character == "t")
try test.assert(scanner.next()?.character == "\"")
try test.assert(scanner.next()?.character == " ")
try test.assert(scanner.next()?.character == "\"")
try test.assert(scanner.next()?.character == "l")
try test.assert(scanner.next()?.character == "i")
try test.assert(scanner.next()?.character == "b")
try test.assert(scanner.next()?.character == "/")
try test.assert(scanner.next()?.character == "*")
try test.assert(scanner.next()?.character == "*")
try test.assert(scanner.next()?.character == ".")
try test.assert(scanner.next()?.character == "s")
try test.assert(scanner.next()?.character == "w")
try test.assert(scanner.next()?.character == "i")
try test.assert(scanner.next()?.character == "f")
try test.assert(scanner.next()?.character == "t")
try test.assert(scanner.next()?.character == "\"")
try test.assert(scanner.next()?.character == " ")
try test.assert(scanner.next()?.character == "]")
try test.assert(scanner.next()?.character == "}")
try test.assert(scanner.next()?.character == "}")
......
// Copyright (c) 2016 Anarchy Tools Contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import atpkg
/**
* A stub tool that does no work. This tool is primary used to group
* dependencies together.
*/
final class Nop: Tool {
func run(task: Task) {}
}
// PlatformPaths.swift
// © 2016 Anarchy Tools Contributors.
// This file is part of atbuild. It is subject to the license terms in the LICENSE
// file found in the top level of this distribution
// No part of atbuild, including this file, may be copied, modified,
// propagated, or distributed except according to the terms contained
// in the LICENSE file.
// Copyright (c) 2016 Anarchy Tools Contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
......
// Copyright (c) 2016 Anarchy Tools Contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
import atpkg
/**
* The shell tool forks a new process with `/bin/sh -c`. Any arguments specified
* within the task will also be sent across.
* If the tool returns with an error code of non-zero, the tool will fail.
*/
final class Shell : Tool {
func run(task: Task) {
guard let script = task["script"]?.string else { fatalError("Invalid 'script' argument to shell tool.") }
let t = NSTask.launchedTaskWithLaunchPath("/bin/sh", arguments: ["-c", script])
t.waitUntilExit()
if t.terminationStatus != 0 {
fatalError("/bin/sh -c \(script)")
}
}
}
\ No newline at end of file
// Copyright (c) 2016 Anarchy Tools Contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import atpkg
/**
* Provides the functionality of running a particular task from the build
* configuration file. The primary work for the task is done via the tool
* that is specified within the task.
*/
final public class TaskRunner {
private init() {}
static public func runTask(task: Task, package: Package) {
for dependency in task.dependencies {
guard let depTask = package.tasks[dependency] else { fatalError("The given dependency does not exist: \(dependency)") }
TaskRunner.runTask(depTask, package: package)
}