yonaskolb / Beak

A command line interface for your Swift scripts

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Document how to run other tools on command line

Jeehut opened this issue · comments

While Beak is very useful and supports SPM packages, sometimes it would make life much easier if one could run another command line tool to do a specific task instead of writing Swift code for that task. While it is not directly the duty of Beak to teach people how to run command line tools from within Swift, it perfectly makes sense from my point of view to help users by providing one "recommended" way of running them which we will make sure it always works (as long as Swift supports that method).

Especially it can teach Beak users that there's at least the possibility to use other tools from within the Beak script which shows how much more useful Beak can become than they might have initially thought.

One way could be to include something like the following code in a beak.swift file:

typealias CommandResult = (outputLines: [String], errorLines: [String], exitCode: Int32)

@discardableResult
func run(_ command: String) -> CommandResult {
    let commandComponents = command.components(separatedBy: .whitespacesAndNewlines)

    let commandLineTask = Process()
    commandLineTask.launchPath = "/usr/bin/env"
    commandLineTask.arguments = commandComponents

    let outputPipe = Pipe()
    commandLineTask.standardOutput = outputPipe
    let errorPipe = Pipe()
    commandLineTask.standardError = errorPipe

    commandLineTask.launch()

    var errorLines: [String] = []
    let errorData = errorPipe.fileHandleForReading.readDataToEndOfFile()

    if var errorDataString = String(data: errorData, encoding: .utf8) {
        errorDataString = errorDataString.trimmingCharacters(in: .newlines)
        errorLines = errorDataString.components(separatedBy: .newlines)
    }

    var outputLines: [String] = []
    let outputData = outputPipe.fileHandleForReading.readDataToEndOfFile()

    if var outputDataString = String(data: outputData, encoding: .utf8) {
        outputDataString = outputDataString.trimmingCharacters(in: .newlines)
        outputLines = outputDataString.components(separatedBy: .newlines)
    }

    commandLineTask.waitUntilExit()
    let exitCode = commandLineTask.terminationStatus

    return (outputLines, errorLines, exitCode)
}

This enables the following lines:

run("ruby -v") // => (outputLines: ["ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin17]"], errorLines: [""], exitCode: 0)
run("ruby -v").outputLines // => ["ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin17]"]
run("ruby -v").errorLines // => [""]
run("ruby -v").exitCode // => 0

Alternatively one could point to tools like SwiftShell and ShellOut) which both support SPM and therefore Beak.