From 76ff28c71989cb8596ce505e6c69e78b1e063688 Mon Sep 17 00:00:00 2001 From: tommy shem Date: Thu, 21 Nov 2024 19:55:06 +0000 Subject: [PATCH] #472 Migrate buckets command to cobra style commands Signed-off-by: tommy shem --- cmd/bbolt/command_buckets.go | 45 +++++++++++++++++++++++ cmd/bbolt/command_buckets_test.go | 48 +++++++++++++++++++++++++ cmd/bbolt/command_root.go | 1 + cmd/bbolt/main.go | 59 ------------------------------- cmd/bbolt/main_test.go | 30 ---------------- 5 files changed, 94 insertions(+), 89 deletions(-) create mode 100644 cmd/bbolt/command_buckets.go create mode 100644 cmd/bbolt/command_buckets_test.go diff --git a/cmd/bbolt/command_buckets.go b/cmd/bbolt/command_buckets.go new file mode 100644 index 000000000..be5ac2746 --- /dev/null +++ b/cmd/bbolt/command_buckets.go @@ -0,0 +1,45 @@ +package main + +import ( + "fmt" + + "github.com/spf13/cobra" + bolt "go.etcd.io/bbolt" +) + +func newBucketsCommand() *cobra.Command { + var bucketsCmd = &cobra.Command{ + Use: "buckets ", + Short: "print a list of buckets", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + return bucketsFunc(cmd, args[0]) + }, + } + return bucketsCmd +} + +func bucketsFunc(cmd *cobra.Command, srcDBPath string) error { + // Required database path. + if srcDBPath == "" { + return ErrPathRequired + // Verify if the specified database file exists. + } else if _, err := checkSourceDBPath(srcDBPath); err != nil { + return err + } + + // Open database. + db, err := bolt.Open(srcDBPath, 0600, &bolt.Options{ReadOnly: true}) + if err != nil { + return err + } + defer db.Close() + + // Print the list of buckets in the database. + return db.View(func(tx *bolt.Tx) error { + return tx.ForEach(func(name []byte, _ *bolt.Bucket) error { + fmt.Fprintln(cmd.OutOrStdout(), string(name)) + return nil + }) + }) +} diff --git a/cmd/bbolt/command_buckets_test.go b/cmd/bbolt/command_buckets_test.go new file mode 100644 index 000000000..5d7168ec7 --- /dev/null +++ b/cmd/bbolt/command_buckets_test.go @@ -0,0 +1,48 @@ +package main_test + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/require" + + bolt "go.etcd.io/bbolt" + main "go.etcd.io/bbolt/cmd/bbolt" + "go.etcd.io/bbolt/internal/btesting" +) + +// Ensure the "buckets" command can print a list of buckets. +func TestBuckets(t *testing.T) { + // Create a test database and populate it with sample buckets. + t.Log("Creating sample DB") + db := btesting.MustCreateDB(t) + t.Log("Creating sample Buckets") + if err := db.Update(func(tx *bolt.Tx) error { + for _, name := range []string{"foo", "bar", "baz"} { + _, err := tx.CreateBucket([]byte(name)) + if err != nil { + return err + } + } + return nil + }); err != nil { + t.Fatal(err) + } + db.Close() + defer requireDBNoChange(t, dbData(t, db.Path()), db.Path()) + + // setup the buckets command. + t.Log("Running buckets command") + rootCmd := main.NewRootCommand() + var args []string = []string{"buckets", db.Path()} + outputBuf := bytes.NewBufferString("") + rootCmd.SetOut(outputBuf) + rootCmd.SetErr(outputBuf) + rootCmd.SetArgs(args) + _, err := rootCmd.ExecuteC() + actualOutput := outputBuf.String() + require.NoError(t, err) + t.Log("Verify result") + expected := "bar\nbaz\nfoo\n" + require.EqualValues(t, expected, actualOutput) +} diff --git a/cmd/bbolt/command_root.go b/cmd/bbolt/command_root.go index 0336ea36c..a278458b7 100644 --- a/cmd/bbolt/command_root.go +++ b/cmd/bbolt/command_root.go @@ -21,6 +21,7 @@ func NewRootCommand() *cobra.Command { newSurgeryCommand(), newInspectCommand(), newCheckCommand(), + newBucketsCommand(), ) return rootCmd diff --git a/cmd/bbolt/main.go b/cmd/bbolt/main.go index a9256a699..b934b9900 100644 --- a/cmd/bbolt/main.go +++ b/cmd/bbolt/main.go @@ -122,8 +122,6 @@ func (m *Main) Run(args ...string) error { return ErrUsage case "bench": return newBenchCommand(m).Run(args[1:]...) - case "buckets": - return newBucketsCommand(m).Run(args[1:]...) case "compact": return newCompactCommand(m).Run(args[1:]...) case "dump": @@ -763,63 +761,6 @@ experience corruption, please submit a ticket to the etcd-io/bbolt project page: `, "\n") } -// bucketsCommand represents the "buckets" command execution. -type bucketsCommand struct { - baseCommand -} - -// newBucketsCommand returns a bucketsCommand. -func newBucketsCommand(m *Main) *bucketsCommand { - c := &bucketsCommand{} - c.baseCommand = m.baseCommand - return c -} - -// Run executes the command. -func (cmd *bucketsCommand) Run(args ...string) error { - // Parse flags. - fs := flag.NewFlagSet("", flag.ContinueOnError) - help := fs.Bool("h", false, "") - if err := fs.Parse(args); err != nil { - return err - } else if *help { - fmt.Fprintln(cmd.Stderr, cmd.Usage()) - return ErrUsage - } - - // Require database path. - path := fs.Arg(0) - if path == "" { - return ErrPathRequired - } else if _, err := os.Stat(path); os.IsNotExist(err) { - return ErrFileNotFound - } - - // Open database. - db, err := bolt.Open(path, 0600, &bolt.Options{ReadOnly: true}) - if err != nil { - return err - } - defer db.Close() - - // Print buckets. - return db.View(func(tx *bolt.Tx) error { - return tx.ForEach(func(name []byte, _ *bolt.Bucket) error { - fmt.Fprintln(cmd.Stdout, string(name)) - return nil - }) - }) -} - -// Usage returns the help message. -func (cmd *bucketsCommand) Usage() string { - return strings.TrimLeft(` -usage: bolt buckets PATH - -Print a list of buckets. -`, "\n") -} - // keysCommand represents the "keys" command execution. type keysCommand struct { baseCommand diff --git a/cmd/bbolt/main_test.go b/cmd/bbolt/main_test.go index 727b38f55..ef2b6f78e 100644 --- a/cmd/bbolt/main_test.go +++ b/cmd/bbolt/main_test.go @@ -274,36 +274,6 @@ func TestStatsCommand_Run(t *testing.T) { } } -// Ensure the "buckets" command can print a list of buckets. -func TestBucketsCommand_Run(t *testing.T) { - db := btesting.MustCreateDB(t) - - if err := db.Update(func(tx *bolt.Tx) error { - for _, name := range []string{"foo", "bar", "baz"} { - _, err := tx.CreateBucket([]byte(name)) - if err != nil { - return err - } - } - return nil - }); err != nil { - t.Fatal(err) - } - db.Close() - - defer requireDBNoChange(t, dbData(t, db.Path()), db.Path()) - - expected := "bar\nbaz\nfoo\n" - - // Run the command. - m := NewMain() - if err := m.Run("buckets", db.Path()); err != nil { - t.Fatal(err) - } else if actual := m.Stdout.String(); actual != expected { - t.Fatalf("unexpected stdout:\n\n%s", actual) - } -} - // Ensure the "keys" command can print a list of keys for a bucket. func TestKeysCommand_Run(t *testing.T) { testCases := []struct {