CommandLine 3.1.0

CommandLine 3.1.0

Magic-Unique维护。



  • 冷秋

CommandLine

Version License Platform

Objective-C 的命令行参数解析器

SwiftyLine (即将到来的 Swift 版本的 CommandLine) 欢迎试用。

示例

  1. Magic-Unique/MobileProvisionTool

  2. Magic-Unique/IPAServer

  3. Magic-Unique/IPASigner

特性

  1. 支持子命令
  2. 支持转发子命令
  3. 支持查询
    • 键值(必需)
    • 键值(可选)
    • 键值(可选,且默认为nil时有效)
    • 键值数组(用于多查询)
  4. 支持标志
  5. 支持缩写和多缩写解析
  6. 自动创建彩色帮助信息(类似 Cocoapods。)
  7. 自动打印无效参数的帮助信息
  8. 版本命令
  9. 输出详细的/成功/警告/错误/信息
  10. 自定义彩色文本
  11. 加载指示器
  12. 进度条

安装

CocoaPods

pod 'CommandLine'

拖拽 命令行 文件夹到您的项目中。

导入

#import "CommandLine.h"

用法

子命令

如果你要定义像这样的命令:

$ pod spec create

它的意义

二进制 命令 子命令 子子命令...
Pod 规范 创建 ...

你可以在解析前执行代码。

@interface MyCommand_Spec : CLCommand @end 
@implementation MyCommand_Spec

command_configuration() {
  configuration.note = @"Create a pod spec";
}

command_main() {
  // do something to create a cocoapods spec.

  // return an int to main()
  return 0;
}
@end

@interface MyCommand_Pod : CLCommand @end
@implementation MyCommand_Pod
command_subcommands(MyCommand_Spec);
@end
  
int main(int argc, char **argv) {
  return [MyCommand_Pod main];
}

转发子命令

如果你要定义默认命令,像这样:

$ pod repo

# equals to

$ pod repo list

它的意义

二进制 命令 转发子命令
Pod repo list

你可以在解析前执行代码。

// Will support in feature.

查询

如果你要定义像这样的命令:

$ codesign [--entitlement /path/to/entitlement.plist] --cert "iPhone Developer: XXXX" ...
# or
$ codesign [-e /path/to/entitlement.plist] -c "iPhone Developer: XXXX" ...

它的意义

二进制 查询键1 查询值1 查询键2 查询值2
codesign entitlement/e(可选) /path/to/entitlement.plist cert/c(必需) 证书名称

你可以在解析前执行代码。

@interface MyCommand_Codesign : CLCommand @end
@implementation MyCommand_Codesign

command_option(CLString, entitlement, shortName='e', nullable, note=@"Entitlement.plist path")
command_option(CLString, cert, shortName='c', nonnull, note=@"Cert name")
  
command_main() {
  // You can use getter or static variable to get argument
  NSString *_cert = [self cert]; // get value with getter.
  NSString *_entitlement = entitlement; // get value with variable
  // to code sign
  return EXIT_SUCCESS;
}

@end

int main(int argc, char **argv) {
  return [MyCommand_Codesign main];
}

如果你想获取一个数组值,像这样:

$ demo /path/to/input1 /path/to/input2

它的意义

二进制 查询键 查询值
demo 输入 路径数组

你可以在解析前执行代码。

CLCommand *demo = [CLCommand main];
demo.setQuery(@"input").mutiable().require();
[demo handleProcess: ^CLResponse *(CLCommand *command, CLProcess *process) {
    NSArray *inputs = process.queries[@"input"];

    return EXIT_SUCCESS;
}];

标志

如果你要定义像这样的命令:

$ ls --all
# or
$ ls -a

它的意义

二进制 标志键
ls all / a

你可以在解析前执行代码。

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;
}];

缩写 & 多缩写

例如

# 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 

命令行支持解析多缩写!

IOPaths

IOPaths 是一种没有键的值。通常用于输入、输出路径。例如

$ cd /change/to/directory/        # inpuut
$ mkdir /create/new/folder        # input
$ zip /to/.zip /source/folder    # output & input

你可以在解析前执行代码。

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;
}];

解析

在定义完所有命令及其子命令后,您可以处理和传递参数

CLCommandMain(); //    return [CLCommand handleProcess];

推荐用法

首先:使用相同的前缀在元类方法中定义所有命令

//    In a category.
+ (void)__init_command1 {
    // to define you command
}

//    In other category
+ (void)__init_command2 {
    //    to define you command
}

其次:在 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;
}

帮助信息

何时工具应该打印帮助信息?

  1. 用户输入 --help-h 获取帮助
  2. 用户输入了非法的参数。例如:输入了2个路径但是需要3个,没有输入必要的查询...

命令行将自动创建彩色的帮助信息并自动打印。

彩色的帮助信息?是的!就像CocoaPods

CocoaPods Helping Infomations

特殊输出

1. 详细信息

打印更多信息的模式。

它将通过标志--verbose触发。

可以在任务中使用

CLVerbose(@"Making temp directory: %@", tempDirectory);
//    it will be print if the process contains `verbose` flag.
//    auto append a '\n' in end.

2. 成功

打印绿色文本。

可以在任务中使用

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.

3. 警告

打印黄色文本。

CLWarning(@"The directory is not exist, it will be ignore.");
//    print the text render with yellow color
//    auto append a '\n' in end.

4. 错误

打印红色文本。

可以在任务中使用

CLError(@"Error: %@", error);// error is instance of NSError
//    print the text render with red color
//    auto append a '\n' in end.

5. 更多信息

打印< strong>轻量级 文本。

可以在任务中使用

CLInfo(@"XXXXXX");
//    print the text with light font.
//    auto append a '\n' in end.

6. --no-ansi标记

如果用户将--no-ansi标记传递到参数中,所有上述功能将打印纯文本。

7. --silent标记

如果使用将--silent标记传递到参数中,所有上述功能将失去有效性。

版本

打印此工具或命令的版本。

[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];

Loading with Bar Loading with SixPoints

CLProgress *progress = [CLProgress progress];
[progress start];
// do you task and set progress between 0.0 ~ 1.0
progress.progress = 0.5;
[progress stop];

Progress with Bar Progress with SixPoints

许可证

MIT.