Skip to content

Commit

Permalink
Add cli usage docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex Schneider authored Apr 9, 2021
2 parents d37f3c8 + 33787e4 commit 3dbf849
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 45 deletions.
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
build:
go build -race -v -o couper main.go

image:
docker build -t avenga/couper:latest .

Expand Down
4 changes: 3 additions & 1 deletion command/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ import (

type Cmd interface {
Execute(args Args, config *config.Couper, logger *logrus.Entry) error
Usage() string
Usage()
}

func NewCommand(ctx context.Context, cmd string) Cmd {
switch strings.ToLower(cmd) {
case "run":
return NewRun(ContextWithSignal(ctx))
case "help":
return NewHelp(ctx)
case "version":
return NewVersion()
default:
Expand Down
55 changes: 46 additions & 9 deletions command/help.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,55 @@
package command

// Help shows available commands and options.
func Help() { // TODO: generate from command and options list
println(`couper usage:
import (
"context"
"fmt"

couper <cmd> <options>
"github.com/avenga/couper/config"
"github.com/sirupsen/logrus"
)

global options:
var _ Cmd = &Help{}

-f couper hcl configuration file
-log-format format option for json or common logs
// Synopsis shows available commands and options.
func Synopsis() { // TODO: generate from command and options list
println(`
Couper usage:
couper <cmd> <options>
available commands:
Available commands:
run Start the server with given configuration file.
version Print the current version and build information.
help Usage for given command.
run starts the server
Examples:
couper run
couper run -f couper.hcl
couper run -watch -log-format json -log-pretty -p 3000
`)
}

type Help struct {
ctx context.Context
}

func NewHelp(ctx context.Context) *Help {
return &Help{ctx: ctx}
}

func (h Help) Execute(args Args, _ *config.Couper, _ *logrus.Entry) error {
defer Synopsis()
if len(args) == 0 {
h.Usage()
return fmt.Errorf("missing command argument")
}
cmd := NewCommand(h.ctx, args[0])
if cmd == nil {
return fmt.Errorf("unknown command: %s", args[0])
}
cmd.Usage()
return nil
}

func (h Help) Usage() {
println("Usage of help:\n help <command> Print usage information of given command.")
}
38 changes: 24 additions & 14 deletions command/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,31 @@ var _ Cmd = &Run{}
// Run starts the frontend gateway server and listen
// for requests on the configured hosts and ports.
type Run struct {
context context.Context
context context.Context
flagSet *flag.FlagSet
settings *config.Settings
}

func NewRun(ctx context.Context) *Run {
return &Run{context: ctx}
settings := config.DefaultSettings
set := flag.NewFlagSet("run", flag.ContinueOnError)
set.StringVar(&settings.HealthPath, "health-path", settings.HealthPath, "-health-path /healthz")
set.IntVar(&settings.DefaultPort, "p", settings.DefaultPort, "-p 8080")
set.BoolVar(&settings.XForwardedHost, "xfh", settings.XForwardedHost, "-xfh")
set.BoolVar(&settings.NoProxyFromEnv, "no-proxy-from-env", settings.NoProxyFromEnv, "-no-proxy-from-env")
set.StringVar(&settings.RequestIDFormat, "request-id-format", settings.RequestIDFormat, "-request-id-format uuid4")
set.StringVar(&settings.SecureCookies, "secure-cookies", settings.SecureCookies, "-secure-cookies strip")
return &Run{
context: ctx,
flagSet: set,
settings: &settings,
}
}

func (r Run) Execute(args Args, config *config.Couper, logEntry *logrus.Entry) error {
// TODO: Extract and execute flagSet & env handling in a more generic way for future commands.
set := flag.NewFlagSet("settings", flag.ContinueOnError)
set.StringVar(&config.Settings.HealthPath, "health-path", config.Settings.HealthPath, "-health-path /healthz")
set.IntVar(&config.Settings.DefaultPort, "p", config.Settings.DefaultPort, "-p 8080")
set.BoolVar(&config.Settings.XForwardedHost, "xfh", config.Settings.XForwardedHost, "-xfh")
set.BoolVar(&config.Settings.NoProxyFromEnv, "no-proxy-from-env", config.Settings.NoProxyFromEnv, "-no-proxy-from-env")
set.StringVar(&config.Settings.RequestIDFormat, "request-id-format", config.Settings.RequestIDFormat, "-request-id-format uuid4")
set.StringVar(&config.Settings.SecureCookies, "secure-cookies", config.Settings.SecureCookies, "-secure-cookies strip")
if err := set.Parse(args.Filter(set)); err != nil {
*r.settings = *config.Settings

if err := r.flagSet.Parse(args.Filter(r.flagSet)); err != nil {
return err
}

Expand All @@ -43,7 +51,9 @@ func (r Run) Execute(args Args, config *config.Couper, logEntry *logrus.Entry) e
return fmt.Errorf("invalid value for the -secure-cookies flag given: '%s' only 'strip' is supported", config.Settings.SecureCookies)
}

env.Decode(config.Settings)
// Some remapping due to flag set pre-definition
env.Decode(r.settings)
config.Settings = r.settings

timings := runtime.DefaultTimings
env.Decode(&timings)
Expand All @@ -64,6 +74,6 @@ func (r Run) Execute(args Args, config *config.Couper, logEntry *logrus.Entry) e
return nil
}

func (r Run) Usage() string {
panic("implement me")
func (r Run) Usage() {
r.flagSet.Usage()
}
4 changes: 2 additions & 2 deletions command/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ func (v Version) Execute(_ Args, _ *config.Couper, _ *logrus.Entry) error {
return nil
}

func (v Version) Usage() string {
return "couper version"
func (v Version) Usage() {
println("Usage of version:\n version Print current version and build information.")
}
26 changes: 26 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

* [Introduction](#introduction)
* [Core concepts](#core-concepts)
* [Command line interface](#command-line-interface)
* [Global options](#global-options)
* [Configuration file](#configuration-file)
* [Syntax](#syntax)
* [File name](#file-name)
Expand Down Expand Up @@ -72,6 +74,30 @@ need any special development skills and offers easy configuration and integratio
| Backend Service(s) | External API or micro services where Couper fetches data from. |
| Validation | Couper supports validation of outgoing and incoming requests to and from the origin. |

## Command Line Interface

Couper is build as binary called `couper` with the following commands:

| Command | Description |
|:----------|:--------------------------------------------------|
| `run` | Start the server with given configuration file. |
| | *Note*: `run` options can also be configured with [settings](#settings-block) or related [environment variables](./../DOCKER.md).
| `help` | Print the usage for the given command: `help run` |
| `version` | Print the current version and build information. |

### Global Options

| Argument | Default | Environment | Description |
|:----------|:-------------|:------------------|:------------------------------------------------------------------|
| `-f` | `couper.hcl` | `COUPER_FILE` | File path to your Couper configuration file. |
| `-watch` | `false` | `COUPER_WATCH` | Watch for configuration file changes and reload on modifications. |
| `-watch-retries` | `5` | `COUPER_WATCH_RETRIES` | Maximal retry count for configuration reloads which could not bind the configured port. |
| `-watch-retry-delay` | `500ms` | `COUPER_WATCH_RETRY_DELAY` | Delay duration before next attempt if an error occurs. |
| `-log-format` | `common` | `COUPER_LOG_FORMAT` | Can be set to `json` output format. |
| `-log-pretty` | `false` | `COUPER_LOG_PRETTY` | Option for `json` log format which pretty prints with basic key coloring. |

*Note*: `log-format` and `log-pretty` also maps to [settings](#settings-block).

## Configuration file

### Syntax
Expand Down
45 changes: 26 additions & 19 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"os"
"time"

"github.com/fatih/color"
"github.com/sirupsen/logrus"

"github.com/avenga/couper/command"
Expand All @@ -36,19 +37,6 @@ func realmain(arguments []string) int {
args := command.NewArgs(arguments)
ctx := context.Background()

if len(args) == 0 || command.NewCommand(ctx, args[0]) == nil {
command.Help()
return 1
}

cmd := args[0]
args = args[1:]

if cmd == "version" { // global options are not required, fast exit.
_ = command.NewCommand(ctx, cmd).Execute(args, nil, nil)
return 0
}

type globalFlags struct {
FilePath string `env:"file"`
FileWatch bool `env:"watch"`
Expand All @@ -59,19 +47,38 @@ func realmain(arguments []string) int {
}
var flags globalFlags

set := flag.NewFlagSet("global", flag.ContinueOnError)
set.StringVar(&flags.FilePath, "f", config.DefaultFilename, "-f ./couper.hcl")
set := flag.NewFlagSet("global options", flag.ContinueOnError)
set.StringVar(&flags.FilePath, "f", config.DefaultFilename, "-f ./my-path/couper.hcl")
set.BoolVar(&flags.FileWatch, "watch", false, "-watch")
set.DurationVar(&flags.FileWatchRetryDelay, "watch-retry-delay", time.Millisecond*500, "-watch-retry-delay 500ms")
set.IntVar(&flags.FileWatchRetries, "watch-retries", 5, "-watch-retries 5")
set.StringVar(&flags.LogFormat, "log-format", config.DefaultSettings.LogFormat, "-log-format=common")
set.DurationVar(&flags.FileWatchRetryDelay, "watch-retry-delay", time.Millisecond*500, "-watch-retry-delay 1s")
set.IntVar(&flags.FileWatchRetries, "watch-retries", 5, "-watch-retries 10")
set.StringVar(&flags.LogFormat, "log-format", config.DefaultSettings.LogFormat, "-log-format=json")
set.BoolVar(&flags.LogPretty, "log-pretty", config.DefaultSettings.LogPretty, "-log-pretty")

if len(args) == 0 || command.NewCommand(ctx, args[0]) == nil {
command.Synopsis()
set.Usage()
return 1
}

cmd := args[0]
args = args[1:]

if cmd != "run" { // global options are not required atm, fast exit.
err := command.NewCommand(ctx, cmd).Execute(args, nil, nil)
if err != nil {
set.Usage()
color.Red("\n%v", err)
return 1
}
return 0
}

err := set.Parse(args.Filter(set))
if err != nil {
newLogger(flags.LogFormat, flags.LogPretty).Error(err)
return 1
}

env.Decode(&flags)

confFile, err := configload.LoadFile(flags.FilePath)
Expand Down

0 comments on commit 3dbf849

Please sign in to comment.