Skip to content

moul/climan

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

5 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

climan

πŸ˜„ CLI manager library, heavily inspired by ffcli.

go.dev reference License GitHub release Docker Metrics Made by Manfred Touron

Go Release PR GolangCI codecov Go Report Card CodeFactor

Gitpod ready-to-code

This package is originally based on peterbourgon's ff package (Apache2 License).

It implements small changes that don't fit with the original's author Goals and Non-goals.


Changes include:

  • Adding an optional Command.FlagSetBuilder callback to configure commands and subcommands dynamically and support sharing the same flag targets.
  • Using flag.ContinueOnError by default instead of flag.ExitOnError.
  • Printing usage instead of an returning an error if a command does not implements an Exec func.
  • Use a different DefaultUsageFunc.

Example

import (
	"context"
	"flag"
	"fmt"
	"log"
	"os"

	"github.com/peterbourgon/ff/v3"
	"moul.io/climan"
)

var opts struct {
	debug   bool
	fooFlag string
}

func Example() {
	root := &climan.Command{
		Name:       "example",
		ShortUsage: "example [global flags] <subcommand> [flags] [args...]",
		ShortHelp:  "example's short help",
		LongHelp:   "example's longer help.\nwith more details.",
		FlagSetBuilder: func(fs *flag.FlagSet) {
			fs.BoolVar(&opts.debug, "debug", opts.debug, "debug mode")
		},
		Exec: doRoot,
		Subcommands: []*climan.Command{
			&climan.Command{
				Name: "foo",
				FlagSetBuilder: func(fs *flag.FlagSet) {
					fs.BoolVar(&opts.debug, "debug", opts.debug, "debug mode")
					fs.StringVar(&opts.fooFlag, "flag", opts.fooFlag, "foo's flag")
				},
				ShortUsage: "foo [flags]",
				ShortHelp:  "foo things",
				Exec:       doFoo,
			},
		},
		FFOptions: []ff.Option{ff.WithEnvVarPrefix("EXAMPLE")},
	}

	if err := root.Parse(os.Args[1:]); err != nil {
		log.Fatal(fmt.Errorf("parse error: %w", err))
	}

	if err := root.Run(context.Background()); err != nil {
		log.Fatal(fmt.Errorf("run error: %w", err))
	}
}

func doRoot(ctx context.Context, args []string) error {
	fmt.Println("args", args)
	return nil
}

func doFoo(ctx context.Context, args []string) error {
	fmt.Println("flag", opts.fooFlag)
	return nil
}

Usage

TYPES

type Command struct {
	Name           string
	Exec           func(context.Context, []string) error
	FlagSetBuilder func(fs *flag.FlagSet)
	Subcommands    []*Command
	ShortUsage     string
	ShortHelp      string
	LongHelp       string
	FFOptions      []ff.Option
	FlagSet        *flag.FlagSet
	UsageFunc      func(c *Command) string

	// Has unexported fields.
}

func (c *Command) Parse(args []string) error

func (c *Command) Run(ctx context.Context) error

Install

Using go

go get moul.io/climan

Releases

See https://github.com/moul/climan/releases

Contribute

Contribute <3

I really welcome contributions. Your input is the most precious material. I'm well aware of that and I thank you in advance. Everyone is encouraged to look at what they can do on their own scale; no effort is too small.

Everything on contribution is sum up here: CONTRIBUTING.md

Dev helpers

Pre-commit script for install: https://pre-commit.com

Contributors ✨

All Contributors

Thanks goes to these wonderful people (emoji key):


Manfred Touron

🚧 πŸ“– ⚠️ πŸ’»

moul-bot

🚧

This project follows the all-contributors specification. Contributions of any kind welcome!

Stargazers over time

Stargazers over time

License

Β© 2021 Manfred Touron

Licensed under the Apache License, Version 2.0 (LICENSE-APACHE) or the MIT license (LICENSE-MIT), at your option. See the COPYRIGHT file for more details.

SPDX-License-Identifier: (Apache-2.0 OR MIT)