Skip to content

Commit

Permalink
#472 Migrate buckets command to cobra style commands
Browse files Browse the repository at this point in the history
Signed-off-by: tommy shem <[email protected]>
  • Loading branch information
tommy shem committed Nov 13, 2024
1 parent a28237b commit a039306
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 89 deletions.
51 changes: 51 additions & 0 deletions cmd/bbolt/command_buckets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package main

import (
"fmt"
"os"

"github.com/spf13/cobra"
bolt "go.etcd.io/bbolt"
)

// newBucketsCommand creates a new command that prints a list of buckets in the given Bolt database.
//
// The path to a Bolt database must be specified as an argument.
func newBucketsCommand() *cobra.Command {
var bucketsCmd = &cobra.Command{
Use: "buckets <path>",
Short: "Print a list of buckets",
Long: "Print a list of buckets in the given Bolt database\nThe path to a Bolt database must be specified as an argument",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return printBucketsList(cmd, args[0])
},
}
return bucketsCmd
}

// printBucketsList prints a list of buckets in the given Bolt database.
func printBucketsList(cmd *cobra.Command, path string) error {
// Required database path.
if path == "" {
return ErrPathRequired
// Verify if the specified database file exists.
} 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 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
})
})
}
53 changes: 53 additions & 0 deletions cmd/bbolt/command_buckets_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package main_test

import (
"bytes"
"testing"

"github.com/spf13/cobra"
"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 bucketscommand.
t.Log("Running buckets command")
rootCmd := main.NewRootCommand()
_, actualOutput, err := executeCommand(rootCmd, "buckets", db.Path()) //rootCmd, "buckets", db.Path())
require.NoError(t, err)
t.Log("Verify result")
expected := "bar\nbaz\nfoo\n"
require.EqualValues(t, expected, actualOutput)
}

// executeCommand runs the given command and returns the output and error.
func executeCommand(rootCmd *cobra.Command, args ...string) (*cobra.Command, string, error) {
outputBuf := bytes.NewBufferString("")
rootCmd.SetOut(outputBuf)
rootCmd.SetErr(outputBuf)
rootCmd.SetArgs(args)
c, err := rootCmd.ExecuteC()
return c, outputBuf.String(), err
}
1 change: 1 addition & 0 deletions cmd/bbolt/command_root.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ func NewRootCommand() *cobra.Command {
newSurgeryCommand(),
newInspectCommand(),
newCheckCommand(),
newBucketsCommand(),
)

return rootCmd
Expand Down
59 changes: 0 additions & 59 deletions cmd/bbolt/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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":
Expand Down Expand Up @@ -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
Expand Down
30 changes: 0 additions & 30 deletions cmd/bbolt/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit a039306

Please sign in to comment.