Skip to content

Instantly share code, notes, and snippets.

@gabrieloc
Last active December 29, 2023 00:26
Show Gist options
  • Save gabrieloc/a27e27434ea01f6c58e24faaad344836 to your computer and use it in GitHub Desktop.
Save gabrieloc/a27e27434ea01f6c58e24faaad344836 to your computer and use it in GitHub Desktop.
Utilities for writing command line code in Swift
#!/usr/bin/env swift
import Foundation
struct TerminationStatus: Error {
let code: Int32
}
func run(_ command: Command) throws {
print(command.rendered.joined(separator: " "))
let task = Process()
task.launchPath = "/usr/bin/env"
task.arguments = command.rendered
task.launch()
task.waitUntilExit()
if task.terminationStatus != 0 {
throw TerminationStatus(code: task.terminationStatus)
}
}
@dynamicMemberLookup
@dynamicCallable
struct Command {
typealias Component = (String, [String: String?])
let components: [Component]
init(components: [Component] = []) {
self.components = components
}
var rendered: [String] {
components.flatMap { c in
[c.0] + c.1.flatMap { ["-\($0.0)", $0.1] }.compactMap { $0 }
}
}
subscript(dynamicMember member: String) -> Self {
addingComponent(member)
}
func dynamicallyCall(withKeywordArguments args: KeyValuePairs<String, String?>) throws {
try run(self.addingArguments(args))
}
func addingComponent(_ component: String) -> Command {
Command(
components: components + [(component, [:])]
)
}
func addingArguments(_ arguments: [String, String?]) -> Command {
guard components.count > 0 else {
return Command(components: [("", arguments)])
}
var c = self
c.components.last?.1 += arguments
return c
}
}
// Examples
let cmd = Command()
try cmd.xcodebuild.archive(
project: "projectPath/ProjectName.xcodeproj",
scheme: "production"
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment