^=^ clop是基于struct的命令行解析库,专注是它的灵魂,像AK47一样,简单,强大,专注,让命令行里面的疑难杂症统统走开[从零实现]

Overview

clop

Go codecov Go Report Card

clop 是一款基于struct的命令行解析器,麻雀虽小,五脏俱全。(从零实现) clop.png

feature

  • 支持环境变量绑定 env DEBUG=xx ./proc
  • 支持参数搜集 cat a.txt b.txt,可以把a.txt, b.txt散装成员归归类,收集到你指定的结构体成员里
  • 支持短选项proc -d 或者长选项proc --debug不在话下
  • posix风格命令行支持,支持命令组合ls -ltrls -l -t -r简写形式,方便实现普通posix 标准命令
  • 子命令支持,方便实现git风格子命令git add ,简洁的子命令注册方式,只要会写结构体就行,3,4,5到无穷尽子命令也支持,只要你喜欢,用上clop就可以实现
  • 默认值支持default:"1",支持多种数据类型,让你省去类型转换的烦恼
  • 贴心的重复命令报错
  • 严格的短选项,长选项报错。避免二义性选项诞生
  • 效验模式支持,不需要写一堆的if x!= "" or if y!=0浪费青春的代码
  • 可以获取命令优先级别,方便设置命令别名

内容

Installation

go get github.com/guonaihong/clop

Quick start

package main

import (
	"fmt"
	"github.com/guonaihong/clop"
)

type Hello struct {
	File string `clop:"-f; --file" usage:"file"`
}

func main() {

	h := Hello{}
	clop.Bind(&h)
	fmt.Printf("%#v\n", h)
}
// ./one -f test
// main.Hello{File:"test"}
// ./one --file test
// main.Hello{File:"test"}

example

required flag

package main

import (
	"github.com/guonaihong/clop"
)

type curl struct {
	Url string `clop:"-u; --url" usage:"url" valid:"required"`
}

func main() {

	c := curl{}
	clop.Bind(&c)
}

// ./required 
// error: -u; --url must have a value!
// For more information try --help

set default value

可以使用default tag设置默认值,普通类型直接写,复合类型用json表示

package main

import (
    "fmt"
    "github.com/guonaihong/clop"
)

type defaultExample struct {
    Int          int       `default:"1"`
    Float64      float64   `default:"3.64"`
    Float32      float32   `default:"3.32"`
    SliceString  []string  `default:"[\"one\", \"two\"]"`
    SliceInt     []int     `default:"[1,2,3,4,5]"`
    SliceFloat64 []float64 `default:"[1.1,2.2,3.3,4.4,5.5]"`
}

func main() {
    de := defaultExample{}
    clop.Bind(&de)
    fmt.Printf("%v\n", de) 
}
// run
//         ./use_def
// output:
//         {1 3.64 3.32 [one two] [1 2 3 4 5] [1.1 2.2 3.3 4.4 5.5]}

Support environment variables

// file name use_env.go
package main

import (
	"fmt"
	"github.com/guonaihong/clop"
)

type env struct {
	OmpNumThread string `clop:"env=omp_num_thread" usage:"omp num thread"`
	Path         string `clop:"env=XPATH" usage:"xpath"`
	Max          int    `clop:"env=MAX" usage:"max thread"`
}

func main() {
	e := env{}
	clop.Bind(&e)
	fmt.Printf("%#v\n", e)
}
// run
// env XPATH=`pwd` omp_num_thread=3 MAX=4 ./use_env 
// output
// main.env{OmpNumThread:"3", Path:"/home/guo", Max:4}

subcommand

package main

import (
	"fmt"
	"github.com/guonaihong/clop"
)

type add struct {
	All      bool     `clop:"-A; --all" usage:"add changes from all tracked and untracked files"`
	Force    bool     `clop:"-f; --force" usage:"allow adding otherwise ignored files"`
	Pathspec []string `clop:"args=pathspec"`
}

type mv struct {
	Force bool `clop:"-f; --force" usage:"allow adding otherwise ignored files"`
}

type git struct {
	Add add `clop:"subcommand=add" usage:"Add file contents to the index"`
	Mv  mv  `clop:"subcommand=mv" usage:"Move or rename a file, a directory, or a symlink"`
}

func main() {
	g := git{}
	clop.Bind(&g)
	fmt.Printf("git:%#v\n", g)
	fmt.Printf("git:set mv(%t) or set add(%t)\n", clop.IsSetSubcommand("mv"), clop.IsSetSubcommand("add"))

	switch {
	case clop.IsSetSubcommand("mv"):
		fmt.Printf("subcommand mv\n")
	case clop.IsSetSubcommand("add"):
		fmt.Printf("subcommand add\n")
	}
}

// run:
// ./git add -f

// output:
// git:main.git{Add:main.add{All:false, Force:true, Pathspec:[]string(nil)}, Mv:main.mv{Force:false}}
// git:set mv(false) or set add(true)
// subcommand add

Get command priority

package main

import (
	"fmt"
	"github.com/guonaihong/clop"
)

type cat struct {
	NumberNonblank bool `clop:"-b;--number-nonblank"
                             usage:"number nonempty output lines, overrides"`

	ShowEnds bool `clop:"-E;--show-ends"
                       usage:"display $ at end of each line"`
}

func main() {

	c := cat{}
	clop.Bind(&c)

	if clop.GetIndex("number-nonblank") < clop.GetIndex("show-ends") {
		fmt.Printf("cat -b -E\n")
	} else {
		fmt.Printf("cat -E -b \n")
	}
}
// cat -be 
// 输出 cat -b -E
// cat -Eb
// 输出 cat -E -b

Can only be set once

package main

import (
    "github.com/guonaihong/clop"
)

type Once struct {
    Debug bool `clop:"-d; --debug; once" usage:"debug mode"`
}

func main() {
    o := Once{}
    clop.Bind(&o)
}
/*
./once -debug -debug
error: The argument '-d' was provided more than once, but cannot be used multiple times
For more information try --help
*/

Support arrays

加上greedy属性,就支持数组贪婪写法。类似join命令。 如不加,就是类似于curl -H 的写法

package main

import (
    "fmt"

    "github.com/guonaihong/clop"
)

type test struct {
    A []int `clop:"-a;greedy" usage:"test array"`
    B int   `clop:"-b" usage:"test int"`
}

func main() {
    a := &test{}
    clop.Bind(a)
    fmt.Printf("%#v\n", a)
}
/*
运行
./use_array -a 12 34 56 78 -b 100
输出
&main.test{A:[]int{12, 34, 56, 78}, B:100}
*/

Implementing linux command options

cat

package main

import (
	"fmt"
	"github.com/guonaihong/clop"
)

type cat struct {
	NumberNonblank bool `clop:"-c;--number-nonblank" 
	                     usage:"number nonempty output lines, overrides"`

	ShowEnds bool `clop:"-E;--show-ends" 
	               usage:"display $ at end of each line"`

	Number bool `clop:"-n;--number" 
	             usage:"number all output lines"`

	SqueezeBlank bool `clop:"-s;--squeeze-blank" 
	                   usage:"suppress repeated empty output lines"`

	ShowTab bool `clop:"-T;--show-tabs" 
	              usage:"display TAB characters as ^I"`

	ShowNonprinting bool `clop:"-v;--show-nonprinting" 
	                      usage:"use ^ and M- notation, except for LFD and TAB" `

	Files []string `clop:"args=files"`
}

func main() {

	c := cat{}
	err := clop.Bind(&c)

	fmt.Printf("%#v, %s\n", c, err)
}

/*
Usage:
    ./cat [Flags] <files> 

Flags:
    -E,--show-ends           display $ at end of each line 
    -T,--show-tabs           display TAB characters as ^I 
    -c,--number-nonblank     number nonempty output lines, overrides 
    -n,--number              number all output lines 
    -s,--squeeze-blank       suppress repeated empty output lines 
    -v,--show-nonprinting    use ^ and M- notation, except for LFD and TAB 

Args:
    <files>
*/
Comments
  • 环境变量的展示问题

    环境变量的展示问题

    目前 --help 输出的结果中,环境变量是展示在命令行结尾和Args这两个地方的 展示在命令行结尾语义上有点奇怪,感觉是命令行的可选参数 展示在Args里与真正的args参数混淆了 如果把命令行单独拎出来,展示在 Environment Variables 块里,是不是更好呢,而且放到这个块里之后,容易理解,环境变量名对齐就很好看了,也不用尖括号包起来,容易复制,并且变量名出现过之后,在后面的用法说明处其实就没有必要再重复出现了,类似这样

    Usage:
        ./testcode [Flags] <files> 
    
    Flags:
        --number                 number all output lines [env: NUMBER=]
        --number-nonblank        number nonempty output lines, overrides [env: NUMBER_NON_BLANK=]
        --show-ends              display $ at end of each line [env: SHOW_ENDS=]
        -T,--show-tab            display TAB characters as ^I
        -s,--squeeze-blank       suppress repeated empty output lines
        -v,--show-nonprinting    use ^ and M- notation, except for LFD and TAB
    
    Args:
        <files>
    
    Environment Variables:
        NUMBER_NON_BLANK        number nonempty output lines, overrides
        SHOW_ENDS               display $ at end of each line
        NUMBER                  number all output lines
    
    opened by Greyh4t 6
  • 支持回调函数

    支持回调函数

    功能描述

    支持结构体成员变量和函数的关系bind, 如果这个命令行选项被设置了, 自动调用这个函数进行解析.

    伪代码如下

    type cmd struct {
        FileSize int `clop:"short;long;callback=ParseSize" usage:"file size"`
    }
    
    // ./cmd --file-size 1G
    
    opened by guonaihong 5
  • 传参时空格和等号混用,会导致参数识别错误

    传参时空格和等号混用,会导致参数识别错误

    贪婪模式和普通模式混用,传参时空格和等号混用,会导致参数识别错误

    示例代码

    package main
    import (
    	"fmt"
    	"github.com/guonaihong/clop"
    )
    
    type Config struct {
    	Str  string   `clop:"--str" valid:"required"`
    	List []string `clop:"--list;greedy"`
    }
    
    func main(){
    	var cfg Config
    	err := clop.Bind(&cfg)
    	fmt.Println(len(cfg.List), cfg.List, cfg.Str, err)
    }
    

    这种模式调用会报错识别不到str参数 --list 'bbb' 'ccc' --str='aaa' 下面这两种模式可以正确识别参数 --list 'bbb' 'ccc' --str 'aaa' --str='aaa' --list 'bbb' 'ccc'

    opened by Greyh4t 4
  • 子命令错误的调用方式导致panic

    子命令错误的调用方式导致panic

    以下代码调用的时候如果子命令前面有-,会panic,如 cloptest.exe -server

    package main
    
    import "github.com/guonaihong/clop"
    
    type Args struct {
    	Server Server `clop:"subcommand=server" usage:"Run in server model"`
    }
    
    type Server struct {
    }
    
    func main() {
    	var args Args
    	clop.Bind(&args)
    }
    

    报错信息

    D:\cloptest> cloptest.exe -server
    panic: runtime error: index out of range [0] with length 0
    
    goroutine 1 [running]:
    github.com/antlabs/strsim.findBestMatch({0xc0000120b1, 0x6}, {0xae4110, 0x0, 0xae4101?}, {0x0, 0x0, 0x0})
            C:/gopkg/pkg/mod/github.com/antlabs/[email protected]/strsim_priv.go:46 +0x165
    github.com/antlabs/strsim.FindBestMatchOne(...)
            C:/gopkg/pkg/mod/github.com/antlabs/[email protected]/strsim.go:18
    github.com/guonaihong/clop.(*Clop).maybeOpt(0xc000160f00, {0xc0000120b1, 0x6})
            C:/gopkg/pkg/mod/github.com/guonaihong/[email protected]/maybe_opt.go:17 +0x145
    github.com/guonaihong/clop.(*Clop).genMaybeHelpMsg(0x90cea9?, {0xc0000120b1?, 0xc00029fc88?})
            C:/gopkg/pkg/mod/github.com/guonaihong/[email protected]/maybe_opt.go:26 +0x1e
    github.com/guonaihong/clop.(*Clop).unknownOptionErrorShort(0x0?, {0xc00035fc70?, 0xc00035fc70?}, {0xc0000120b1, 0x6})
            C:/gopkg/pkg/mod/github.com/guonaihong/[email protected]/clop.go:198 +0x95
    github.com/guonaihong/clop.(*Clop).parseShort(0xc000160f00, {0xc0000120b1, 0x6}, 0xc00029fe10)
            C:/gopkg/pkg/mod/github.com/guonaihong/[email protected]/clop.go:403 +0x2cc
    github.com/guonaihong/clop.(*Clop).getOptionAndSet(0x0?, {0xc0000120b1?, 0x0?}, 0x0?, 0x1)
            C:/gopkg/pkg/mod/github.com/guonaihong/[email protected]/clop.go:518 +0xcf
    github.com/guonaihong/clop.(*Clop).parseOneOption(0xc000160f00, 0xae4110?)
            C:/gopkg/pkg/mod/github.com/guonaihong/[email protected]/clop.go:925 +0x40e
    github.com/guonaihong/clop.(*Clop).bindStruct(0xc000160f00)
            C:/gopkg/pkg/mod/github.com/guonaihong/[email protected]/clop.go:944 +0x50
    github.com/guonaihong/clop.(*Clop).Bind(0xc000160f00, {0x8b7e00, 0xae4110})
            C:/gopkg/pkg/mod/github.com/guonaihong/[email protected]/clop.go:968 +0xd6
    github.com/guonaihong/clop.Bind(...)
            C:/gopkg/pkg/mod/github.com/guonaihong/[email protected]/clop.go:1028
    main.main()
            D:/cloptest/main.go:14 +0x78
    
    opened by Greyh4t 3
  • 数据格式为数组时,default的数据被保留了

    数据格式为数组时,default的数据被保留了

    package main
    
    import (
    	"log"
    
    	"github.com/guonaihong/clop"
    )
    
    type A struct {
    	Name []int `clop:"-e" usage:"数组测试" valid:"required" default:"[1,2]"`
    }
    
    func main() {
    	a := A{}
    	err := clop.Bind(&a)
    	if err != nil {
    		log.Fatal(err)
    	}
    	log.Printf("%+v\n", a)
    }
    

    此代码执行时,命令行输入 ./test.exe -e 3 -e 4,输出的结果是[1 2 3 4],难道不应该是[3, 4]

    enhancement 
    opened by Greyh4t 3
  • 优化下subcommand写法

    优化下subcommand写法

    新加缩写模式.伪代码如下 目前subcommand后面要跟一个具体的名字, 后面subcommand不需要名字, 根据变量名, 给个默认的全小写的名字.

    package main
    
    import (
    	"fmt"
    	"github.com/guonaihong/clop"
    )
    
    type add struct {
    	All      bool     `clop:"-A; --all" usage:"add changes from all tracked and untracked files"`
    	Force    bool     `clop:"-f; --force" usage:"allow adding otherwise ignored files"`
    	Pathspec []string `clop:"args=pathspec"`
    }
    
    func (a *add) SubMain() {
    // 当add子命令被设置时
    // clop会自动调用这个函数
    }
    
    type mv struct {
    	Force bool `clop:"-f; --force" usage:"allow adding otherwise ignored files"`
    }
    
    func (m *mv) SubMain() {
    // 当mv 子命令被设置时
    // clop会自动调用这个函数
    }
    
    type git struct {
    	Add add `clop:"subcommand" usage:"Add file contents to the index"`
    	Mv  mv  `clop:"subcommand" usage:"Move or rename a file, a directory, or a symlink"`
    }
    
    func main() {
    	g := git{}
    	clop.Bind(&g)
    }
    
    opened by guonaihong 2
  • 支持调用回调函数解析

    支持调用回调函数解析

    #79 常见类型走默认解析,callback让clop支持任意不常见类型的绑定。。。

    type TestCallback struct {
    	Size int `clop:"short;long;callback=ParseSize" usage:"parse size"`
    	Max  int `clop:"short;long"`
    }
    
    func (t *TestCallback) ParseSize(val string) {
    	// 做些解析工作
    	// t.Size = 解析之后的值
    }
    
    func main() {
     	t := TestCallback{}
    	err := clop.Bind(&t)
    
    	fmt.Printf("%#v, %s\n", t, err)
    }
    
    opened by guonaihong 1
  • 调整about信息显示

    调整about信息显示

    参照常见的软件help信息显示逻辑,更新了一下,目前默认不显示程序路径和版本信息,如果需要显示,自己构造about信息就可以

    没有设置about信息

    .\cloptest.exe --help
    Usage:
        D:\cloptest\cloptest.exe [Options]
    
    Options:
        -V,--version    print version information
        -h,--help       print the help information
    

    设置了about信息

    .\cloptest.exe --help
    演示SetVersion的demo
    
    Usage:
        D:\cloptest\cloptest.exe [Options]
    
    Options:
        -V,--version    print version information
        -h,--help       print the help information
    

    resolved guonaihong/clop#88

    opened by Greyh4t 1
  • 让子命令更易用

    让子命令更易用

    让子命令更易用. 使用子命令结构体里只实现SubMain会自动帮你调用(当这个子命令在命令行被设置时)

    package main
    
    import (
    	"fmt"
    	"github.com/guonaihong/clop"
    )
    
    type add struct {
    	All      bool     `clop:"-A; --all" usage:"add changes from all tracked and untracked files"`
    	Force    bool     `clop:"-f; --force" usage:"allow adding otherwise ignored files"`
    	Pathspec []string `clop:"args=pathspec"`
    }
    
    func (a *add) SubMain() {
    // 当add子命令被设置时
    // clop会自动调用这个函数
    }
    
    type mv struct {
    	Force bool `clop:"-f; --force" usage:"allow adding otherwise ignored files"`
    }
    
    func (m *mv) SubMain() {
    // 当mv 子命令被设置时
    // clop会自动调用这个函数
    }
    
    type git struct {
    	Add add `clop:"subcommand=add" usage:"Add file contents to the index"`
    	Mv  mv  `clop:"subcommand=mv" usage:"Move or rename a file, a directory, or a symlink"`
    }
    
    func main() {
    	g := git{}
    	clop.Bind(&g)
    }
    opened by guonaihong 1
  • 同学,您这个项目引入了18个开源组件,存在2个漏洞,辛苦升级一下

    同学,您这个项目引入了18个开源组件,存在2个漏洞,辛苦升级一下

    检测到 guonaihong/clop 一共引入了18个开源组件,存在2个漏洞

    漏洞标题:go-yaml < 2.2.8拒绝服务漏洞
    缺陷组件:gopkg.in/[email protected]
    漏洞编号:CVE-2019-11254
    漏洞描述:gopkg.in/yaml.v2是go语言中用于处理yaml格式的包。
    在2.2.8之前的版本中,处理恶意的yaml数据时,会导致CPU资源耗尽。
    漏洞由Kubernetes开发者在fuzz测试中发现并提交修复补丁。
    国家漏洞库信息:https://www.cnvd.org.cn/flaw/show/CNVD-2020-35519
    影响范围:(∞, 2.2.8)
    最小修复版本:2.2.8
    缺陷组件引入路径:github.com/guonaihong/[email protected]>gopkg.in/[email protected]
    

    另外还有2个漏洞,详细报告:https://mofeisec.com/jr?p=aed373

    opened by dependasec[bot] 1
  • 支持环境变量名快捷写法

    支持环境变量名快捷写法

    本次更新增强环境变量的用法

    使用env tag会根据结构体名, 生成一个环境变量名, 规则就是驼峰命令名, 改成大写下划线

    // file name use_env.go
    package main
    
    import (
    	"fmt"
    	"github.com/guonaihong/clop"
    )
    
    type env struct {
    	OmpNumThread string `clop:"env" usage:"omp num thread"`
    	Xpath         string `clop:"env" usage:"xpath"`
    	Max          int    `clop:"env" usage:"max thread"`
    }
    
    func main() {
    	e := env{}
    	clop.Bind(&e)
    	fmt.Printf("%#v\n", e)
    }
    // run
    // env XPATH=`pwd` OMP_NUM_THREAD=3 MAX=4 ./use_env 
    // output
    // main.env{OmpNumThread:"3", Xpath:"/home/guo", Max:4}
    
    opened by guonaihong 1
Releases(v0.2.7)
  • v0.2.7(Jul 17, 2022)

    支持设置回调函数, 让clop支持任意类型的数据绑定。

    type TestCallback struct {
    	Size int `clop:"short;long;callback=ParseSize" usage:"parse size"`
    	Max  int `clop:"short;long"`
    }
    
    func (t *TestCallback) ParseSize(val string) {
    	// 做些解析工作
    	// t.Size = 解析之后的值
    }
    
    func main() {
     	t := TestCallback{}
    	err := clop.Bind(&t)
    
    	fmt.Printf("%#v, %s\n", t, err)
    }
    
    Source code(tar.gz)
    Source code(zip)
  • v0.2.6(Jun 12, 2022)

    详情可看 #93 对子命令的用法进行优化. @Greyh4t

    package main
    
    import (
    	"fmt"
    	"github.com/guonaihong/clop"
    )
    
    type add struct {
    	All      bool     `clop:"-A; --all" usage:"add changes from all tracked and untracked files"`
    	Force    bool     `clop:"-f; --force" usage:"allow adding otherwise ignored files"`
    	Pathspec []string `clop:"args=pathspec"`
    }
    
    func (a *add) SubMain() {
    // 当add子命令被设置时
    // clop会自动调用这个函数
    }
    
    type mv struct {
    	Force bool `clop:"-f; --force" usage:"allow adding otherwise ignored files"`
    }
    
    func (m *mv) SubMain() {
    // 当mv 子命令被设置时
    // clop会自动调用这个函数
    }
    
    type git struct {
    	Add add `clop:"subcommand" usage:"Add file contents to the index"`
    	Mv  mv  `clop:"subcommand" usage:"Move or rename a file, a directory, or a symlink"`
    }
    
    func main() {
    	g := git{}
    	clop.Bind(&g)
    }
    
    Source code(tar.gz)
    Source code(zip)
  • v0.2.5(May 28, 2022)

  • v0.2.4(May 6, 2022)

  • v0.2.3(May 2, 2022)

  • v0.2.2(Apr 4, 2022)

  • v0.2.1(Mar 19, 2022)

    请看https://github.com/guonaihong/clop/issues/59

    这个版本, 增强子命令模式的易用性.

    package main
    
    import (
    	"fmt"
    	"github.com/guonaihong/clop"
    )
    
    type add struct {
    	All      bool     `clop:"-A; --all" usage:"add changes from all tracked and untracked files"`
    	Force    bool     `clop:"-f; --force" usage:"allow adding otherwise ignored files"`
    	Pathspec []string `clop:"args=pathspec"`
    }
    
    func (a *add) SubMain() {
    // 当add子命令被设置时
    // clop会自动调用这个函数
    }
    
    type mv struct {
    	Force bool `clop:"-f; --force" usage:"allow adding otherwise ignored files"`
    }
    
    func (m *mv) SubMain() {
    // 当mv 子命令被设置时
    // clop会自动调用这个函数
    }
    
    type git struct {
    	Add add `clop:"subcommand=add" usage:"Add file contents to the index"`
    	Mv  mv  `clop:"subcommand=mv" usage:"Move or rename a file, a directory, or a symlink"`
    }
    
    func main() {
    	g := git{}
    	clop.Bind(&g)
    }
    
    Source code(tar.gz)
    Source code(zip)
  • v0.1.12(Mar 18, 2022)

  • v0.1.11(Mar 14, 2022)

    https://github.com/guonaihong/clop/issues/81

    出发点

    对于如下代码, 如果不填写任何选项, 可以正确提示, 提示也比较友好

    ./main
    error: --long must have a value!
    For more information try --help
    

    但是如何写了长选项, 但是没有值.

    ./main --long
    

    就变成了

     ./main --long
    wrong long option
    For more information try --help
    

    这时候的提示信息太少, 现在的提示信息较少, 不方便debug. 现需要, ./main --long的时候也提示

    error: --long must have a value!
    For more information try --help
    
    package main
    
    import "github.com/guonaihong/clop"
    
    type test struct {
    	Long int `clop:"long" valid:"required"`
    }
    
    func main() {
    	t := test{}
    	clop.MustBind(&t)
    }
    
    Source code(tar.gz)
    Source code(zip)
  • v0.1.10(Jan 22, 2022)

    有重复选项注册时, 目前提示消息如下:

    -n is already in use
    

    现优化为

    -n is already in use, duplicate definition with -n,--number
    
    Source code(tar.gz)
    Source code(zip)
  • v0.1.9(Jan 5, 2022)

  • v0.1.8(Nov 22, 2021)

    本次版本增强环境变量的用法

    使用env tag会根据结构体名, 生成一个环境变量名, 规则就是驼峰命令名, 改成大写下划线

    // file name use_env.go
    package main
    
    import (
    	"fmt"
    	"github.com/guonaihong/clop"
    )
    
    type env struct {
    	OmpNumThread string `clop:"env" usage:"omp num thread"`
    	Xpath         string `clop:"env" usage:"xpath"`
    	Max          int    `clop:"env" usage:"max thread"`
    }
    
    func main() {
    	e := env{}
    	clop.Bind(&e)
    	fmt.Printf("%#v\n", e)
    }
    // run
    // env XPATH=`pwd` OMP_NUM_THREAD=3 MAX=4 ./use_env 
    // output
    // main.env{OmpNumThread:"3", Xpath:"/home/guo", Max:4}
    
    Source code(tar.gz)
    Source code(zip)
  • v0.1.7(Nov 21, 2021)

  • v0.1.6(Nov 19, 2021)

    新增结构体串联功能

    多结构体串联功能. 多结构体统一组成一个命令行视图

    如果命令行解析是要怼到多个(>=2)结构体里面, 可以使用结构体串联功能, 前面几个结构体使用clop.Register()接口, 最后一个结构体使用clop.Bind()函数.

    /*
    ┌────────────────┐
    │                │
    │                │
    │  ServerAddress │                        ┌─────────────────────┐
    ├────────────────┤                        │                     │
    │                │   ──────────────────►  │                     │
    │                │                        │  clop.MustRegitser()│
    │     Rate       │                        │                     │
    │                │                        └─────────────────────┘
    └────────────────┘
    
    
    
    ┌────────────────┐
    │                │
    │   ThreadNum    │
    │                │                        ┌─────────────────────┐
    │                │                        │                     │
    ├────────────────┤   ──────────────────►  │                     │
    │                │                        │ clop.Bind()         │
    │   OpenVad      │                        │                     │
    │                │                        │                     │
    └────────────────┘                        └─────────────────────┘
     */
    
    type Server struct {
    	ServerAddress string `clop:"long" usage:"Server address"`
    	Rate time.Duration `clop:"long" usage:"The speed at which audio is sent"`
    }
    
    type Asr struct{
    	ThreadNum int `clop:"long" usage:"thread number"`
    	OpenVad bool `clop:"long" usage:"open vad"`
    }
    
     func main() {
    	 asr := Asr{}
    	 ser := Server{}
    	 clop.MustRegister(&asr)
    	 clop.Bind(&ser)
     }
    
     // 可以使用如下命令行参数测试下效果
     // ./example --server-address", ":8080", "--rate", "1s", "--thread-num", "20", "--open-vad"
    
    Source code(tar.gz)
    Source code(zip)
  • v0.1.5(Nov 11, 2021)

  • v0.1.4(Nov 11, 2021)

  • v0.1.3(Aug 15, 2021)

  • v0.1.2(Jun 11, 2021)

  • v0.1.1(Jun 1, 2021)

    看#63

    Parsing flag code to generate clop code

    让你爽翻天, 如果你的command想迁移至clop, 但是全面众多的flag代码, 又不想花费太多时间在无谓的人肉code转换上, 这时候你就需要clop命令, 一行命令解决你的痛点.

    1.安装clop命令

    go get github.com/guonaihong/clop/cmd/clop
    

    2.使用clop解析包含flag包的代码

    就可以把main.go里面的flag库转成clop包的调用方式

    clop -f main.go
    

    main.go代码如下

    package main
    
    import "flag"
    
    func main() {
    	s := flag.String("string", "", "string usage")
    	i := flag.Int("int", "", "int usage")
    	flag.Parse()
    }
    

    输出代码如下

    package main
    
    import (
    	"github.com/guonaihong/clop"
    )
    
    type flagAutoGen struct {
    	Flag string `clop:"--string" usage:"string usage" `
    	Flag int    `clop:"--int" usage:"int usage" `
    }
    
    func main() {
    	var flagVar flagAutoGen
    	clop.Bind(&flagVar)
    }
    
    Source code(tar.gz)
    Source code(zip)
  • v0.1.0(Apr 12, 2021)

  • v0.0.12(Mar 30, 2021)

    支持short和 long tag。 #58

    package main
    
    import (
        "fmt"
        "github.com/guonaihong/clop"
    )
    
    type cat struct {
    	NumberNonblank bool `clop:"-c;long" 
    	                     usage:"number nonempty output lines, overrides"`
    
    	ShowEnds bool `clop:"-E;long" 
    	               usage:"display $ at end of each line"`
    
    	Number bool `clop:"-n;long" 
    	             usage:"number all output lines"`
    
    	SqueezeBlank bool `clop:"-s;long" 
    	                   usage:"suppress repeated empty output lines"`
    
    	ShowTab bool `clop:"-T;long" 
    	              usage:"display TAB characters as ^I"`
    
    	ShowNonprinting bool `clop:"-v;long" 
    	                      usage:"use ^ and M- notation, except for LFD and TAB" `
    
    	Files []string `clop:"args=files"`
    }
    
    func main() {
     	c := cat{}
    	err := clop.Bind(&c)
    
    	fmt.Printf("%#v, %s\n", c, err)
    }
    
    Source code(tar.gz)
    Source code(zip)
  • v0.0.11(Aug 19, 2020)

    see #55

    支持如果输入错误选项,推荐正确的选项。

    • 示例代码
    package main
    
    import (
    	"fmt"
    
    	"github.com/guonaihong/clop"
    )
    
    type T struct {
    	Num  int `clop:"--num" usage:"a"`
    	Rate int `clop:"--rate" usage:"b"`
    }
    
    func main() {
    	t := T{}
    	clop.Bind(&t)
    	fmt.Printf("%d:%d\n", clop.GetIndex("a"), clop.GetIndex("b"))
    
    	fmt.Printf("%v\n", t)
    
    }
    
    
    • 输出
    ./t --number
    error: Found argument '--number' which wasn't expected, or isn't valid in this context
    	Did you mean --num?
    
    For more information try --help
    
    
    Source code(tar.gz)
    Source code(zip)
  • v0.0.10(Jun 7, 2020)

  • v0.0.9(Jun 2, 2020)

  • v0.0.8(May 19, 2020)

  • v0.0.7(May 8, 2020)

  • v0.0.6(May 3, 2020)

    新增全局配置,可以关闭usage信息里面的default值

    issue 移步 #43

    package main
    
    import (
            "fmt"
            "github.com/guonaihong/clop"
    )
    
    type Hello struct {
            File string `clop:"-f; --file" usage:"file" default:"./my.log"`
    }
    
    func main() {
    
            clop.ShowUsageDefault = false // v0.0.6新加功能
    
            h := Hello{}
            clop.Bind(&h)
            fmt.Printf("%#v\n", h)
    }
    
    
    Source code(tar.gz)
    Source code(zip)
  • v0.0.5(Apr 29, 2020)

  • v0.0.4(Apr 22, 2020)

    #26 可以控制选项只能被设置一次

    package main
    
    import (
        "github.com/guonaihong/clop"
    )
    
    type Once struct {
        Debug bool `clop:"-d; --debug; once" usage:"debug mode"`
    }
    
    func main() {
        o := Once{}
        clop.Bind(&o)
    }
    /*
    ./once -debug -debug
    error: The argument '-d' was provided more than once, but cannot be used multiple times
    For more information try --help
    */
    

    #35 -h; --help选项可以被重载

    Source code(tar.gz)
    Source code(zip)
  • v0.0.3(Mar 31, 2020)

    #33 可以获取命令行选项优先级别

    package main
    
    import (
    	"fmt"
    	"github.com/guonaihong/clop"
    )
    
    type cat struct {
    	NumberNonblank bool `clop:"-b;--number-nonblank"
                                 usage:"number nonempty output lines, overrides"`
    
    	ShowEnds bool `clop:"-E;--show-ends"
                           usage:"display $ at end of each line"`
    }
    
    func main() {
    
    	c := cat{}
    	clop.Bind(&c)
    
    	if clop.GetIndex("number-nonblank") < clop.GetIndex("show-ends") {
    		fmt.Printf("cat -b -E\n")
    	} else {
    		fmt.Printf("cat -E -b \n")
    	}
    }
    // cat -be 
    // 输出 cat -b -E
    // cat -Eb
    // 输出 cat -E -b
    
    Source code(tar.gz)
    Source code(zip)
Owner
guonaihong
in coding as in eating? bit世界如此多娇,引无数英雄竞折腰。 俱往矣,数风流人物,还看今朝。
guonaihong