clix

package module
v0.1.1-0...-d3e9ef5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 23, 2020 License: MIT Imports: 8 Imported by: 0

README

clix

godoc Licence Latest version

Build Status Code quality Code coverage

Modulable CLI builder that call agnostic go idiomatic isolated cli handler, inspired by net/http.

Motivation

As of today, there are very few nice library to use to handle command line interface; one of them is cobra. It is not super obvious how to make cobra-agnostic cli handler that have dependencies (like a logger, some usecases, ...) that can be injected (so that the handler can be properly tested). This project aims to define cli command tree in a visual way (through the builder pattern) with an easy way to decorelate handler from cli initialization, and to help injecting dependencies (that requires flags to be build for example) in subcommands (like a logger, a database, ...).

Usage and example

// TODO More doc and examples in the clix's godoc.

License

This project is under the MIT licence, please see the LICENCE file.

Documentation

Overview

Package clix ...

Example
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/krostar/clix"
	"github.com/krostar/logger"
	"github.com/spf13/cobra"
)

func main() {
	// cli is buildable and modulable
	// here we use the default root command that does nothing
	cli := clix.Command(commandA)

	// or even more complex command tree
	cli = cli.SubCommand(clix.
		Command(commandB).
		SubCommand(commandBB).
		Build(),
	)

	// let's add even more commands
	cli = cli.SubCommand(commandC)

	/*
		Which produces the following command tree:

		commandA
		├── commandB
		│   └── commandBB
		└── commandC
	*/

	// once the cli is defined, we only have to execute it with chosen context and arguments
	// context can be set to be canceled by CTRL+C, timeout, ...
	// depending on the task executed (cron, daemon, ...)
	// here we use an empty one
	ctx := context.Background()
	// args should probably be set to os.Args
	// but for simplicity sake here we hardcode them
	args := []string{"commandB", "commandBB"}

	if err := cli.Exec(ctx, args); err != nil {
		// something didn't worked as expected
		log.Println(fmt.Errorf("cli execution failed: %w", err))
	}

}

// commandBB builds the BB cobra command, define flags, ...
func commandBB(ctx context.Context) (*cobra.Command, context.Context, error) {
	return &cobra.Command{
		Use: "commandBB",
		RunE: clix.ExecHandler(ctx, func(showHelp func()) (clix.Handler, error) {
			// inject any dependencies the bb command handler needs
			return &handleBB{
				help: showHelp,
				log:  clix.LoggerFromContext(ctx),
			}, nil
		}),
	}, ctx, nil
}

// handleBB implements clix.Handler, is a clean, cobra-unrelated, reusable
// function that handle the bb command
type handleBB struct {
	help func()
	log  logger.Logger
}

// abstract cli handler that call whatener business logic it needs
// following whatever architecture it wants, 100% testable as every dependencies are injected
func (h handleBB) Handle(ctx context.Context, args, dashed []string) error {
	fmt.Println("bb handled")
	return nil
}

func commandA(ctx context.Context) (*cobra.Command, context.Context, error) {
	return &cobra.Command{
		Use: "commandA",
		Run: func(cmd *cobra.Command, args []string) {},
	}, ctx, nil
}

func commandB(ctx context.Context) (*cobra.Command, context.Context, error) {
	return &cobra.Command{
		Use: "commandB",
		Run: func(cmd *cobra.Command, args []string) {},
	}, ctx, nil
}

func commandC(ctx context.Context) (*cobra.Command, context.Context, error) {
	return &cobra.Command{
		Use: "commandC",
		Run: func(cmd *cobra.Command, args []string) {},
	}, ctx, nil
}
Output:
bb handled

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func ExecHandler

func ExecHandler(ctx context.Context, getHandler GetHandlerFunc) func(*cobra.Command, []string) error

ExecHandler execs the provided handler function.

func LoggerFromContext

func LoggerFromContext(ctx context.Context) logger.Logger

LoggerFromContext returns the logger from the context, if present

func NewContextCancelableBySignal

func NewContextCancelableBySignal(signals ...os.Signal) (context.Context, func())

NewContextCancelableBySignal creates a new context that cancels when provided signals are triggered.

Types

type CLI

type CLI struct {
	// contains filtered or unexported fields
}

CLI stores the command line interfaces command and subcommands.

func Command

func Command(command CommandBuilderFunc) *CLI

Command creates a new root cli instance.

func (*CLI) Build

func (cli *CLI) Build() CommandBuilderFunc

Build return a concatenated command builder that adds all subcommands to the root command.

func (*CLI) Exec

func (cli *CLI) Exec(ctx context.Context, args []string) error

Exec executes the command given by args.

func (*CLI) SubCommand

func (cli *CLI) SubCommand(cmd CommandBuilderFunc) *CLI

SubCommand adds a sub command to the main command.

type CommandBuilderFunc

type CommandBuilderFunc func(context.Context) (*cobra.Command, context.Context, error)

CommandBuilderFunc defines a cobra command builder func.

func WithLogger

WithLogger adds to an existing command log flags, and config requirements.

type GetHandlerFunc

type GetHandlerFunc func(help func()) (Handler, error)

GetHandlerFunc returns a handler, providing it's help function.

type Handler

type Handler interface {
	Handle(ctx context.Context, args []string, dashedArgs []string) error
}

Handler abstracts a cli command handler.

type HandlerFunc

type HandlerFunc func(ctx context.Context, args []string, dashedArgs []string) error

HandlerFunc implements Handler.

func (HandlerFunc) Handle

func (h HandlerFunc) Handle(ctx context.Context, args []string, dashedArgs []string) error

Handle implement Handler.

type LoggerCommandOption

type LoggerCommandOption func(o *loggerCommandOptions)

LoggerCommandOption defines the signature of an option applier.

func LoggerWithAppName

func LoggerWithAppName(appName string) LoggerCommandOption

LoggerWithAppName sets the root command app name.

func LoggerWithCreateFunc

func LoggerWithCreateFunc(fct func(log logger.Config) (logger.Logger, error)) LoggerCommandOption

LoggerWithCreateFunc sets the logger creation function.

func LoggerWithPersistentFlagsFunc

func LoggerWithPersistentFlagsFunc(fct func(flags *pflag.FlagSet, cfg *logger.Config)) LoggerCommandOption

LoggerWithPersistentFlagsFunc overrides the defaults persistent flag set.

func LoggerWithVersion

func LoggerWithVersion(version string) LoggerCommandOption

LoggerWithVersion sets the root command app version.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL