diff --git a/cmd/common/flags.go b/cmd/common/flags.go index f71f6fba..80f711a6 100644 --- a/cmd/common/flags.go +++ b/cmd/common/flags.go @@ -3,6 +3,7 @@ package common import ( "context" "fmt" + "strings" flag "github.com/spf13/pflag" @@ -10,19 +11,57 @@ import ( ) var ( - selectedHeight int64 - force bool - answerYes bool + // HeightFlag is the flag for specifying block height. + HeightFlag *flag.FlagSet + + // ForceFlag is a force mode switch. + ForceFlag *flag.FlagSet + + // AnswerYesFlag answers yes to all questions. + AnswerYesFlag *flag.FlagSet + + // FormatFlag specifies the command's output format (text/json). + FormatFlag *flag.FlagSet ) -// HeightFlag is the flag for specifying block height. -var HeightFlag *flag.FlagSet +// FormatType specifies the type of format for output of commands. +type FormatType string -// ForceFlag is a force mode switch. -var ForceFlag *flag.FlagSet +// Supported output formats for the format flag. +const ( + // Output plain text. + FormatText FormatType = "text" + // Output JSON. + FormatJSON FormatType = "json" +) + +// String returns a string representation of the output format type. +func (f *FormatType) String() string { + return string(*f) +} -// AnswerYesFlag answers yes to all questions. -var AnswerYesFlag *flag.FlagSet +// Set sets the value of the type to the argument given. +func (f *FormatType) Set(v string) error { + switch strings.ToLower(v) { + case string(FormatText), string(FormatJSON): + *f = FormatType(v) + return nil + default: + return fmt.Errorf("unknown output format type, must be one of: %s", strings.Join([]string{string(FormatText), string(FormatJSON)}, ", ")) + } +} + +// Type returns the type of the flag. +func (f *FormatType) Type() string { + return "FormatType" +} + +var ( + selectedHeight int64 + force bool + answerYes bool + outputFormat = FormatText +) // GetHeight returns the user-selected block height. func GetHeight() int64 { @@ -34,11 +73,17 @@ func IsForce() bool { return force } -// IsForce returns force mode. +// GetAnswerYes returns whether all interactive questions should be answered +// with yes. func GetAnswerYes() bool { return answerYes } +// OutputFormat returns the format of the command's output. +func OutputFormat() FormatType { + return outputFormat +} + // GetActualHeight returns the user-selected block height if explicitly // specified, or the current latest height. func GetActualHeight( @@ -65,4 +110,7 @@ func init() { AnswerYesFlag = flag.NewFlagSet("", flag.ContinueOnError) AnswerYesFlag.BoolVarP(&answerYes, "yes", "y", false, "answer yes to all questions") + + FormatFlag = flag.NewFlagSet("", flag.ContinueOnError) + FormatFlag.Var(&outputFormat, "format", "output format ["+strings.Join([]string{string(FormatText), string(FormatJSON)}, ",")+"]") } diff --git a/cmd/network/show.go b/cmd/network/show.go index 11839083..63e8da39 100644 --- a/cmd/network/show.go +++ b/cmd/network/show.go @@ -9,7 +9,6 @@ import ( "strings" "github.com/spf13/cobra" - flag "github.com/spf13/pflag" "github.com/oasisprotocol/oasis-core/go/common/crypto/signature" consensusPretty "github.com/oasisprotocol/oasis-core/go/common/prettyprint" @@ -428,7 +427,7 @@ func showParameters(ctx context.Context, npa *common.NPASelection, height int64, doc := make(map[string]interface{}) doSection := func(name string, params interface{}) { - if outputFormat == formatJSON { + if common.OutputFormat() == common.FormatJSON { doc[name] = params } else { fmt.Printf("=== %s PARAMETERS ===\n", strings.ToUpper(name)) @@ -446,7 +445,7 @@ func showParameters(ctx context.Context, npa *common.NPASelection, height int64, doSection("beacon", beaconParams) doSection("governance", governanceParams) - if outputFormat == formatJSON { + if common.OutputFormat() == common.FormatJSON { pp, err := json.MarshalIndent(doc, "", " ") cobra.CheckErr(err) fmt.Printf("%s\n", pp) @@ -454,10 +453,7 @@ func showParameters(ctx context.Context, npa *common.NPASelection, height int64, } func init() { - formatFlag := flag.NewFlagSet("", flag.ContinueOnError) - formatFlag.StringVar(&outputFormat, "format", formatText, "output format ["+strings.Join([]string{formatText, formatJSON}, ",")+"]") - showCmd.Flags().AddFlagSet(formatFlag) - showCmd.Flags().AddFlagSet(common.SelectorNFlags) showCmd.Flags().AddFlagSet(common.HeightFlag) + showCmd.Flags().AddFlagSet(common.FormatFlag) } diff --git a/cmd/network/status.go b/cmd/network/status.go index 30926453..30398aff 100644 --- a/cmd/network/status.go +++ b/cmd/network/status.go @@ -8,7 +8,6 @@ import ( "time" "github.com/spf13/cobra" - flag "github.com/spf13/pflag" coreCommon "github.com/oasisprotocol/oasis-core/go/common" @@ -29,202 +28,191 @@ func getParatimeName(cfg *cliConfig.Config, id string) string { return ("unknown") } -const ( - formatText = "text" - formatJSON = "json" -) +var statusCmd = &cobra.Command{ + Use: "status", + Short: "Show the current status of the node and the network", + Args: cobra.NoArgs, + Run: func(_ *cobra.Command, _ []string) { + cfg := cliConfig.Global() + npa := common.GetNPASelection(cfg) + + // Establish connection with the target network. + ctx := context.Background() + conn, err := connection.Connect(ctx, npa.Network) + cobra.CheckErr(err) -var ( - outputFormat string + ctrlConn := conn.Control() - statusCmd = &cobra.Command{ - Use: "status", - Short: "Show the current status of the node and the network", - Args: cobra.NoArgs, - Run: func(_ *cobra.Command, _ []string) { - cfg := cliConfig.Global() - npa := common.GetNPASelection(cfg) + nodeStatus, err := ctrlConn.GetStatus(ctx) + cobra.CheckErr(err) - // Establish connection with the target network. - ctx := context.Background() - conn, err := connection.Connect(ctx, npa.Network) + switch common.OutputFormat() { + case common.FormatJSON: + nodeStr, err := common.PrettyJSONMarshal(nodeStatus) cobra.CheckErr(err) - ctrlConn := conn.Control() + fmt.Println(string(nodeStr)) + default: + fmt.Println("=== NETWORK STATUS ===") + fmt.Printf("Network: %s", npa.PrettyPrintNetwork()) + fmt.Println() - nodeStatus, err := ctrlConn.GetStatus(ctx) - cobra.CheckErr(err) + fmt.Printf("Node's ID: %s", nodeStatus.Identity.Node) + fmt.Println() - switch outputFormat { - case formatJSON: - nodeStr, err := common.PrettyJSONMarshal(nodeStatus) - cobra.CheckErr(err) + fmt.Printf("Core version: %s", nodeStatus.SoftwareVersion) + fmt.Println() - fmt.Println(string(nodeStr)) - default: - fmt.Println("=== NETWORK STATUS ===") - fmt.Printf("Network: %s", npa.PrettyPrintNetwork()) - fmt.Println() + fmt.Println() + fmt.Printf("==== Consensus ====") + fmt.Println() - fmt.Printf("Node's ID: %s", nodeStatus.Identity.Node) + consensus := nodeStatus.Consensus + if consensus != nil { + fmt.Printf("Status: %s", consensus.Status.String()) fmt.Println() - fmt.Printf("Core version: %s", nodeStatus.SoftwareVersion) + fmt.Printf("Version: %s", consensus.Version.String()) fmt.Println() - fmt.Println() - fmt.Printf("==== Consensus ====") + fmt.Printf("Chain context: %s", consensus.ChainContext) fmt.Println() - consensus := nodeStatus.Consensus - if consensus != nil { - fmt.Printf("Status: %s", consensus.Status.String()) - fmt.Println() - - fmt.Printf("Version: %s", consensus.Version.String()) - fmt.Println() + date := time.Unix(nodeStatus.Consensus.LatestTime.Unix(), 0) + fmt.Printf("Latest height: %d (%s)", consensus.LatestHeight, date) + fmt.Println() - fmt.Printf("Chain context: %s", consensus.ChainContext) - fmt.Println() + fmt.Printf("Latest block hash: %s", consensus.LatestHash) + fmt.Println() - date := time.Unix(nodeStatus.Consensus.LatestTime.Unix(), 0) - fmt.Printf("Latest height: %d (%s)", consensus.LatestHeight, date) - fmt.Println() + fmt.Printf("Latest epoch: %d", consensus.LatestEpoch) + fmt.Println() - fmt.Printf("Latest block hash: %s", consensus.LatestHash) - fmt.Println() + fmt.Printf("Is validator: %t", consensus.IsValidator) + fmt.Println() + } - fmt.Printf("Latest epoch: %d", consensus.LatestEpoch) - fmt.Println() + registration := nodeStatus.Registration + if registration != nil { + fmt.Printf("Registration: %t", registration.LastAttemptSuccessful) + fmt.Println() - fmt.Printf("Is validator: %t", consensus.IsValidator) + if !registration.LastRegistration.IsZero() { + fmt.Printf(" Last: %s", registration.LastRegistration) fmt.Println() } - registration := nodeStatus.Registration - if registration != nil { - fmt.Printf("Registration: %t", registration.LastAttemptSuccessful) - fmt.Println() - - if !registration.LastRegistration.IsZero() { - fmt.Printf(" Last: %s", registration.LastRegistration) + if !nodeStatus.Registration.LastAttemptSuccessful { + if !registration.LastAttempt.IsZero() { + fmt.Printf(" Last attempt: %s", registration.LastAttempt) fmt.Println() } - if !nodeStatus.Registration.LastAttemptSuccessful { - if !registration.LastAttempt.IsZero() { - fmt.Printf(" Last attempt: %s", registration.LastAttempt) - fmt.Println() - } - - if registration.LastAttemptErrorMessage != "" { - fmt.Printf(" Last attempt error: %s", registration.LastAttemptErrorMessage) - fmt.Println() - } - } - - descriptor := registration.Descriptor - if descriptor != nil { - fmt.Printf(" Entity ID: %s", descriptor.EntityID) + if registration.LastAttemptErrorMessage != "" { + fmt.Printf(" Last attempt error: %s", registration.LastAttemptErrorMessage) fmt.Println() } } - if len(nodeStatus.Runtimes) > 0 { + descriptor := registration.Descriptor + if descriptor != nil { + fmt.Printf(" Entity ID: %s", descriptor.EntityID) fmt.Println() - fmt.Println("==== ParaTimes ====") } + } - keys := make([]coreCommon.Namespace, 0, len(nodeStatus.Runtimes)) - for key := range nodeStatus.Runtimes { - keys = append(keys, key) - } - sort.Slice(keys, func(i, j int) bool { - var iParatimeName, jParatimeName string + if len(nodeStatus.Runtimes) > 0 { + fmt.Println() + fmt.Println("==== ParaTimes ====") + } - iDescriptor := nodeStatus.Runtimes[keys[i]].Descriptor - jDescriptor := nodeStatus.Runtimes[keys[j]].Descriptor + keys := make([]coreCommon.Namespace, 0, len(nodeStatus.Runtimes)) + for key := range nodeStatus.Runtimes { + keys = append(keys, key) + } + sort.Slice(keys, func(i, j int) bool { + var iParatimeName, jParatimeName string - if iDescriptor != nil { - iDescriptorID := iDescriptor.ID.String() - iParatimeName = getParatimeName(cfg, iDescriptorID) + iDescriptorID - } + iDescriptor := nodeStatus.Runtimes[keys[i]].Descriptor + jDescriptor := nodeStatus.Runtimes[keys[j]].Descriptor - if jDescriptor != nil { - jDescriptorID := jDescriptor.ID.String() - jParatimeName = getParatimeName(cfg, jDescriptorID) + jDescriptorID - } + if iDescriptor != nil { + iDescriptorID := iDescriptor.ID.String() + iParatimeName = getParatimeName(cfg, iDescriptorID) + iDescriptorID + } - return iParatimeName < jParatimeName - }) + if jDescriptor != nil { + jDescriptorID := jDescriptor.ID.String() + jParatimeName = getParatimeName(cfg, jDescriptorID) + jDescriptorID + } - for _, key := range keys { - runtime := nodeStatus.Runtimes[key] - descriptor := runtime.Descriptor - if descriptor != nil { - paratimeName := getParatimeName(cfg, descriptor.ID.String()) - fmt.Printf("%s (%s):", paratimeName, descriptor.ID) - fmt.Println() + return iParatimeName < jParatimeName + }) - fmt.Printf(" Kind: %s", descriptor.Kind) - fmt.Println() + for _, key := range keys { + runtime := nodeStatus.Runtimes[key] + descriptor := runtime.Descriptor + if descriptor != nil { + paratimeName := getParatimeName(cfg, descriptor.ID.String()) + fmt.Printf("%s (%s):", paratimeName, descriptor.ID) + fmt.Println() - fmt.Printf(" Is confidential: %t", (descriptor.TEEHardware > 0)) - fmt.Println() - } + fmt.Printf(" Kind: %s", descriptor.Kind) + fmt.Println() - committee := runtime.Committee - if committee != nil { - fmt.Printf(" Status: %s", committee.Status) - fmt.Println() - } + fmt.Printf(" Is confidential: %t", (descriptor.TEEHardware > 0)) + fmt.Println() + } - date := time.Unix(int64(runtime.LatestTime), 0) - fmt.Printf(" Latest round: %d (%s)", runtime.LatestRound, date) + committee := runtime.Committee + if committee != nil { + fmt.Printf(" Status: %s", committee.Status) fmt.Println() + } - storage := runtime.Storage - if storage != nil { - fmt.Printf(" Last finalized round: %d", storage.LastFinalizedRound) - fmt.Println() + date := time.Unix(int64(runtime.LatestTime), 0) + fmt.Printf(" Latest round: %d (%s)", runtime.LatestRound, date) + fmt.Println() - fmt.Printf(" Storage status: %s", storage.Status) - fmt.Println() - } + storage := runtime.Storage + if storage != nil { + fmt.Printf(" Last finalized round: %d", storage.LastFinalizedRound) + fmt.Println() - if committee != nil { - activeVersion := committee.ActiveVersion - if activeVersion != nil { - fmt.Printf(" Active version: %s", activeVersion) - fmt.Println() - } - } + fmt.Printf(" Storage status: %s", storage.Status) + fmt.Println() + } - var availableVersions []string - if descriptor != nil { - deployments := descriptor.Deployments - if deployments != nil { - for _, deployment := range deployments { - availableVersions = append(availableVersions, deployment.Version.String()) - } - fmt.Printf(" Available version(s): %s", strings.Join(availableVersions, ", ")) - fmt.Println() - } + if committee != nil { + activeVersion := committee.ActiveVersion + if activeVersion != nil { + fmt.Printf(" Active version: %s", activeVersion) + fmt.Println() } + } - if committee != nil { - fmt.Printf(" Number of peers: %d", len(committee.Peers)) + var availableVersions []string + if descriptor != nil { + deployments := descriptor.Deployments + if deployments != nil { + for _, deployment := range deployments { + availableVersions = append(availableVersions, deployment.Version.String()) + } + fmt.Printf(" Available version(s): %s", strings.Join(availableVersions, ", ")) fmt.Println() } } + + if committee != nil { + fmt.Printf(" Number of peers: %d", len(committee.Peers)) + fmt.Println() + } } - }, - } -) + } + }, +} func init() { - formatFlag := flag.NewFlagSet("", flag.ContinueOnError) - formatFlag.StringVar(&outputFormat, "format", formatText, "output format ["+strings.Join([]string{formatText, formatJSON}, ",")+"]") - statusCmd.Flags().AddFlagSet(formatFlag) + statusCmd.Flags().AddFlagSet(common.FormatFlag) statusCmd.Flags().AddFlagSet(common.SelectorNFlags) } diff --git a/cmd/paratime/show.go b/cmd/paratime/show.go index ec425af0..25185fb9 100644 --- a/cmd/paratime/show.go +++ b/cmd/paratime/show.go @@ -32,16 +32,11 @@ import ( type propertySelector int -const ( - selRoundLatest = "latest" - formatText = "text" - formatJSON = "json" -) - const ( selInvalid propertySelector = iota selParameters selEvents + selRoundLatest = "latest" ) var eventDecoders = []func(*types.Event) ([]client.DecodedEvent, error){ @@ -54,7 +49,6 @@ var eventDecoders = []func(*types.Event) ([]client.DecodedEvent, error){ } var ( - outputFormat string selectedRound uint64 showCmd = &cobra.Command{ @@ -98,7 +92,7 @@ var ( conn, err := connection.Connect(ctx, npa.Network) cobra.CheckErr(err) - if outputFormat == formatText { + if common.OutputFormat() == common.FormatText { fmt.Printf("Network: %s", npa.NetworkName) if len(npa.Network.Description) > 0 { fmt.Printf(" (%s)", npa.Network.Description) @@ -496,7 +490,7 @@ func showParameters(ctx context.Context, npa *common.NPASelection, round uint64, doc := make(map[string]interface{}) doSection := func(name string, params interface{}) { - if outputFormat == formatJSON { + if common.OutputFormat() == common.FormatJSON { doc[name] = params } else { fmt.Printf("\n=== %s PARAMETERS ===\n", strings.ToUpper(name)) @@ -507,7 +501,7 @@ func showParameters(ctx context.Context, npa *common.NPASelection, round uint64, doSection("rofl", stakeThresholds) - if outputFormat == formatJSON { + if common.OutputFormat() == common.FormatJSON { pp, err := json.MarshalIndent(doc, "", " ") cobra.CheckErr(err) fmt.Printf("%s\n", pp) @@ -519,7 +513,7 @@ func showEvents(ctx context.Context, round uint64, rt connection.RuntimeClient) cobra.CheckErr(err) if len(evs) == 0 { - if outputFormat == formatJSON { + if common.OutputFormat() == common.FormatJSON { fmt.Printf("[]\n") } else { fmt.Println("No events emitted in this block.") @@ -527,7 +521,7 @@ func showEvents(ctx context.Context, round uint64, rt connection.RuntimeClient) return } - if outputFormat == formatJSON { + if common.OutputFormat() == common.FormatJSON { jsonPrintEvents(evs) } else { for evIndex, ev := range evs { @@ -538,13 +532,10 @@ func showEvents(ctx context.Context, round uint64, rt connection.RuntimeClient) } func init() { - formatFlag := flag.NewFlagSet("", flag.ContinueOnError) - formatFlag.StringVar(&outputFormat, "format", formatText, "output format ["+strings.Join([]string{formatText, formatJSON}, ",")+"]") - roundFlag := flag.NewFlagSet("", flag.ContinueOnError) roundFlag.Uint64Var(&selectedRound, "round", client.RoundLatest, "explicitly set block round to use") + showCmd.Flags().AddFlagSet(common.FormatFlag) showCmd.Flags().AddFlagSet(common.SelectorNPFlags) showCmd.Flags().AddFlagSet(roundFlag) - showCmd.Flags().AddFlagSet(formatFlag) }