Refactor describe(), add llbuild tool types #175

Merged
merged 1 commit into from Mar 9, 2016
Jump to file or symbol
Failed to load files and symbols.
+207 −89
Diff settings

Always

Just for now

View
@@ -8,56 +8,35 @@
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
*/
-import struct Utility.Path
-import struct libc.FILE
-import func libc.fclose
-import POSIX
-
-class YAML {
- let path: String
- private let fp: UnsafeMutablePointer<FILE>
-
- init(path: String...) throws {
- self.path = Path.join(path)
- fp = try fopen(self.path, mode: .Write)
- }
+protocol YAMLRepresentable {
+ var YAML: String { get }
+}
- func close() {
- fclose(fp)
+extension String: YAMLRepresentable {
+ var YAML: String {
+ if self == "" { return "\"\"" }
+ return self
}
+}
- func write(anys: Any...) throws {
- var anys = anys
- try fputs(anys.removeFirst() as! String, fp)
- if !anys.isEmpty {
- try fputs(anys.map(toYAML).joinWithSeparator(""), fp)
- }
- try fputs("\n", fp)
-
+extension Bool: YAMLRepresentable {
+ var YAML: String {
+ if self { return "true" }
+ return "false"
}
}
-private func toYAML(any: Any) -> String {
-
- func quote(input: String) -> String {
- for c in input.characters {
- if c == "@" || c == " " || c == "-" {
- return "\"\(input)\""
+extension Array where Element: YAMLRepresentable {
+ var YAML: String {
+ func quote(input: String) -> String {
+ for c in input.characters {
+ if c == "@" || c == " " || c == "-" {
+ return "\"\(input)\""
+ }
}
+ return input
}
- return input
- }
-
- switch any {
- case let string as String where string == "":
- return "\"\""
- case let string as String:
- return string
- case let array as [String]:
- return "[" + array.map(quote).joinWithSeparator(", ") + "]"
- case let bool as Bool:
- return bool ? "true" : "false"
- default:
- fatalError("Unimplemented YAML type")
+ let stringArray = self.flatMap { String($0) }
+ return "[" + stringArray.map(quote).joinWithSeparator(", ") + "]"
}
}
@@ -12,6 +12,8 @@ import func POSIX.getenv
import func POSIX.mkdir
import PackageType
import Utility
+import func POSIX.fopen
+import func libc.fclose
/**
- Returns: path to generated YAML for consumption by the llbuild based swift-build-tool
@@ -25,25 +27,20 @@ public func describe(prefix: String, _ conf: Configuration, _ modules: [Module],
let Xcc = Xcc.flatMap{ ["-Xcc", $0] }
let Xld = Xld.flatMap{ ["-Xlinker", $0] }
let prefix = try mkdir(prefix, conf.dirname)
- let yaml = try YAML(path: "\(prefix).yaml")
- let write = yaml.write
- let (buildableTests, buildableNonTests) = (modules.map{$0 as Buildable} + products.map{$0 as Buildable}).partition{$0.isTest}
- let (tests, nontests) = (buildableTests.map{$0.targetName}, buildableNonTests.map{$0.targetName})
-
- defer { yaml.close() }
-
- try write("client:")
- try write(" name: swift-build")
- try write("tools: {}")
- try write("targets:")
- try write(" default: ", nontests)
- try write(" test: ", tests)
- try write("commands: ")
+ var nonTests = [Command]()
+ var tests = [Command]()
+
+ /// Appends the command to appropriate array
+ func append(command: Command, buildable: Buildable) {
+ if buildable.isTest {
+ tests.append(command)
+ } else {
+ nonTests.append(command)
+ }
+ }
var mkdirs = Set<String>()
-
-
let swiftcArgs = Xcc + Xswiftc
for case let module as SwiftModule in modules {
@@ -65,23 +62,22 @@ public func describe(prefix: String, _ conf: Configuration, _ modules: [Module],
#endif
let node = IncrementalNode(module: module, prefix: prefix)
-
- try write(" ", module.targetName, ":")
- try write(" tool: swift-compiler")
- try write(" executable: ", Resources.path.swiftc)
- try write(" module-name: ", module.c99name)
- try write(" module-output-path: ", node.moduleOutputPath)
- try write(" inputs: ", node.inputs)
- try write(" outputs: ", node.outputs)
- try write(" import-paths: ", prefix)
- try write(" temps-path: ", node.tempsPath)
- try write(" objects: ", node.objectPaths)
- try write(" other-args: ", args + otherArgs)
- try write(" sources: ", module.sources.paths)
-
- // this must be set or swiftc compiles single source file
- // modules with a main() for some reason
- try write(" is-library: ", module.type == .Library)
+ let swiftc = SwiftcTool(
+ inputs: node.inputs,
+ outputs: node.outputs,
+ executable: Resources.path.swiftc,
+ moduleName: module.c99name,
+ moduleOutputPath: node.moduleOutputPath,
+ importPaths: prefix,
+ tempsPath: node.tempsPath,
+ objects: node.objectPaths,
+ otherArgs: args + otherArgs,
+ sources: module.sources.paths,
+ isLibrary: module.type == .Library) /// this must be set or swiftc compiles single source
+ /// file modules with a main() for some reason
+
+ let command = Command(name: module.targetName, tool: swiftc)
+ append(command, buildable: module)
for o in node.objectPaths {
mkdirs.insert(o.parentDirectory)
@@ -96,12 +92,14 @@ public func describe(prefix: String, _ conf: Configuration, _ modules: [Module],
args += ["-parse-as-library"]
}
- try write(" ", module.targetName, ":")
- try write(" tool: shell")
- try write(" description: Compiling \(module.name)")
- try write(" inputs: ", inputs)
- try write(" outputs: ", [productPath, module.targetName])
- try write(" args: ", [Resources.path.swiftc, "-o", productPath] + args + module.sources.paths + otherArgs)
+ let shell = ShellTool(
+ description: "Compiling \(module.name)",
+ inputs: inputs,
+ outputs: [productPath, module.targetName],
+ args: [Resources.path.swiftc, "-o", productPath] + args + module.sources.paths + otherArgs)
+
+ let command = Command(name: module.targetName, tool: shell)
+ append(command, buildable: module)
}
}
@@ -178,15 +176,30 @@ public func describe(prefix: String, _ conf: Configuration, _ modules: [Module],
let inputs = product.modules.flatMap{ [$0.targetName] + IncrementalNode(module: $0, prefix: prefix).inputs }
- try write(" \(product.targetName):")
- try write(" tool: shell")
- try write(" description: Linking \(product)")
- try write(" inputs: ", inputs)
- try write(" outputs: ", [product.targetName, outpath])
- try write(" args: ", args)
+ let shell = ShellTool(
+ description: "Linking \(product)",
+ inputs: inputs,
+ outputs: [product.targetName, outpath],
+ args: args)
+
+ let command = Command(name: product.targetName, tool: shell)
+ append(command, buildable: product)
}
- return yaml.path
+ //Create Targets
+ let nontestTarget = Target(name: "default", commands: nonTests)
+ let testTarget = Target(name: "test", commands: tests)
+
+ //Generate YAML String for the targets
+ let yamlString = llbuildYAML(targets: [nontestTarget, testTarget])
+
+ //Write YAML to file
+ let yamlPath = "\(prefix).yaml"
+ let fp = try fopen(yamlPath, mode: .Write)
+ defer { fclose(fp) }
+ try fputs(yamlString, fp)
+
+ return yamlPath
}
View
@@ -0,0 +1,126 @@
+/*
+This source file is part of the Swift.org open source project
+
+Copyright 2015 - 2016 Apple Inc. and the Swift project authors
+Licensed under Apache License v2.0 with Runtime Library Exception
+
+See http://swift.org/LICENSE.txt for license information
+See http://swift.org/CONTRIBUTORS.txt for Swift project authors
+*/
+
+protocol ToolType {
+ var name: String { get }
+ var inputs: [String] { get }
+ var outputs: [String] { get }
+ ///YAML representation of the tool
+ var llbuildYAML: String { get }
+}
+
+protocol ShellToolType: ToolType {
+ var description: String { get }
+ var args: [String] { get }
+}
+
+extension ShellToolType {
+
+ var name: String {
+ return "shell"
+ }
+
+ var llbuildYAML: String {
+ var yaml = ""
+ yaml += " tool: " + name.YAML + "\n"
+ yaml += " description: " + description.YAML + "\n"
+ yaml += " inputs: " + inputs.YAML + "\n"
+ yaml += " outputs: " + outputs.YAML + "\n"
+ yaml += " args: " + args.YAML + "\n"
+ return yaml
+ }
+}
+
+struct ShellTool: ShellToolType {
+ let description: String
+ let inputs: [String]
+ let outputs: [String]
+ let args: [String]
+}
+
+protocol SwiftcToolType: ToolType {
+ var executable: String { get }
+ var moduleName: String { get }
+ var moduleOutputPath: String { get }
+ var importPaths: String { get }
+ var tempsPath: String { get }
+ var objects: [String] { get }
+ var otherArgs: [String] { get }
+ var sources: [String] { get }
+ var isLibrary: Bool { get }
+}
+
+extension SwiftcToolType {
+
+ var name: String {
+ return "swift-compiler"
+ }
+
+ var llbuildYAML: String {
+ var yaml = ""
+ yaml += " tool: " + name.YAML + "\n"
+ yaml += " executable: " + executable.YAML + "\n"
+ yaml += " module-name: " + moduleName.YAML + "\n"
+ yaml += " module-output-path: " + moduleOutputPath.YAML + "\n"
+ yaml += " inputs: " + inputs.YAML + "\n"
+ yaml += " outputs: " + outputs.YAML + "\n"
+ yaml += " import-paths: " + importPaths.YAML + "\n"
+ yaml += " temps-path: " + tempsPath.YAML + "\n"
+ yaml += " objects: " + objects.YAML + "\n"
+ yaml += " other-args: " + otherArgs.YAML + "\n"
+ yaml += " sources: " + sources.YAML + "\n"
+ yaml += " is-library: " + isLibrary.YAML + "\n"
+ return yaml
+ }
+}
+
+struct SwiftcTool: SwiftcToolType {
+ let inputs: [String]
+ let outputs: [String]
+ let executable: String
+ let moduleName: String
+ let moduleOutputPath: String
+ let importPaths: String
+ let tempsPath: String
+ let objects: [String]
+ let otherArgs: [String]
+ let sources: [String]
+ let isLibrary: Bool
+}
+
+typealias Command = (name: String, tool: ToolType)
+
+struct Target {
+ let name: String
+ let commands: [Command]
+}
+
+func llbuildYAML(targets targets: [Target]) -> String {
+
+ var yaml = ""
+ yaml += "client:" + "\n"
+ yaml += " name: swift-build" + "\n"
+ yaml += "tools: {}" + "\n"
+
+ yaml += "targets:" + "\n"
+ for target in targets {
+ yaml += " \(target.name): " + target.commands.map{$0.name}.YAML + "\n"
+ }
+
+ yaml += "commands: " + "\n"
+
+ let commands = targets.reduce([Command]()) { $0 + $1.commands }
+ for command in commands {
+ yaml += " " + command.name + ":" + "\n"
+ yaml += command.tool.llbuildYAML
+ }
+
+ return yaml
+}