kylef / commander Goto Github PK
View Code? Open in Web Editor NEWCompose beautiful command line interfaces in Swift
License: BSD 3-Clause "New" or "Revised" License
Compose beautiful command line interfaces in Swift
License: BSD 3-Clause "New" or "Revised" License
Say I have an option call count
- xxx count 10
and I want to add a short flag option so I can call it xxx -c 10
Is there any way to do this?
I received the following complier warnings while building the Commander package.
warning: use of 'typealias' to declare associated types is deprecated; use 'associatedtype' instead.
Sources/ArgumentDescription.swift:7:3
I'm struggling with using Curassow, because it's using Commander for input arguments. I'd like to add my own arguments and parse my app's specific ones only, and leave Curassow to parse its own as well. Unfortunately currently Commander errors out if any command is unused, making this usecase impossible.
Assuming I'm not missing anything, I'd like there to be an option to not error out when unrecognized arguments are passed, instead they'd be ignored, making multi-layer argument parsing possible.
And no CHANGELOG either 😜
Currently, the help text shows only the long flags, suche as e.g. --verbose
, but not the short flag -f
which can be configured via
let main = command(
Flag("verbose", flag: "v")
) {
// ...
}
I noticed that the xcodeproj along with the shared schemes are deleted in a recent commit(9926257), but the current Readme still says Carthage is supported. Is it an accident or do we have to give up Carthage if we would like to get the latest version from now on?
I'm currently developing a command line tool and I personally prefer the submodule way of managing dependencies, which is provided by Carthage.
Conche is good, but it is not the right choice for me since I'm using a Xcode project and packed all resources into an app bundle. Using Cocoapods & Carthage together is definitely a mess, so I really hope you could bring back the xcodeproj along with the shared schemes. Otherwise it should be painful in case Swift's next update breaks Commander and I have to constantly sync all the new commits from this repo to my fork.
Thank you.
I haven't had time to investigate this too much yet, but updating from 0.8.0 to 0.9.0 broke RasterizeXCAssets, even though my understanding was that the only breaking change should be requiring a more recent version of Swift?
When positional arguments is missing, it correctly prints that it's missing those arguments. But when they are given it prints an "Unknown Arguments" error:
$ swift run rasterizexcassets
[0/0] Build complete!
An error occurred: Missing value for `source`
$ swift run rasterizexcassets a
[0/0] Build complete!
An error occurred: Missing value for `output`
$ swift run rasterizexcassets a b
[0/0] Build complete!
Unknown Arguments: a b
Here is the code used to set up the command:
func main(source: String, output: String, size: Size) throws {
// ...
}
command(
Argument<String>("source", description: "Source SVG file"),
Argument<String>("output", description: "Output path for resulting asset"),
Option<Size>("size", default: Size(width: 64, height: 64), description: "Size (in points) of the output asset (e.g. 120x120)"),
main
).run()
Is it possible to specify an option without default value?
I might be missing something, but it seems that the default value is mandatory. While I can set it to some magic value, the problem is that it is printed using the "[default: XXX]" in help.
Hi there!
I'm writing a cli to interact through serial with a robot.
The cli should not return unless the quit
command is called and thus would be waiting for user input.
Would it be possible to do that with Commander? Waiting for user input with readline()
and pass the string to Commander?
Thank you for your help!
Like rm
command, has no subcommand.
ex: rm filepath
How can I create such command with CLIKit?
I think command
should be made a type, so we'd write Command
instead.
This is more consistent with Option
and Command
.
I also think with how it is now, it's not very clear that this block of code:
command {
}
does not actually execute anything.
In version 0.7.0
, Package.swift
needs the products to be defined.
Without, it is not possible to link, and therefore to import, Commander into any project.
The Flag constructor takes default
as the last argument where as Option takes it as the second argument.
When using both in a single command it's a bit weird to have:
Flag("web", description: "Whether or not to search the web", default: false),
Option("remote", "cocoapods.org", description: "Custom remote host"),
Hey 👋
I'm currently using the following overload for command
in order to be able to return a Promise
from PromiseKit directly from my command. This, I think, makes it very easy to write asynchronous CLI apps (e.g. performing multiple tasks in parallel).
This example is only for the very specific "two argument descriptor and an executor" overload, but could easily be written for every already existing overload.
import Foundation
import Commander
import PromiseKit
public func command<A:ArgumentDescriptor, A1:ArgumentDescriptor>(_ descriptor: A, _ descriptor1:A1, _ closure:@escaping (A.ValueType, A1.ValueType) throws -> Promise<Void>) -> CommandType {
return command(descriptor, descriptor1) { (value0: A.ValueType, value1: A1.ValueType) throws -> () in
firstly {
try closure(value0, value1)
}.done { _ in
exit(0)
}.catch { err in
command({ throw err }).run()
}
CFRunLoopRun()
}
}
How would you feel about a pull request that would add these overloads? (probably as a new target, so that it's opt-in for consumers)
I would also like to improve the error handling (command({ throw err }).run()
), how would you feel about extracting out the following lines to a separate function?
Commander/Sources/Commander/CommandRunner.swift
Lines 25 to 46 in 314f8d7
Thanks for a great library 🍻
With the following swift file called main
:
#! /usr/bin/env cato 2.1
import Commander
Group {
$0.command("init") { (name: String) in
print("Initializing \(name)")
}
}.run()
As expected, running:
$ chmod +x main
$ ./main
results in
Usage:
$ ./main
Commands:
+ init
Which is great! However, when I run the following command, I get the same result:
$ ./main init test
Usage:
$ ./main
Commands:
+ init
instead of the expected:
$ ./main init test
Creating test
Is this an error on my part or is it broken?
By the way, I'm on OS X El Capitan running Xcode 7.1 Beta 2, if it matters.
There are some deprecation warnings received when compiling the Commander package with the latest version of Swift 2.2-dev Feb 3, 2016.
warning: '++' is deprecated: it will be removed in Swift 3
Sources/ArgumentParser.swift:121:9
Sources/ArgumentParser.swift:163:7
Sources/ArgumentParser.swift:189:7
Sources/ArgumentParser.swift:214:9
When running the application in Xcode the Framework incorrectly detects that the Xcode debug console supports colors:
Sample output
Unknown Arguments: -DnuvMSbNcReotdimsg
Arguments:
�[34mmode�[0m - The mode in which the app will run
I've been working on extending a dockerfile for server side swift dev https://gist.github.com/johndpope/01a74ffb93921df48e334097117be1b3
maybe of some use with in conjunction with this project.
I reached out because I saw you were logging out to console
and this container will spit out colors using zsh.
I encountered the crash fixed in #18. Instead of reporting an unknown command, Commander crashes.
I just started using Commander and it is awesome. I just had one question. Are options with optional values available? What I would like is to have an option that if the user did not specify that option with a value on the command line, I would like to receive nil for that option's value.
I see that the default
parameter for the Option
class is not optional. In my use case, there is no possible default value. If the user specifies a value, I add it to the service call's query parameter, if not, it is omitted. When I try something like this:
Option<String?>("campaign", default: nil, description: "The campaign identifier used to narrow the search."),
I get the following error:
Type 'String?' does not conform to protocol 'ArgumentConvertible'
Is there currently anyway to do this using Commander?
If you configure an option to accept a number, it seems it's impossible to pass a negative number for the value of the option since it's interpreted as a flag instead.
I'm not 100% sure what the right way to resolve this would be without making a mess of things, but I figure it's something that should at least have a workaround.
Group {
$0.command("submit", Option<Double>("nice", default: 0, flag: "n")) { niceValue in
print(niceValue)
}
}.run()
Attempts to use that flag:
$ swiftmatrix submit --nice 123
123.0
$ swiftmatrix submit --nice -123
An error occurred: Unexpected flag `-123` as a value for `--nice`
$ swiftmatrix submit --nice -0.123
An error occurred: Unexpected flag `-0.123` as a value for `--nice`
$ swiftmatrix submit --nice=-123
Unknown Arguments: --nice=-123
Options:
--nice [default: 0.0]
$ swiftmatrix submit --nice=123
Unknown Arguments: --nice=123
Options:
--nice [default: 0.0]
Given an example app like:
if CommandLine.arguments.count == 1 {
CommandLine.arguments += [
"create",
"--help"
]
}
let app = Group { app in
app.command("create",
Argument<String>("First Name", description: "The user's first name"),
Argument<String>("Last Name", description: "The user's last name"), { fn, ln in
print("fn: \(fn), ln: \(ln)")
})
}
app.run()
The help printed is just:
Usage:
$ ./App <First Name> <Last Name>
I think it's weird that the Argument
constructor takes a description yet it never gets displayed.
I think maybe it should instead:
Usage:
$ ./App create <First Name> <Last Name>
Arguments:
<First Name> - The user's first name.
<Last Name> - The user's last name.
Would you be willing to accept a PR on this?
Commander shows bad help text for Option
where type is Optional
and default value is nil
.
Option<String?>("name", default: nil, description: "The name")
shows
Options:
--name [default: ] - The name
instead of
Options:
--name - The name
Given an option defined like this:
let outputOption = Option("output", OutputDestination.Console, flag: "o", description: "The path to the file to generate (Omit to generate to stdout)")
Using -o
doesn't work, while using --output
does.
(The -o
doesn't show up in the help either btw, not sure that's expected)
$ swiftgen images -o out.swift share/swiftgen/fixtures/Images.xcassets
Unknown Arguments: -o
Options:
--output - The path to the file to generate (Omit to generate to stdout)
--template - The name of the template to use for code generation (without the "images" prefix nor extension).
--templatePath - The path of the template to use for code generation. Overrides -t.
--enumName - The name of the enum to generate
$ swiftgen images --output out.swift share/swiftgen/fixtures/Images.xcassets
File written: out.swift
Was working in Commander 0.2.2, stopped working on 3.0.0
I want to do something like:
command --set x --set y --set z ARG1 ARG2
which would parse out as an array of strings for set
. I don't think this is currently possible because the Options
object takes a specific count and expects all the arguments to immediately follow the --set
option. Is that right? Is this a good thing to add if so?
Hey @kylef, thanks for the awesome project. I went searching for it on GitHub and ended up resurrecting one of the old projects in order to find what was that CLI framework I used…
This repo clearly must be on the first page, but it's not:
Adding topics/tags would really help more people find this project! ❤️
Hello thanks for this package! Is there a way to make commander be a static library? It would benice to just be able to copy the cli executable arround without worring about the libraries being in the same folder.
Thanks
Defining a version
argument appears to conflict with some internal definition.
Given the argument:
Option<String?>(
"version",
default: nil,
description: "The version number of the build"),
Commander always fails to parse the value:
$ mytool mycmd --version 123
Unknown Arguments: 123
Hi, wtf?
i got error when try using in terminal
go to folder with project, adding repo to Package.swift
go to terminal --> swift build and got error
Desktop:cryptpwd username$ swift build warning: refname '0.8.0' is ambiguous. warning: refname '0.8.0' is ambiguous. HEAD is now at e5b50ad chore: Release 0.8.0 Resolved version: 0.8.0 /Users/username/Desktop/cryptpwd/Packages/Commander/Package.swift:13:3: error: argument 'targets' must precede argument 'dependencies' targets: [ ^ Can't parse Package.swift manifest file because it contains invalid format. Fix Package.swift file format and try again. error: The package at
/Users/username/Desktop/cryptpwd/Packages/Commander' has no Package.swift for the specific version: 0.8.0
`
This is marked as a TODO in the source, willing to submit a PR do we want it rendered just as:
--<name> - <description> (Default: <default>)
Flags should also probably be updated to --[no-]<name> - <description> (Default: false)
Your license still has a placeholder: {organization}. Mind filling that in? Thanks.
Hi, i'm trying to use your project in my console app, i'm noobie in swift but i have problem using
listing of commands in class
for example i got a class and inside i got Group with commands when i try to call a method where this group i got error `
import Commander
class MainController {
private var result = false
func auth() {
Group {
$0.command("login") { (name:String) in
print("Hello (name)")
self.result = true
}
$0.command("logout") {
print("Goodbye.")
}
}
}
func getInfo() {
self.auth()
if self.result {
print("login confirmed!")
} else {
print("login not confirmed!")
}
}
}
var doing = MainController()
doing.getInfo()`
Whenever I try to run a CLI (my own or the playground) I get this error:
dyld: Library not loaded: @rpath/libswiftAppKit.dylib
Referenced from: /Users/justinmakaila/Library/Developer/Xcode/DerivedData/HLSKit-cli-hajfgtnswuxgqkgwgdfrmsdooeoc/Build/Products/Debug/CLIKit.framework/Versions/A/CLIKit
Reason: image not found
I've added CLIKit as a target dependency, is there anything else I should be aware of?
Also, Integration instructions in the README would be excellent.
Hi Kyle,
Thanks for your contributions to OSS, Stencil is incredibly useful for something that I'm working on!
I'm attempting to use both Commander and Stencil in the same project, however when attempting to run swift package fetch
it's returning an error, as both libraries require Spectre.
It appears to be an issue with Swift PM not resolving the dependency correctly. What do you think?
I've attached a small project to demonstrate.
error: rename error: Directory not empty (66):
/Users/kramer_max/Desktop/CommanderStencil/Packages/Spectre.git -> /Users/kramer_max/Desktop/CommanderStencil/Packages/Spectre-0.7.2
Package.swift:
let package = Package(
name: "cerberus",
dependencies: [
.Package(url: "https://github.com/kylef/Stencil.git", majorVersion: 0, minor: 7),
.Package(url: "https://github.com/kylef/Commander.git", majorVersion: 0)
]
)
Cheers,
Max.
Tried to add Commander to a SPM project with the following Package.swift
:
// swift-tools-version:4.0
import PackageDescription
let package = Package(
name: "LocalizableCheck",
dependencies: [
.package(url: "https://github.com/kylef/Commander.git", from: "0.8.0"),
.package(url: "https://github.com/kylef/PathKit.git", from: "0.8.0"),
.package(url: "https://github.com/sharplet/Regex.git", from: "1.1.0"),
],
targets: [
.target(
name: "LocalizableCheck",
dependencies: [
"PathKit",
"Regex"
]
)
]
)
When I try swift package update
, I get the following error:
error: dependency graph is unresolvable; found these conflicting requirements:
Dependencies:
https://github.com/kylef/PathKit.git @ 0.8.0..<1.0.0
Note that it complains about PathKit, but it happens when I add Commander to the project. Without Commander there's no issue. I have no clue why this is, but I'm guessing this is because of the common dependency on Spectre
, with different version requirements from: "0.8.0"
and .upToNextMinor(from:"0.8.0")
.
I am using the following enum as an argument:
enum SyncSource: String, ArgumentConvertible {
case finder
case iptc
case both
public init(parser: ArgumentParser) throws {
if let value = parser.shift() {
if let value = SyncSource(rawValue: value) {
self.init(rawValue: value.rawValue)!
} else {
throw ArgumentError.invalidType(value: value, type:"SyncSource", argument: nil)
}
} else {
throw ArgumentError.missingValue(argument: nil)
}
}
public var description: String {
return self.rawValue
}
}
Even though I did implement description I do not get a default value printed for a SyncSource option declared like this:
Option("source", default: SyncSource.both, description: "Sync attributes source \([SyncSource.finder.rawValue, SyncSource.iptc.rawValue, SyncSource.both.rawValue])"),
Is it currently possible to run an async command, e.g. a download?
Sorry for a possibly confusing title...
If I set a group and subsequent command similar to,
let test = Group {
$0.command("get",
Option("user", default: "", description: "The user to get."),
description: "Get User Information")
But I call the program as so:
$ test get -user myuser
Notice how "-user" should have an extra "-", this causes the "Unknown Arguments" error to print out:
Unknown Arguments: -usre myuser
Options:
--user [default: ] - The user to get.
Notice "-usre" is garbled. Upon further runs, this word seems to rotate through it's order of letters. Very strange.
Apologies if I just missed a step in setup or so, but I'm using Commander as part of Sourcery and am running out of command line arguments. It seems there is a limit of about 16 arguments in Commander.
Am I missing some script I need to run to re-generate the templated classes to be able to specify more arguments (Sourcery has many options, and I need to add some new ones)?
I couldn't find anything about this limit or avoiding it in Github issues, the Readme, nor the Wiki on Github.
Maybe I'm missing something, but still cannot get arguments to print as part of the "help" menu.
Usage:
$ .build/x86_64-apple-macosx10.10/debug/Mothership-CLI testflight
Commands:
+ login
import Commander
import Mothership
let mothership = Mothership()
let testFlight = TestFlight()
let group = Group {
$0.command("help") {}
$0.command("login") { (username:String, password:String) in
print("logging \(username) into Mothership")
let credentials = LoginCredentials(accountName: username, password:password)
mothership.login(with: credentials)
}
$0.group("testflight") {
$0.command(
"login",
Argument<String>("username", description: "iTunes Connect Email"),
Argument<String>("password", description: "iTunes Connect Password")
) { (username:String, password:String) in
print("logging \(username) in to Testflight")
let credentials = LoginCredentials(accountName: username, password:password)
testFlight.login(with: credentials)
}
}
}
group.run()
Hi,
I'm trying to determine if the command is receiving a specific command.
I saw this example in README, Is this still valid?
command { (name:String, parser:ArgumentParser) in
if parser.hasOption("verbose") {
print("Verbose mode enabled")
}
print("Hello \(name)")
}
Probably I'm missing something here, but as far I can understand looking to Command.swift
the parser is never passed to the closure
as parameter.
Is there another way to do what I'm trying to achieve without accessing the parser?
I tried adding
github "Kylef/Commander"
but didn't help.
What is the proper way to use commander with Cartfile?
This should be generated from the registered commands in the manager.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.