[#854] cli: Do not use global flags

Also delete `ttl` and `xhdr` flags from
`accounting balance` command and refactor
command initialization.

Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
This commit is contained in:
Pavel Karpy 2021-09-27 18:36:14 +03:00 committed by Alex Vanin
parent 4ccb3d05d8
commit 8c59ade4ed
8 changed files with 562 additions and 219 deletions

View file

@ -8,6 +8,7 @@ import (
"github.com/nspcc-dev/neofs-api-go/pkg/accounting"
"github.com/nspcc-dev/neofs-api-go/pkg/owner"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var (
@ -19,6 +20,16 @@ var accountingCmd = &cobra.Command{
Use: "accounting",
Short: "Operations with accounts and balances",
Long: `Operations with accounts and balances`,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
flags := cmd.Flags()
_ = viper.BindPFlag(binaryKey, flags.Lookup(binaryKey))
_ = viper.BindPFlag(walletPath, flags.Lookup(walletPath))
_ = viper.BindPFlag(wif, flags.Lookup(wif))
_ = viper.BindPFlag(address, flags.Lookup(address))
_ = viper.BindPFlag(rpc, flags.Lookup(rpc))
_ = viper.BindPFlag(verbose, flags.Lookup(verbose))
},
}
var accountingBalanceCmd = &cobra.Command{
@ -57,6 +68,19 @@ var accountingBalanceCmd = &cobra.Command{
},
}
func initAccountingBalanceCmd() {
ff := accountingBalanceCmd.Flags()
ff.StringP(binaryKey, binaryKeyShorthand, binaryKeyDefault, binaryKeyUsage)
ff.StringP(walletPath, walletPathShorthand, walletPathDefault, walletPathUsage)
ff.StringP(wif, wifShorthand, wifDefault, wifUsage)
ff.StringP(address, addressShorthand, addressDefault, addressUsage)
ff.StringP(rpc, rpcShorthand, rpcDefault, rpcUsage)
ff.BoolP(verbose, verboseShorthand, verboseDefault, verboseUsage)
accountingBalanceCmd.Flags().StringVar(&balanceOwner, "owner", "", "owner of balance account (omit to use owner from private key)")
}
func init() {
rootCmd.AddCommand(accountingCmd)
accountingCmd.AddCommand(accountingBalanceCmd)
@ -71,7 +95,7 @@ func init() {
// is called directly, e.g.:
// accountingCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
accountingBalanceCmd.Flags().StringVar(&balanceOwner, "owner", "", "owner of balance account (omit to use owner from private key)")
initAccountingBalanceCmd()
}
func prettyPrintDecimal(cmd *cobra.Command, decimal *accounting.Decimal) {
@ -79,7 +103,7 @@ func prettyPrintDecimal(cmd *cobra.Command, decimal *accounting.Decimal) {
return
}
if verbose {
if viper.GetBool(verbose) {
cmd.Println("value:", decimal.Value())
cmd.Println("precision:", decimal.Precision())
} else {

View file

@ -79,6 +79,11 @@ var containerCmd = &cobra.Command{
Use: "container",
Short: "Operations with containers",
Long: "Operations with containers",
PersistentPreRun: func(cmd *cobra.Command, args []string) {
// bind exactly that cmd's flags to
// the viper before execution
bindCommonFlags(cmd)
},
}
var listContainersCmd = &cobra.Command{
@ -429,15 +434,89 @@ Container ID in EACL table will be substituted with ID from the CLI.`,
},
}
func initContainerListContainersCmd() {
initCommonFlags(listContainersCmd)
flags := listContainersCmd.Flags()
flags.StringVar(&containerOwner, "owner", "", "owner of containers (omit to use owner from private key)")
}
func initContainerCreateCmd() {
initCommonFlags(createContainerCmd)
flags := createContainerCmd.Flags()
flags.StringVar(&containerACL, "basic-acl", basicACLPrivate, fmt.Sprintf("hex encoded basic ACL value or keywords '%s', '%s', '%s'", basicACLPublic, basicACLPrivate, basicACLReadOnly))
flags.StringVarP(&containerPolicy, "policy", "p", "", "QL-encoded or JSON-encoded placement policy or path to file with it")
flags.StringSliceVarP(&containerAttributes, "attributes", "a", nil, "comma separated pairs of container attributes in form of Key1=Value1,Key2=Value2")
flags.StringVarP(&containerNonce, "nonce", "n", "", "UUIDv4 nonce value for container")
flags.BoolVar(&containerAwait, "await", false, "block execution until container is persisted")
flags.StringVar(&containerName, "name", "", "container name attribute")
flags.BoolVar(&containerNoTimestamp, "disable-timestamp", false, "disable timestamp container attribute")
}
func initContainerDeleteCmd() {
initCommonFlags(deleteContainerCmd)
flags := deleteContainerCmd.Flags()
flags.StringVar(&containerID, "cid", "", "container ID")
flags.BoolVar(&containerAwait, "await", false, "block execution until container is removed")
}
func initContainerListObjectsCmd() {
initCommonFlags(listContainerObjectsCmd)
flags := listContainerObjectsCmd.Flags()
flags.StringVar(&containerID, "cid", "", "container ID")
}
func initContainerInfoCmd() {
initCommonFlags(getContainerInfoCmd)
flags := getContainerInfoCmd.Flags()
flags.StringVar(&containerID, "cid", "", "container ID")
flags.StringVar(&containerPathTo, "to", "", "path to dump encoded container")
flags.StringVar(&containerPathFrom, "from", "", "path to file with encoded container")
flags.BoolVar(&containerJSON, "json", false, "print or dump container in JSON format")
}
func initContainerGetEACLCmd() {
initCommonFlags(getExtendedACLCmd)
flags := getExtendedACLCmd.Flags()
flags.StringVar(&containerID, "cid", "", "container ID")
flags.StringVar(&containerPathTo, "to", "", "path to dump encoded container (default: binary encoded)")
flags.BoolVar(&containerJSON, "json", false, "encode EACL table in json format")
}
func initContainerSetEACLCmd() {
initCommonFlags(setExtendedACLCmd)
flags := setExtendedACLCmd.Flags()
flags.StringVar(&containerID, "cid", "", "container ID")
flags.StringVar(&eaclPathFrom, "table", "", "path to file with JSON or binary encoded EACL table")
flags.BoolVar(&containerAwait, "await", false, "block execution until EACL is persisted")
}
func init() {
containerChildCommand := []*cobra.Command{
listContainersCmd,
createContainerCmd,
deleteContainerCmd,
listContainerObjectsCmd,
getContainerInfoCmd,
getExtendedACLCmd,
setExtendedACLCmd,
}
rootCmd.AddCommand(containerCmd)
containerCmd.AddCommand(listContainersCmd)
containerCmd.AddCommand(createContainerCmd)
containerCmd.AddCommand(deleteContainerCmd)
containerCmd.AddCommand(listContainerObjectsCmd)
containerCmd.AddCommand(getContainerInfoCmd)
containerCmd.AddCommand(getExtendedACLCmd)
containerCmd.AddCommand(setExtendedACLCmd)
containerCmd.AddCommand(containerChildCommand...)
// Here you will define your flags and configuration settings.
@ -449,43 +528,20 @@ func init() {
// is called directly, e.g.:
// containerCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
// container list
listContainersCmd.Flags().StringVar(&containerOwner, "owner", "", "owner of containers (omit to use owner from private key)")
initContainerListContainersCmd()
initContainerCreateCmd()
initContainerDeleteCmd()
initContainerListObjectsCmd()
initContainerInfoCmd()
initContainerGetEACLCmd()
initContainerSetEACLCmd()
// container create
createContainerCmd.Flags().StringVar(&containerACL, "basic-acl", basicACLPrivate,
fmt.Sprintf("hex encoded basic ACL value or keywords '%s', '%s', '%s'", basicACLPublic, basicACLPrivate, basicACLReadOnly))
createContainerCmd.Flags().StringVarP(&containerPolicy, "policy", "p", "",
"QL-encoded or JSON-encoded placement policy or path to file with it")
createContainerCmd.Flags().StringSliceVarP(&containerAttributes, "attributes", "a", nil,
"comma separated pairs of container attributes in form of Key1=Value1,Key2=Value2")
createContainerCmd.Flags().StringVarP(&containerNonce, "nonce", "n", "", "UUIDv4 nonce value for container")
createContainerCmd.Flags().BoolVar(&containerAwait, "await", false, "block execution until container is persisted")
createContainerCmd.Flags().StringVar(&containerName, "name", "", "container name attribute")
createContainerCmd.Flags().BoolVar(&containerNoTimestamp, "disable-timestamp", false, "disable timestamp container attribute")
for _, containerCommand := range containerChildCommand {
flags := containerCommand.Flags()
// container delete
deleteContainerCmd.Flags().StringVar(&containerID, "cid", "", "container ID")
deleteContainerCmd.Flags().BoolVar(&containerAwait, "await", false, "block execution until container is removed")
// container list-object
listContainerObjectsCmd.Flags().StringVar(&containerID, "cid", "", "container ID")
// container get
getContainerInfoCmd.Flags().StringVar(&containerID, "cid", "", "container ID")
getContainerInfoCmd.Flags().StringVar(&containerPathTo, "to", "", "path to dump encoded container")
getContainerInfoCmd.Flags().StringVar(&containerPathFrom, "from", "", "path to file with encoded container")
getContainerInfoCmd.Flags().BoolVar(&containerJSON, "json", false, "print or dump container in JSON format")
// container get-eacl
getExtendedACLCmd.Flags().StringVar(&containerID, "cid", "", "container ID")
getExtendedACLCmd.Flags().StringVar(&containerPathTo, "to", "", "path to dump encoded container (default: binary encoded)")
getExtendedACLCmd.Flags().BoolVar(&containerJSON, "json", false, "encode EACL table in json format")
// container set-eacl
setExtendedACLCmd.Flags().StringVar(&containerID, "cid", "", "container ID")
setExtendedACLCmd.Flags().StringVar(&eaclPathFrom, "table", "", "path to file with JSON or binary encoded EACL table")
setExtendedACLCmd.Flags().BoolVar(&containerAwait, "await", false, "block execution until EACL is persisted")
flags.StringSliceVarP(&xHeaders, xHeadersKey, xHeadersShorthand, xHeadersDefault, xHeadersUsage)
flags.Uint32P(ttl, ttlShorthand, ttlDefault, ttlUsage)
}
for _, cmd := range []*cobra.Command{
createContainerCmd,

View file

@ -53,6 +53,41 @@ var (
var netmapStatus string
func initControlHealthCheckCmd() {
initCommonFlags(healthCheckCmd)
healthCheckCmd.Flags().BoolVar(&healthCheckIRVar, healthcheckIRFlag, false, "Communicate with IR node")
}
func initControlSetNetmapStatusCmd() {
initCommonFlags(setNetmapStatusCmd)
setNetmapStatusCmd.Flags().StringVarP(&netmapStatus, netmapStatusFlag, "", "",
fmt.Sprintf("new netmap status keyword ('%s', '%s')",
netmapStatusOnline,
netmapStatusOffline,
),
)
_ = setNetmapStatusCmd.MarkFlagRequired(netmapStatusFlag)
}
func initControlDropObjectsCmd() {
initCommonFlags(dropObjectsCmd)
dropObjectsCmd.Flags().StringSliceVarP(&dropObjectsList, dropObjectsFlag, "o", nil,
"List of object addresses to be removed in string format")
_ = dropObjectsCmd.MarkFlagRequired(dropObjectsFlag)
}
func initControlSnapshotCmd() {
initCommonFlags(snapshotCmd)
snapshotCmd.Flags().BoolVar(&netmapSnapshotJSON, "json", false,
"print netmap structure in JSON format")
}
func init() {
rootCmd.AddCommand(controlCmd)
@ -63,24 +98,10 @@ func init() {
snapshotCmd,
)
setNetmapStatusCmd.Flags().StringVarP(&netmapStatus, netmapStatusFlag, "", "",
fmt.Sprintf("new netmap status keyword ('%s', '%s')",
netmapStatusOnline,
netmapStatusOffline,
),
)
_ = setNetmapStatusCmd.MarkFlagRequired(netmapStatusFlag)
dropObjectsCmd.Flags().StringSliceVarP(&dropObjectsList, dropObjectsFlag, "o", nil,
"List of object addresses to be removed in string format")
_ = dropObjectsCmd.MarkFlagRequired(dropObjectsFlag)
healthCheckCmd.Flags().BoolVar(&healthCheckIRVar, healthcheckIRFlag, false, "Communicate with IR node")
snapshotCmd.Flags().BoolVar(&netmapSnapshotJSON, "json", false,
"print netmap structure in JSON format")
initControlHealthCheckCmd()
initControlSetNetmapStatusCmd()
initControlDropObjectsCmd()
initControlSnapshotCmd()
}
func healthCheck(cmd *cobra.Command, _ []string) {

View file

@ -22,18 +22,35 @@ var netmapCmd = &cobra.Command{
Use: "netmap",
Short: "Operations with Network Map",
Long: `Operations with Network Map`,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
// bind exactly that cmd's flags to
// the viper before execution
bindCommonFlags(cmd)
},
}
func init() {
rootCmd.AddCommand(netmapCmd)
netmapCmd.AddCommand(
netmapChildCommands := []*cobra.Command{
getEpochCmd,
localNodeInfoCmd,
netInfoCmd,
)
}
rootCmd.AddCommand(netmapCmd)
netmapCmd.AddCommand(netmapChildCommands...)
initCommonFlags(getEpochCmd)
initCommonFlags(netInfoCmd)
initCommonFlags(localNodeInfoCmd)
localNodeInfoCmd.Flags().BoolVar(&nodeInfoJSON, "json", false, "print node info in JSON format")
for _, netmapCommand := range netmapChildCommands {
flags := netmapCommand.Flags()
flags.StringSliceVarP(&xHeaders, xHeadersKey, xHeadersShorthand, xHeadersDefault, xHeadersUsage)
flags.Uint32P(ttl, ttlShorthand, ttlDefault, ttlUsage)
}
}
var getEpochCmd = &cobra.Command{

View file

@ -42,6 +42,11 @@ var (
Use: "object",
Short: "Operations with Objects",
Long: `Operations with Objects`,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
// bind exactly that cmd's flags to
// the viper before execution
bindCommonFlags(cmd)
},
}
objectPutCmd = &cobra.Command{
@ -114,74 +119,139 @@ const putExpiresOnFlag = "expires-on"
var putExpiredOn uint64
func init() {
rootCmd.AddCommand(objectCmd)
objectCmd.PersistentFlags().String("bearer", "", "File with signed JSON or binary encoded bearer token")
func initObjectPutCmd() {
initCommonFlags(objectPutCmd)
objectCmd.AddCommand(objectPutCmd)
objectPutCmd.Flags().String("file", "", "File with object payload")
flags := objectPutCmd.Flags()
flags.String("file", "", "File with object payload")
_ = objectPutCmd.MarkFlagFilename("file")
_ = objectPutCmd.MarkFlagRequired("file")
objectPutCmd.Flags().String("cid", "", "Container ID")
flags.String("cid", "", "Container ID")
_ = objectPutCmd.MarkFlagRequired("cid")
objectPutCmd.Flags().String("attributes", "", "User attributes in form of Key1=Value1,Key2=Value2")
objectPutCmd.Flags().Bool("disable-filename", false, "Do not set well-known filename attribute")
objectPutCmd.Flags().Bool("disable-timestamp", false, "Do not set well-known timestamp attribute")
objectPutCmd.Flags().Uint64VarP(&putExpiredOn, putExpiresOnFlag, "e", 0,
"Last epoch in the life of the object")
objectCmd.AddCommand(objectDelCmd)
objectDelCmd.Flags().String("cid", "", "Container ID")
flags.String("attributes", "", "User attributes in form of Key1=Value1,Key2=Value2")
flags.Bool("disable-filename", false, "Do not set well-known filename attribute")
flags.Bool("disable-timestamp", false, "Do not set well-known timestamp attribute")
flags.Uint64VarP(&putExpiredOn, putExpiresOnFlag, "e", 0, "Last epoch in the life of the object")
}
func initObjectDeleteCmd() {
initCommonFlags(objectDelCmd)
flags := objectDelCmd.Flags()
flags.String("cid", "", "Container ID")
_ = objectDelCmd.MarkFlagRequired("cid")
objectDelCmd.Flags().String("oid", "", "Object ID")
flags.String("oid", "", "Object ID")
_ = objectDelCmd.MarkFlagRequired("oid")
}
objectCmd.AddCommand(objectGetCmd)
objectGetCmd.Flags().String("file", "", "File to write object payload to. Default: stdout.")
objectGetCmd.Flags().String("header", "", "File to write header to. Default: stdout.")
objectGetCmd.Flags().String("cid", "", "Container ID")
func initObjectGetCmd() {
initCommonFlags(objectGetCmd)
flags := objectGetCmd.Flags()
flags.String("cid", "", "Container ID")
_ = objectGetCmd.MarkFlagRequired("cid")
objectGetCmd.Flags().String("oid", "", "Object ID")
flags.String("oid", "", "Object ID")
_ = objectGetCmd.MarkFlagRequired("oid")
objectGetCmd.Flags().Bool(rawFlag, false, rawFlagDesc)
objectCmd.AddCommand(objectSearchCmd)
objectSearchCmd.Flags().String("cid", "", "Container ID")
flags.String("file", "", "File to write object payload to. Default: stdout.")
flags.String("header", "", "File to write header to. Default: stdout.")
flags.Bool(rawFlag, false, rawFlagDesc)
}
func initObjectSearchCmd() {
initCommonFlags(objectSearchCmd)
flags := objectSearchCmd.Flags()
flags.String("cid", "", "Container ID")
_ = objectSearchCmd.MarkFlagRequired("cid")
objectSearchCmd.Flags().StringSliceVarP(&searchFilters, "filters", "f", nil,
flags.StringSliceVarP(&searchFilters, "filters", "f", nil,
"Repeated filter expressions or files with protobuf JSON")
objectSearchCmd.Flags().Bool("root", false, "Search for user objects")
objectSearchCmd.Flags().Bool("phy", false, "Search physically stored objects")
objectSearchCmd.Flags().String(searchOIDFlag, "", "Search object by identifier")
objectCmd.AddCommand(objectHeadCmd)
objectHeadCmd.Flags().String("file", "", "File to write header to. Default: stdout.")
objectHeadCmd.Flags().String("cid", "", "Container ID")
flags.Bool("root", false, "Search for user objects")
flags.Bool("phy", false, "Search physically stored objects")
flags.String(searchOIDFlag, "", "Search object by identifier")
}
func initObjectHeadCmd() {
initCommonFlags(objectHeadCmd)
flags := objectHeadCmd.Flags()
flags.String("cid", "", "Container ID")
_ = objectHeadCmd.MarkFlagRequired("cid")
objectHeadCmd.Flags().String("oid", "", "Object ID")
flags.String("oid", "", "Object ID")
_ = objectHeadCmd.MarkFlagRequired("oid")
objectHeadCmd.Flags().Bool("main-only", false, "Return only main fields")
objectHeadCmd.Flags().Bool("json", false, "Marshal output in JSON")
objectHeadCmd.Flags().Bool("proto", false, "Marshal output in Protobuf")
objectHeadCmd.Flags().Bool(rawFlag, false, rawFlagDesc)
objectCmd.AddCommand(objectHashCmd)
objectHashCmd.Flags().String("cid", "", "Container ID")
flags.String("file", "", "File to write header to. Default: stdout.")
flags.Bool("main-only", false, "Return only main fields")
flags.Bool("json", false, "Marshal output in JSON")
flags.Bool("proto", false, "Marshal output in Protobuf")
flags.Bool(rawFlag, false, rawFlagDesc)
}
func initObjectHashCmd() {
initCommonFlags(objectHashCmd)
flags := objectHashCmd.Flags()
flags.String("cid", "", "Container ID")
_ = objectHashCmd.MarkFlagRequired("cid")
objectHashCmd.Flags().String("oid", "", "Object ID")
_ = objectHashCmd.MarkFlagRequired("oid")
objectHashCmd.Flags().String("range", "", "Range to take hash from in the form offset1:length1,...")
objectHashCmd.Flags().String("type", hashSha256, "Hash type. Either 'sha256' or 'tz'")
objectHashCmd.Flags().String(getRangeHashSaltFlag, "", "Salt in hex format")
objectCmd.AddCommand(objectRangeCmd)
objectRangeCmd.Flags().String("cid", "", "Container ID")
flags.String("oid", "", "Object ID")
_ = objectHashCmd.MarkFlagRequired("oid")
flags.String("range", "", "Range to take hash from in the form offset1:length1,...")
flags.String("type", hashSha256, "Hash type. Either 'sha256' or 'tz'")
flags.String(getRangeHashSaltFlag, "", "Salt in hex format")
}
func initObjectRangeCmd() {
initCommonFlags(objectRangeCmd)
flags := objectRangeCmd.Flags()
flags.String("cid", "", "Container ID")
_ = objectRangeCmd.MarkFlagRequired("cid")
objectRangeCmd.Flags().String("oid", "", "Object ID")
flags.String("oid", "", "Object ID")
_ = objectRangeCmd.MarkFlagRequired("oid")
objectRangeCmd.Flags().String("range", "", "Range to take data from in the form offset:length")
objectRangeCmd.Flags().String("file", "", "File to write object payload to. Default: stdout.")
objectRangeCmd.Flags().Bool(rawFlag, false, rawFlagDesc)
flags.String("range", "", "Range to take data from in the form offset:length")
flags.String("file", "", "File to write object payload to. Default: stdout.")
flags.Bool(rawFlag, false, rawFlagDesc)
}
func init() {
objectChildCommands := []*cobra.Command{
objectPutCmd,
objectDelCmd,
objectGetCmd,
objectSearchCmd,
objectHeadCmd,
objectHashCmd,
objectRangeCmd,
}
rootCmd.AddCommand(objectCmd)
objectCmd.AddCommand(objectChildCommands...)
for _, objCommand := range objectChildCommands {
flags := objCommand.Flags()
flags.String("bearer", "", "File with signed JSON or binary encoded bearer token")
flags.StringSliceVarP(&xHeaders, xHeadersKey, xHeadersShorthand, xHeadersDefault, xHeadersUsage)
flags.Uint32P(ttl, ttlShorthand, ttlDefault, ttlUsage)
}
// Here you will define your flags and configuration settings.
@ -192,6 +262,14 @@ func init() {
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// objectCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
initObjectPutCmd()
initObjectDeleteCmd()
initObjectGetCmd()
initObjectSearchCmd()
initObjectHeadCmd()
initObjectHashCmd()
initObjectRangeCmd()
}
func initSession(ctx context.Context, key *ecdsa.PrivateKey) (client.Client, *session.Token, error) {

View file

@ -26,8 +26,6 @@ import (
const (
envPrefix = "NEOFS_CLI"
ttlDefaultValue = 2
)
const xHeadersFlag = "xhdr"
@ -37,9 +35,58 @@ var xHeaders []string
// Global scope flags.
var (
cfgFile string
verbose bool
)
const (
// Common CLI flag keys, shorthands, default
// values and their usage descriptions.
generateKey = "generate-key"
generateKeyShorthand = ""
generateKeyDefault = false
generateKeyUsage = "generate new private key"
binaryKey = "binary-key"
binaryKeyShorthand = ""
binaryKeyDefault = ""
binaryKeyUsage = "path to the raw private key file"
walletPath = "wallet"
walletPathShorthand = "w"
walletPathDefault = ""
walletPathUsage = "path to the wallet"
wif = "wif"
wifShorthand = ""
wifDefault = ""
wifUsage = "WIF or NEP-2"
address = "address"
addressShorthand = ""
addressDefault = ""
addressUsage = "address of wallet account"
rpc = "rpc-endpoint"
rpcShorthand = "r"
rpcDefault = ""
rpcUsage = "remote node address (as 'multiaddr' or '<host>:<port>')"
verbose = "verbose"
verboseShorthand = "v"
verboseDefault = false
verboseUsage = "verbose output"
ttl = "ttl"
ttlShorthand = ""
ttlDefault = 2
ttlUsage = "TTL value in request meta header"
xHeadersKey = "xhdr"
xHeadersShorthand = "x"
xHeadersUsage = "Request X-Headers in form of Key=Value"
)
var xHeadersDefault []string
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "neofs-cli",
@ -71,42 +118,14 @@ func Execute() {
func init() {
cobra.OnInitialize(initConfig)
// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.
// use stdout as default output for cmd.Print()
rootCmd.SetOut(os.Stdout)
// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.
rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file (default is $HOME/.config/neofs-cli/config.yaml)")
// Key options.
rootCmd.PersistentFlags().BoolP("generate-key", "", false, "generate new private key")
_ = viper.BindPFlag("generate-key", rootCmd.PersistentFlags().Lookup("generate-key"))
rootCmd.PersistentFlags().StringP("binary-key", "", "", "path to the raw private key file")
_ = viper.BindPFlag("binary-key", rootCmd.PersistentFlags().Lookup("binary-key"))
rootCmd.PersistentFlags().StringP("wif", "", "", "WIF or NEP-2")
_ = viper.BindPFlag("wif", rootCmd.PersistentFlags().Lookup("wif"))
rootCmd.PersistentFlags().StringP("wallet", "w", "", "path to the wallet")
_ = viper.BindPFlag("wallet", rootCmd.PersistentFlags().Lookup("wallet"))
rootCmd.PersistentFlags().StringP("address", "", "", "address of wallet account")
_ = viper.BindPFlag("address", rootCmd.PersistentFlags().Lookup("address"))
rootCmd.PersistentFlags().StringP("rpc-endpoint", "r", "", "remote node address (as 'multiaddr' or '<host>:<port>')")
_ = viper.BindPFlag("rpc", rootCmd.PersistentFlags().Lookup("rpc-endpoint"))
rootCmd.PersistentFlags().Uint32("ttl", ttlDefaultValue, "TTL value in request meta header")
_ = viper.BindPFlag("ttl", rootCmd.PersistentFlags().Lookup("ttl"))
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "verbose output")
rootCmd.PersistentFlags().StringSliceVarP(&xHeaders, xHeadersFlag, "x", nil,
"Request X-Headers in form of Key=Value")
_ = viper.BindPFlag(xHeadersFlag, rootCmd.PersistentFlags().Lookup(xHeadersFlag))
// Cobra also supports local flags, which will only run
// when this action is called directly.
rootCmd.Flags().Bool("version", false, "Application version and NeoFS API compatibility")
@ -157,7 +176,7 @@ const nep2Base58Length = 58
// getKey returns private key that was provided in global arguments.
func getKey() (*ecdsa.PrivateKey, error) {
if viper.GetBool("generate-key") {
if viper.GetBool(generateKey) {
priv, err := keys.NewPrivateKey()
if err != nil {
return nil, errCantGenerateKey
@ -165,19 +184,19 @@ func getKey() (*ecdsa.PrivateKey, error) {
return &priv.PrivateKey, nil
}
if keyPath := viper.GetString("binary-key"); keyPath != "" {
if keyPath := viper.GetString(binaryKey); keyPath != "" {
return getKeyFromFile(keyPath)
}
if walletPath := viper.GetString("wallet"); walletPath != "" {
if walletPath := viper.GetString(walletPath); walletPath != "" {
w, err := wallet.NewWalletFromFile(walletPath)
if err != nil {
return nil, fmt.Errorf("%w: %v", errInvalidKey, err)
}
return getKeyFromWallet(w, viper.GetString("address"))
return getKeyFromWallet(w, viper.GetString(address))
}
wif := viper.GetString("wif")
wif := viper.GetString(wif)
if len(wif) == nep2Base58Length {
return getKeyFromNEP2(wif)
}
@ -260,7 +279,7 @@ func getKeyFromWallet(w *wallet.Wallet, addrStr string) (*ecdsa.PrivateKey, erro
// getEndpointAddress returns network address structure that stores multiaddr
// inside, parsed from global arguments.
func getEndpointAddress() (addr network.Address, err error) {
endpoint := viper.GetString("rpc")
endpoint := viper.GetString(rpc)
err = addr.FromString(endpoint)
if err != nil {
@ -296,7 +315,7 @@ func getSDKClient(key *ecdsa.PrivateKey) (client.Client, error) {
}
func getTTL() uint32 {
ttl := viper.GetUint32("ttl")
ttl := viper.GetUint32(ttl)
printVerbose("TTL: %d", ttl)
return ttl
@ -315,7 +334,7 @@ func ownerFromString(s string) (*owner.ID, error) {
}
func printVerbose(format string, a ...interface{}) {
if verbose {
if viper.GetBool(verbose) {
fmt.Printf(format+"\n", a...)
}
}
@ -351,3 +370,35 @@ func globalCallOptions() []client.CallOption {
return opts
}
// add common flags to the command:
// - key;
// - wallet;
// - WIF;
// - address;
// - RPC;
// - verbose;
func initCommonFlags(cmd *cobra.Command) {
ff := cmd.Flags()
ff.BoolP(generateKey, generateKeyShorthand, generateKeyDefault, generateKeyUsage)
ff.StringP(binaryKey, binaryKeyShorthand, binaryKeyDefault, binaryKeyUsage)
ff.StringP(walletPath, walletPathShorthand, walletPathDefault, walletPathUsage)
ff.StringP(wif, wifShorthand, wifDefault, wifUsage)
ff.StringP(address, addressShorthand, addressDefault, addressUsage)
ff.StringP(rpc, rpcShorthand, rpcDefault, rpcUsage)
ff.BoolP(verbose, verboseShorthand, verboseDefault, verboseUsage)
}
// bind common command flags to the viper
func bindCommonFlags(cmd *cobra.Command) {
ff := cmd.Flags()
_ = viper.BindPFlag(generateKey, ff.Lookup(generateKey))
_ = viper.BindPFlag(binaryKey, ff.Lookup(binaryKey))
_ = viper.BindPFlag(walletPath, ff.Lookup(walletPath))
_ = viper.BindPFlag(wif, ff.Lookup(wif))
_ = viper.BindPFlag(address, ff.Lookup(address))
_ = viper.BindPFlag(rpc, ff.Lookup(rpc))
_ = viper.BindPFlag(verbose, ff.Lookup(verbose))
}

View file

@ -20,6 +20,11 @@ var storagegroupCmd = &cobra.Command{
Use: "storagegroup",
Short: "Operations with Storage Groups",
Long: `Operations with Storage Groups`,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
// bind exactly that cmd's flags to
// the viper before execution
bindCommonFlags(cmd)
},
}
var sgPutCmd = &cobra.Command{
@ -61,36 +66,74 @@ var (
sgID string
)
func init() {
rootCmd.AddCommand(storagegroupCmd)
func initSGPutCmd() {
initCommonFlags(sgPutCmd)
storagegroupCmd.PersistentFlags().String(sgBearerFlag, "",
"File with signed JSON or binary encoded bearer token")
flags := sgPutCmd.Flags()
storagegroupCmd.AddCommand(sgPutCmd)
sgPutCmd.Flags().String("cid", "", "Container ID")
flags.String("cid", "", "Container ID")
_ = sgPutCmd.MarkFlagRequired("cid")
sgPutCmd.Flags().StringSliceVarP(&sgMembers, sgMembersFlag, "m", nil,
"ID list of storage group members")
flags.StringSliceVarP(&sgMembers, sgMembersFlag, "m", nil, "ID list of storage group members")
_ = sgPutCmd.MarkFlagRequired(sgMembersFlag)
}
storagegroupCmd.AddCommand(sgGetCmd)
sgGetCmd.Flags().String("cid", "", "Container ID")
func initSGGetCmd() {
initCommonFlags(sgGetCmd)
flags := sgGetCmd.Flags()
flags.String("cid", "", "Container ID")
_ = sgGetCmd.MarkFlagRequired("cid")
sgGetCmd.Flags().StringVarP(&sgID, sgIDFlag, "", "", "storage group identifier")
_ = sgGetCmd.MarkFlagRequired(sgIDFlag)
storagegroupCmd.AddCommand(sgListCmd)
flags.StringVarP(&sgID, sgIDFlag, "", "", "storage group identifier")
_ = sgGetCmd.MarkFlagRequired(sgIDFlag)
}
func initSGListCmd() {
initCommonFlags(sgListCmd)
sgListCmd.Flags().String("cid", "", "Container ID")
_ = sgListCmd.MarkFlagRequired("cid")
}
storagegroupCmd.AddCommand(sgDelCmd)
sgDelCmd.Flags().String("cid", "", "Container ID")
func initSGDeleteCmd() {
initCommonFlags(sgDelCmd)
flags := sgDelCmd.Flags()
flags.String("cid", "", "Container ID")
_ = sgDelCmd.MarkFlagRequired("cid")
sgDelCmd.Flags().StringVarP(&sgID, sgIDFlag, "", "", "storage group identifier")
flags.StringVarP(&sgID, sgIDFlag, "", "", "storage group identifier")
_ = sgDelCmd.MarkFlagRequired(sgIDFlag)
}
func init() {
storageGroupChildCommands := []*cobra.Command{
sgPutCmd,
sgGetCmd,
sgListCmd,
sgDelCmd,
}
rootCmd.AddCommand(storagegroupCmd)
storagegroupCmd.AddCommand(storageGroupChildCommands...)
for _, sgCommand := range storageGroupChildCommands {
flags := sgCommand.Flags()
flags.String(sgBearerFlag, "", "File with signed JSON or binary encoded bearer token")
flags.StringSliceVarP(&xHeaders, xHeadersKey, xHeadersShorthand, xHeadersDefault, xHeadersUsage)
flags.Uint32P(ttl, ttlShorthand, ttlDefault, ttlUsage)
}
initSGPutCmd()
initSGGetCmd()
initSGListCmd()
initSGDeleteCmd()
}
type sgHeadReceiver struct {
ctx context.Context

View file

@ -19,6 +19,7 @@ import (
continentsdb "github.com/nspcc-dev/neofs-node/pkg/util/locode/db/continents/geojson"
csvlocode "github.com/nspcc-dev/neofs-node/pkg/util/locode/table/csv"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var errKeyerSingleArgument = errors.New("pass only one argument at a time")
@ -27,6 +28,16 @@ var (
utilCmd = &cobra.Command{
Use: "util",
Short: "Utility operations",
PersistentPreRun: func(cmd *cobra.Command, args []string) {
flags := cmd.Flags()
_ = viper.BindPFlag(generateKey, flags.Lookup(generateKey))
_ = viper.BindPFlag(binaryKey, flags.Lookup(binaryKey))
_ = viper.BindPFlag(walletPath, flags.Lookup(walletPath))
_ = viper.BindPFlag(wif, flags.Lookup(wif))
_ = viper.BindPFlag(address, flags.Lookup(address))
_ = viper.BindPFlag(verbose, flags.Lookup(verbose))
},
}
signCmd = &cobra.Command{
@ -171,74 +182,116 @@ var (
}
)
func init() {
rootCmd.AddCommand(utilCmd)
utilCmd.AddCommand(signCmd)
utilCmd.AddCommand(convertCmd)
utilCmd.AddCommand(keyerCmd)
utilCmd.AddCommand(locodeCmd)
signCmd.AddCommand(signBearerCmd)
signBearerCmd.Flags().String("from", "", "File with JSON or binary encoded bearer token to sign")
_ = signBearerCmd.MarkFlagFilename("from")
_ = signBearerCmd.MarkFlagRequired("from")
signBearerCmd.Flags().String("to", "", "File to dump signed bearer token (default: binary encoded)")
signBearerCmd.Flags().Bool("json", false, "Dump bearer token in JSON encoding")
signCmd.AddCommand(signSessionCmd)
signSessionCmd.Flags().String("from", "", "File with JSON encoded session token to sign")
_ = signSessionCmd.MarkFlagFilename("from")
_ = signSessionCmd.MarkFlagRequired("from")
signSessionCmd.Flags().String("to", "", "File to save signed session token (optional)")
convertCmd.AddCommand(convertEACLCmd)
convertEACLCmd.Flags().String("from", "", "File with JSON or binary encoded extended ACL table")
_ = convertEACLCmd.MarkFlagFilename("from")
_ = convertEACLCmd.MarkFlagRequired("from")
convertEACLCmd.Flags().String("to", "", "File to dump extended ACL table (default: binary encoded)")
convertEACLCmd.Flags().Bool("json", false, "Dump extended ACL table in JSON encoding")
func initUtilKeyerCmd() {
keyerCmd.Flags().BoolP("generate", "g", false, "generate new private key")
keyerCmd.Flags().Bool("hex", false, "print all values in hex encoding")
keyerCmd.Flags().BoolP("uncompressed", "u", false, "use uncompressed public key format")
keyerCmd.Flags().BoolP("multisig", "m", false, "calculate multisig address from public keys")
}
locodeCmd.AddCommand(locodeGenerateCmd)
func initCommonFlagsWithoutRPC(cmd *cobra.Command) {
flags := cmd.Flags()
locodeGenerateCmd.Flags().StringSliceVar(&locodeGenerateInPaths, locodeGenerateInputFlag, nil,
"List of paths to UN/LOCODE tables (csv)")
flags.BoolP(generateKey, generateKeyShorthand, generateKeyDefault, generateKeyUsage)
flags.StringP(binaryKey, binaryKeyShorthand, binaryKeyDefault, binaryKeyUsage)
flags.StringP(walletPath, walletPathShorthand, walletPathDefault, walletPathUsage)
flags.StringP(wif, wifShorthand, wifDefault, wifUsage)
flags.StringP(address, addressShorthand, addressDefault, addressUsage)
flags.StringP(rpc, rpcShorthand, rpcDefault, rpcUsage)
flags.BoolP(verbose, verboseShorthand, verboseDefault, verboseUsage)
}
func initUtilSignBearerCmd() {
initCommonFlagsWithoutRPC(signBearerCmd)
flags := signBearerCmd.Flags()
flags.String("from", "", "File with JSON or binary encoded bearer token to sign")
_ = signBearerCmd.MarkFlagFilename("from")
_ = signBearerCmd.MarkFlagRequired("from")
flags.String("to", "", "File to dump signed bearer token (default: binary encoded)")
flags.Bool("json", false, "Dump bearer token in JSON encoding")
}
func initUtilSignSessionCmd() {
initCommonFlagsWithoutRPC(signSessionCmd)
flags := signSessionCmd.Flags()
flags.String("from", "", "File with JSON encoded session token to sign")
_ = signSessionCmd.MarkFlagFilename("from")
_ = signSessionCmd.MarkFlagRequired("from")
flags.String("to", "", "File to save signed session token (optional)")
}
func initUtilConvertEACLCmd() {
flags := convertEACLCmd.Flags()
flags.String("from", "", "File with JSON or binary encoded extended ACL table")
_ = convertEACLCmd.MarkFlagFilename("from")
_ = convertEACLCmd.MarkFlagRequired("from")
flags.String("to", "", "File to dump extended ACL table (default: binary encoded)")
flags.Bool("json", false, "Dump extended ACL table in JSON encoding")
}
func initUtilLocodeGenerateCmd() {
flags := locodeGenerateCmd.Flags()
flags.StringSliceVar(&locodeGenerateInPaths, locodeGenerateInputFlag, nil, "List of paths to UN/LOCODE tables (csv)")
_ = locodeGenerateCmd.MarkFlagRequired(locodeGenerateInputFlag)
locodeGenerateCmd.Flags().StringVar(&locodeGenerateSubDivPath, locodeGenerateSubDivFlag, "",
"Path to UN/LOCODE subdivision database (csv)")
flags.StringVar(&locodeGenerateSubDivPath, locodeGenerateSubDivFlag, "", "Path to UN/LOCODE subdivision database (csv)")
_ = locodeGenerateCmd.MarkFlagRequired(locodeGenerateSubDivFlag)
locodeGenerateCmd.Flags().StringVar(&locodeGenerateAirportsPath, locodeGenerateAirportsFlag, "",
"Path to OpenFlights airport database (csv)")
flags.StringVar(&locodeGenerateAirportsPath, locodeGenerateAirportsFlag, "", "Path to OpenFlights airport database (csv)")
_ = locodeGenerateCmd.MarkFlagRequired(locodeGenerateAirportsFlag)
locodeGenerateCmd.Flags().StringVar(&locodeGenerateCountriesPath, locodeGenerateCountriesFlag, "",
"Path to OpenFlights country database (csv)")
flags.StringVar(&locodeGenerateCountriesPath, locodeGenerateCountriesFlag, "", "Path to OpenFlights country database (csv)")
_ = locodeGenerateCmd.MarkFlagRequired(locodeGenerateCountriesFlag)
locodeGenerateCmd.Flags().StringVar(&locodeGenerateContinentsPath, locodeGenerateContinentsFlag, "",
"Path to continent polygons (GeoJSON)")
flags.StringVar(&locodeGenerateContinentsPath, locodeGenerateContinentsFlag, "", "Path to continent polygons (GeoJSON)")
_ = locodeGenerateCmd.MarkFlagRequired(locodeGenerateContinentsFlag)
locodeGenerateCmd.Flags().StringVar(&locodeGenerateOutPath, locodeGenerateOutputFlag, "",
"Target path for generated database")
flags.StringVar(&locodeGenerateOutPath, locodeGenerateOutputFlag, "", "Target path for generated database")
_ = locodeGenerateCmd.MarkFlagRequired(locodeGenerateOutputFlag)
}
locodeCmd.AddCommand(locodeInfoCmd)
func initUtilLocodeInfoCmd() {
flags := locodeInfoCmd.Flags()
locodeInfoCmd.Flags().StringVar(&locodeInfoDBPath, locodeInfoDBFlag, "",
"Path to NeoFS UN/LOCODE database")
_ = locodeGenerateCmd.MarkFlagRequired(locodeInfoDBFlag)
flags.StringVar(&locodeInfoDBPath, locodeInfoDBFlag, "", "Path to NeoFS UN/LOCODE database")
_ = locodeInfoCmd.MarkFlagRequired(locodeInfoDBFlag)
locodeInfoCmd.Flags().StringVar(&locodeInfoCode, locodeInfoCodeFlag, "",
"UN/LOCODE")
_ = locodeGenerateCmd.MarkFlagRequired(locodeInfoCodeFlag)
flags.StringVar(&locodeInfoCode, locodeInfoCodeFlag, "", "UN/LOCODE")
_ = locodeInfoCmd.MarkFlagRequired(locodeInfoCodeFlag)
}
func init() {
rootCmd.AddCommand(utilCmd)
utilCmd.AddCommand(
signCmd,
convertCmd,
keyerCmd,
locodeCmd,
)
signCmd.AddCommand(signBearerCmd, signSessionCmd)
convertCmd.AddCommand(convertEACLCmd)
locodeCmd.AddCommand(locodeGenerateCmd, locodeInfoCmd)
initUtilKeyerCmd()
initUtilSignBearerCmd()
initUtilSignSessionCmd()
initUtilConvertEACLCmd()
initUtilLocodeInfoCmd()
initUtilLocodeGenerateCmd()
}
func signBearerToken(cmd *cobra.Command, _ []string) {