Skip to content

Instantly share code, notes, and snippets.

@Grayson
Created April 19, 2017 12:40
Show Gist options
  • Save Grayson/0512824a6dae381a3ff6ab797f88d95d to your computer and use it in GitHub Desktop.
Save Grayson/0512824a6dae381a3ff6ab797f88d95d to your computer and use it in GitHub Desktop.
Prototypical swift script to build dependencies in Package.swift
#!/usr/bin/swift
import Foundation
struct Project {
let name: String
let path: URL
let url: URL
let version: String
let dependencies: [Project]
static func from(_ dict: [String: Any]) -> Project? {
guard
let name = dict["name"] as? String,
let pathString = dict["path"] as? String,
let urlString = dict["url"] as? String,
let url = URL(string: urlString),
let version = dict["version"] as? String,
let dependenciesDictArray = dict["dependencies"] as? [[String: Any]]
else { return nil }
let path = URL(fileURLWithPath: pathString)
let dependencies = dependenciesDictArray.flatMap(Project.from)
return Project(name: name, path: path, url: url, version: version, dependencies: dependencies)
}
}
extension String {
func trim() -> String {
return self.trimmingCharacters(in: NSCharacterSet.whitespacesAndNewlines)
}
}
@discardableResult
func sh(_ command: String, _ args: [String] = [], _ wd: URL? = nil) -> String {
let process = Process()
process.launchPath = command
process.arguments = args
if let wd = wd { process.currentDirectoryPath = wd.path }
let standardOut = Pipe()
process.standardOutput = standardOut
process.launch()
let result = String(data: standardOut.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) ?? ""
process.waitUntilExit()
return result
}
func scriptPath() -> URL {
let scriptRelPath = ProcessInfo.processInfo.arguments.drop { $0 != "-interpret" }.dropFirst().first!
return URL(string: scriptRelPath, relativeTo: URL(fileURLWithPath: ProcessInfo.processInfo.environment["PWD"]!))!.absoluteURL
}
func which(_ command: String) -> String {
return sh("/bin/sh", ["-c", "which \(command)"]).trim()
}
let swiftPath = which("swift")
let lnPath = which("ln")
let mkdirPath = which("mkdir")
func recursivelySymlinkDependencies(from: Project, into: URL, fileManager: FileManager = FileManager.default) {
from.dependencies.forEach { project in
let destination = into.appendingPathComponent(project.name)
if fileManager.fileExists(atPath: destination.path) { return }
print("Symlinking: \(project.name) into \(destination.path)")
sh(lnPath, ["-s", project.path.path, destination.path])
}
}
func buildDependencies(from: Project, fileManager: FileManager = FileManager.default) {
from.dependencies.forEach { project in
if !fileManager.fileExists(atPath: project.path.path) { return }
for config in ["debug", "release"] {
print("Building: \(project.name) (\(config))")
sh(swiftPath, ["build", "-c", config, "--build-path", "./build"], project.path)
}
}
}
func main() {
let rootPath = URL(string: "../", relativeTo: scriptPath())!.absoluteURL
let packageDirectory = rootPath.deletingLastPathComponent()
sh(swiftPath, ["package", "fetch"], packageDirectory)
let dependencyJsonString = sh(swiftPath, ["package", "show-dependencies", "--format", "json"], rootPath)
guard
let dependencyJsonData = dependencyJsonString.data(using: .utf8),
let dependencyJson = try? JSONSerialization.jsonObject(with: dependencyJsonData, options: []),
let jsonDict = dependencyJson as? [String: Any],
let project = Project.from(jsonDict)
else {
print("Unable to get dependency graph data.")
exit(-1)
}
let dependenciesPath = rootPath.appendingPathComponent("Packages")
if (!FileManager.default.fileExists(atPath: dependenciesPath.path)) {
print("Creating \(dependenciesPath)")
sh(mkdirPath, ["-p", dependenciesPath.path])
}
recursivelySymlinkDependencies(from: project, into: dependenciesPath)
buildDependencies(from: project)
}
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment