mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
etcdctlv3: use spf13/cobra for cli interface
This replaces codegansta/cli with spf13/cobra base on this guideline: https://github.com/coreos/docs/blob/master/golang/README.md#cli.
This commit is contained in:
parent
a6bb74e9ff
commit
b7647e0b55
@ -15,38 +15,42 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/codegangsta/cli"
|
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/spf13/cobra"
|
||||||
"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
|
"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
|
||||||
"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc"
|
"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc"
|
||||||
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewCompactionCommand returns the CLI command for "compaction".
|
// NewCompactionCommand returns the cobra command for "compaction".
|
||||||
func NewCompactionCommand() cli.Command {
|
func NewCompactionCommand() *cobra.Command {
|
||||||
return cli.Command{
|
return &cobra.Command{
|
||||||
Name: "compaction",
|
Use: "compaction",
|
||||||
Action: func(c *cli.Context) {
|
Short: "Compaction compacts the event history in etcd.",
|
||||||
compactionCommandFunc(c)
|
Run: compactionCommandFunc,
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// compactionCommandFunc executes the "compaction" command.
|
// compactionCommandFunc executes the "compaction" command.
|
||||||
func compactionCommandFunc(c *cli.Context) {
|
func compactionCommandFunc(cmd *cobra.Command, args []string) {
|
||||||
if len(c.Args()) != 1 {
|
if len(args) != 1 {
|
||||||
panic("bad arg")
|
ExitWithError(ExitBadArgs, fmt.Errorf("compaction command needs 1 argument."))
|
||||||
}
|
}
|
||||||
|
|
||||||
rev, err := strconv.ParseInt(c.Args()[0], 10, 64)
|
rev, err := strconv.ParseInt(args[0], 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("bad arg")
|
ExitWithError(ExitError, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := grpc.Dial(c.GlobalString("endpoint"))
|
endpoint, err := cmd.Flags().GetString("endpoint")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
ExitWithError(ExitError, err)
|
||||||
|
}
|
||||||
|
conn, err := grpc.Dial(endpoint)
|
||||||
|
if err != nil {
|
||||||
|
ExitWithError(ExitBadConnection, err)
|
||||||
}
|
}
|
||||||
kv := pb.NewKVClient(conn)
|
kv := pb.NewKVClient(conn)
|
||||||
req := &pb.CompactionRequest{Revision: rev}
|
req := &pb.CompactionRequest{Revision: rev}
|
@ -17,36 +17,40 @@ package command
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/codegangsta/cli"
|
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/spf13/cobra"
|
||||||
"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
|
"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
|
||||||
"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc"
|
"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc"
|
||||||
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewDeleteRangeCommand returns the CLI command for "deleteRange".
|
// NewDeleteRangeCommand returns the cobra command for "deleteRange".
|
||||||
func NewDeleteRangeCommand() cli.Command {
|
func NewDeleteRangeCommand() *cobra.Command {
|
||||||
return cli.Command{
|
return &cobra.Command{
|
||||||
Name: "delete-range",
|
Use: "delete-range",
|
||||||
Action: func(c *cli.Context) {
|
Short: "DeleteRange deletes the given range from the store.",
|
||||||
deleteRangeCommandFunc(c)
|
Run: deleteRangeCommandFunc,
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// deleteRangeCommandFunc executes the "delegeRange" command.
|
// deleteRangeCommandFunc executes the "deleteRange" command.
|
||||||
func deleteRangeCommandFunc(c *cli.Context) {
|
func deleteRangeCommandFunc(cmd *cobra.Command, args []string) {
|
||||||
if len(c.Args()) == 0 {
|
if len(args) == 0 {
|
||||||
panic("bad arg")
|
ExitWithError(ExitBadArgs, fmt.Errorf("delete-range command needs arguments."))
|
||||||
}
|
}
|
||||||
|
|
||||||
var rangeEnd []byte
|
var rangeEnd []byte
|
||||||
key := []byte(c.Args()[0])
|
key := []byte(args[0])
|
||||||
if len(c.Args()) > 1 {
|
if len(args) > 1 {
|
||||||
rangeEnd = []byte(c.Args()[1])
|
rangeEnd = []byte(args[1])
|
||||||
}
|
}
|
||||||
conn, err := grpc.Dial(c.GlobalString("endpoint"))
|
|
||||||
|
endpoint, err := cmd.Flags().GetString("endpoint")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
ExitWithError(ExitError, err)
|
||||||
|
}
|
||||||
|
conn, err := grpc.Dial(endpoint)
|
||||||
|
if err != nil {
|
||||||
|
ExitWithError(ExitBadConnection, err)
|
||||||
}
|
}
|
||||||
kv := pb.NewKVClient(conn)
|
kv := pb.NewKVClient(conn)
|
||||||
req := &pb.DeleteRangeRequest{Key: key, RangeEnd: rangeEnd}
|
req := &pb.DeleteRangeRequest{Key: key, RangeEnd: rangeEnd}
|
||||||
|
39
etcdctlv3/command/error.go
Normal file
39
etcdctlv3/command/error.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// Copyright 2015 CoreOS, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/coreos/etcd/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// http://tldp.org/LDP/abs/html/exitcodes.html
|
||||||
|
ExitSuccess = iota
|
||||||
|
ExitError
|
||||||
|
ExitBadConnection
|
||||||
|
ExitInvalidInput // for txn, watch command
|
||||||
|
ExitBadArgs = 128
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExitWithError(code int, err error) {
|
||||||
|
fmt.Fprintln(os.Stderr, "Error: ", err)
|
||||||
|
if cerr, ok := err.(*client.ClusterError); ok {
|
||||||
|
fmt.Fprintln(os.Stderr, cerr.Detail())
|
||||||
|
}
|
||||||
|
os.Exit(code)
|
||||||
|
}
|
21
etcdctlv3/command/global.go
Normal file
21
etcdctlv3/command/global.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright 2015 CoreOS, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package command
|
||||||
|
|
||||||
|
// GlobalFlags are flags that defined globally
|
||||||
|
// and are inherited to all sub-commands.
|
||||||
|
type GlobalFlags struct {
|
||||||
|
Endpoints string
|
||||||
|
}
|
@ -17,33 +17,37 @@ package command
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/codegangsta/cli"
|
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/spf13/cobra"
|
||||||
"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
|
"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
|
||||||
"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc"
|
"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc"
|
||||||
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewPutCommand returns the CLI command for "put".
|
// NewPutCommand returns the cobra command for "put".
|
||||||
func NewPutCommand() cli.Command {
|
func NewPutCommand() *cobra.Command {
|
||||||
return cli.Command{
|
return &cobra.Command{
|
||||||
Name: "put",
|
Use: "put",
|
||||||
Action: func(c *cli.Context) {
|
Short: "Put puts the given key into the store.",
|
||||||
putCommandFunc(c)
|
Run: putCommandFunc,
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// putCommandFunc executes the "put" command.
|
// putCommandFunc executes the "put" command.
|
||||||
func putCommandFunc(c *cli.Context) {
|
func putCommandFunc(cmd *cobra.Command, args []string) {
|
||||||
if len(c.Args()) != 2 {
|
if len(args) != 2 {
|
||||||
panic("bad arg")
|
ExitWithError(ExitBadArgs, fmt.Errorf("put command needs 2 arguments."))
|
||||||
}
|
}
|
||||||
|
|
||||||
key := []byte(c.Args()[0])
|
key := []byte(args[0])
|
||||||
value := []byte(c.Args()[1])
|
value := []byte(args[1])
|
||||||
conn, err := grpc.Dial(c.GlobalString("endpoint"))
|
|
||||||
|
endpoint, err := cmd.Flags().GetString("endpoint")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
ExitWithError(ExitError, err)
|
||||||
|
}
|
||||||
|
conn, err := grpc.Dial(endpoint)
|
||||||
|
if err != nil {
|
||||||
|
ExitWithError(ExitBadConnection, err)
|
||||||
}
|
}
|
||||||
kv := pb.NewKVClient(conn)
|
kv := pb.NewKVClient(conn)
|
||||||
req := &pb.PutRequest{Key: key, Value: value}
|
req := &pb.PutRequest{Key: key, Value: value}
|
||||||
|
@ -17,36 +17,40 @@ package command
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/codegangsta/cli"
|
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/spf13/cobra"
|
||||||
"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
|
"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
|
||||||
"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc"
|
"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc"
|
||||||
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewRangeCommand returns the CLI command for "range".
|
// NewRangeCommand returns the cobra command for "range".
|
||||||
func NewRangeCommand() cli.Command {
|
func NewRangeCommand() *cobra.Command {
|
||||||
return cli.Command{
|
return &cobra.Command{
|
||||||
Name: "range",
|
Use: "range",
|
||||||
Action: func(c *cli.Context) {
|
Short: "Range gets the keys in the range from the store.",
|
||||||
rangeCommandFunc(c)
|
Run: rangeCommandFunc,
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// rangeCommandFunc executes the "range" command.
|
// rangeCommandFunc executes the "range" command.
|
||||||
func rangeCommandFunc(c *cli.Context) {
|
func rangeCommandFunc(cmd *cobra.Command, args []string) {
|
||||||
if len(c.Args()) == 0 {
|
if len(args) == 0 {
|
||||||
panic("bad arg")
|
ExitWithError(ExitBadArgs, fmt.Errorf("range command needs arguments."))
|
||||||
}
|
}
|
||||||
|
|
||||||
var rangeEnd []byte
|
var rangeEnd []byte
|
||||||
key := []byte(c.Args()[0])
|
key := []byte(args[0])
|
||||||
if len(c.Args()) > 1 {
|
if len(args) > 1 {
|
||||||
rangeEnd = []byte(c.Args()[1])
|
rangeEnd = []byte(args[1])
|
||||||
}
|
}
|
||||||
conn, err := grpc.Dial(c.GlobalString("endpoint"))
|
|
||||||
|
endpoint, err := cmd.Flags().GetString("endpoint")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
ExitWithError(ExitError, err)
|
||||||
|
}
|
||||||
|
conn, err := grpc.Dial(endpoint)
|
||||||
|
if err != nil {
|
||||||
|
ExitWithError(ExitBadConnection, err)
|
||||||
}
|
}
|
||||||
kv := pb.NewKVClient(conn)
|
kv := pb.NewKVClient(conn)
|
||||||
req := &pb.RangeRequest{Key: key, RangeEnd: rangeEnd}
|
req := &pb.RangeRequest{Key: key, RangeEnd: rangeEnd}
|
||||||
|
@ -21,26 +21,25 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/codegangsta/cli"
|
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/spf13/cobra"
|
||||||
"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
|
"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
|
||||||
"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc"
|
"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc"
|
||||||
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewTxnCommand returns the CLI command for "txn".
|
// NewTxnCommand returns the cobra command for "txn".
|
||||||
func NewTxnCommand() cli.Command {
|
func NewTxnCommand() *cobra.Command {
|
||||||
return cli.Command{
|
return &cobra.Command{
|
||||||
Name: "txn",
|
Use: "txn",
|
||||||
Action: func(c *cli.Context) {
|
Short: "Txn processes all the requests in one transaction.",
|
||||||
txnCommandFunc(c)
|
Run: txnCommandFunc,
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// txnCommandFunc executes the "txn" command.
|
// txnCommandFunc executes the "txn" command.
|
||||||
func txnCommandFunc(c *cli.Context) {
|
func txnCommandFunc(cmd *cobra.Command, args []string) {
|
||||||
if len(c.Args()) != 0 {
|
if len(args) != 0 {
|
||||||
panic("unexpected args")
|
ExitWithError(ExitBadArgs, fmt.Errorf("txn command does not accept argument."))
|
||||||
}
|
}
|
||||||
|
|
||||||
reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
@ -51,15 +50,19 @@ func txnCommandFunc(c *cli.Context) {
|
|||||||
next = next(txn, reader)
|
next = next(txn, reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := grpc.Dial(c.GlobalString("endpoint"))
|
endpoint, err := cmd.Flags().GetString("endpoint")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
ExitWithError(ExitError, err)
|
||||||
|
}
|
||||||
|
conn, err := grpc.Dial(endpoint)
|
||||||
|
if err != nil {
|
||||||
|
ExitWithError(ExitBadConnection, err)
|
||||||
}
|
}
|
||||||
kv := pb.NewKVClient(conn)
|
kv := pb.NewKVClient(conn)
|
||||||
|
|
||||||
resp, err := kv.Txn(context.Background(), txn)
|
resp, err := kv.Txn(context.Background(), txn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
ExitWithError(ExitError, err)
|
||||||
}
|
}
|
||||||
if resp.Succeeded {
|
if resp.Succeeded {
|
||||||
fmt.Println("executed success request list")
|
fmt.Println("executed success request list")
|
||||||
@ -75,7 +78,7 @@ func compareState(txn *pb.TxnRequest, r *bufio.Reader) stateFunc {
|
|||||||
|
|
||||||
line, err := r.ReadString('\n')
|
line, err := r.ReadString('\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
os.Exit(1)
|
ExitWithError(ExitInvalidInput, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(line) == 1 {
|
if len(line) == 1 {
|
||||||
@ -86,8 +89,7 @@ func compareState(txn *pb.TxnRequest, r *bufio.Reader) stateFunc {
|
|||||||
line = line[:len(line)-1]
|
line = line[:len(line)-1]
|
||||||
c, err := parseCompare(line)
|
c, err := parseCompare(line)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
ExitWithError(ExitInvalidInput, err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
txn.Compare = append(txn.Compare, c)
|
txn.Compare = append(txn.Compare, c)
|
||||||
@ -100,7 +102,7 @@ func successState(txn *pb.TxnRequest, r *bufio.Reader) stateFunc {
|
|||||||
|
|
||||||
line, err := r.ReadString('\n')
|
line, err := r.ReadString('\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
os.Exit(1)
|
ExitWithError(ExitInvalidInput, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(line) == 1 {
|
if len(line) == 1 {
|
||||||
@ -111,8 +113,7 @@ func successState(txn *pb.TxnRequest, r *bufio.Reader) stateFunc {
|
|||||||
line = line[:len(line)-1]
|
line = line[:len(line)-1]
|
||||||
ru, err := parseRequestUnion(line)
|
ru, err := parseRequestUnion(line)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
ExitWithError(ExitInvalidInput, err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
txn.Success = append(txn.Success, ru)
|
txn.Success = append(txn.Success, ru)
|
||||||
@ -125,7 +126,7 @@ func failureState(txn *pb.TxnRequest, r *bufio.Reader) stateFunc {
|
|||||||
|
|
||||||
line, err := r.ReadString('\n')
|
line, err := r.ReadString('\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
os.Exit(1)
|
ExitWithError(ExitInvalidInput, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(line) == 1 {
|
if len(line) == 1 {
|
||||||
@ -136,8 +137,7 @@ func failureState(txn *pb.TxnRequest, r *bufio.Reader) stateFunc {
|
|||||||
line = line[:len(line)-1]
|
line = line[:len(line)-1]
|
||||||
ru, err := parseRequestUnion(line)
|
ru, err := parseRequestUnion(line)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
ExitWithError(ExitInvalidInput, err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
txn.Failure = append(txn.Failure, ru)
|
txn.Failure = append(txn.Failure, ru)
|
||||||
|
35
etcdctlv3/command/version_command.go
Normal file
35
etcdctlv3/command/version_command.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2015 CoreOS, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/spf13/cobra"
|
||||||
|
"github.com/coreos/etcd/version"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewVersionCommand prints out the version of etcd.
|
||||||
|
func NewVersionCommand() *cobra.Command {
|
||||||
|
return &cobra.Command{
|
||||||
|
Use: "version",
|
||||||
|
Short: "Print the version of etcdctlv3.",
|
||||||
|
Run: versionCommandFunc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func versionCommandFunc(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Println(version.Version)
|
||||||
|
}
|
@ -21,33 +21,36 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/codegangsta/cli"
|
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/spf13/cobra"
|
||||||
"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
|
"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
|
||||||
"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc"
|
"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc"
|
||||||
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewWatchCommand returns the CLI command for "watch".
|
// NewWatchCommand returns the cobra command for "watch".
|
||||||
func NewWatchCommand() cli.Command {
|
func NewWatchCommand() *cobra.Command {
|
||||||
return cli.Command{
|
return &cobra.Command{
|
||||||
Name: "watch",
|
Use: "watch",
|
||||||
Action: func(c *cli.Context) {
|
Short: "Watch watches the events happening or happened.",
|
||||||
watchCommandFunc(c)
|
Run: watchCommandFunc,
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// watchCommandFunc executes the "watch" command.
|
// watchCommandFunc executes the "watch" command.
|
||||||
func watchCommandFunc(c *cli.Context) {
|
func watchCommandFunc(cmd *cobra.Command, args []string) {
|
||||||
conn, err := grpc.Dial(c.GlobalString("endpoint"))
|
endpoint, err := cmd.Flags().GetString("endpoint")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
ExitWithError(ExitInvalidInput, err)
|
||||||
|
}
|
||||||
|
conn, err := grpc.Dial(endpoint)
|
||||||
|
if err != nil {
|
||||||
|
ExitWithError(ExitBadConnection, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
wAPI := pb.NewWatchClient(conn)
|
wAPI := pb.NewWatchClient(conn)
|
||||||
wStream, err := wAPI.Watch(context.TODO())
|
wStream, err := wAPI.Watch(context.TODO())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
ExitWithError(ExitBadConnection, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
go recvLoop(wStream)
|
go recvLoop(wStream)
|
||||||
@ -57,8 +60,7 @@ func watchCommandFunc(c *cli.Context) {
|
|||||||
for {
|
for {
|
||||||
l, err := reader.ReadString('\n')
|
l, err := reader.ReadString('\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error reading watch request line: %v", err)
|
ExitWithError(ExitInvalidInput, fmt.Errorf("Error reading watch request line: %v", err))
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
l = strings.TrimSuffix(l, "\n")
|
l = strings.TrimSuffix(l, "\n")
|
||||||
|
|
||||||
@ -91,10 +93,10 @@ func recvLoop(wStream pb.Watch_WatchClient) {
|
|||||||
for {
|
for {
|
||||||
resp, err := wStream.Recv()
|
resp, err := wStream.Recv()
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
os.Exit(0)
|
os.Exit(ExitSuccess)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
ExitWithError(ExitError, err)
|
||||||
}
|
}
|
||||||
fmt.Printf("%s: %s %s\n", resp.Event.Type, string(resp.Event.Kv.Key), string(resp.Event.Kv.Value))
|
fmt.Printf("%s: %s %s\n", resp.Event.Type, string(resp.Event.Kv.Key), string(resp.Event.Kv.Value))
|
||||||
}
|
}
|
||||||
|
166
etcdctlv3/help.go
Normal file
166
etcdctlv3/help.go
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
// Copyright 2015 CoreOS, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// copied from https://github.com/coreos/rkt/blob/master/rkt/help.go
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"text/tabwriter"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/spf13/cobra"
|
||||||
|
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/spf13/pflag"
|
||||||
|
"github.com/coreos/etcd/version"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
commandUsageTemplate *template.Template
|
||||||
|
templFuncs = template.FuncMap{
|
||||||
|
"descToLines": func(s string) []string {
|
||||||
|
// trim leading/trailing whitespace and split into slice of lines
|
||||||
|
return strings.Split(strings.Trim(s, "\n\t "), "\n")
|
||||||
|
},
|
||||||
|
"cmdName": func(cmd *cobra.Command, startCmd *cobra.Command) string {
|
||||||
|
parts := []string{cmd.Name()}
|
||||||
|
for cmd.HasParent() && cmd.Parent().Name() != startCmd.Name() {
|
||||||
|
cmd = cmd.Parent()
|
||||||
|
parts = append([]string{cmd.Name()}, parts...)
|
||||||
|
}
|
||||||
|
return strings.Join(parts, " ")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
commandUsage := `
|
||||||
|
{{ $cmd := .Cmd }}\
|
||||||
|
{{ $cmdname := cmdName .Cmd .Cmd.Root }}\
|
||||||
|
NAME:
|
||||||
|
{{ if not .Cmd.HasParent }}\
|
||||||
|
{{printf "\t%s - %s" .Cmd.Name .Cmd.Short}}
|
||||||
|
{{else}}\
|
||||||
|
{{printf "\t%s - %s" $cmdname .Cmd.Short}}
|
||||||
|
{{end}}\
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
{{printf "\t%s" .Cmd.UseLine}}
|
||||||
|
{{ if not .Cmd.HasParent }}\
|
||||||
|
|
||||||
|
VERSION:
|
||||||
|
{{printf "\t%s" .Version}}
|
||||||
|
{{end}}\
|
||||||
|
{{if .Cmd.HasSubCommands}}\
|
||||||
|
|
||||||
|
COMMANDS:
|
||||||
|
{{range .SubCommands}}\
|
||||||
|
{{ $cmdname := cmdName . $cmd }}\
|
||||||
|
{{ if .Runnable }}\
|
||||||
|
{{printf "\t%s\t%s" $cmdname .Short}}
|
||||||
|
{{end}}\
|
||||||
|
{{end}}\
|
||||||
|
{{end}}\
|
||||||
|
{{ if .Cmd.Long }}\
|
||||||
|
|
||||||
|
DESCRIPTION:
|
||||||
|
{{range $line := descToLines .Cmd.Long}}{{printf "\t%s" $line}}
|
||||||
|
{{end}}\
|
||||||
|
{{end}}\
|
||||||
|
{{if .Cmd.HasLocalFlags}}\
|
||||||
|
|
||||||
|
OPTIONS:
|
||||||
|
{{.LocalFlags}}\
|
||||||
|
{{end}}\
|
||||||
|
{{if .Cmd.HasInheritedFlags}}\
|
||||||
|
|
||||||
|
GLOBAL OPTIONS:
|
||||||
|
{{.GlobalFlags}}\
|
||||||
|
{{end}}
|
||||||
|
`[1:]
|
||||||
|
|
||||||
|
commandUsageTemplate = template.Must(template.New("command_usage").Funcs(templFuncs).Parse(strings.Replace(commandUsage, "\\\n", "", -1)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func etcdFlagUsages(flagSet *pflag.FlagSet) string {
|
||||||
|
x := new(bytes.Buffer)
|
||||||
|
|
||||||
|
flagSet.VisitAll(func(flag *pflag.Flag) {
|
||||||
|
if len(flag.Deprecated) > 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
format := ""
|
||||||
|
if len(flag.Shorthand) > 0 {
|
||||||
|
format = " -%s, --%s"
|
||||||
|
} else {
|
||||||
|
format = " %s --%s"
|
||||||
|
}
|
||||||
|
if len(flag.NoOptDefVal) > 0 {
|
||||||
|
format = format + "["
|
||||||
|
}
|
||||||
|
if flag.Value.Type() == "string" {
|
||||||
|
// put quotes on the value
|
||||||
|
format = format + "=%q"
|
||||||
|
} else {
|
||||||
|
format = format + "=%s"
|
||||||
|
}
|
||||||
|
if len(flag.NoOptDefVal) > 0 {
|
||||||
|
format = format + "]"
|
||||||
|
}
|
||||||
|
format = format + "\t%s\n"
|
||||||
|
shorthand := flag.Shorthand
|
||||||
|
fmt.Fprintf(x, format, shorthand, flag.Name, flag.DefValue, flag.Usage)
|
||||||
|
})
|
||||||
|
|
||||||
|
return x.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSubCommands(cmd *cobra.Command) []*cobra.Command {
|
||||||
|
var subCommands []*cobra.Command
|
||||||
|
for _, subCmd := range cmd.Commands() {
|
||||||
|
subCommands = append(subCommands, subCmd)
|
||||||
|
subCommands = append(subCommands, getSubCommands(subCmd)...)
|
||||||
|
}
|
||||||
|
return subCommands
|
||||||
|
}
|
||||||
|
|
||||||
|
func usageFunc(cmd *cobra.Command) error {
|
||||||
|
subCommands := getSubCommands(cmd)
|
||||||
|
tabOut := getTabOutWithWriter(os.Stdout)
|
||||||
|
commandUsageTemplate.Execute(tabOut, struct {
|
||||||
|
Cmd *cobra.Command
|
||||||
|
LocalFlags string
|
||||||
|
GlobalFlags string
|
||||||
|
SubCommands []*cobra.Command
|
||||||
|
Version string
|
||||||
|
}{
|
||||||
|
cmd,
|
||||||
|
etcdFlagUsages(cmd.LocalFlags()),
|
||||||
|
etcdFlagUsages(cmd.InheritedFlags()),
|
||||||
|
subCommands,
|
||||||
|
version.Version,
|
||||||
|
})
|
||||||
|
tabOut.Flush()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTabOutWithWriter(writer io.Writer) *tabwriter.Writer {
|
||||||
|
aTabOut := new(tabwriter.Writer)
|
||||||
|
aTabOut.Init(writer, 0, 8, 1, '\t', 0)
|
||||||
|
return aTabOut
|
||||||
|
}
|
@ -16,29 +16,55 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"text/tabwriter"
|
||||||
|
|
||||||
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/codegangsta/cli"
|
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/spf13/cobra"
|
||||||
"github.com/coreos/etcd/etcdctlv3/command"
|
"github.com/coreos/etcd/etcdctlv3/command"
|
||||||
"github.com/coreos/etcd/version"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
const (
|
||||||
app := cli.NewApp()
|
cliName = "etcdctlv3"
|
||||||
app.Name = "etcdctlv3"
|
cliDescription = "A simple command line client for etcd3."
|
||||||
app.Version = version.Version
|
)
|
||||||
app.Usage = "A simple command line client for etcd3."
|
|
||||||
app.Flags = []cli.Flag{
|
var (
|
||||||
cli.StringFlag{Name: "endpoint", Value: "127.0.0.1:2378", Usage: "gRPC endpoint"},
|
tabOut *tabwriter.Writer
|
||||||
|
globalFlags = command.GlobalFlags{}
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
rootCmd = &cobra.Command{
|
||||||
|
Use: cliName,
|
||||||
|
Short: cliDescription,
|
||||||
|
SuggestFor: []string{"etcctlv3", "etcdcltv3", "etlctlv3"},
|
||||||
}
|
}
|
||||||
app.Commands = []cli.Command{
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.PersistentFlags().StringVar(&globalFlags.Endpoints, "endpoint", "127.0.0.1:2378", "gRPC endpoint")
|
||||||
|
|
||||||
|
rootCmd.AddCommand(
|
||||||
command.NewRangeCommand(),
|
command.NewRangeCommand(),
|
||||||
command.NewPutCommand(),
|
command.NewPutCommand(),
|
||||||
command.NewDeleteRangeCommand(),
|
command.NewDeleteRangeCommand(),
|
||||||
command.NewTxnCommand(),
|
command.NewTxnCommand(),
|
||||||
command.NewCompactionCommand(),
|
command.NewCompactionCommand(),
|
||||||
command.NewWatchCommand(),
|
command.NewWatchCommand(),
|
||||||
|
command.NewVersionCommand(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Run(os.Args)
|
func init() {
|
||||||
|
cobra.EnablePrefixMatching = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
rootCmd.SetUsageFunc(usageFunc)
|
||||||
|
|
||||||
|
// Make help just show the usage
|
||||||
|
rootCmd.SetHelpTemplate(`{{.UsageString}}`)
|
||||||
|
|
||||||
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
command.ExitWithError(command.ExitError, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user