mirror of
https://github.com/zrepl/zrepl.git
synced 2025-02-16 10:29:54 +01:00
cli: refactor to allow definition of subcommands next to their implementation
This commit is contained in:
parent
aeb87ffbcf
commit
5c3c83b2cb
105
cli/cli.go
Normal file
105
cli/cli.go
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
"github.com/zrepl/zrepl/config"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var rootArgs struct {
|
||||||
|
configPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
var rootCmd = &cobra.Command{
|
||||||
|
Use: "zrepl",
|
||||||
|
Short: "One-stop ZFS replication solution",
|
||||||
|
}
|
||||||
|
|
||||||
|
var bashcompCmd = &cobra.Command{
|
||||||
|
Use: "bashcomp path/to/out/file",
|
||||||
|
Short: "generate bash completions",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
fmt.Fprintf(os.Stderr, "specify exactly one positional agument\n")
|
||||||
|
cmd.Usage()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
if err := rootCmd.GenBashCompletionFile(args[0]); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "error generating bash completion: %s", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Hidden: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.PersistentFlags().StringVar(&rootArgs.configPath, "config", "", "config file path")
|
||||||
|
rootCmd.AddCommand(bashcompCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Subcommand struct {
|
||||||
|
Use string
|
||||||
|
Short string
|
||||||
|
NoRequireConfig bool
|
||||||
|
Run func(subcommand *Subcommand, args []string) error
|
||||||
|
SetupFlags func(f *pflag.FlagSet)
|
||||||
|
|
||||||
|
config *config.Config
|
||||||
|
configErr error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Subcommand) ConfigParsingError() error {
|
||||||
|
return s.configErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Subcommand) Config() *config.Config {
|
||||||
|
if !s.NoRequireConfig && s.config == nil {
|
||||||
|
panic("command that requires config is running and has no config set")
|
||||||
|
}
|
||||||
|
return s.config
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Subcommand) run(cmd *cobra.Command, args []string) {
|
||||||
|
s.tryParseConfig()
|
||||||
|
err := s.Run(s, args)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Subcommand) tryParseConfig() {
|
||||||
|
config, err := config.ParseConfig(rootArgs.configPath)
|
||||||
|
s.configErr = err
|
||||||
|
if err != nil {
|
||||||
|
if s.NoRequireConfig {
|
||||||
|
// doesn't matter
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(os.Stderr, "could not parse config: %s\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.config = config
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddSubcommand(s *Subcommand) {
|
||||||
|
cmd := cobra.Command{
|
||||||
|
Use: s.Use,
|
||||||
|
Short: s.Short,
|
||||||
|
Run: s.run,
|
||||||
|
}
|
||||||
|
if s.SetupFlags != nil {
|
||||||
|
s.SetupFlags(cmd.Flags())
|
||||||
|
}
|
||||||
|
rootCmd.AddCommand(&cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func Run() {
|
||||||
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,36 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import "github.com/zrepl/zrepl/config"
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/kr/pretty"
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
"github.com/zrepl/yaml-config"
|
||||||
|
"github.com/zrepl/zrepl/cli"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
func RunConfigcheck(conf *config.Config, args []string) error {
|
var configcheckArgs struct {
|
||||||
// TODO: do the 'build' steps, e.g. build the jobs and see if that fails
|
format string
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ConfigcheckCmd = &cli.Subcommand{
|
||||||
|
Use: "configcheck",
|
||||||
|
Short: "check if config can be parsed without errors",
|
||||||
|
SetupFlags: func(f *pflag.FlagSet) {
|
||||||
|
f.StringVar(&configcheckArgs.format, "format", "", "dump parsed config object [pretty|yaml|json]")
|
||||||
|
},
|
||||||
|
Run: func(subcommand *cli.Subcommand, args []string) error {
|
||||||
|
switch configcheckArgs.format {
|
||||||
|
case "pretty":
|
||||||
|
_, err := pretty.Println(subcommand.Config())
|
||||||
|
return err
|
||||||
|
case "json":
|
||||||
|
return json.NewEncoder(os.Stdout).Encode(subcommand.Config())
|
||||||
|
case "yaml":
|
||||||
|
return yaml.NewEncoder(os.Stdout).Encode(subcommand.Config())
|
||||||
|
default: // no output
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -1,17 +1,48 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/zrepl/zrepl/cli"
|
||||||
"github.com/zrepl/zrepl/config"
|
"github.com/zrepl/zrepl/config"
|
||||||
"github.com/zrepl/zrepl/daemon"
|
"github.com/zrepl/zrepl/daemon"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PProfArgs struct {
|
var pprofArgs struct {
|
||||||
daemon.PprofServerControlMsg
|
daemon.PprofServerControlMsg
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunPProf(conf *config.Config, args PProfArgs) {
|
var PprofCmd = &cli.Subcommand{
|
||||||
|
Use: "pprof off | [on TCP_LISTEN_ADDRESS]",
|
||||||
|
Short: "start a http server exposing go-tool-compatible profiling endpoints at TCP_LISTEN_ADDRESS",
|
||||||
|
Run: func(subcommand *cli.Subcommand, args []string) error {
|
||||||
|
if len(args) < 1 {
|
||||||
|
goto enargs
|
||||||
|
}
|
||||||
|
switch args[0] {
|
||||||
|
case "on":
|
||||||
|
pprofArgs.Run = true
|
||||||
|
if len(args) != 2 {
|
||||||
|
return errors.New("must specify TCP_LISTEN_ADDRESS as second positional argument")
|
||||||
|
}
|
||||||
|
pprofArgs.HttpListenAddress = args[1]
|
||||||
|
case "off":
|
||||||
|
if len(args) != 1 {
|
||||||
|
goto enargs
|
||||||
|
}
|
||||||
|
pprofArgs.Run = false
|
||||||
|
}
|
||||||
|
|
||||||
|
RunPProf(subcommand.Config())
|
||||||
|
return nil
|
||||||
|
enargs:
|
||||||
|
return errors.New("invalid number of positional arguments")
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunPProf(conf *config.Config) {
|
||||||
log := log.New(os.Stderr, "", 0)
|
log := log.New(os.Stderr, "", 0)
|
||||||
|
|
||||||
die := func() {
|
die := func() {
|
||||||
@ -26,7 +57,7 @@ func RunPProf(conf *config.Config, args PProfArgs) {
|
|||||||
log.Printf("error creating http client: %s", err)
|
log.Printf("error creating http client: %s", err)
|
||||||
die()
|
die()
|
||||||
}
|
}
|
||||||
err = jsonRequestResponse(httpc, daemon.ControlJobEndpointPProf, args.PprofServerControlMsg, struct{}{})
|
err = jsonRequestResponse(httpc, daemon.ControlJobEndpointPProf, pprofArgs.PprofServerControlMsg, struct{}{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error sending control message: %s", err)
|
log.Printf("error sending control message: %s", err)
|
||||||
die()
|
die()
|
||||||
|
@ -2,11 +2,20 @@ package client
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/zrepl/zrepl/cli"
|
||||||
"github.com/zrepl/zrepl/config"
|
"github.com/zrepl/zrepl/config"
|
||||||
"github.com/zrepl/zrepl/daemon"
|
"github.com/zrepl/zrepl/daemon"
|
||||||
)
|
)
|
||||||
|
|
||||||
func RunSignal(config *config.Config, args []string) error {
|
var SignalCmd = &cli.Subcommand{
|
||||||
|
Use: "signal [wakeup|reset] JOB",
|
||||||
|
Short: "wake up a job from wait state or abort its current invocation",
|
||||||
|
Run: func(subcommand *cli.Subcommand, args []string) error {
|
||||||
|
return runSignalCmd(subcommand.Config(), args)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func runSignalCmd(config *config.Config, args []string) error {
|
||||||
if len(args) != 2 {
|
if len(args) != 2 {
|
||||||
return errors.Errorf("Expected 2 arguments: [wakeup|reset] JOB")
|
return errors.Errorf("Expected 2 arguments: [wakeup|reset] JOB")
|
||||||
}
|
}
|
||||||
|
@ -4,21 +4,22 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/nsf/termbox-go"
|
"github.com/nsf/termbox-go"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/spf13/pflag"
|
||||||
"github.com/zrepl/yaml-config"
|
"github.com/zrepl/yaml-config"
|
||||||
"github.com/zrepl/zrepl/config"
|
"github.com/zrepl/zrepl/cli"
|
||||||
"github.com/zrepl/zrepl/daemon"
|
"github.com/zrepl/zrepl/daemon"
|
||||||
"github.com/zrepl/zrepl/daemon/job"
|
"github.com/zrepl/zrepl/daemon/job"
|
||||||
"github.com/zrepl/zrepl/daemon/pruner"
|
"github.com/zrepl/zrepl/daemon/pruner"
|
||||||
"github.com/zrepl/zrepl/replication"
|
"github.com/zrepl/zrepl/replication"
|
||||||
"github.com/zrepl/zrepl/replication/fsrep"
|
"github.com/zrepl/zrepl/replication/fsrep"
|
||||||
|
"io"
|
||||||
"math"
|
"math"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"net/http"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type tui struct {
|
type tui struct {
|
||||||
@ -73,17 +74,26 @@ func (t *tui) addIndent(indent int) {
|
|||||||
t.moveLine(0, 0)
|
t.moveLine(0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
type StatusFlags struct {
|
var statusFlags struct {
|
||||||
Raw bool
|
Raw bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunStatus(flags StatusFlags, config *config.Config, args []string) error {
|
var StatusCmd = &cli.Subcommand{
|
||||||
httpc, err := controlHttpClient(config.Global.Control.SockPath)
|
Use: "status",
|
||||||
|
Short: "show job activity or dump as JSON for monitoring",
|
||||||
|
SetupFlags: func(f *pflag.FlagSet) {
|
||||||
|
f.BoolVar(&statusFlags.Raw, "raw", false, "dump raw status description from zrepl daemon")
|
||||||
|
},
|
||||||
|
Run: runStatus,
|
||||||
|
}
|
||||||
|
|
||||||
|
func runStatus(s *cli.Subcommand, args []string) error {
|
||||||
|
httpc, err := controlHttpClient(s.Config().Global.Control.SockPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if flags.Raw {
|
if statusFlags.Raw {
|
||||||
resp, err := httpc.Get("http://unix"+daemon.ControlJobEndpointStatus)
|
resp, err := httpc.Get("http://unix"+daemon.ControlJobEndpointStatus)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1,18 +1,26 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/zrepl/zrepl/cli"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"github.com/problame/go-netssh"
|
"github.com/problame/go-netssh"
|
||||||
|
"github.com/zrepl/zrepl/config"
|
||||||
"log"
|
"log"
|
||||||
"path"
|
"path"
|
||||||
"github.com/zrepl/zrepl/config"
|
|
||||||
"errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var StdinserverCmd = &cli.Subcommand{
|
||||||
|
Use: "stdinserver CLIENT_IDENTITY",
|
||||||
|
Short: "stdinserver transport mode (started from authorized_keys file as forced command)",
|
||||||
|
Run: func(subcommand *cli.Subcommand, args []string) error {
|
||||||
|
return runStdinserver(subcommand.Config(), args)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
func RunStdinserver(config *config.Config, args []string) error {
|
func runStdinserver(config *config.Config, args []string) error {
|
||||||
|
|
||||||
// NOTE: the netssh proxying protocol requires exiting with non-zero status if anything goes wrong
|
// NOTE: the netssh proxying protocol requires exiting with non-zero status if anything goes wrong
|
||||||
defer os.Exit(1)
|
defer os.Exit(1)
|
||||||
|
@ -2,27 +2,39 @@ package client
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
"github.com/zrepl/zrepl/cli"
|
||||||
"github.com/zrepl/zrepl/config"
|
"github.com/zrepl/zrepl/config"
|
||||||
"github.com/zrepl/zrepl/daemon"
|
"github.com/zrepl/zrepl/daemon"
|
||||||
"github.com/zrepl/zrepl/version"
|
"github.com/zrepl/zrepl/version"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
type VersionArgs struct {
|
var versionArgs struct {
|
||||||
Show string
|
Show string
|
||||||
Config *config.Config
|
Config *config.Config
|
||||||
|
ConfigErr error
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunVersion(args VersionArgs) {
|
var VersionCmd = &cli.Subcommand{
|
||||||
|
Use: "version",
|
||||||
|
Short: "print version of zrepl binary and running daemon",
|
||||||
|
NoRequireConfig: true,
|
||||||
|
SetupFlags: func(f *pflag.FlagSet) {
|
||||||
|
f.StringVar(&versionArgs.Show, "show", "", "version info to show (client|daemon)")
|
||||||
|
},
|
||||||
|
Run: func(subcommand *cli.Subcommand, args []string) error {
|
||||||
|
versionArgs.Config = subcommand.Config()
|
||||||
|
versionArgs.ConfigErr = subcommand.ConfigParsingError()
|
||||||
|
return runVersionCmd()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
die := func() {
|
func runVersionCmd() error {
|
||||||
fmt.Fprintf(os.Stderr, "exiting after error\n")
|
args := versionArgs
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if args.Show != "daemon" && args.Show != "client" && args.Show != "" {
|
if args.Show != "daemon" && args.Show != "client" && args.Show != "" {
|
||||||
fmt.Fprintf(os.Stderr, "show flag must be 'client' or 'server' or be left empty")
|
return fmt.Errorf("show flag must be 'client' or 'server' or be left empty")
|
||||||
die()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var clientVersion, daemonVersion *version.ZreplVersionInformation
|
var clientVersion, daemonVersion *version.ZreplVersionInformation
|
||||||
@ -32,17 +44,19 @@ func RunVersion(args VersionArgs) {
|
|||||||
}
|
}
|
||||||
if args.Show == "daemon" || args.Show == "" {
|
if args.Show == "daemon" || args.Show == "" {
|
||||||
|
|
||||||
|
if args.ConfigErr != nil {
|
||||||
|
return fmt.Errorf("config parsing error: %s", args.ConfigErr)
|
||||||
|
}
|
||||||
|
|
||||||
httpc, err := controlHttpClient(args.Config.Global.Control.SockPath)
|
httpc, err := controlHttpClient(args.Config.Global.Control.SockPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "server: error: %s\n", err)
|
return fmt.Errorf("server: error: %s\n", err)
|
||||||
die()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var info version.ZreplVersionInformation
|
var info version.ZreplVersionInformation
|
||||||
err = jsonRequestResponse(httpc, daemon.ControlJobEndpointVersion, "", &info)
|
err = jsonRequestResponse(httpc, daemon.ControlJobEndpointVersion, "", &info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "server: error: %s\n", err)
|
return fmt.Errorf("server: error: %s\n", err)
|
||||||
die()
|
|
||||||
}
|
}
|
||||||
daemonVersion = &info
|
daemonVersion = &info
|
||||||
fmt.Printf("server: %s\n", daemonVersion.String())
|
fmt.Printf("server: %s\n", daemonVersion.String())
|
||||||
@ -54,4 +68,5 @@ func RunVersion(args VersionArgs) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,16 @@
|
|||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/zrepl/zrepl/cli"
|
||||||
"github.com/zrepl/zrepl/logger"
|
"github.com/zrepl/zrepl/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Logger = logger.Logger
|
type Logger = logger.Logger
|
||||||
|
|
||||||
|
var DaemonCmd = &cli.Subcommand {
|
||||||
|
Use: "daemon",
|
||||||
|
Short: "run the zrepl daemon",
|
||||||
|
Run: func(subcommand *cli.Subcommand, args []string) error {
|
||||||
|
return Run(subcommand.Config())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
169
main.go
169
main.go
@ -2,172 +2,21 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"github.com/zrepl/zrepl/cli"
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"github.com/zrepl/zrepl/client"
|
"github.com/zrepl/zrepl/client"
|
||||||
"github.com/zrepl/zrepl/config"
|
|
||||||
"github.com/zrepl/zrepl/daemon"
|
"github.com/zrepl/zrepl/daemon"
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"fmt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var rootCmd = &cobra.Command{
|
|
||||||
Use: "zrepl",
|
|
||||||
Short: "One-stop ZFS replication solution",
|
|
||||||
}
|
|
||||||
|
|
||||||
var daemonCmd = &cobra.Command{
|
|
||||||
Use: "daemon",
|
|
||||||
Short: "run the zrepl daemon",
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
conf, err := config.ParseConfig(rootArgs.configFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return daemon.Run(conf)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var signalCmd = &cobra.Command{
|
|
||||||
Use: "signal [wakeup|reset] JOB",
|
|
||||||
Short: "wake up a job from wait state or abort its current invocation",
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
conf, err := config.ParseConfig(rootArgs.configFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return client.RunSignal(conf, args)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var statusCmdFlags client.StatusFlags
|
|
||||||
|
|
||||||
var statusCmd = &cobra.Command{
|
|
||||||
Use: "status",
|
|
||||||
Short: "show job activity or dump as JSON for monitoring",
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
conf, err := config.ParseConfig(rootArgs.configFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return client.RunStatus(statusCmdFlags, conf, args)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var stdinserverCmd = &cobra.Command{
|
|
||||||
Use: "stdinserver CLIENT_IDENTITY",
|
|
||||||
Short: "stdinserver transport mode (started from authorized_keys file as forced command)",
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
conf, err := config.ParseConfig(rootArgs.configFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return client.RunStdinserver(conf, args)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var bashcompCmd = &cobra.Command{
|
|
||||||
Use: "bashcomp path/to/out/file",
|
|
||||||
Short: "generate bash completions",
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
|
||||||
if len(args) != 1 {
|
|
||||||
fmt.Fprintf(os.Stderr, "specify exactly one positional agument\n")
|
|
||||||
cmd.Usage()
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
if err := rootCmd.GenBashCompletionFile(args[0]); err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "error generating bash completion: %s", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Hidden: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
var configcheckCmd = &cobra.Command{
|
|
||||||
Use: "configcheck",
|
|
||||||
Short: "check if config can be parsed without errors",
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
conf, err := config.ParseConfig(rootArgs.configFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return client.RunConfigcheck(conf, args)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var versionCmdArgs client.VersionArgs
|
|
||||||
var versionCmd = &cobra.Command{
|
|
||||||
Use: "version",
|
|
||||||
Short: "print version of zrepl binary and running daemon",
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
|
||||||
conf, err := config.ParseConfig(rootArgs.configFile)
|
|
||||||
if err == nil {
|
|
||||||
versionCmdArgs.Config = conf
|
|
||||||
}
|
|
||||||
client.RunVersion(versionCmdArgs)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var pprofCmd = &cobra.Command{
|
|
||||||
Use: "pprof off | [on TCP_LISTEN_ADDRESS]",
|
|
||||||
Short: "start a http server exposing go-tool-compatible profiling endpoints at TCP_LISTEN_ADDRESS",
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
conf, err := config.ParseConfig(rootArgs.configFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var pprofCmdArgs client.PProfArgs
|
|
||||||
if cmd.Flags().NArg() < 1 {
|
|
||||||
goto enargs
|
|
||||||
}
|
|
||||||
switch cmd.Flags().Arg(0) {
|
|
||||||
case "on":
|
|
||||||
pprofCmdArgs.Run = true
|
|
||||||
if cmd.Flags().NArg() != 2 {
|
|
||||||
return errors.New("must specify TCP_LISTEN_ADDRESS as second positional argument")
|
|
||||||
}
|
|
||||||
pprofCmdArgs.HttpListenAddress = cmd.Flags().Arg(1)
|
|
||||||
case "off":
|
|
||||||
if cmd.Flags().NArg() != 1 {
|
|
||||||
goto enargs
|
|
||||||
}
|
|
||||||
pprofCmdArgs.Run = false
|
|
||||||
}
|
|
||||||
|
|
||||||
client.RunPProf(conf, pprofCmdArgs)
|
|
||||||
return nil
|
|
||||||
enargs:
|
|
||||||
return errors.New("invalid number of positional arguments")
|
|
||||||
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var rootArgs struct {
|
|
||||||
configFile string
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
//cobra.OnInitialize(initConfig)
|
cli.AddSubcommand(daemon.DaemonCmd)
|
||||||
rootCmd.PersistentFlags().StringVar(&rootArgs.configFile, "config", "", "config file path")
|
cli.AddSubcommand(client.StatusCmd)
|
||||||
rootCmd.AddCommand(daemonCmd)
|
cli.AddSubcommand(client.SignalCmd)
|
||||||
rootCmd.AddCommand(signalCmd)
|
cli.AddSubcommand(client.StdinserverCmd)
|
||||||
statusCmd.Flags().BoolVar(&statusCmdFlags.Raw, "raw", false, "dump raw status description from zrepl daemon")
|
cli.AddSubcommand(client.ConfigcheckCmd)
|
||||||
rootCmd.AddCommand(statusCmd)
|
cli.AddSubcommand(client.VersionCmd)
|
||||||
rootCmd.AddCommand(stdinserverCmd)
|
cli.AddSubcommand(client.PprofCmd)
|
||||||
rootCmd.AddCommand(bashcompCmd)
|
|
||||||
rootCmd.AddCommand(configcheckCmd)
|
|
||||||
versionCmd.Flags().StringVar(&versionCmdArgs.Show, "show", "", "version info to show (client|daemon)")
|
|
||||||
rootCmd.AddCommand(versionCmd)
|
|
||||||
rootCmd.AddCommand(pprofCmd)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
cli.Run()
|
||||||
if err := rootCmd.Execute(); err != nil {
|
|
||||||
log.Printf("error executing root command: %s", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user