A command line arguments parser of Objective-C
SwiftyLine (CommandLine for Swift) is coming soon.
- Support subcommands
- Support forwarding subcommand
- Support Queries
- key-value (require)
- key-value (optional)
- key-value (optional & default-if-nil)
- key-values (as array, for multi-queries)
- Support Flags
- Support Abbr and multi-abbrs parsing
- Auto create colorful help infomation (just like cocoapods.)
- Auto print helping infomation if arguments is invalid
- Version command
- Output with verbose/success/warning/error/info
- Custom colorful text
- Loading Indicator
- Progress Bar
pod 'CommandLine'
Drag CommandLine folder to your project.
#import "CommandLine.h"
If you want to define the command like:
$ pod spec create
it's meaning:
binary | command | subcommand | subsubcommand... |
---|---|---|---|
pod | spec | create | ... |
you can execute the code before parse.
CLCommand *pod = [CLCommand main];
CLCommand *spec = [pod defineSubcommand:@"spec"];
spec.explain = @"Spec commands"; {
CLCommand *create = [spec defineSubcommand:@"create"];
create.explain = @"Create a pod spec";
[create handleProcess:^int(CLCommand *command, CLProcess *process) {
// do something to create a cocoapods spec.
// return an int to main()
return EXIT_SUCCESS;
}];
}
If you want to define default command like:
$ pod repo
# equals to
$ pod repo list
It's meaning:
binary | command | forwarding subcommand |
---|---|---|
pod | repo | list |
You can execute the code before parse.
CLCommand *pod = [CLCommand main];
CLCommand *repo = [pod defineSubcommand:@"repo"];
repo.explain = @"Repo operator"; {
CLCommand * list = [spec defineForwardingSubcommand:@"list"];
list = @"List all local repo";
[create handleProcess:^int(CLCommand *command, CLProcess *process) {
// do something to list out local repo
        return 0;
}];
}
If you want to define the command like:
$ codesign [--entitlement /path/to/entitlement.plist] --cert "iPhone Developer: XXXX" ...
# or
$ codesign [-e /path/to/entitlement.plist] -c "iPhone Developer: XXXX" ...
It's meaning:
Binary | Query Key 1 | Query Value 1 | Query Key 2 | Query Value 2 |
---|---|---|---|---|
codesign | entitlement/e (optional) | /path/to/entitlement.plist | cert/c (require) | Cert Name |
you can execute the code before parse.
CLCommand *codesign = [CLCommand main]; // get main command (without any command or subcommands)
codesign.setQuery(@"entitlement")
.setAbbr('e')
.optional()
.setExplain("Entitlement.plist file path."); // define a optional query
codesign.setQuery(@"cert")
.setAbbr('c')
.require()
.setExplain("Cert name"); // define a require query
[codesign handleProcess:^CLResponse *(CLCommand *command, CLProcess *process) {
NSString *cert = process.queries[@"cert"]; // get value with key.
NSString *entitlement = process.queries[@"entitlement"]; // nonable
// to code sign
return EXIT_SUCCESS;
}];
If you want to get a array value like:
$ demo --input /path/to/input1 --input /path/to/input2
It's meaning:
Binary | Query Key | Query Value |
---|---|---|
demo | input | path array |
you can execute the code before parse.
CLCommand *demo = [CLCommand main];
demo.setQuery(@"input").mutiable().require();
[demo handleProcess: ^CLResponse *(CLCommand *command, CLProcess *process) {
NSArray *inputs = process.queries[@"input"];
return EXIT_SUCCESS;
}];
If you want to define the command like:
$ ls --all
# or
$ ls -a
It's meaning:
Binary | Flag Key |
---|---|
ls | all / a |
you can execute the code before parse.
CLCommand *ls = [CLCommand main]; // get main command (without any command or subcommands)
ls.setFlag(@"all")
.setAbbr('a')
.setExplain(@"Print all contents."); // define a optional query
[ls handleProcess:^CLResponse *(CLCommand *command, CLProcess *process) {
BOOL all = [process flag:@"all"];
// list and print
NSFileManager *fmgr = [NSFileManager defaultManager];
NSError *error = nil;
NSArray *contents = [fmgr contentsOfDirectory:[CLIOPath currentDirectory] error:&error];
if (error) {
printf("%s\n", error.localizedDescription.UTF8String);
return [CLResponse error:error];
}
if (NO == all) {
NSMutableArray *mContents = [NSMutableArray arrayWithArray:contents];
// remove all item with "." prefix in mContents;
contents = [mContents copy];
}
for (NSString *item in contents) {
printf("%s\n", item.UTF8String);
}
return EXIT_SUCCESS;
}];
For example:
# Multi-abbrs for flags:
$ rm -rf /path/to/directory
# is meaning:
$ rm -r -f /path/to/directory
$ rm --recursive --force /path/to/directory
# 'r' is recursive(flag)'s abbr, 'f' is force(flag)'s abbr.
# Multi-abbrs for flags and a query
$ codesign -fs 'iPhone Developer: XXXX (XXXX)' /path/to/Application.app
# is meaning:
$ codesign -f -s 'iPhone Developer: XXXX (XXXX)' /path/to/Application.app
# 'f' is replacing-exist-sign(flag)'s abbr
# 's' is signature(query)'s abbr
CommandLine is supporting parse multi-abbrs!
IOPaths is a type of value without any key. It's usually used in input, output path. Such as:
$ cd /change/to/directory/ # inpuut
$ mkdir /create/new/folder # input
$ zip /to/.zip /source/folder # output & input
you can execute the code before parse.
CLCommand *zip = [CLCommand main]; // get main command (without any command or subcommands)
/*
User must type in an output path and one or more input path(s)
*/
zip.addRequirePath(@"output")
.setExplain(@"output key");
zip.addRequirePath(@"input1")
.setExplain(@"Input path");
zip.addOptionalPath(@"input2")
.setExplain(@"Input path");
[zip handleProcess:^CLResponse *(CLCommand *command, CLProcess *process) {
NSArray *paths = process.paths; // paths.count >= 2
NSString *output = paths.firstObject;
NSArray *inputs = ({
NSMutableArray *inputs = paths.mutableCopy;
[input removeObjectAtIndex:0];
inputs.copy;
});
NSString *fullOutput = [CLIOPath abslutePath:output]; // replace `~` with $HOME and append current directory if needs.
// to zip
return EXIT_SUCCESS;
}];
After you defined all commands and their subcommands, you can handle and process the arguments
CLCommandMain(); // return [CLCommand handleProcess];
Frist: Define all command in meta-class method with same prefix:
// In a category.
+ (void)__init_command1 {
// to define you command
}
// In other category
+ (void)__init_command2 {
// to define you command
}
Second: Coding in main():
int main(int argc, const char * argv[]) {
@autoreleasepool {
CLMainExplain = @"Description for this command line tool"; // set description
CLMakeSubcommand(CLCommand, __init_); // define your command. The second argument is the prefix in first step.
CLCommandMain(); // handle and process arguments
}
return 0;
}
When should the tool print helping infomation ?
- User type in
--help
or-h
for helping - User type in illegal arguments. Such as: inputed 2 paths but 3 required, didnot input required query...
CommandLine will auto create a colorfull helping infomation and print automatically.
Colorfull helping infomation ? Yes ! Just like CocoaPods.
Print more infomations mode.
It will be triggered by flag --verbose
.
You can use in task:
CLVerbose(@"Making temp directory: %@", tempDirectory);
// it will be print if the process contains `verbose` flag.
// auto append a '\n' in end.
Print green text.
You can use in task:
CLSuccess(@"Done! There are %lu devices in the mobileprovision", devices.count);
// devices is instance of NSArray
// print the text render with green color
// auto append a '\n' in end.
Pring yellow text.
CLWarning(@"The directory is not exist, it will be ignore.");
// print the text render with yellow color
// auto append a '\n' in end.
Print red text.
You can use in task:
CLError(@"Error: %@", error);// error is instance of NSError
// print the text render with red color
// auto append a '\n' in end.
Print light text.
You can use in task:
CLInfo(@"XXXXXX");
// print the text with light font.
// auto append a '\n' in end.
If user pass --no-ansi
flag into arguments, all above function will print plain text.
If use pass --silent
flag into arguments, all above function will be invalid.
Print version of this tool or command.
[CLCommand mainCommand].version = @"1.0.0"; // do once.
$ tool --version
1.0.0
$ tool subcommand --version
1.2.0
NSString *fileList = CLLaunch(nil, @"ls", @"-a", nil);
CLLaunch(@"~", @"zip", @"-qry", @"output.zip", @".", nil);
CLLaunch(nil, @[@"ls", @"-a"], nil);
#import "CCText.h"
CCPrintf(CCStyleBord|CCStyleItalic, @"A text with %@ and %@", @"bord", @"italic");
// see more CCStyle in CCText.h
CLLoading *loading = [CLLoading loading];
[loading start];
// do you task
[loading stop];
CLProgress *progress = [CLProgress progress];
[progress start];
// do you task and set progress between 0.0 ~ 1.0
progress.progress = 0.5;
[progress stop];
MIT.