Giter Site home page Giter Site logo

go-clipper's Introduction

clipper

A simple Go package to parse command-line arguments getopt(3) style. Designed especially for making CLI based libraries with ease. It has built-in support for sub-commands, long and short flag name combination (for example --version <==> -v), --flag=<value> syntax, inverted flag (for example --no-clean), variadic arguments for long-style flags(_for example --dir... /data1 /data2), etc.

Main advantage - state might be reset to initial state (to default values and set unchanged). So can be simple reused in embedded interactive CLI.

Based on clapper, but typed (not string for all) and has more features.

Can be simple extended for additional types (see Value interface, base on extended pflag).

Documentation

pkg.go.dev

Installation

$ go get "github.com/msaf1980/go-clipper"

Usage

// cmd.go
package main

import (
	"fmt"
	"os"

	"github.com/msaf1980/go-clipper"
)

var (
	VERSION = "0.0.1"
)

func main() {

	var (
		rootForce, rootVerbose bool
		rootDir   string
		root                   []string

		infoVerbose, infoNoClean bool
		infoVersion, infoOutput  string

		list, listDir []string
		listVerbose int
	)

	// create a new registry
	registry := clipper.NewRegistry("programm description message")

	// register the root command
	if _, ok := os.LookupEnv("NO_ROOT"); !ok {
		rootCommand, _ := registry.Register("", "root help") // root command
		// rootCommand.AddArg("output", "")                    //
		rootCommand.AddFlag("force", "f", &rootForce, "flag help")             // --force, -f | default value: "false"
		rootCommand.AddFlag("verbose", "v", &rootVerbose, "flag help")         // --verbose, -v | default value: "false"
		rootCommand.AddString("dir", "d", "/var/users", &rootDir, "flag help") // --dir <value> | default value: "/var/users"
		rootCommand.AddStringArgs(-1, &root, "args help") // root unnamed args
		rootCommand.AddVersionHelper("version", "V", registry.Description, VERSION)
	}

	// register the `info` sub-command
	infoCommand, _ := registry.Register("info", "info help")              // sub-command
	infoCommand.AddFlag("verbose", "v", &infoVerbose, "flag help")        // --verbose, -v | default value: "false"
	infoCommand.AddString("version", "V", "", &infoVersion, "flag help"). // --version, -V | default value: "false"
									SetValidValues([]string{"", "1.0.1", "2.0.0"}). // valid versions
									SetRequired(true)                               // version are required
	infoCommand.AddString("output", "o", "./", &infoOutput, "flag help") // --output, -o <value> | default value: "./"
	infoCommand.AddFlag("no-clean", "N", &infoNoClean, "flag help")      // --no-clean | default value: "true"

	listCommand, _ := registry.Register("list", "list help")                     // sub-command
	listCommand.AddStringArray("dir", "d", []string{"a"}, &listDir, "flag help") // --output, -o <value> | default value: "./"
	listCommand.AddStringArgs(-1, &list, "args help")
	listCommand.AddCounterFlag("verbose", "v", &listVerbose, "multi-flag verbose") // --verbose, -v | default value: 0

	// register the `ghost` sub-command
	ghostCommand, _ := registry.Register("ghost", "ghost help")
	ghostCommand.AddVersionHelper("version", "V", registry.Description, VERSION)

	/*----------------*/

	// parse command-line arguments
	command, err := registry.Parse(os.Args[1:])

   	// For interactive use (don't exit after help print, check helpRequested and break command execution if set)
   	// command, helpRequested, err := registry.ParseInteract(os.Args[1:], false)
   	// if !helpRequested {
   	// // execute command
   	//     ..
   	// }

	/*----------------*/

	// check for error
	if err != nil {
		fmt.Printf("error => %#v\n", err)
		return
	}

    // get executed sub-command name
	fmt.Printf("sub-command => %#v\n  Dump variables\n", command)
	c := registry.Commands[command]
	for _, name := range c.OptsOrder {
		opt := c.Opts[name]
		fmt.Printf("    %s=%q\n", name, opt.Value.String())
	}
	// get unnamed args
	if args := c.Args.String(); args != "" {
		fmt.Printf("    args=%s\n", args)
	}}
}

In the above example, we have registred a root command and an info command. The registry can parse arguments passed to the command that executed this program.

Example 1

When the root command is executed with no command-line arguments.

$ go run demo/cmd.go

sub-command => ""
  Dump variables
    force="false"
    verbose="false"
    version=""
    dir="/var/users"
    args=[]

Example 2

When the root command is executed but not registered.

$ NO_ROOT=TRUE go run demo/cmd.go

error => clipper.ErrorUnknownCommand{Name:""}

Example 3

When the root command is executed with short/long flag names as well as by changing the positions of the arguments.

$ go run demo/cmd.go userinfo -V 1.0.1 -v --force --dir ./sub/dir
$ go run demo/cmd.go -V 1.0.1 --verbose --force userinfo --dir ./sub/dir
$ go run demo/cmd.go -V 1.0.1 -v --force --dir ./sub/dir userinfo
$ go run demo/cmd.go --version 1.0.1 --verbose --force --dir ./sub/dir userinfo

sub-command => ""
  Dump variables
    force="true"
    verbose="true"
    version="1.0.1"
    dir="./sub/di"
    args=[userinfo]

Example 4

When an unregistered flag is provided in the command-line arguments.


$ go run demo/cmd.go userinfo -V 1.0.1 -v --force --d ./sub/dir
error => clipper.ErrorUnknownFlag{Name:"--d"}

$ go run demo/cmd.go userinfo -V 1.0.1 -v --force --directory ./sub/dir
error => clipper.ErrorUnknownFlag{Name:"--directory"}

Example 5

When information was intended to be a sub-command but not registered and the root command accepts arguments.

$ go run demo/cmd.go information --force

sub-command => ""
  Dump variables
    force="true"
    verbose="false"
    version=""
    dir="/var/users"
    args=[information]

Example 6

When an unnamed args (not allowed) is provided in the command-line arguments.

$ go run demo/cmd.go info student -V -v --output ./opt/dir

error => clipper.ErrorUnsupportedFlag{Name:"student"}

Example 7

When a command is executed with an inverted flag (flag that starts with --no- prefix).

$ go run demo/cmd.go info -V -v --output ./opt/dir --no-clean

sub-command => "info"
  Dump variables
    verbose="true"
    version=""
    output="./opt/dir"
    clean="false

Example 8

When the position of argument values are changed and variadic arguments are provided.

$ go run demo/cmd.go list student --dir... /data1 /data2

sub-command => "list"
  Dump variables
    dir="[/data1,/data2]"
    args=[student]

Example 9

When a sub-command is registered without any flags.

$ go run demo/cmd.go ghost -v thatisuday -V 2.0.0 teachers

error => clipper.ErrorUnknownFlag{Name:"-v"}

Example 10

When a sub-command is registered without any arguments.

$ go run demo/cmd.go ghost
$ go run demo/cmd.go ghost thatisuday extra

sub-command => "ghost

Example 11

When the root command is not registered or the root command is registered with no arguments.

$ NO_ROOT=TRUE go run demo/cmd.go information
error => clipper.ErrorUnknownCommand{Name:"information"}

$ go run cmd.go ghost
sub-command => "ghost"

Example 12

When unsupported flag format is provided.

$ go run demo/cmd.go ---version 
error => clipper.ErrorUnsupportedFlag{Name:"---version"}

$ go run demo/cmd.go ---v=1.0.0 
error => clipper.ErrorUnsupportedFlag{Name:"---v"}

$ go run demo/cmd.go -version 
error => clipper.ErrorUnsupportedFlag{Name:"-version"}

$ go run demo/cmd.go list student -d... /data1 /data2
error => clipper.ErrorUnsupportedFlag{Name:"-d..."}

Contribution

A lot of improvements can be made to this library, one of which is the support for combined short flags, like -abc. If you are willing to contribute, create a pull request and mention your bug fixes or enhancements in the comment.

go-clipper's People

Contributors

msaf1980 avatar

Stargazers

Andrew Johnson avatar

Watchers

 avatar

go-clipper's Issues

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.