Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use SwiftCLI #29

Merged
merged 4 commits into from
Jun 1, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 16 additions & 25 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"repositoryURL": "https://github.com/norio-nomura/Clang_C.git",
"state": {
"branch": null,
"revision": "90a9574276f0fd17f02f58979423c3fd4d73b59e",
"version": "1.0.2"
"revision": "7b7d3eed8080d14ba39c50e29fa8c7b051bcf969",
"version": "1.0.3"
}
},
{
Expand All @@ -24,8 +24,8 @@
"repositoryURL": "https://github.com/Quick/Nimble.git",
"state": {
"branch": null,
"revision": "22800b0954c89344bb8c87f8ab93378076716fb7",
"version": "7.0.3"
"revision": "21f4fed2052cea480f5f1d2044d45aa25fdfb988",
"version": "7.1.1"
}
},
{
Expand All @@ -42,8 +42,8 @@
"repositoryURL": "https://github.com/Quick/Quick.git",
"state": {
"branch": null,
"revision": "0ff81f2c665b4381f526bd656f8708dd52a9ea2f",
"version": "1.2.0"
"revision": "3e3023569c8d4c4a0d000f58db765df53041117f",
"version": "1.3.0"
}
},
{
Expand All @@ -69,8 +69,8 @@
"repositoryURL": "https://github.com/jpsim/SourceKitten",
"state": {
"branch": null,
"revision": "e06eb730499439ae32c5fbb6f72809ebec2371fd",
"version": "0.19.1"
"revision": "7c09176766d4bbc5da377ad857953fb49510a6aa",
"version": "0.21.0"
}
},
{
Expand All @@ -83,39 +83,30 @@
}
},
{
"package": "SwiftPM",
"repositoryURL": "https://github.com/apple/swift-package-manager",
"package": "SwiftCLI",
"repositoryURL": "https://github.com/jakeheis/SwiftCLI",
"state": {
"branch": null,
"revision": "63a01220e93271dc3bf204b9e13dd1aeb2beefee",
"version": "0.2.0"
}
},
{
"package": "SwiftShell",
"repositoryURL": "https://github.com/kareman/SwiftShell.git",
"state": {
"branch": null,
"revision": "b9fd06798993153bc57cde10ee6c75ddc55c2dbd",
"version": "4.0.2"
"revision": "995f5966072bded933400bbe77ad24914f01d0c0",
"version": "5.1.1"
}
},
{
"package": "SWXMLHash",
"repositoryURL": "https://github.com/drmohundro/SWXMLHash.git",
"state": {
"branch": null,
"revision": "17d992beb3aaeda403fd35f8d5e70ab1a8124f35",
"version": "4.6.0"
"revision": "2211b35c2e0e8b08493f86ba52b26e530cabb751",
"version": "4.7.0"
}
},
{
"package": "Yams",
"repositoryURL": "https://github.com/jpsim/Yams.git",
"state": {
"branch": null,
"revision": "95f45caf07472ec78223ebada45255086a85b01a",
"version": "0.5.0"
"revision": "6652aa7b793d3c8a075db0614acb575fcaecf457",
"version": "0.7.0"
}
}
]
Expand Down
6 changes: 2 additions & 4 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ let package = Package(
.package(url: "https://github.com/jpsim/SourceKitten", from: "0.19.1"),
.package(url: "https://github.com/kylef/PathKit.git", from: "0.8.0"),
.package(url: "https://github.com/kylef/Spectre.git", from: "0.8.0"),
.package(url: "https://github.com/apple/swift-package-manager", from: "0.2.0"),
.package(url: "https://github.com/kareman/SwiftShell.git", from: "4.0.0"),
.package(url: "https://github.com/jakeheis/SwiftCLI", from: "5.1.0"),
],
targets: [
.target(
Expand All @@ -26,8 +25,7 @@ let package = Package(
dependencies: [
"SourceKittenFramework",
"PathKit",
"Utility",
"SwiftShell",
"SwiftCLI",
]),
.testTarget(name: "BeakTests", dependencies: [
"BeakCore",
Expand Down
18 changes: 4 additions & 14 deletions Sources/Beak/main.swift
Original file line number Diff line number Diff line change
@@ -1,17 +1,7 @@
import BeakCore
import Foundation
import PathKit
import Utility

do {
let options = BeakOptions()
let beak = Beak(options: options)
try beak.execute(arguments: Array(ProcessInfo.processInfo.arguments.dropFirst()))
} catch {
if error._domain == NSCocoaErrorDomain {
print("⚠️ \(error.localizedDescription)")
} else {
print("⚠️ \(error)")
}
exit(1)
}
let options = BeakOptions()
let beak = Beak(options: options)
let result = beak.execute()
exit(result)
40 changes: 12 additions & 28 deletions Sources/BeakCore/Beak.swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import Basic
import Foundation
import PathKit
import SourceKittenFramework
import SwiftShell
import Utility
import SwiftCLI

public struct BeakOptions {

Expand All @@ -25,31 +21,19 @@ public class Beak {
self.options = options
}

public func execute(arguments: [String]) throws {

let parser = ArgumentParser(commandName: "beak", usage: "[--path] [subcommand]", overview: "Beak can inspect and run functions in your swift scripts")
let versionArgument = parser.add(option: "--version", shortName: "-v", kind: Bool.self, usage: "Prints the current version of Beak")
_ = parser.add(option: "--path", shortName: "-p", kind: String.self, usage: "The path to a swift file. Defaults to beak.swift", completion: .filename)

let commands = [
"list": ListCommand(options: options, parentParser: parser),
"function": FunctionCommand(options: options, parentParser: parser),
"run": RunCommand(options: options, parentParser: parser),
"edit": EditCommand(options: options, parentParser: parser),
public func execute(arguments: [String]? = nil) -> Int32 {
let cli = CLI(name: "beak", version: version, description: "Beak can inspect and run functions in your swift scripts")
cli.globalOptions.append(GlobalOptions.path)
cli.commands = [
ListCommand(),
FunctionCommand(),
RunCommand(options: options),
EditCommand(options: options)
]

let parsedArguments = try parser.parse(arguments)

if let printVersion = parsedArguments.get(versionArgument), printVersion == true {
print(version)
return
}

if let subParser = parsedArguments.subparser(parser),
let command = commands[subParser] {
try command.execute(parsedArguments: parsedArguments)
if let arguments = arguments {
return cli.go(with: arguments)
} else {
parser.printUsage(on: stdoutStream)
return cli.go()
}
}
}
17 changes: 14 additions & 3 deletions Sources/BeakCore/BeakError.swift
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
import Foundation
import SourceKittenFramework
import SwiftCLI

public enum BeakError: Error, CustomStringConvertible {
public enum BeakError: ProcessError, CustomStringConvertible {
case fileNotFound(String)
case compileError(String)
case invalidFunction(String)
case missingRequiredParam(Function.Param)
case parsingError(SwiftStructure)

case conversionError(Function.Param, String)

public var description: String {
switch self {
case let .fileNotFound(file): return "File not found: \(file)"
case let .compileError(error): return "File could not be compiled: \(error)"
case let .invalidFunction(function): return "Function \(function) was not found"
case let .missingRequiredParam(param): return "Missing required param \(param.name)"
case let .parsingError(structure): return "Could not parse Beak file structure:\n\(toJSON(structure))"
case let .conversionError(param, value): return "'\(value)' is not convertible to \(param.type.string) for argument \(param.name)"
}
}

public var message: String? {
return "⚠️ \(description)"
}

public var exitStatus: Int32 {
return 1
}

}
34 changes: 17 additions & 17 deletions Sources/BeakCore/Commands/BeakCommand.swift
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import Foundation
import PathKit
import Utility
import SwiftCLI

class BeakCommand {
struct GlobalOptions {
static let path = Key<String>("-p", "--path", description: "The path to a swift file. Defaults to beak.swift")
private init() {}
}

let parser: ArgumentParser
let options: BeakOptions
let pathArgument: OptionArgument<String>
protocol BeakCommand: Command {
func execute(path: Path, beakFile: BeakFile) throws
}

init(options: BeakOptions, parentParser: ArgumentParser, name: String, description: String) {
self.options = options
parser = parentParser.add(subparser: name, overview: description)
pathArgument = parser.add(option: "--path", shortName: "-p", kind: String.self, usage: "The path to a swift file. Defaults to beak.swift", completion: .filename)
extension BeakCommand {

var path: Key<String> {
return GlobalOptions.path
}

func execute(parsedArguments: ArgumentParser.Result) throws {
let path = Path(parsedArguments.get(pathArgument) ?? "beak.swift").normalize()
func execute() throws {
let path = Path(self.path.value ?? "beak.swift").normalize()
let beakFile = try BeakFile(path: path)
try execute(path: path, beakFile: beakFile, parsedArguments: parsedArguments)
}

func execute(path: Path, beakFile: BeakFile, parsedArguments: ArgumentParser.Result) throws {
try execute(path: path, beakFile: beakFile)
}

}
48 changes: 23 additions & 25 deletions Sources/BeakCore/Commands/EditCommand.swift
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
import Foundation
import Utility
import PathKit
import SwiftShell
import SwiftCLI

class EditCommand: BeakCommand {

let name = "edit"
let shortDescription = "Edit the Swift file in an Xcode Project with imported dependencies"

let options: BeakOptions

init(options: BeakOptions, parentParser: ArgumentParser) {
super.init(
options: options,
parentParser: parentParser,
name: "edit",
description: "Edit the Swift file in an Xcode Project with imported dependencies"
)
init(options: BeakOptions) {
self.options = options
}

override func execute(path: Path, beakFile: BeakFile, parsedArguments: ArgumentParser.Result) throws {


func execute(path: Path, beakFile: BeakFile) throws {
let directory = path.absolute().parent()

// create package
Expand All @@ -24,27 +21,28 @@ class EditCommand: BeakCommand {
try packageManager.write(filePath: path)

// generate project
var packageContext = CustomContext(main)
packageContext.currentdirectory = packagePath.string
let buildOutput = packageContext.run(bash: "swift package generate-xcodeproj")
if let error = buildOutput.error {
print(buildOutput.stdout)
print(buildOutput.stderror)
do {
_ = try capture("swift", arguments: ["package", "generate-xcodeproj"], directory: packagePath.string)
} catch let error as CaptureError {
stderr <<< error.captured.rawStdout
stderr <<< error.captured.rawStderr
throw error
}
print("Generating project...")
stdout <<< "Generating project..."

// run package
try packageContext.runAndPrint(bash: "open \(options.packageName).xcodeproj")
print("Edit the file \"Sources/\(options.packageName)/main.swift\"")
print("When you're finished type \"c\" to commit the changes and copy the file back to \(path.string), otherwise type anything else")
try run("open", arguments: ["\(options.packageName).xcodeproj"], directory: packagePath.string)

stdout <<< "Edit the file \"Sources/\(options.packageName)/main.swift\""
stdout <<< "When you're finished type \"c\" to commit the changes and copy the file back to \(path.string), otherwise type anything else"

let line = readLine()
if line?.lowercased() == "c" {
try path.delete()
try packageManager.mainFilePath.copy(path)
print("Copied edited file back to \(path.string)")
stdout <<< "Copied edited file back to \(path.string)"
} else {
print("Changes not copied back to \(path.string)")
stdout <<< "Changes not copied back to \(path.string)"
}
}
}
33 changes: 12 additions & 21 deletions Sources/BeakCore/Commands/FunctionCommand.swift
Original file line number Diff line number Diff line change
@@ -1,29 +1,20 @@
import Foundation
import PathKit
import Utility
import SwiftCLI

class FunctionCommand: BeakCommand {

let name = "function"
let shortDescription = "Info about a specific function"

let functionName = Parameter()

var functionArgument: PositionalArgument<String>!

init(options: BeakOptions, parentParser: ArgumentParser) {
super.init(
options: options,
parentParser: parentParser,
name: "function",
description: "Info about a specific function"
)
functionArgument = parser.add(positional: "function", kind: String.self, optional: false, usage: "The function to get info about", completion: ShellCompletion.none)
}

override func execute(path: Path, beakFile: BeakFile, parsedArguments: ArgumentParser.Result) throws {
let functionName = parsedArguments.get(functionArgument)!
guard let function = beakFile.functions.first(where: { $0.name == functionName }) else {
throw BeakError.invalidFunction(functionName)
func execute(path: Path, beakFile: BeakFile) throws {
guard let function = beakFile.functions.first(where: { $0.name == functionName.value }) else {
throw BeakError.invalidFunction(functionName.value)
}
let params = function.params.map { param in
"\(param.name): \(param.optionalType)\(param.defaultValue != nil ? " = \(param.defaultValue!)" : "")\(param.description != nil ? " - \(param.description!)" : "")"
stdout <<< "\(function.name):\(function.docsDescription != nil ? " \(function.docsDescription!)" : "")"
function.params.forEach { param in
stdout <<< " \(param.name): \(param.optionalType)\(param.defaultValue != nil ? " = \(param.defaultValue!)" : "")\(param.description != nil ? " - \(param.description!)" : "")"
}
print("\(function.name):\(function.docsDescription != nil ? " \(function.docsDescription!)" : "")\n \(params.joined(separator: "\n "))")
}
}
Loading