hzDocs
hzDocs
Articles / Postshedzr.comIntroduction

Guide

Your First CLI AppConcise Version
Step by step
Concepts
CommandCommand: Invoke programCommand: Presetting ArgsCommand: RedirectToCommand: DynCommandCommand: Aliases from ConfigCommand: Event HandlersFlagFlag: RequiredFlag: Toggle GroupFlag: Valid ArgsFlag: `Head -1` styleFlag: External EditorFlag: NegatableFlag: Leading Plus Sign `+`Flag: Event Handlers解析结果Builtin Commands & Flags帮助子系统Shared App辨析Package level functionsWithOptsBackstage
Howto ...
Auto-close the ClosersRead config into structUsing is DetectorsUsing Store

References

What's New
Packages

Others

Examples
Blueprint
产品发布
产品发布之前

Concise Version

Best practise for project layout

Small app with a better project layout

In last examples, we show you how to create a tiny CLI app from scratch, by cmdr.

It has a clear code ochestration step by step, including how to build a cli.App object, to add commands and to add flags into it, and so on.

And, in a truth, there is another way to clearify all of above, by Create().

The Builder interface returned by Create() supports these methods: WithAdders(...) can receive a set of subcommand definitions, and adds bunch of them into app.RootCommand.

Tip

Create() is our recommendation when using cmdr.v2.

./examples/tiny1/main.go
package main

import (
	"context"
	"os"

	"github.com/hedzr/cmdr/v2"
	"github.com/hedzr/cmdr/v2/examples/cmd"
	"github.com/hedzr/cmdr/v2/pkg/logz"
)

const (
	appName = "concise"
	desc    = `concise version of tiny app.`
	version = cmdr.Version
	author  = `The Example Authors`
)

func main() {
	app := cmdr.Create(appName, version, author, desc).
		WithAdders(cmd.Commands...).
		Build()

	ctx := context.Background()
	if err := app.Run(ctx); err != nil {
		logz.ErrorContext(ctx, "Application Error:", "err", err) // stacktrace if in debug mode/build
		os.Exit(app.SuggestRetCode())
	} else if rc := app.SuggestRetCode(); rc != 0 {
		os.Exit(rc)
	}
}
./examples/cmd/all.go
package cmd

import (
	"github.com/hedzr/cmdr/v2/cli"
)

var Commands = []cli.CmdAdder{
	jumpCmd{},
	// wrongCmd{},
}
./examples/cmd/all.go
package cmd

import (
	"context"

	"github.com/hedzr/cmdr/v2"
	"github.com/hedzr/cmdr/v2/cli"
	"github.com/hedzr/cmdr/v2/examples/dyncmd"
	"github.com/hedzr/cmdr/v2/pkg/dir"
	logz "github.com/hedzr/logg/slog"
)

type jumpCmd struct{}

func (jumpCmd) Add(app cli.App) {
	app.Cmd("jump").
		Description("jump command").
		Examples(`jump example`). // {{.AppName}}, {{.AppVersion}}, {{.DadCommands}}, {{.Commands}}, ...
		Deprecated(`v1.1.0`).
		Group("Test").
		// Group(cli.UnsortedGroup).
		// Hidden(false).
		// OnEvaluateSubCommands(dyncmd.OnEvalJumpSubCommands).
		// Both With(cb) and Build() to end a building sequence
		With(func(b cli.CommandBuilder) {
			b.Cmd("to").
				Description("to command").
				Examples(``).
				Deprecated(`v0.1.1`).
				OnAction(func(ctx context.Context, cmd cli.Cmd, args []string) (err error) {
					// cmd.Set() == cmdr.Set(), cmd.Store() == cmdr.Store(cmd.GetDottedPath())
					_, _ = cmd.Set().Set("tiny3.working", dir.GetCurrentDir())
					println()
					println("dir:", cmd.Set().WithPrefix("tiny3").MustString("working"))

					cs := cmd.Set().WithPrefix(cli.CommandsStoreKey, "jump.to")
					if cs.MustBool("full") {
						println()
						println(cmd.Set().Dump())
					}
					cs2 := cmd.Store()
					if cs2.MustBool("full") != cs.MustBool("full") {
						logz.Panic("a bug found")
					}
					app.SetSuggestRetCode(1) // ret code must be in 0-255
					return                   // handling command action here
				}).
				With(func(b cli.CommandBuilder) {
					b.Flg("full", "f").
						Default(false).
						Description("full command").
						Build()
				})
		})
}
all.go
jump.go
main.go

In the subpackage cmd/, you can split each subcommand definition within a standalone file.

All of these commands will be collected as var Commands, in cmd/all.go, then passed into Create(...).WithAdders(cmd.Commands...).

So we think it is a better style.

Although it does not make the codes less.

With Store, and loading external sources

This topic will be discussed at next two sections.

The forecast is, by using loaders.Create instead of cmdr.Create, you will get it done.

What is Next?

How is this guide?

Last updated on

Your First CLI App

Getting Started

Step by step

Getting Started

On this page

Small app with a better project layout
With Store, and loading external sources