Package args

import "gitlab.com/zoralab/cerigo/os/args"

Package args is an extended command line interface processor from the standard library’s flag package. It uses the standard library’s “os.Args” as the primary input.

DIFFERENCES

  1. the Manager object is completely discardable after argument parsing.

  2. Help (-h, –help) is not run by default, allowing one to customize accordingly.

  3. Support flag with multiple argument labels like “-h”, “–help”, “help”.

SUPPORTED DATA TYPES

args package has limited data type conversion which is strictly towards the basic types. It does not use Go’s reflect package for code clarity reason. They are:

  1. int, int8, int16, int32, int64
  2. uint, uint8, uint16, uint32, uint64
  3. float32, float64
  4. bool
  5. []byte, *[]byte
  6. string

If you need to support some custom definition type, you need to convert it on your own. Any unsupported data types will be ignored in the conversion steps.

Important Note: You need to supply these data types' variable pointer into Flag’s Value element. Example, to support variable a that is int type, you fill in the Flag’s Value as &a instead. Here is an example: var a int f := Flag { … Value: &a, … }

UNSUPPORTED DATA TYPES

These are the data types that were confirmed not to be supported to keep the package sane to use. They are:

  1. any forms of array
  2. any forms of maps

Rationale: It is hard to track all permutations and combinations without using reflect package. Also, each time when array or maps occurs, it is use-case specific and can’t be generalized without complicated algorithms.

Hence, for these cases, user is advised to parse the entire list as string and then perform the splitting on your side.

Example

ackage args

import (
"fmt"
)

type exampleMyConfig struct {
actionstring
aint
bint
}

func (c *exampleMyConfig) Add() int {
return c.a + c.b
}

func Example() {
var err error
// ...you have your own configuration variables...
c := exampleMyConfig{}

// 1. create a manager
m := NewManager()
m.Name = "My Program Title"
m.Description = `
This is a long single paragraph description about the program. You can write
it this way using Go's raw string. Unicode is supported.
`
m.Version = "0.2.0"
m.Examples = []string{"",
"call for help:   $ ./program --help",
"set A        :   $ ./prgoram --set-a 123",
"set B        :   $ ./program --set-b 123",
}
m.ShowFlagExamples = true

// 2. add your flags accordingly
err = m.Add(&Flag{
Name:"help",
Label:[]string{"-h", "--help", "help"},
Value:&c.action,
Help:"to print help",
HelpExamples: []string{"",
"$ ./program -h",
"$ ./program --help",
"$ ./program help",
},
})
if err != nil {
// handle error
return
}

err = m.Add(&Flag{
Name:"set A",
Label:[]string{"-sa", "--set-a"},
Value:&c.a,
Help:"to add",
HelpExamples: []string{"",
"$ ./program -sa 123",
"$ ./program --set-a 123",
},
})
if err != nil {
// handle error
return
}

err = m.Add(&Flag{
Name:"set B",
Label:[]string{"-sb", "--set-b"},
Value:&c.b,
Help:"to add",
HelpExamples: []string{"",
"$ ./program -sb 123",
"$ ./program --set-b 123",
},
})
if err != nil {
// handle error
return
}

// 3. parse the flags
m.Parse()

// 4. execute based on your configs
switch c.action {
case "-h":
fallthrough
case "--help":
fallthrough
case "help":
// 5. generate help output from config
help := m.PrintHelp()
fmt.Printf("%s", help)
default:
fmt.Printf("total: %v\n", c.Add())
}
}

// Output CLI:
//
// u0:gosandbox$ ./main help
// MY PROGRAM TITLE (0.2.0)
// ────────────────────────
// This is a long single paragraph description about the program. You can write
// it this way using Go's raw string. Unicode is supported.
//
//
// USAGES
// ──────
// 1)  call for help:   $ ./program --help
// 2)  set A        :   $ ./prgoram --set-a 123
// 3)  set B        :   $ ./program --set-b 123
//
//
// ARGUMENTS
// ─────────
// -h, --help, help     to print help
//                      EXAMPLES
//                        1) $ ./program -h
//                        2) $ ./program --help
//                        3) $ ./program help
//
// -sa, --set-a         to add
//                      EXAMPLES
//                       1) $ ./program -sa 123
//                       2) $ ./program --set-a 123
//
// -sb, --set-b         to add
//                     EXAMPLES
//                       1) $ ./program -sb 123
//                       2) $ ./program --set-b 123
// u0:gosandbox$
// u0:gosandbox$ ./main -sa 43 -sb 123
// total: 166
// u0:gosandbox$

Constants

const (
	// ErrorMissingFlag is the error message for missing flag
	// object
	ErrorMissingFlag = "missing flag"

	// ErrorConflictedFlag is the error message for flag with
	// conflicted labels
	ErrorConflictedFlag = "detected conflicted label"
)

Flag

type Flag struct {
	Name         string
	Label        []string
	ValueLabel   string
	Value        interface{}
	Help         string
	HelpExamples []string
	DisableHelp  bool
	ExampleLabel string
	// contains filtered or unexported fields
}

Flag is the data structure for each of the argument types. It is safe to create using the conventional structure{} method. Flag needs the following minimum elements to work properly.

  1. Name
  2. Label
  3. Value
  4. Help

Once done, you can use the Manager’s Add(…) function to register the Flag object. If you encounter panics, usually that means there is a critical issue (e.g. conflicted Label) requires your attention.

ELEMENTS SPECIFICATIONS

  1. Name

Name is the element strictly for internal reference only. This is for code developers to reference or to search a particular flag based on the name without going through the Label slices.

This is compulsory to fill in.

  1. Label

These are the argument “flags” (e.g. -h, –help, help) saved in a string slice. A flag is only specific to one purpose but has the ability to offer different styles of inputs.

This is compulsory to fill in.

  1. ValueLabel

This is for labeling the value part of the value-taking arguments (e.g. –add [ VALUE ]). It only affects printing help statement and not the parsing algorithms. Example:

  1. If set to “number”, the help printout would be: “-h, –help, help [ NUMBER ]”
  2. If set to empty (""), the help printout would be: “-h, –help, help”
  3. If set to “名字”, the help printout would be: “-h, –help, help [ 名字 ]”

This is optional to fill in.

  1. Value

This is the variable pointer field for Flag to parse the results into. The value for this field MUST be a supported data types (see SUPPORTED DATA TYPES section) variable pointer. Otherwise, the parsed value will be discarded.

Passing a full variable (not a pointer) will not work for this field.

This is compulsory to fill in.

  1. Help

The argument help description. This single paragraph string holds the short explainations about the flag / arguments (usually printed to the right).

This package uses a word-wrap algorithm to style the output. Hence, if you pass a multi-paragraphs (are you mad?) string into this field, it will be wrapped into a single paragraph instead.

This is compulsory to fill in.

  1. Help Examples

This is for printing examples of use for the flag / arguments. It is meant for printing help statement. It is a string slice so you can supply as many as you want. Flag does automatic numbering so you do not need to do it manually. If the list is empty, it is treated as no examples. Example:

CASE 1 - If set to:
                  []string{}   OR    nil
The argument help output would be:
      -a, --append [ VALUE ]     to append a round number into the
                                 inputs. This can be a very long value
                                 and can be a very long description.

CASE 2 - If set to:
                  []string{"$ ./program -a 123",
                           "$ ./program --append 123",
                           "$ ./program -append '123'",
                  }
The argument help output would be:
      -a, --append [ VALUE ]     to append a round number into the
                                 inputs. This can be a very long value
                                 and can be a very long description.
                                 EXAMPLES
                                   1) $ ./program -a 123
                                   2) $ ./program --append 123
                                   3) $ ./program -append '123'

This is optional to fill in.

  1. DisableHelp

This is a switch to tell the manager to discard the printout for this flag while processng the arguments help output. The default is false (off).

This is optional to fill in.

  1. ExampleLabel

This is the string that alters the “EXAMPLES” text for the HelpExamples. It is offered explicitly to facilitate i18n. By default, it uses English word “Examples”.

This is optional to fill in.

Manager

type Manager struct {
	// program metadata
	Name             string
	Description      string
	Version          interface{}
	Examples         []string
	ShowFlagExamples bool

	// label texts for i18n
	ArgumentLabel string
	UsageLabel    string
	// contains filtered or unexported fields
}

Manager is the core arguments structure that holds all the flags and processes them accordingly.

This structure contains important private data elements so use NewManager() function to create one instead of the conventional structure{} method. Without doing so can cause unforseenable fatal error or panics.

ELEMENTS SPECIFICATIONS

  1. Name

Name is the program name where the field is used to print the overall help output in PrintHelp(…) function.

This is compulsory to fill in.

  1. Description

Description is a short explanation (limit it to 1 short paragraph) explaining the program. It is used to print the overall help output in PrintHelp(…) function. Unicode is supported.

This is compulsory to fill in.

  1. Version

Version is the version number of the program usually in the form of string or number types used to print the overall help output in PrintHelp(…) function.

This is optional to fill in.

  1. Examples

This is the “how-to” examples for using the program. It is a string slice offering the program “usage”, allowing users to quickly learn to use. Manager does automatic numbering so you do not need to do it manually. If the list is empty, it is treated as no examples. Example: CASE 1 - If set to: []string{} OR nil The argument help output would be: MY PROGRAM (0.2.0) ────────────────── η»΄ζŠ€ε–θ‰²ι»„θ‰²θ€ŒεŽζΆεŒ–θ€ŒθΏ™ζ˜―θ―θ―­η»΄ζŠ€ε–θ‰²ι»„θ‰²θ€ŒεŽζΆεŒ–θ€ŒθΏ™ζ˜―θ― θ€ŒθΏ™ζ˜―θ― θ―­η»΄ζŠ€ε–θ‰² ι»„θ‰²θ€ŒεŽ ζΆεŒ–θ€Œ θΏ™ζ˜―θ―θ―­ η»΄ζŠ€ε– ι»„θ‰²θ€ŒεŽζΆεŒ–θ€ŒθΏ™ ζ˜―θ―θ―­η»΄ζŠ€ε–θ‰²ι»„ θ‰²θ€Œ

          ARGUMENTS
          ─────────
          ...

CASE 2 - If set to:
              []string{"",
                       "$ ./program --help",
                       "$ ./program --list",
              }
The argument help output would be:
          MY PROGRAM (0.2.0)
          ──────────────────
          η»΄ζŠ€ε–θ‰²ι»„θ‰²θ€ŒεŽζΆεŒ–θ€ŒθΏ™ζ˜―θ―θ―­η»΄ζŠ€ε–θ‰²ι»„θ‰²θ€ŒεŽζΆεŒ–θ€ŒθΏ™ζ˜―θ―
          θ€ŒθΏ™ζ˜―θ― θ―­η»΄ζŠ€ε–θ‰² ι»„θ‰²θ€ŒεŽ ζΆεŒ–θ€Œ θΏ™ζ˜―θ―θ―­ η»΄ζŠ€ε–
          ι»„θ‰²θ€ŒεŽζΆεŒ–θ€ŒθΏ™ ζ˜―θ―θ―­η»΄ζŠ€ε–θ‰²ι»„ θ‰²θ€Œ

          USAGES
          ──────
          1)  $ ./program --help
          2)  $ ./program --list

          ARGUMENTS
          ─────────
          ...

This is optional to fill in.

  1. ShowFlagExamples

This is the master switch to show all flag respective examples. By default, it is false (off).

This is optional to fill in.

  1. ArgumentLabel

This is the string that alters the ARGUMENT title in the help printout. It is offered explicitly to facilitate i18n. By default, it uses English word “ARGUMENTS”.

This is optional to fill in.

  1. UsageLabel

This is the string that alters the USAGE title in the help printout. It is offered explicitly to facilitate i18n. By default, it uses English word “USAGES”.

Func NewManager() *Manager

NewManager creates and initializes the Manager structure ready for use.

Func (m *Manager) Add(f *Flag) error

Add takes a Flag object and registers into the manager.

It returns:

  1. nil - successful register
  2. err - error occurred (e.g. missing flag)
  3. panic - critical error requires upfront attention (e.g. conflicted labels)

Func (m *Manager) Parse()

Parse starts the argument parsing process.

Func (m *Manager) PrintHelp() (out string)

PrintHelp creates the help menu based on the given flags and manager’s data. It will output the final formatted string with help contents ready for printout.

It returns:

  1. string - the help statement