Skip to content

Latest commit

 

History

History
298 lines (228 loc) · 10.5 KB

README.md

File metadata and controls

298 lines (228 loc) · 10.5 KB

cmdr

Go GitHub tag (latest SemVer) GoDoc FOSSA Status go.dev Go Report Card codecov Mentioned in Awesome Go

cmdr is a POSIX-compliant, command-line UI (CLI) library in Golang. It is a getopt-like parser of command-line options, be compatible with the getopt_long command line UI, which is an extension of the syntax recommended by POSIX.

We made many enhancements beyond the standard library flag.

There is a fully-functional Options Store (configurations) for your hierarchical configuration dataset too.

The .netCore version Cmdr.Core is available now. And, a cxx version cmdr-cxx was pre-released just now (Happy Spring Festival 2021).

ee99d078e2f7

See the image frames at #1.

See our extras:

and Bonus of #cmdr Series:

News

  • docs (WIP):

  • v1.11.9 (FRZ)

    • upgrade [hedzr/log](https:/github.com/hedzr/log) to simplify error branch and log.Fatal
    • security maintains
    • added new ExecOptions: WithIIfOpt(cond, true_opt, false_opt) & WithIfOpt(cond, true_opt)
  • v1.11.8 (FRZ)

    • upgrade [hedzr/errors.v3](https:/github.com/hedzr/errors) to compliant with go1.20+
  • ...

  • v1.11.5 (FRZ)

    • replace old clone codes with [hedzr/evendeep](https://github.com/hedzr/evendeep)
    • BROKEN: remove supports to go1.13 - go1.16 since our go.mod can't work for them after upgrade golang/x packages.
  • ...

  • v1.10.49 (FRZ)

    • NOTE: we declared a go1.18 Module in go.mod.
    • ...
  • More details at CHANGELOG

Features

Features.md

Old README.md: README.old.md

For Developer

For Developer

Fast Guide

See example-app, examples/, and cmdr-examples

Expand to source codes
package main

import (
	"fmt"

	"github.com/hedzr/cmdr"
	"github.com/hedzr/cmdr/plugin/pprof"
	"github.com/hedzr/cmdr/tool"
	"github.com/hedzr/log"
	"github.com/hedzr/log/buildtags"
	"github.com/hedzr/log/isdelve"
	"github.com/hedzr/logex/build"
	"gopkg.in/hedzr/errors.v3"
)

func main() {
	Entry()
}

func Entry() {
	root := buildRootCmd()
	if err := cmdr.Exec(root, options...); err != nil {
		log.Fatalf("error occurs in app running: %+v\n", err)
	}
}

func buildRootCmd() (rootCmd *cmdr.RootCommand) {
	root := cmdr.Root(appName, version).
		// AddGlobalPreAction(func(cmd *cmdr.Command, args []string) (err error) {
		//	// cmdr.Set("enable-ueh", true)
		//	return
		// }).
		// AddGlobalPreAction(func(cmd *cmdr.Command, args []string) (err error) {
		//	//fmt.Printf("# global pre-action 2, exe-path: %v\n", cmdr.GetExecutablePath())
		//	return
		// }).
		// AddGlobalPostAction(func(cmd *cmdr.Command, args []string) {
		//	//fmt.Println("# global post-action 1")
		// }).
		// AddGlobalPostAction(func(cmd *cmdr.Command, args []string) {
		//	//fmt.Println("# global post-action 2")
		// }).
		Copyright(copyright, "hedzr").
		Description(desc, longDesc).
		Examples(examples)
	rootCmd = root.RootCommand()

	// for your biz-logic, constructing an AttachToCmdr(root *cmdr.RootCmdOpt) is recommended.
	// see our full sample and template repo: https://github.com/hedzr/cmdr-go-starter
	// core.AttachToCmdr(root.RootCmdOpt())

	// These lines are removable

	cmdr.NewBool(false).
		Titles("enable-ueh", "ueh").
		Description("Enables the unhandled exception handler?").
		AttachTo(root)
	// cmdrPanic(root)
	cmdrSoundex(root)
	// pprof.AttachToCmdr(root.RootCmdOpt())
	return
}

func cmdrSoundex(root cmdr.OptCmd) {
	cmdr.NewSubCmd().Titles("soundex", "snd", "sndx", "sound").
		Description("soundex test").
		Group("Test").
		TailPlaceholder("[text1, text2, ...]").
		Action(func(cmd *cmdr.Command, args []string) (err error) {
			for ix, s := range args {
				fmt.Printf("%5d. %s => %s\n", ix, s, tool.Soundex(s))
			}
			return
		}).
		AttachTo(root)
}

func onUnhandledErrorHandler(err interface{}) {
	if cmdr.GetBoolR("enable-ueh") {
		dumpStacks()
	}

	panic(err) // re-throw it
}

func dumpStacks() {
	fmt.Printf("\n\n=== BEGIN goroutine stack dump ===\n%s\n=== END goroutine stack dump ===\n\n", errors.DumpStacksAsString(true))
}

func init() {
	options = append(options,
		cmdr.WithUnhandledErrorHandler(onUnhandledErrorHandler),

		// cmdr.WithLogxShort(defaultDebugEnabled,defaultLoggerBackend,defaultLoggerLevel),
		cmdr.WithLogx(build.New(build.NewLoggerConfigWith(
			defaultDebugEnabled, defaultLoggerBackend, defaultLoggerLevel,
			log.WithTimestamp(true, "")))),

		cmdr.WithHelpTailLine(`
# Type '-h'/'-?' or '--help' to get command help screen.
# Star me if it's helpful: https://github.com/hedzr/cmdr/examples/example-app
`),
	)

	if isDebugBuild() {
		options = append(options, pprof.GetCmdrProfilingOptions())
	}

	// enable '--trace' command line option to toggle a internal trace mode (can be retrieved by cmdr.GetTraceMode())
	// import "github.com/hedzr/cmdr-addons/pkg/plugins/trace"
	// trace.WithTraceEnable(defaultTraceEnabled)
	// Or:
	optAddTraceOption := cmdr.WithXrefBuildingHooks(func(root *cmdr.RootCommand, args []string) {
		cmdr.NewBool(false).
			Titles("trace", "tr").
			Description("enable trace mode for tcp/mqtt send/recv data dump", "").
			// Action(func(cmd *cmdr.Command, args []string) (err error) { println("trace mode on"); cmdr.SetTraceMode(true); return; }).
			Group(cmdr.SysMgmtGroup).
			AttachToRoot(root)
	}, nil)
	options = append(options, optAddTraceOption)
	// options = append(options, optAddServerExtOpt«ion)

	// allow and search '.<appname>.yml' at first
	locations := []string{".$APPNAME.yml"}
	locations = append(locations, cmdr.GetPredefinedLocations()...)
	options = append(options, cmdr.WithPredefinedLocations(locations...))

	// options = append(options, internal.NewAppOption())
}

var options []cmdr.ExecOption

func isDebugBuild() bool         { return isdelve.Enabled }
func isDockerBuild() bool        { return buildtags.IsDockerBuild() }
func isRunningInDockerEnv() bool { return cmdr.InDockerEnv() }

//goland:noinspection GoNameStartsWithPackageName
const (
	appName   = "example-app"
	version   = "0.2.5"
	copyright = "example-app - A devops tool - cmdr series"
	desc      = "example-app is an effective devops tool. It make an demo application for 'cmdr'"
	longDesc  = `example-app is an effective devops tool. It make an demo application for 'cmdr'.
`
	examples = `
$ {{.AppName}} gen shell [--bash|--zsh|--fish|--auto]
  generate bash/shell completion scripts
$ {{.AppName}} gen man
  generate linux man page 1
$ {{.AppName}} --help
  show help screen.
$ {{.AppName}} --help --man
  show help screen in manpage viewer (for linux/darwin).
`
	// overview = ``
	// zero = 0

	// defaultTraceEnabled  = true
	defaultDebugEnabled  = false
	defaultLoggerLevel   = "debug"
	defaultLoggerBackend = "logrus"
)

Tips for Building Your App

As building your app with cmdr, some build tags are suggested:

export GIT_REVISION="$(git rev-parse --short HEAD)"
export GIT_SUMMARY="$(git describe --tags --dirty --always)"
export GOVERSION="$(go version)"
export BUILDTIME="$(date -u '+%Y-%m-%d_%H-%M-%S')"
export VERSION="$(grep -E "Version[ \t]+=[ \t]+" doc.go|grep -Eo "[0-9.]+")"
export W_PKG="github.com/hedzr/cmdr/conf"
export LDFLAGS="-s -w \
    -X '$W_PKG.Githash=$GIT_REVISION' \
    -X '$W_PKG.GitSummary=$GIT_SUMMARY' \
    -X '$W_PKG.GoVersion=$GOVERSION' \
    -X '$W_PKG.Buildstamp=$BUILDTIME' \
    -X '$W_PKG.Version=$VERSION'"

go build -v -ldflags "$LDFLAGS" -o ./bin/your-app ./your-app/

Contrib

Feel free to issue me bug reports and fixes. Many thanks to all contributors.

Thanks to JODL

Thanks to JetBrains for donating product licenses to help develop cmdr
jetbrains goland

License

MIT

FOSSA Status