Skip to content

Commit

Permalink
Refine flags (#16)
Browse files Browse the repository at this point in the history
* Utilize go-flags's key-value-delimiter
* Print help when flag parsing is failed
* Make execution with --help be terminated successfly
  • Loading branch information
apstndb authored Oct 30, 2024
1 parent 70891d4 commit c11998b
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 31 deletions.
3 changes: 3 additions & 0 deletions cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,9 @@ func (c *Cli) PrintProgressingMark() func() {
progressMarks := []string{`-`, `\`, `|`, `/`}
ticker := time.NewTicker(time.Millisecond * 100)
go func() {
// wait to avoid corruption with first output of command
<-ticker.C

i := 0
for {
<-ticker.C
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
cloud.google.com/go/spanner v1.62.0
github.com/cloudspannerecosystem/memefish v0.0.0-20241029131948-98b8bf288447
github.com/google/go-cmp v0.6.0
github.com/jessevdk/go-flags v1.4.0
github.com/jessevdk/go-flags v1.6.1
github.com/olekukonko/tablewriter v0.0.5
github.com/reeflective/readline v1.0.15
github.com/samber/lo v1.47.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4=
github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
Expand Down
59 changes: 29 additions & 30 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,39 +20,40 @@ package main
import (
"fmt"
"io"
"maps"
"os"
"os/user"
"path/filepath"
"strings"

"github.com/samber/lo"

sppb "cloud.google.com/go/spanner/apiv1/spannerpb"
"github.com/jessevdk/go-flags"
"github.com/samber/lo"
"spheric.cloud/xiter"
)

type globalOptions struct {
Spanner spannerOptions `group:"spanner"`
}

type spannerOptions struct {
ProjectId string `short:"p" long:"project" env:"SPANNER_PROJECT_ID" description:"(required) GCP Project ID."`
InstanceId string `short:"i" long:"instance" env:"SPANNER_INSTANCE_ID" description:"(required) Cloud Spanner Instance ID"`
DatabaseId string `short:"d" long:"database" env:"SPANNER_DATABASE_ID" description:"(required) Cloud Spanner Database ID."`
Execute string `short:"e" long:"execute" description:"Execute SQL statement and quit. --sql is an alias."`
File string `short:"f" long:"file" description:"Execute SQL statement from file and quit."`
Table bool `short:"t" long:"table" description:"Display output in table format for batch mode."`
Verbose bool `short:"v" long:"verbose" description:"Display verbose output."`
Credential string `long:"credential" description:"Use the specific credential file"`
Prompt string `long:"prompt" description:"Set the prompt to the specified format"`
LogMemefish bool `long:"log-memefish" description:"Emit SQL parse log using memefish"`
HistoryFile string `long:"history" description:"Set the history file to the specified path"`
Priority string `long:"priority" description:"Set default request priority (HIGH|MEDIUM|LOW)"`
Role string `long:"role" description:"Use the specific database role"`
Endpoint string `long:"endpoint" description:"Set the Spanner API endpoint (host:port)"`
DirectedRead string `long:"directed-read" description:"Directed read option (replica_location:replica_type). The replicat_type is optional and either READ_ONLY or READ_WRITE"`
SQL string `long:"sql" description:"alias of --execute" hidden:"true"`
Set []string `long:"set" description:"Set system variables e.g. --set=name1=value1 --set=name2=value2"`
ProjectId string `long:"project" short:"p" env:"SPANNER_PROJECT_ID" description:"(required) GCP Project ID."`
InstanceId string `long:"instance" short:"i" env:"SPANNER_INSTANCE_ID" description:"(required) Cloud Spanner Instance ID"`
DatabaseId string `long:"database" short:"d" env:"SPANNER_DATABASE_ID" description:"(required) Cloud Spanner Database ID."`
Execute string `long:"execute" short:"e" description:"Execute SQL statement and quit. --sql is an alias."`
File string `long:"file" short:"f" description:"Execute SQL statement from file and quit."`
Table bool `long:"table" short:"t" description:"Display output in table format for batch mode."`
Verbose bool `long:"verbose" short:"v" description:"Display verbose output."`
Credential string `long:"credential" description:"Use the specific credential file"`
Prompt string `long:"prompt" description:"Set the prompt to the specified format"`
LogMemefish bool `long:"log-memefish" description:"Emit SQL parse log using memefish"`
HistoryFile string `long:"history" description:"Set the history file to the specified path"`
Priority string `long:"priority" description:"Set default request priority (HIGH|MEDIUM|LOW)"`
Role string `long:"role" description:"Use the specific database role"`
Endpoint string `long:"endpoint" description:"Set the Spanner API endpoint (host:port)"`
DirectedRead string `long:"directed-read" description:"Directed read option (replica_location:replica_type). The replicat_type is optional and either READ_ONLY or READ_WRITE"`
SQL string `long:"sql" hidden:"true" description:"alias of --execute"`
Set map[string]string `long:"set" key-value-delimiter:"=" description:"Set system variables e.g. --set=name1=value1 --set=name2=value2"`
}

var logMemefish bool
Expand All @@ -65,24 +66,20 @@ func main() {
}

// then, process environment variables and command line options
// use another parser to process environment variable
if _, err := flags.NewParser(&gopts, flags.Default).Parse(); err != nil {
// use another parser to process environment variables with higher precedence than configuration files
flagParser := flags.NewParser(&gopts, flags.Default)
if _, err := flagParser.Parse(); flags.WroteHelp(err) {
// exit successfully
return
} else if err != nil {
flags.NewParser(&gopts, flags.Default).WriteHelp(os.Stderr)
exitf("Invalid options\n")
}

opts := gopts.Spanner

var sysVars systemVariables

sets := make(map[string]string)
for _, s := range opts.Set {
k, v, ok := strings.Cut(s, "=")
if !ok {
exitf("invalid system variable %v\n", s)
}
sets[strings.ToUpper(k)] = v
}

logMemefish = opts.LogMemefish

if opts.ProjectId == "" || opts.InstanceId == "" || opts.DatabaseId == "" {
Expand Down Expand Up @@ -127,6 +124,8 @@ func main() {
}
}

sets := maps.Collect(xiter.MapKeys(maps.All(opts.Set), strings.ToUpper))

for k, v := range sets {
if err := sysVars.Set(k, v); err != nil {
exitf("failed to set system variable. name: %v, value: %v, err: %v\n", k, v, err)
Expand Down

0 comments on commit c11998b

Please sign in to comment.