Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: overhaul gnoland secrets and gnoland config to output JSON #2393

Merged
merged 17 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions docs/gno-infrastructure/setting-up-a-local-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ In this tutorial, you will learn how to start a local Gno node (and chain!).
Additionally, you will see the different options you can use to make your Gno instance unique.

## Prerequisites

- **Git**
- **`make` (for running Makefiles)**
- **Go 1.21+**
- **Go Environment Setup**: Ensure you have Go set up as outlined in the [Go official installation documentation](https://go.dev/doc/install) for your environment
- **Go Environment Setup**: Ensure you have Go set up as outlined in
the [Go official installation documentation](https://go.dev/doc/install) for your environment

## Installation

Expand Down Expand Up @@ -153,7 +155,7 @@ A couple of things to note:
- `gnoland config init` initializes a default configuration
- `gnoland secrets init` initializes new node secrets (validator key, node p2p key)

Essentially, `gnoland start --lazy` is simply a combination of `gnoland secrets generate` and `gnoland config generate`,
Essentially, `gnoland start --lazy` is simply a combination of `gnoland secrets init` and `gnoland config init`,
with the default options enabled.

#### Changing the node configuration
Expand Down Expand Up @@ -244,7 +246,7 @@ locally will be the validator node for the new Gno network.
To display the generated node key data, run the following command:

```shell
gnoland secrets get ValidatorPrivateKey
gnoland secrets get validator_key
```

This will display the information we need for updating the `genesis.json`:
Expand Down
57 changes: 57 additions & 0 deletions gno.land/cmd/gnoland/config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"encoding/json"
"flag"
"fmt"
"path/filepath"
Expand Down Expand Up @@ -58,6 +59,62 @@
)
}

// printKeyValue searches and prints the given key value in JSON
func printKeyValue[T *secrets | *config.Config](
input T,
raw bool,
io commands.IO,
key ...string,
) error {
// prepareOutput prepares the JSON output, taking into account raw mode
prepareOutput := func(input any) (string, error) {
encoded, err := json.MarshalIndent(input, "", " ")
if err != nil {
return "", fmt.Errorf("unable to marshal JSON, %w", err)

Check warning on line 73 in gno.land/cmd/gnoland/config.go

View check run for this annotation

Codecov / codecov/patch

gno.land/cmd/gnoland/config.go#L73

Added line #L73 was not covered by tests
}

output := string(encoded)

if raw {
if err := json.Unmarshal(encoded, &output); err != nil {
return "", fmt.Errorf("unable to unmarshal raw JSON, %w", err)

Check warning on line 80 in gno.land/cmd/gnoland/config.go

View check run for this annotation

Codecov / codecov/patch

gno.land/cmd/gnoland/config.go#L80

Added line #L80 was not covered by tests
}
}

return output, nil
}

if len(key) == 0 {
// Print the entire input
output, err := prepareOutput(input)
if err != nil {
return err

Check warning on line 91 in gno.land/cmd/gnoland/config.go

View check run for this annotation

Codecov / codecov/patch

gno.land/cmd/gnoland/config.go#L91

Added line #L91 was not covered by tests
}

io.Println(output)

return nil
}

// Get the value using reflect
secretValue := reflect.ValueOf(input).Elem()

// Get the value path, with sections separated out by a period
field, err := getFieldAtPath(secretValue, strings.Split(key[0], "."))
if err != nil {
return err

Check warning on line 105 in gno.land/cmd/gnoland/config.go

View check run for this annotation

Codecov / codecov/patch

gno.land/cmd/gnoland/config.go#L105

Added line #L105 was not covered by tests
}

output, err := prepareOutput(field.Interface())
if err != nil {
return err

Check warning on line 110 in gno.land/cmd/gnoland/config.go

View check run for this annotation

Codecov / codecov/patch

gno.land/cmd/gnoland/config.go#L110

Added line #L110 was not covered by tests
}

io.Println(output)

return nil
}

// getFieldAtPath fetches the given field from the given path
func getFieldAtPath(currentValue reflect.Value, path []string) (*reflect.Value, error) {
// Look at the current section, and figure out if
Expand Down
52 changes: 25 additions & 27 deletions gno.land/cmd/gnoland/config_get.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,29 @@
import (
"context"
"errors"
"flag"
"fmt"
"reflect"
"strings"

"github.com/gnolang/gno/tm2/pkg/bft/config"
"github.com/gnolang/gno/tm2/pkg/commands"
)

var errInvalidConfigGetArgs = errors.New("invalid number of config get arguments provided")

type configGetCfg struct {
configCfg

raw bool
}

// newConfigGetCmd creates the config get command
func newConfigGetCmd(io commands.IO) *commands.Command {
cfg := &configCfg{}
cfg := &configGetCfg{}

cmd := commands.NewCommand(
commands.Metadata{
thehowl marked this conversation as resolved.
Show resolved Hide resolved
Name: "get",
ShortUsage: "config get <key>",
ShortUsage: "config get [flags] [<key>]",
ShortHelp: "shows the Gno node configuration",
LongHelp: "Shows the Gno node configuration at the given path " +
"by fetching the option specified at <key>",
Expand All @@ -34,40 +39,33 @@
return cmd
}

func execConfigGet(cfg *configCfg, io commands.IO, args []string) error {
func (c *configGetCfg) RegisterFlags(fs *flag.FlagSet) {
c.configCfg.RegisterFlags(fs)

fs.BoolVar(
&c.raw,
"raw",
false,
"output raw string values, rather than as JSON strings",
)
}

func execConfigGet(cfg *configGetCfg, io commands.IO, args []string) error {
// Load the config
loadedCfg, err := config.LoadConfigFile(cfg.configPath)
if err != nil {
return fmt.Errorf("%s, %w", tryConfigInit, err)
}

// Make sure the edit arguments are valid
if len(args) != 1 {
// Make sure the get arguments are valid
if len(args) > 1 {
return errInvalidConfigGetArgs
}

// Find and print the config field, if any
if err := printConfigField(loadedCfg, args[0], io); err != nil {
return fmt.Errorf("unable to update config field, %w", err)
}

return nil
}

// printConfigField prints the value of the field at the given path
func printConfigField(config *config.Config, key string, io commands.IO) error {
// Get the config value using reflect
configValue := reflect.ValueOf(config).Elem()

// Get the value path, with sections separated out by a period
path := strings.Split(key, ".")

field, err := getFieldAtPath(configValue, path)
if err != nil {
return err
if err := printKeyValue(loadedCfg, cfg.raw, io, args...); err != nil {
return fmt.Errorf("unable to get config field, %w", err)

Check warning on line 67 in gno.land/cmd/gnoland/config_get.go

View check run for this annotation

Codecov / codecov/patch

gno.land/cmd/gnoland/config_get.go#L67

Added line #L67 was not covered by tests
}

io.Printf("%v", field.Interface())

return nil
}
Loading
Loading