Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 48 additions & 88 deletions cmd/benchttp/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import (
"io"
"os"

"github.com/benchttp/engine/runner"
"github.com/benchttp/engine/benchttp"
"github.com/benchttp/engine/configio"

"github.com/benchttp/cli/internal/configfile"
"github.com/benchttp/cli/internal/configflag"
"github.com/benchttp/cli/internal/output"
"github.com/benchttp/cli/internal/render"
Expand All @@ -21,133 +21,93 @@ import (
type cmdRun struct {
flagset *flag.FlagSet

// configFile is the parsed value for flag -configFile
configFile string
configFile string // parsed value for flag -configFile
silent bool // parsed value for flag -silent

// silent is the parsed value for flag -silent
silent bool

// config is the runner config resulting from parsing CLI flags.
config runner.Config
}

// init initializes cmdRun with default values.
func (cmd *cmdRun) init() {
cmd.config = runner.DefaultConfig()
cmd.configFile = configfile.Find([]string{
"./.benchttp.yml",
"./.benchttp.yaml",
"./.benchttp.json",
})
builder configio.Builder
}

// execute runs the benchttp runner: it parses CLI flags, loads config
// from config file and parsed flags, then runs the benchmark and outputs
// it according to the config.
func (cmd *cmdRun) execute(args []string) error {
cmd.init()
if err := cmd.parseArgs(args); err != nil {
return err
}

// Generate merged config (default < config file < CLI flags)
cfg, err := cmd.makeConfig(args)
config, err := buildConfig(cmd.builder, cmd.configFile)
if err != nil {
return err
}

report, err := runBenchmark(cfg, cmd.silent)
report, err := runBenchmark(config, cmd.silent)
if err != nil {
return err
}

return renderReport(os.Stdout, report, cmd.silent)
}

// parseArgs parses input args as config fields and returns
// a slice of fields that were set by the user.
func (cmd *cmdRun) parseArgs(args []string) []string {
// skip parsing if no flags are provided
if len(args) == 0 {
return []string{}
}

// config file path
cmd.flagset.StringVar(&cmd.configFile,
"configFile",
cmd.configFile,
"Config file path",
)

// silent mode
cmd.flagset.BoolVar(&cmd.silent,
"silent",
false,
"Silent mode",
)

// attach config options flags to the flagset
// and bind their value to the config struct
configflag.Bind(cmd.flagset, &cmd.config)

cmd.flagset.Parse(args) //nolint:errcheck // never occurs due to flag.ExitOnError

return configflag.Which(cmd.flagset)
func (cmd *cmdRun) parseArgs(args []string) error {
cmd.flagset.StringVar(&cmd.configFile, "configFile", configio.FindFile(), "Config file path")
cmd.flagset.BoolVar(&cmd.silent, "silent", false, "Silent mode")
configflag.Bind(cmd.flagset, &cmd.builder)
return cmd.flagset.Parse(args)
}

// makeConfig returns a runner.ConfigGlobal initialized with config file
// options if found, overridden with CLI options listed in fields
// slice param.
func (cmd *cmdRun) makeConfig(args []string) (cfg runner.Config, err error) {
// Set CLI config from flags and retrieve fields that were set
fields := cmd.parseArgs(args)

// configFile not set and default ones not found:
// skip the merge and return the cli config
if cmd.configFile == "" {
return cmd.config, cmd.config.Validate()
}
func buildConfig(
b configio.Builder,
filePath string,
) (benchttp.Runner, error) {
// use default runner as a base
runner := benchttp.DefaultRunner()

fileConfig, err := configfile.Parse(cmd.configFile)
if err != nil && !errors.Is(err, configfile.ErrFileNotFound) {
// override with config file values
err := configio.UnmarshalFile(filePath, &runner)
if err != nil && !errors.Is(err, configio.ErrFileNotFound) {
// config file is not mandatory: discard ErrFileNotFound.
// other errors are critical
return
return runner, err
}

mergedConfig := cmd.config.WithFields(fields...).Override(fileConfig)
// override with CLI flags values
b.Mutate(&runner)

return mergedConfig, mergedConfig.Validate()
return runner, nil
}

func onRecordingProgress(silent bool) func(runner.RecordingProgress) {
if silent {
return func(runner.RecordingProgress) {}
}

// hack: write a blank line as render.Progress always
// erases the previous line
fmt.Println()

return func(progress runner.RecordingProgress) {
render.Progress(os.Stdout, progress) //nolint: errcheck
}
}

func runBenchmark(cfg runner.Config, silent bool) (*runner.Report, error) {
func runBenchmark(runner benchttp.Runner, silent bool) (*benchttp.Report, error) {
// Prepare graceful shutdown in case of os.Interrupt (Ctrl+C)
ctx, cancel := context.WithCancel(context.Background())
go signals.ListenOSInterrupt(cancel)

// Stream progress to stdout
runner.OnProgress = onRecordingProgress(silent)

// Run the benchmark
report, err := runner.
New(onRecordingProgress(silent)).
Run(ctx, cfg)
report, err := runner.Run(ctx)
if err != nil {
return report, err
}

return report, nil
}

func renderReport(w io.Writer, report *runner.Report, silent bool) error {
func onRecordingProgress(silent bool) func(benchttp.RecordingProgress) {
if silent {
return func(benchttp.RecordingProgress) {}
}

// hack: write a blank line as render.Progress always
// erases the previous line
fmt.Println()

return func(progress benchttp.RecordingProgress) {
render.Progress(os.Stdout, progress) //nolint: errcheck
}
}

func renderReport(w io.Writer, report *benchttp.Report, silent bool) error {
writeIfNotSilent := output.ConditionalWriter{Writer: w}.If(!silent)

if _, err := render.ReportSummary(writeIfNotSilent, report); err != nil {
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ module github.com/benchttp/cli

go 1.17

require github.com/benchttp/engine v0.1.0
require github.com/benchttp/engine v0.2.0

require (
github.com/google/go-cmp v0.5.9 // indirect
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
15 changes: 4 additions & 11 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
github.com/benchttp/engine v0.0.0-20221008174504-d1162e9ac007 h1:h6ON0tn3i/83eUMoXq0FHxBMLYIA/OIli3m9KYkcxPI=
github.com/benchttp/engine v0.0.0-20221008174504-d1162e9ac007/go.mod h1:FRfUnUjoL1s0aHVGlrxB3pdPAEDLNCnWh6cVOur24hM=
github.com/benchttp/engine v0.1.0 h1:FpQOwHklBITuRd7B/AGKqr0mAmbXgTwzQiPHlhUktbQ=
github.com/benchttp/engine v0.1.0/go.mod h1:FRfUnUjoL1s0aHVGlrxB3pdPAEDLNCnWh6cVOur24hM=
github.com/drykit-go/cond v0.1.0 h1:y7MNxREQLT83vGfcfSKjyFPLC/ZDjYBNp6KuaVVjOg4=
github.com/drykit-go/cond v0.1.0/go.mod h1:7MXBFjjaB5ZCEB8Q4w2euNOaWuTqf7NjOFZAyV1Jpfg=
github.com/drykit-go/strcase v0.2.0/go.mod h1:cWK0/az2f09UPIbJ42Sb8Iqdv01uENrFX+XXKGjPo+8=
github.com/drykit-go/testx v0.1.0/go.mod h1:qGXb49a8CzQ82crBeCVW8R3kGU1KRgWHnI+Q6CNVbz8=
github.com/drykit-go/testx v1.2.0 h1:UsH+tFd24z3Xu+mwvwPY+9eBEg9CUyMsUeMYyUprG0o=
github.com/drykit-go/testx v1.2.0/go.mod h1:qTzXJgnAg8n31woklBzNTaWzLMJrnFk93x/aeaIpc20=
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/benchttp/engine v0.2.0 h1:r3zKs7ZOgRC0uDsHabD76sIoiF57MwGl0ouhFGpbu+A=
github.com/benchttp/engine v0.2.0/go.mod h1:70imLQ2ONTEMGcbJimOirjz57uw3aix9RI8yZVZxLdc=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
Expand Down
26 changes: 0 additions & 26 deletions internal/configfile/error.go

This file was deleted.

14 changes: 0 additions & 14 deletions internal/configfile/find.go

This file was deleted.

31 changes: 0 additions & 31 deletions internal/configfile/find_test.go

This file was deleted.

Loading