Skip to content
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
11 changes: 10 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ build-linux-docker:
docker-compose run -w /work swift
@echo "\nLinux version built at bin/linux/guaka\n"

build-all-local: clean build-linux-docker build-project-darwin
build-all-local: clone-swiftline clean build-linux-docker build-project-darwin
@echo "Binaries built at bin/\n"

release-local:
Expand All @@ -93,6 +93,15 @@ release-publish-local:
make release-local
make publish-local

clone-swiftline:
@echo "Removing old Swiftline"
@echo ""
rm -rf SwiftLineTemp

@echo "Clone new Swiftline from oarrabi/linux! branch"
git clone -b oarrabi/linux! https://github.com/oarrabi/Swiftline.git SwiftLineTemp
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we commiting to maintaing this branch green. I think we shoudl use another name. Like 'vendored'.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The branch in Swiftline is about making it work on linux nsomar/Swiftline#30

I think we should keep the name until we merge it

mv SwiftLineTemp/Sources/*.* Sources/Swiftline/
rm -rf SwiftLineTemp

release-and-deploy:
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then make build-project-darwin release-darwin VERSION=${TRAVIS_TAG} GITHUB_TOKEN=${GITHUB_TOKEN} ; fi
Expand Down
3 changes: 2 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ let package = Package(
name: "guaka-cli",
targets: [
Target(name: "guaka-cli", dependencies: ["GuakaClILib"]),
Target(name: "GuakaClILib"),
Target(name: "Swiftline"),
Target(name: "GuakaClILib", dependencies: ["Swiftline"]),
],
dependencies: [
.Package(url: "https://github.com/oarrabi/Guaka.git", majorVersion: 0),
Expand Down
8 changes: 6 additions & 2 deletions Sources/GuakaClILib/GeneratorParts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ public enum GeneratorParts {
generatedComment,
"func setupCommands() {",
comamndAddingPlaceholder,
"}"
"}",
""
].joined(separator: "\n")
}

Expand All @@ -41,6 +42,7 @@ public enum GeneratorParts {
"setupCommands()",
"",
"rootCommand.execute()",
""
].joined(separator: "\n")
}

Expand All @@ -66,6 +68,7 @@ public enum GeneratorParts {
" // Execute code here",
" print(\"\(commandName) called\")",
"}",
""
].joined(separator: "\n")
}

Expand All @@ -77,7 +80,8 @@ public enum GeneratorParts {
" dependencies: [",
" .Package(url: \"\(guakaURL)\", majorVersion: \(guakaVersion)),",
" ]",
")"
")",
""
].joined(separator: "\n")
}

Expand Down
42 changes: 32 additions & 10 deletions Sources/GuakaClILib/MiscTypes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
// Created by Omar Abdelhafith on 27/11/2016.
//
//
import Swiftline


public struct GuakaCliConfig {
public static var dir: DirectoryType.Type = FileSystemDirectory.self
Expand All @@ -20,35 +22,53 @@ public enum GuakaError: Error {
case cannotReadFile(String)
case setupFileAltered
case notAGuakaProject
case commandAlreadyExist(String, String)
case missingCommandName
case tooManyArgsPassed
case wrongCommandNameFormat(String)

public var error: String {
switch self {
case .wrongDirectoryGiven(let path):
return "The path given cannot be used \(path)"
return [
"Wrong path given:",
" \(path)",
"The path must be an empty directory"
].joined(separator: "\n").f.red

case .triedToCreateProjectInNonEmptyDirectory(let path):
return "Cannot create project in non empty directory \(path)\n"
return "Cannot create project in non empty directory: \(path)\n".f.red

case .failedCreatingFolder(let path):
return "Failed creating directory \(path)"
return "Failed creating directory \(path)".f.red

case .cannotCreateFile (let name):
return "Cannot generate \(name) file"
return "Cannot generate \(name) file".f.red

case .cannotReadFile(let path):
return "Cannot read contents of file \(path)"
return "Cannot read contents of file \(path)".f.red

case .setupFileAltered:
return "Guaka setup.swift file has been altered.\nThe placeholder used to insert commands cannot be found \(GeneratorParts.comamndAddingPlaceholder).\nYou can try to add it yourself by updating `setup.swift` to look like\n\n\(GeneratorParts.setupFileContent())\n\nAdding command wont be possible."
return "Guaka setup.swift file has been altered.\nThe placeholder used to insert commands cannot be found \(GeneratorParts.comamndAddingPlaceholder).\nYou can try to add it yourself by updating `setup.swift` to look like\n\n\(GeneratorParts.setupFileContent())\n\nAdding command won't be possible.".f.red

case .notAGuakaProject:
return "This command can only be executed in a Guaka project.\nThe following directory does not contain guaka files"
return "This command can only be executed inside a Guaka project.".f.red

case .missingCommandName:
return [
"`guaka add` requires a command that was not given.",
"Missing CommandName for `guaka add`.".f.red,
"",
"Call `guaka add CommandName` to create a new command.",
""
].joined(separator: "\n")

case .commandAlreadyExist(let name, let path):
return [ "The command `\(name)` already exist:".f.red,
" \(path)".f.red,
"Please use a differnt command name"].joined(separator: "\n")

case .wrongCommandNameFormat(let name):
return [ "The command name passed `\(name)` is incorrect.",
return [ "The command name passed `\(name)` is incorrect.".f.red,
"Please use only letters, numbers, underscodes and dashes.",
"",
"Valid examples:",
Expand All @@ -57,8 +77,10 @@ public enum GuakaError: Error {
" guaka new my-command",
" guaka new my_command",
" guaka new myCommand"].joined(separator: "\n")

case .tooManyArgsPassed:
return "Too many arguments passed to command."
return "Too many arguments passed to command.".f.red
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we just ignore the extra args? Also we could say something like "Too many arguments. Trailing arguments will be ignored"

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we scope this out of this PR? I created #6 for that


}

}
Expand Down
4 changes: 4 additions & 0 deletions Sources/GuakaClILib/Paths.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,9 @@ public struct Paths {

return false
}

public func isNewCommand(commandName: String) -> Bool {
return GuakaCliConfig.file.exists(atPath: path(forSwiftFile: commandName)) == false
}

}
23 changes: 23 additions & 0 deletions Sources/Swiftline/Agree.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// Agree.swift
// Agree
//
// Created by Omar Abdelhafith on 03/11/2015.
// Copyright © 2015 Omar Abdelhafith. All rights reserved.
//

/**
Displays a yes/no prompt to the user

- parameter prompt: The prompt to display
- returns: the user decision
*/
public func agree(_ prompt: String) -> Bool {
PromptSettings.print(prompt, terminator: " ")
let value = readStringOrEmpty()

let settings = AgreeSettings(prompt: prompt)
let validatedValue = askForValidatedItem(originalValue: value, validator: settings)

return settings.isPositive(validatedValue)
}
41 changes: 41 additions & 0 deletions Sources/Swiftline/AgreeSettings.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// AgreeSettings.swift
// AgreeSettings
//
// Created by Omar Abdelhafith on 03/11/2015.
// Copyright © 2015 Omar Abdelhafith. All rights reserved.
//


class AgreeSettings: AskerValidator {

let positiveValues = ["Yes", "yes", "Y", "y"]
let negativeValues = ["No", "no", "N", "n"]

let prompt: String

init(prompt: String) {
self.prompt = prompt
}

func validatedItem(forString string: String) -> String {
return string
}

func invalidItemMessage(_ string: String?) -> String? {
if let message = string , positiveValues.contains(message) || negativeValues.contains(message) {
return nil
}

return "Please enter \"yes\" or \"no\"."
}

func newItemPromptMessage() -> String {
return "\(prompt) "
}

func isPositive(_ item: String) -> Bool {
return positiveValues.contains(item)
}

}
63 changes: 63 additions & 0 deletions Sources/Swiftline/ArgConvertible.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//
// ArgConvertible.swift
// ArgConvertible
//
// Created by Omar Abdelhafith on 02/11/2015.
// Copyright © 2015 Omar Abdelhafith. All rights reserved.
//


/**
* Any type that extends ArgConvertibleType can be used in ask and choose
*/
public protocol ArgConvertibleType {

/// Create an instance out of a string
static func fromString(_ string: String) -> Self?

/// Return the display name of a type
static func typeName() -> String
}


extension Int: ArgConvertibleType {
public static func fromString(_ string: String) -> Int? {
return Int(string)
}

public static func typeName() -> String {
return "Integer"
}
}


extension Double: ArgConvertibleType {
public static func fromString(_ string: String) -> Double? {
return Double(string)
}

public static func typeName() -> String {
return "Double"
}
}

extension Float: ArgConvertibleType {
public static func fromString(_ string: String) -> Float? {
return Float(string)
}

public static func typeName() -> String {
return "Float"
}
}


extension String: ArgConvertibleType {
public static func fromString(_ string: String) -> String? {
return string
}

public static func typeName() -> String {
return "String"
}
}
66 changes: 66 additions & 0 deletions Sources/Swiftline/Args.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//
// Args.swift
// Swiftline
//
// Created by Omar Abdelhafith on 25/11/2015.
// Copyright © 2015 Omar Abdelhafith. All rights reserved.
//


/// Return the command line arguments passed to the script
public class Args {

/// Return the list of arguments passed to the script
public static var all: [String] {
return CommandLine.arguments
}

static var cachedResults: ParsedArgs?

/// Return a parsed list of arguments containing the flags and the parameters passed to the scripts
/// The flags are recognized as short flags `-f` or long flags `--force`
/// The flag value will be the argument that follows the flag
/// `--` is used to mark the terminatin of the flags
public static var parsed: ParsedArgs {
let result = parse(argumens: all, cachedResults: cachedResults)
cachedResults = result
return result
}

static func parse(argumens: [String], cachedResults: ParsedArgs?) -> ParsedArgs {
if let result = cachedResults {
return result
}

var parsedFlags = [String: String]()
let parsedArgs = ArgsParser.parseFlags(argumens)

parsedArgs.0.forEach {
parsedFlags[$0.argument.name] = $0.value ?? ""
}

var arguments = parsedArgs.1

// the first argument is always the executable's name
var commandName = ""
if let firstArgument = arguments.first { // just in case!
commandName = firstArgument
arguments.removeFirst(1)
}

return ParsedArgs(command: commandName, flags: parsedFlags, parameters: arguments)
}

}


public struct ParsedArgs {
/// The name of the executable that was invoked from the command line
public let command: String

/// Parsed flags will be prepred in a dictionary, the key is the flag and the value is the flag value
public let flags: [String: String]

/// List of parameters passed to the script
public let parameters: [String]
}
Loading