mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
Cobra automatically displays usage messages, and also a gratuitous
"Error: [...]" line in some cases, when any error at all occurs
running a command. To suppress the usage message, you have to set
cmd.SilenceUsage to true. But the code that would do this doesn't
have access to it. To address this, we introduce a category of
"usage error", implemented with stdlib error wrapping (%w) and
use errors.Is to check for it. There's also utility functions
to do this checking automatically, or indeed, to handle wrapping
of the ctl.SomethingCommand and handle running it with a suitable
context and everything.
In fact, several of the places we're checking for usage errors,
we can never actually report one, but we're checking consistently
so that if we want to report usage errors, we can.
For instance, server.Start and (dax)server.Start don't ever
return usage errors, right now, but we're checking their responses
anyway.
(cherry picked from commit c681642734)
139 lines
3.6 KiB
Go
139 lines
3.6 KiB
Go
// Copyright 2022 Molecula Corp. (DBA FeatureBase).
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
package cmd
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"strconv"
|
|
|
|
"github.com/featurebasedb/featurebase/v3/ctl"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
func newRBFCommand(stdin io.Reader, stdout, stderr io.Writer) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "rbf",
|
|
Short: "Inspect RBF data files.",
|
|
Long: `
|
|
Provides a set of commands for inspecting RBF data files.
|
|
`,
|
|
}
|
|
cmd.AddCommand(newRBFCheckCommand(stdin, stdout, stderr))
|
|
cmd.AddCommand(newRBFDumpCommand(stdin, stdout, stderr))
|
|
cmd.AddCommand(newRBFPagesCommand(stdin, stdout, stderr))
|
|
cmd.AddCommand(newRBFPageCommand(stdin, stdout, stderr))
|
|
return cmd
|
|
}
|
|
|
|
func newRBFCheckCommand(stdin io.Reader, stdout, stderr io.Writer) *cobra.Command {
|
|
c := ctl.NewRBFCheckCommand(stdin, stdout, stderr)
|
|
cmd := &cobra.Command{
|
|
Use: "check [flags] PATH",
|
|
Short: "Run consistency check on RBF data.",
|
|
Long: `
|
|
Executes a consistency check on an RBF data directory.
|
|
`,
|
|
Args: func(cmd *cobra.Command, args []string) error {
|
|
if len(args) == 0 {
|
|
return fmt.Errorf("data directory path required")
|
|
} else if len(args) > 1 {
|
|
return fmt.Errorf("too many command line arguments")
|
|
}
|
|
c.Path = args[0]
|
|
return nil
|
|
},
|
|
RunE: usageErrorWrapper(c),
|
|
}
|
|
return cmd
|
|
}
|
|
|
|
func newRBFDumpCommand(stdin io.Reader, stdout, stderr io.Writer) *cobra.Command {
|
|
c := ctl.NewRBFDumpCommand(stdin, stdout, stderr)
|
|
cmd := &cobra.Command{
|
|
Use: "dump [flags] PATH PGNO [PGNO...]",
|
|
Short: "Prints RBF raw page data",
|
|
Long: `
|
|
Dumps the raw hex data for one or more RBF pages.
|
|
`,
|
|
Args: func(cmd *cobra.Command, args []string) error {
|
|
if len(args) == 0 {
|
|
return fmt.Errorf("data directory path required")
|
|
} else if len(args) == 1 {
|
|
return fmt.Errorf("page number required")
|
|
}
|
|
|
|
c.Path = args[0]
|
|
|
|
for _, arg := range args[1:] {
|
|
pgno, err := strconv.Atoi(arg)
|
|
if err != nil {
|
|
return errors.New("invalid page number")
|
|
}
|
|
c.Pgnos = append(c.Pgnos, uint32(pgno))
|
|
}
|
|
|
|
return nil
|
|
},
|
|
RunE: usageErrorWrapper(c),
|
|
}
|
|
return cmd
|
|
}
|
|
|
|
func newRBFPagesCommand(stdin io.Reader, stdout, stderr io.Writer) *cobra.Command {
|
|
c := ctl.NewRBFPagesCommand(stdin, stdout, stderr)
|
|
cmd := &cobra.Command{
|
|
Use: "pages [flags] PATH",
|
|
Short: "Prints metadata for the list of all pages",
|
|
Long: `
|
|
Prints a line for every page in the database with its type/status.
|
|
`,
|
|
Args: func(cmd *cobra.Command, args []string) error {
|
|
if len(args) == 0 {
|
|
return fmt.Errorf("data directory path required")
|
|
} else if len(args) > 1 {
|
|
return fmt.Errorf("too many command line arguments")
|
|
}
|
|
c.Path = args[0]
|
|
return nil
|
|
},
|
|
RunE: usageErrorWrapper(c),
|
|
}
|
|
|
|
flags := cmd.Flags()
|
|
flags.BoolVar(&c.WithTree, "with-tree", false, "Display b-tree name for each row")
|
|
return cmd
|
|
}
|
|
|
|
func newRBFPageCommand(stdin io.Reader, stdout, stderr io.Writer) *cobra.Command {
|
|
c := ctl.NewRBFPageCommand(stdin, stdout, stderr)
|
|
cmd := &cobra.Command{
|
|
Use: "page [flags] PATH PGNO [PGNO...]",
|
|
Short: "Prints data for a page(s)",
|
|
Long: `
|
|
Prints the header & cell data for one or more pages.
|
|
`,
|
|
Args: func(cmd *cobra.Command, args []string) error {
|
|
if len(args) == 0 {
|
|
return fmt.Errorf("data directory path required")
|
|
} else if len(args) == 1 {
|
|
return fmt.Errorf("page number required")
|
|
}
|
|
|
|
c.Path = args[0]
|
|
|
|
for _, arg := range args[1:] {
|
|
pgno, err := strconv.Atoi(arg)
|
|
if err != nil {
|
|
return errors.New("invalid page number")
|
|
}
|
|
c.Pgnos = append(c.Pgnos, uint32(pgno))
|
|
}
|
|
|
|
return nil
|
|
},
|
|
RunE: usageErrorWrapper(c),
|
|
}
|
|
return cmd
|
|
}
|