Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

command buckets converted to the cobra style #859

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
Comment on lines +11 to +13
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's unnecessary comment to me. The command is self-explanation.

Suggested change
// 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])
},
Comment on lines +17 to +22
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please try to keep consistent with other commands implementation.

Suggested change
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])
},
Short: "print a list of buckets",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return bucketsFunc(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
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use checkSourceDBPath. See example below,

if _, err := checkSourceDBPath(srcDBPath); err != nil {


// 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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just remove this function and get the implementation inlined in the test?

If you want to make it as a generic test utility function (i.e. included in utils_test.go), let's do it in a followup PR and we can discuss it separately.

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