clifx

package module
v0.0.5 Latest Latest
Warning

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

Go to latest
Published: Mar 3, 2025 License: Apache-2.0 Imports: 5 Imported by: 1

README

clifx

Build Status codecov.io Go Report Card Apache V2 License GitHub Release GoDoc

Summary

Provides basic bootstrapping for a parsed command line into an fx.App. Kong is used to parse a command line into an arbitrary golang struct.

Table of Contents

Code of Conduct

This project and everyone participating in it are governed by the XMiDT Code Of Conduct. By participating, you agree to this Code.

Installation

go get github.com/xmidt-org/clifx@latest

Usage

Basic
import github.com/xmidt-org/clifx

type MyCLI struct {
  Debug bool
  Files []string
}

func main() {
  app := fx.New(
    clifx.Provide[MyCLI](
      clifx.StandardArguments(),
    ),
  
    // a component of type MyCLI will now
    // be available for dependency injection.
    // For example:
    fx.Invoke(
      func(cli MyCLI) error {
        // do things
        return nil
      },
    ),

    // you can bind dependencies to the kong.Context.  if desired,
    // you must do this before calling kong.Context.Run:
    fx.Supply("dependency"),
    fx.Invoke(
      func(kctx *kong.Context, dependency string) {
        kctx.Bind(dependency) // this is now available in CLI methods
      }
    ),

    // the kong.Context can be used to run the CLI.
    // This will cause fx.New to run the command:
    fx.Invoke(
      func(kctx *kong.Context, sh fx.Shutdowner) error {
        defer sh.Shutdown() // optional: this ensures the app exits from app.New
        return kctx.Run() // you could pass dependencies to Run
      },
    )
  )
}
Lifecycle

You can bind a CLI to the fx.Lifecycle in the same way as any other component. For example, it's common to want to run the CLI when fx.App.Run is called, then shutdown the app when finished:

import github.com/xmidt-org/clifx

type MyCLI struct {
  Debug bool
  Files []string
}

func main() {
  app := fx.New(
    clifx.Provide[MyCLI](
      clifx.StandardArguments(),
    ),

    fx.Invoke(
      func(kctx *kong.Context, l fx.Lifecycle, sh fx.Shutdowner /* any other dependencies from the enclosing app */) {
        l.Append(fx.Hook{
          OnStart: func(_ context.Context) error {
            // optional:  this just exits from app.Run when the CLI is done.
            // without this, app.Run will not return until explicitly stopped, such as
            // by hitting ctrl+C at a console.
            defer sh.Shutdown()

            // don't forget:  you can pass dependencies from the enclosing app here
            return kctx.Run()
          },
        })
      },
    ),
  )

  // this now causes the CLI to be executed.  Any error that is returned will be
  // from the CLI tool.
  app.Run()
}
Custom options

You can supply custom any number of kong options to Provide.

clifx.Provide[MyCLI](
 clifx.StandardArguments(),
 kong.UsageOnError(),
 kong.Description("here is a custom tool"),
)
Suppressing os.Exit

By default, kong will invoke os.Exit(1) anytime a parse fails. You can suppress this easily by providing a noop Exit function. clifx provides a kong option for this purpose:

import github.com/xmidt-org/clifx

type MyCLI struct {
  Debug bool
  Files []string
}

func main() {
  app := fx.New(
    clifx.Provide[MyCLI](
      clifx.StandardArguments(),
      clifx.SuppressExit(),
    ),
  
    fx.Invoke(
      func(cli MyCLI) error {
        return nil
      },
    ),
  )

  // since we didn't exit the process, we can test app.Err()
  var pe *kong.ParseError
  if errors.As(app.Err(), &pe) {
    // custom behavior in reaction to a bad command-line
  }
}
Custom arguments

clifx.StandardArguments returns the command-line passed to the process. You can supply an arguments you like, which is useful for testing or interactive use:

clifx.Provide[MyCLI](
  clifx.AsArguments("--bind", ":8080", "-v"),
)

Contributing

Refer to CONTRIBUTING.md.

Documentation

Overview

Package clifx provides simple integration between go.uber.org/fx and github.com/alecthomas/kong.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func New

func New[C any](args Arguments, options ...kong.Option) (cli C, kctx *kong.Context, err error)

New parses the command-line given by args. The optional set of Kong options is used to build the parser. This is the most flexible way to bootstrap Kong within an fx application, as it allows a caller to control how all the various objects are seen by the fx.App.

The type C must be a struct. Otherwise, this function returns an error.

func NewConstructor

func NewConstructor[C any](args Arguments, options ...kong.Option) func() (C, *kong.Context, error)

NewConstructor returns a closure that uses New to build the configuration object and context. This function is a useful alternative to New when a caller does not wish to inject the arguments and options.

func Provide

func Provide[C any](args Arguments, options ...kong.Option) fx.Option

Provide implements the simplest use case: Global components for the command-line and the kong context are emitted based the supplied arguments and options.

Example (Basic)

ExampleProvide_basic shows how to bootstrap a basic command line using clifx.

type cli struct {
	Address string `short:"a"`
}

var c cli
var kctx *kong.Context

fx.New(
	fx.NopLogger,
	Provide[cli](
		AsArguments("-a", ":8080"), // can use StandardArguments here to pass the process command-line arguments
		SuppressExit(),             // in case of an error, prevent this example from calling os.Exit
	),
	fx.Populate(
		&c,
		&kctx,
	),
)

fmt.Println(c.Address)
fmt.Println(kctx.Args)
Output:

:8080
[-a :8080]
Example (Run)

ExampleProvide_run shows how to execute a CLI as part of fx.New().

type cli struct {
	Address string `short:"a"`
}

fx.New(
	fx.NopLogger,
	fx.Supply(123), // just to illustrate another component
	Provide[cli](
		AsArguments("-a", ":8080"),
		SuppressExit(),
	),
	fx.Invoke(
		func(kctx *kong.Context, sh fx.Shutdowner, value int) error {
			defer sh.Shutdown() //nolint: errcheck
			fmt.Println(kctx.Args)
			fmt.Println(value)

			// see the Kong documentation for how to implement this:
			return kctx.Run(value)
		},
	),
)
Output:

[-a :8080]
123

func SuppressExit

func SuppressExit() kong.Option

SuppressExit sets a noop exit function so suppress calling os.Exit when the command line parsing fails. This is mostly useful for testing and examples, but can be useful when an application wants to handle parsing errors in a custom manner.

Types

type Arguments

type Arguments []string

Arguments represent the raw command-line arguments passed to the program. This type exists mainly to allow unambiguous dependency injection.

func AsArguments

func AsArguments(args ...string) Arguments

AsArguments provides some syntactic sugar around converting a slice of strings into an Arguments.

func StandardArguments

func StandardArguments() Arguments

StandardArguments returns the command-line arguments passed to this process, i.e. os.Args[1:].

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL
JackTT - Gopher 🇻🇳