Skip to content

Commit 44c8877

Browse files
committed
More usage cleanup
1 parent 3a9334d commit 44c8877

File tree

6 files changed

+90
-76
lines changed

6 files changed

+90
-76
lines changed

handler/errors.go

-25
This file was deleted.

handler/handler.go

+50
Original file line numberDiff line numberDiff line change
@@ -1416,6 +1416,32 @@ func (h *Handler) SetOutput(o io.WriteCloser) {
14161416
h.out = o
14171417
}
14181418

1419+
// Error wraps handler errors.
1420+
type Error struct {
1421+
Buf string
1422+
Err error
1423+
}
1424+
1425+
// WrapErr wraps an [error] using the specified driver when err is not nil.
1426+
func WrapErr(buf string, err error) error {
1427+
if err == nil {
1428+
return nil
1429+
}
1430+
// avoid double wrapping error
1431+
if _, ok := err.(*Error); ok {
1432+
return err
1433+
}
1434+
return &Error{buf, err}
1435+
}
1436+
1437+
// Error satisfies the [error] interface, returning the original error message.
1438+
func (e *Error) Error() string {
1439+
return e.Err.Error()
1440+
}
1441+
1442+
// Unwrap returns the original error.
1443+
func (e *Error) Unwrap() error { return e.Err }
1444+
14191445
func readerOpts() []metadata.ReaderOption {
14201446
var opts []metadata.ReaderOption
14211447
envs := env.All()
@@ -1472,3 +1498,27 @@ func grab(r []rune, i, end int) rune {
14721498
}
14731499
return 0
14741500
}
1501+
1502+
// linetermRE is the end of line terminal.
1503+
var linetermRE = regexp.MustCompile(`(?:\r?\n)+$`)
1504+
1505+
// empty reports whether s contains at least one printable, non-space character.
1506+
func empty(s string) bool {
1507+
i := strings.IndexFunc(s, func(r rune) bool {
1508+
return unicode.IsPrint(r) && !unicode.IsSpace(r)
1509+
})
1510+
return i == -1
1511+
}
1512+
1513+
var ansiRE = regexp.MustCompile(`\x1b[[0-9]+([:;][0-9]+)*m`)
1514+
1515+
// lastcolor returns the last defined color in s, if any.
1516+
func lastcolor(s string) string {
1517+
if i := strings.LastIndex(s, "\n"); i != -1 {
1518+
s = s[:i]
1519+
}
1520+
if i := strings.LastIndex(s, "\x1b[0m"); i != -1 {
1521+
s = s[i+4:]
1522+
}
1523+
return strings.Join(ansiRE.FindAllString(s, -1), "")
1524+
}

handler/util.go

-31
This file was deleted.

main.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ func main() {
3737
return
3838
}
3939
// run
40-
if err := Run(context.Background(), os.Args); err != nil && err != io.EOF && err != rline.ErrInterrupt {
40+
c := NewCommand(os.Args)
41+
if err := c.ExecuteContext(context.Background()); err != nil && err != io.EOF && err != rline.ErrInterrupt {
4142
var he *handler.Error
4243
if !errors.As(err, &he) {
4344
fmt.Fprintf(os.Stderr, "error: %v\n", err)
@@ -58,6 +59,16 @@ func main() {
5859
}
5960
fmt.Fprintf(os.Stderr, "\ntry:\n\n go install -tags %s github.com/xo/usql@%s\n\n", tag, rev)
6061
}
62+
/*
63+
switch estr := err.Error(); {
64+
case err == text.ErrWrongNumberOfArguments,
65+
strings.HasPrefix(estr, "unknown flag:"),
66+
strings.HasPrefix(estr, "unknown shorthand flag:"),
67+
strings.HasPrefix(estr, "bad flag syntax:"),
68+
strings.HasPrefix(estr, "flag needs an argument:"):
69+
metacmd.Usage(os.Stderr, false)
70+
}
71+
*/
6172
os.Exit(1)
6273
}
6374
}

metacmd/cmds.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ func init() {
6464
}
6565
switch name = strings.TrimSpace(strings.ToLower(name)); {
6666
case name == "options":
67-
Usage(stdout)
67+
Usage(stdout, true)
6868
case name == "variables":
6969
env.Listing(stdout)
7070
default:
@@ -981,5 +981,5 @@ func init() {
981981
}
982982

983983
// Usage is used by the [Question] command to display command line options
984-
var Usage = func(io.Writer) {
984+
var Usage = func(io.Writer, bool) {
985985
}

run.go

+26-17
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,25 @@ import (
2020
"github.com/xo/usql/text"
2121
)
2222

23-
// Run processes args, processing args.CommandOrFiles if non-empty, if
24-
// specified, otherwise launch an interactive readline from stdin.
25-
func Run(ctx context.Context, cliargs []string) error {
23+
// ContextExecutor is the command context.
24+
type ContextExecutor interface {
25+
ExecuteContext(context.Context) error
26+
}
27+
28+
// NewCommand builds the command context.
29+
func NewCommand(cliargs []string) ContextExecutor {
2630
args := &Args{}
2731
v := viper.New()
2832
c := &cobra.Command{
2933
Use: text.CommandName + " [flags]... [DSN]",
3034
Short: text.Short(),
3135
Version: text.CommandVersion,
32-
Args: cobra.RangeArgs(0, 1),
36+
Args: func(_ *cobra.Command, cliargs []string) error {
37+
if len(cliargs) > 1 {
38+
return text.ErrWrongNumberOfArguments
39+
}
40+
return nil
41+
},
3342
PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
3443
commandUpper := text.CommandUpper()
3544
configFile := strings.TrimSpace(os.Getenv(commandUpper + "_CONFIG"))
@@ -68,13 +77,13 @@ func Run(ctx context.Context, cliargs []string) error {
6877
if len(cliargs) > 0 {
6978
args.DSN = cliargs[0]
7079
}
71-
return run(cmd.Context(), args)
80+
return Run(cmd.Context(), args)
7281
},
7382
}
7483

7584
c.SetVersionTemplate("{{ .Name }} {{ .Version }}\n")
7685
c.SetArgs(cliargs[1:])
77-
c.SilenceErrors = true
86+
c.SilenceUsage, c.SilenceErrors = true, true
7887
c.SetUsageTemplate(text.UsageTemplate)
7988

8089
flags := c.Flags()
@@ -128,19 +137,24 @@ func Run(ctx context.Context, cliargs []string) error {
128137
flags.Bool("help", false, "show this help, then exit")
129138
_ = c.Flags().SetAnnotation("help", cobra.FlagSetByCobraAnnotation, []string{"true"})
130139
// expose to metacmd
131-
metacmd.Usage = func(w io.Writer) {
132-
_, _ = w.Write([]byte(text.Short() + "\n\n" + c.UsageString()))
140+
metacmd.Usage = func(w io.Writer, banner bool) {
141+
s := "\n\n" + c.UsageString()
142+
if banner {
143+
s = text.Short() + s
144+
}
145+
_, _ = w.Write([]byte(s))
133146
}
134147
// mark hidden
135148
for _, s := range []string{"no-psqlrc", "no-usqlrc", "var", "variable"} {
136149
if err := flags.MarkHidden(s); err != nil {
137-
return err
150+
panic(err)
138151
}
139152
}
140-
return c.ExecuteContext(ctx)
153+
return c
141154
}
142155

143-
func run(ctx context.Context, args *Args) error {
156+
// Run runs the application.
157+
func Run(ctx context.Context, args *Args) error {
144158
// get user
145159
u, err := user.Current()
146160
if err != nil {
@@ -329,17 +343,12 @@ func (vs) String() string {
329343

330344
// Type satisfies the [pflag.Value] interface.
331345
func (p vs) Type() string {
332-
if p.isBool() {
346+
if p.typ == "" {
333347
return "bool"
334348
}
335349
return p.typ
336350
}
337351

338-
// isBool satisfies the pflag.boolFlag interface.
339-
func (p vs) isBool() bool {
340-
return len(p.vals) != 0 && !strings.Contains(p.vals[0], "%")
341-
}
342-
343352
// filevar is a file var.
344353
type filevar struct {
345354
v *string

0 commit comments

Comments
 (0)