Skip to content

Commit

Permalink
feat: Add spinner to indicate build in progress.
Browse files Browse the repository at this point in the history
  • Loading branch information
szkiba committed Jun 28, 2024
1 parent afec44c commit 788da9a
Show file tree
Hide file tree
Showing 5 changed files with 274 additions and 139 deletions.
179 changes: 46 additions & 133 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,70 +2,18 @@
package cmd

import (
"context"
_ "embed"
"log/slog"
"net/url"
"os"

"github.com/grafana/k6deps"
"github.com/grafana/k6exec"
"github.com/spf13/cobra"
)

//go:embed help.md
var help string

type options struct {
k6exec.Options
buildServiceURL string
extensionCatalogURL string
verbose bool
levelVar *slog.LevelVar
}

func (o *options) postProcess() error {
if len(o.buildServiceURL) > 0 {
val, err := url.Parse(o.buildServiceURL)
if err != nil {
return err
}

o.BuildServiceURL = val
}

if len(o.extensionCatalogURL) > 0 {
val, err := url.Parse(o.extensionCatalogURL)
if err != nil {
return err
}

o.ExtensionCatalogURL = val
}

if o.verbose && o.levelVar != nil {
o.levelVar.Set(slog.LevelDebug)
}

return nil
}

//nolint:forbidigo
func (o *options) init() {
if value, found := os.LookupEnv("K6_BUILD_SERVICE_URL"); found {
o.buildServiceURL = value
}

if value, found := os.LookupEnv("K6_EXTENSION_CATALOG_URL"); found {
o.extensionCatalogURL = value
}
}

// New creates new cobra command for exec command.
func New(levelVar *slog.LevelVar) *cobra.Command {
opts := &options{levelVar: levelVar}

opts.init()
state := newState(levelVar)

root := &cobra.Command{
Use: "exec [flags] [command]",
Expand All @@ -75,86 +23,58 @@ func New(levelVar *slog.LevelVar) *cobra.Command {
SilenceErrors: true,
DisableAutoGenTag: true,
CompletionOptions: cobra.CompletionOptions{DisableDefaultCmd: true},
RunE: func(cmd *cobra.Command, _ []string) error { return cmd.Help() },
PersistentPreRunE: func(_ *cobra.Command, _ []string) error { return opts.postProcess() },
PreRunE: func(cmd *cobra.Command, args []string) error {
if state.usage {
return nil
}

state.AppName = cmd.Name()

return state.preRunE(cmd, args)
},
RunE: func(cmd *cobra.Command, args []string) error {
if state.usage {
return cmd.Help()
}

return state.runE(cmd, args)
},
PersistentPreRunE: state.persistentPreRunE,
}

root.SetVersionTemplate(`{{with .Name}}{{printf "%s " .}}{{end}}{{printf "%s\n" .Version}}`)

root.AddCommand(subcommands(opts)...)
for _, name := range commands {
root.AddCommand(newSubcommand(name, state))
}

flags := root.PersistentFlags()

flags.StringVar(
&opts.extensionCatalogURL,
&state.extensionCatalogURL,
"extension-catalog-url",
opts.extensionCatalogURL,
state.extensionCatalogURL,
"URL of the k6 extension catalog to be used",
)
flags.StringVar(
&opts.buildServiceURL,
&state.buildServiceURL,
"build-service-url",
opts.buildServiceURL,
state.buildServiceURL,
"URL of the k6 build service to be used",
)
flags.BoolVarP(
&opts.verbose,
"verbose",
"v",
false,
"enable verbose logging",
)
flags.BoolVarP(&state.verbose, "verbose", "v", false, "enable verbose logging")
flags.BoolVarP(&state.quiet, "quiet", "q", false, "disable progress updates")
flags.BoolVar(&state.quiet, "no-color", false, "disable colored output")
flags.BoolVar(&state.usage, "usage", false, "print launcher usage")

root.InitDefaultHelpFlag()
root.Flags().Lookup("help").Usage = "help for k6"

root.MarkFlagsMutuallyExclusive("extension-catalog-url", "build-service-url")

return root
}

func usage(cmd *cobra.Command, args []string) {
err := exec(cmd, append(args, "-h"), new(options))
if err != nil {
cmd.PrintErr(err)
}
}

func exec(sub *cobra.Command, args []string, opts *options) error {
var (
deps k6deps.Dependencies
err error
dopts k6deps.Options
)

if scriptname, hasScript := scriptArg(sub, args); hasScript {
dopts.Script.Name = scriptname
}

deps, err = k6deps.Analyze(&dopts)
if err != nil {
return err
}

cmdargs := []string{sub.Name()}

if opts.verbose {
cmdargs = append(cmdargs, "-v")
}

cmdargs = append(cmdargs, args...)

cmd, err := k6exec.Command(context.Background(), cmdargs, deps, &opts.Options)
if err != nil {
return err
}

cmd.Stderr = os.Stderr //nolint:forbidigo
cmd.Stdout = os.Stdout //nolint:forbidigo
cmd.Stdin = os.Stdin //nolint:forbidigo

defer k6exec.CleanupState(&opts.Options) //nolint:errcheck

return cmd.Run()
}

func scriptArg(cmd *cobra.Command, args []string) (string, bool) {
if len(cmd.Annotations) == 0 {
return "", false
Expand All @@ -176,30 +96,23 @@ func scriptArg(cmd *cobra.Command, args []string) (string, bool) {
return last, true
}

func subcommands(opts *options) []*cobra.Command {
annext := map[string]string{useExtensions: "true"}

all := make([]*cobra.Command, 0, len(commands))
func newSubcommand(name string, state *state) *cobra.Command {
cmd := &cobra.Command{
Use: name,
PreRunE: state.preRunE,
RunE: state.runE,
SilenceErrors: true,
SilenceUsage: true,
FParseErrWhitelist: cobra.FParseErrWhitelist{UnknownFlags: true},
Hidden: true,
}
cmd.SetHelpFunc(state.helpFunc)

for _, name := range commands {
cmd := &cobra.Command{
Use: name,
RunE: func(cmd *cobra.Command, args []string) error { return exec(cmd, args, opts) },
SilenceErrors: true,
SilenceUsage: true,
FParseErrWhitelist: cobra.FParseErrWhitelist{UnknownFlags: true},
Hidden: true,
}
cmd.SetHelpFunc(usage)

if name == "run" || name == "archive" {
cmd.Annotations = annext
}

all = append(all, cmd)
if name == "run" || name == "archive" {
cmd.Annotations = map[string]string{useExtensions: "true"}
}

return all
return cmd
}

const useExtensions = "useExtensions"
Expand Down
76 changes: 73 additions & 3 deletions cmd/k6exec/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@
package main

import (
"context"
"log/slog"
"os"
"os/signal"
"strings"
"time"

"github.com/briandowns/spinner"
"github.com/fatih/color"
"github.com/grafana/k6exec/cmd"
sloglogrus "github.com/samber/slog-logrus/v2"
"github.com/sirupsen/logrus"
Expand All @@ -19,7 +24,7 @@ var (
)

func initLogging() *slog.LevelVar {
var levelVar = new(slog.LevelVar)
levelVar := new(slog.LevelVar)

logrus.SetLevel(logrus.DebugLevel)

Expand All @@ -32,14 +37,24 @@ func initLogging() *slog.LevelVar {
}

func main() {
levelVar := initLogging()
runCmd(newCmd(os.Args[1:], levelVar)) //nolint:forbidigo
runCmd(newCmd(os.Args[1:], initLogging())) //nolint:forbidigo
}

func newCmd(args []string, levelVar *slog.LevelVar) *cobra.Command {
cmd := cmd.New(levelVar)
cmd.Use = strings.Replace(cmd.Use, cmd.Name(), appname, 1)
cmd.Version = version

if len(args) == 1 && (args[0] == "-h" || args[0] == "--help") {
args[0] = "help"
}

sp := addSpinner(cmd)

if len(args) == 1 && args[0] == "--usage" {
sp.Disable()
}

cmd.SetArgs(args)

return cmd
Expand All @@ -51,3 +66,58 @@ func runCmd(cmd *cobra.Command) {
os.Exit(1) //nolint:forbidigo
}
}

func addSpinner(root *cobra.Command) *spinner.Spinner {
sp := spinner.New(
spinner.CharSets[11],
200*time.Millisecond,
spinner.WithColor("cyan"),
spinner.WithWriterFile(os.Stderr), //nolint:forbidigo
)

red := color.New(color.FgRed)
green := color.New(color.FgGreen)

sp.Prefix = "Preparing k6 "
sp.FinalMSG = sp.Prefix + green.Sprint("✓") + "\n"

c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {
<-c
sp.FinalMSG = sp.Prefix + red.Sprint("✗") + "\n"

sp.Stop()
}()

if slog.Default().Enabled(context.Background(), slog.LevelDebug) {
sp.Disable()
}

prerun := root.PersistentPreRunE
root.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
if cmd == root && len(args) != 0 {
return nil
}

sp.Start()
cmdpre := cmd.PreRunE
cmd.PreRunE = func(cmd *cobra.Command, args []string) error {
var err error

if cmdpre != nil {
err = cmdpre(cmd, args)
if err != nil {
sp.FinalMSG = sp.Prefix + red.Sprint("✗") + "\n"
}
}

sp.Stop()
return err
}

return prerun(cmd, args)
}

return sp
}
Loading

0 comments on commit 788da9a

Please sign in to comment.