Skip to content

Commit

Permalink
feat: add 'gno env' subcommand (#1233)
Browse files Browse the repository at this point in the history
  • Loading branch information
gfanton authored Nov 23, 2023
1 parent ebe47db commit becc4eb
Show file tree
Hide file tree
Showing 26 changed files with 485 additions and 127 deletions.
7 changes: 6 additions & 1 deletion gno.land/cmd/gnokey/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@ import (
"fmt"
"os"

"github.com/gnolang/gno/gnovm/pkg/gnoenv"
"github.com/gnolang/gno/tm2/pkg/commands"
"github.com/gnolang/gno/tm2/pkg/crypto/keys/client"
)

func main() {
cmd := client.NewRootCmd(commands.NewDefaultIO())
baseCfg := client.BaseOptions{
Home: gnoenv.HomeDir(),
Remote: "127.0.0.1:26657",
}

cmd := client.NewRootCmdWithBaseConfig(commands.NewDefaultIO(), baseCfg)
if err := cmd.ParseAndRun(context.Background(), os.Args[1:]); err != nil {
_, _ = fmt.Fprintf(os.Stderr, "%+v\n", err)

Expand Down
3 changes: 2 additions & 1 deletion gno.land/cmd/gnoland/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"time"

"github.com/gnolang/gno/gno.land/pkg/gnoland"
"github.com/gnolang/gno/gnovm/pkg/gnoenv"
abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types"
"github.com/gnolang/gno/tm2/pkg/bft/config"
"github.com/gnolang/gno/tm2/pkg/bft/node"
Expand Down Expand Up @@ -59,7 +60,7 @@ func newStartCmd(io commands.IO) *commands.Command {
}

func (c *startCfg) RegisterFlags(fs *flag.FlagSet) {
gnoroot := gnoland.MustGuessGnoRootDir()
gnoroot := gnoenv.RootDir()
defaultGenesisBalancesFile := filepath.Join(gnoroot, "gno.land", "genesis", "genesis_balances.txt")
defaultGenesisTxsFile := filepath.Join(gnoroot, "gno.land", "genesis", "genesis_txs.txt")

Expand Down
6 changes: 3 additions & 3 deletions gno.land/cmd/gnoweb/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (
"strings"
"testing"

"github.com/gnolang/gno/gno.land/pkg/gnoland"
"github.com/gnolang/gno/gno.land/pkg/integration"
"github.com/gnolang/gno/gnovm/pkg/gnoenv"
"github.com/gnolang/gno/tm2/pkg/log"
"github.com/gotuna/gotuna/test/assert"
)
Expand Down Expand Up @@ -44,7 +44,7 @@ func TestRoutes(t *testing.T) {
{"/404-not-found", notFound, "/404-not-found"},
}

config, _ := integration.TestingNodeConfig(t, gnoland.MustGuessGnoRootDir())
config, _ := integration.TestingNodeConfig(t, gnoenv.RootDir())
node, remoteAddr := integration.TestingInMemoryNode(t, log.NewNopLogger(), config)
defer node.Stop()

Expand Down Expand Up @@ -92,7 +92,7 @@ func TestAnalytics(t *testing.T) {
"/404-not-found",
}

config, _ := integration.TestingNodeConfig(t, gnoland.MustGuessGnoRootDir())
config, _ := integration.TestingNodeConfig(t, gnoenv.RootDir())
node, remoteAddr := integration.TestingInMemoryNode(t, log.NewNopLogger(), config)
defer node.Stop()

Expand Down
50 changes: 2 additions & 48 deletions gno.land/pkg/gnoland/app.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
package gnoland

import (
"errors"
"fmt"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"

"github.com/gnolang/gno/gno.land/pkg/sdk/vm"
"github.com/gnolang/gno/gnovm/pkg/gnoenv"
"github.com/gnolang/gno/tm2/pkg/amino"
abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types"
dbm "github.com/gnolang/gno/tm2/pkg/db"
Expand Down Expand Up @@ -37,7 +33,7 @@ func NewAppOptions() *AppOptions {
return &AppOptions{
Logger: log.NewNopLogger(),
DB: dbm.NewMemDB(),
GnoRootDir: MustGuessGnoRootDir(),
GnoRootDir: gnoenv.RootDir(),
}
}

Expand Down Expand Up @@ -180,45 +176,3 @@ func EndBlocker(vmk vm.VMKeeperI) func(ctx sdk.Context, req abci.RequestEndBlock
return abci.ResponseEndBlock{}
}
}

// XXX: all the method bellow should be removed in favor of
// https://github.com/gnolang/gno/pull/1233
func MustGuessGnoRootDir() string {
root, err := GuessGnoRootDir()
if err != nil {
panic(err)
}

return root
}

func GuessGnoRootDir() (string, error) {
// First try to get the root directory from the GNOROOT environment variable.
if rootdir := os.Getenv("GNOROOT"); rootdir != "" {
return filepath.Clean(rootdir), nil
}

// Try to guess GNOROOT using the nearest go.mod.
if gobin, err := exec.LookPath("go"); err == nil {
// If GNOROOT is not set, try to guess the root directory using the `go list` command.
cmd := exec.Command(gobin, "list", "-m", "-mod=mod", "-f", "{{.Dir}}", "github.com/gnolang/gno")
out, err := cmd.CombinedOutput()
if err == nil {
return strings.TrimSpace(string(out)), nil
}
}

// Try to guess GNOROOT using caller stack.
if _, filename, _, ok := runtime.Caller(1); ok && filepath.IsAbs(filename) {
if currentDir := filepath.Dir(filename); currentDir != "" {
// Gno root directory relative from `app.go` path:
// gno/ .. /gno.land/ .. /pkg/ .. /gnoland/app.go
rootdir, err := filepath.Abs(filepath.Join(currentDir, "..", "..", ".."))
if err == nil {
return rootdir, nil
}
}
}

return "", errors.New("unable to guess gno's root-directory")
}
4 changes: 2 additions & 2 deletions gno.land/pkg/integration/testing_integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"strings"
"testing"

"github.com/gnolang/gno/gno.land/pkg/gnoland"
"github.com/gnolang/gno/gnovm/pkg/gnoenv"
"github.com/gnolang/gno/tm2/pkg/bft/node"
"github.com/gnolang/gno/tm2/pkg/commands"
"github.com/gnolang/gno/tm2/pkg/crypto/keys"
Expand Down Expand Up @@ -63,7 +63,7 @@ func setupGnolandTestScript(t *testing.T, txtarDir string) testscript.Params {

// `gnoRootDir` should point to the local location of the gno repository.
// It serves as the gno equivalent of GOROOT.
gnoRootDir := gnoland.MustGuessGnoRootDir()
gnoRootDir := gnoenv.RootDir()

// `gnoHomeDir` should be the local directory where gnokey stores keys.
gnoHomeDir := filepath.Join(tmpdir, "gno")
Expand Down
9 changes: 7 additions & 2 deletions gnovm/Makefile
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
GNOROOT_DIR ?= $(abspath $(lastword $(MAKEFILE_LIST))/../../)

.PHONY: help
help:
@echo "Available make commands:"
@cat Makefile | grep '^[a-z][^:]*:' | cut -d: -f1 | sort | sed 's/^/ /'

rundep=go run -modfile ../misc/devdeps/go.mod

# We can't use '-trimpath' yet as amino use absolute path from call stack
# to find some directory: see #1236
GOBUILD_FLAGS := -ldflags "-X github.com/gnolang/gno/gnovm/pkg/gnoenv._GNOROOT=$(GNOROOT_DIR)"
.PHONY: build
build:
go build -o build/gno ./cmd/gno
go build $(GOBUILD_FLAGS) -o build/gno ./cmd/gno

.PHONY: install
install:
go install ./cmd/gno
go install $(GOBUILD_FLAGS) ./cmd/gno

.PHONY: clean
clean:
Expand Down
4 changes: 2 additions & 2 deletions gnovm/cmd/gno/clean.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import (
"path/filepath"
"strings"

"github.com/gnolang/gno/gnovm/pkg/gnoenv"
"github.com/gnolang/gno/gnovm/pkg/gnomod"
"github.com/gnolang/gno/tm2/pkg/commands"
"github.com/gnolang/gno/tm2/pkg/crypto/keys/client"
)

type cleanCfg struct {
Expand Down Expand Up @@ -82,7 +82,7 @@ func execClean(cfg *cleanCfg, args []string, io commands.IO) error {
}

if cfg.modCache {
modCacheDir := filepath.Join(client.HomeDir(), "pkg", "mod")
modCacheDir := filepath.Join(gnoenv.HomeDir(), "pkg", "mod")
if !cfg.dryRun {
if err := os.RemoveAll(modCacheDir); err != nil {
return err
Expand Down
3 changes: 2 additions & 1 deletion gnovm/cmd/gno/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"path/filepath"

"github.com/gnolang/gno/gnovm/pkg/doc"
"github.com/gnolang/gno/gnovm/pkg/gnoenv"
"github.com/gnolang/gno/gnovm/pkg/gnomod"
"github.com/gnolang/gno/tm2/pkg/commands"
)
Expand Down Expand Up @@ -77,7 +78,7 @@ func (c *docCfg) RegisterFlags(fs *flag.FlagSet) {
func execDoc(cfg *docCfg, args []string, io commands.IO) error {
// guess opts.RootDir
if cfg.rootDir == "" {
cfg.rootDir = guessRootDir()
cfg.rootDir = gnoenv.RootDir()
}

wd, err := os.Getwd()
Expand Down
113 changes: 113 additions & 0 deletions gnovm/cmd/gno/env.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package main

import (
"context"
"flag"

"github.com/gnolang/gno/gnovm/pkg/gnoenv"
"github.com/gnolang/gno/tm2/pkg/commands"
)

type envCfg struct {
json bool
}

func newEnvCmd(io commands.IO) *commands.Command {
c := &envCfg{}
return commands.NewCommand(
commands.Metadata{
Name: "env",
ShortUsage: "env [flags] <pkgsym>",
ShortHelp: "`env` prints Gno environment information",
},
c,
func(_ context.Context, args []string) error {
return execEnv(c, args, io)
},
)
}

func (c *envCfg) RegisterFlags(fs *flag.FlagSet) {
fs.BoolVar(
&c.json,
"json",
false,
"Prints the environment in JSON format instead of as a shell script.",
)
}

type envVar struct {
Key string
Value string
}

func findEnv(env []envVar, name string) string {
for _, e := range env {
if e.Key == name {
return e.Value
}
}
return ""
}

type envPrinter func(vars []envVar, io commands.IO)

func execEnv(cfg *envCfg, args []string, io commands.IO) error {
envs := []envVar{
// GNOROOT Should point to the local location of the GNO repository.
// It serves as the gno equivalent of `GOROOT`.
{Key: "GNOROOT", Value: gnoenv.RootDir()},
// GNOHOME Should point to the user local configuration.
// The most common place for this should be $HOME/gno.
{Key: "GNOHOME", Value: gnoenv.HomeDir()},
}

// Setup filters
filters := make([]envVar, len(args))
for i, arg := range args {
filters[i] = envVar{Key: arg, Value: findEnv(envs, arg)}
}

// Setup printer
var printerEnv envPrinter
if cfg.json {
printerEnv = printJSON
} else {
printerEnv = getPrinterShell(len(args) == 0)
}

// Print environements
if len(filters) > 0 {
printerEnv(filters, io)
} else {
printerEnv(envs, io)
}

return nil
}

func getPrinterShell(printkeys bool) envPrinter {
return func(vars []envVar, io commands.IO) {
for _, env := range vars {
if printkeys {
io.Printf("%s=%q\n", env.Key, env.Value)
} else {
io.Printf("%s\n", env.Value)
}
}
}
}

func printJSON(vars []envVar, io commands.IO) {
io.Println("{")
for i, env := range vars {
io.Printf("\t%q: %q", env.Key, env.Value)
if i != len(vars)-1 {
io.Printf(",")
}

// Jump to next line
io.Printf("\n")
}
io.Println("}")
}
43 changes: 43 additions & 0 deletions gnovm/cmd/gno/env_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package main

import (
"fmt"
"testing"
)

func TestEnvApp(t *testing.T) {
const (
testGnoRootEnv = "/faster/better/stronger"
testGnoHomeEnv = "/around/the/world"
)

t.Setenv("GNOROOT", testGnoRootEnv)
t.Setenv("GNOHOME", testGnoHomeEnv)
tc := []testMainCase{
// shell
{args: []string{"env", "foo"}, stdoutShouldBe: "\n"},
{args: []string{"env", "foo", "bar"}, stdoutShouldBe: "\n\n"},
{args: []string{"env", "GNOROOT"}, stdoutShouldBe: testGnoRootEnv + "\n"},
{args: []string{"env", "GNOHOME", "storm"}, stdoutShouldBe: testGnoHomeEnv + "\n\n"},
{args: []string{"env"}, stdoutShouldContain: fmt.Sprintf("GNOROOT=%q", testGnoRootEnv)},
{args: []string{"env"}, stdoutShouldContain: fmt.Sprintf("GNOHOME=%q", testGnoHomeEnv)},

// json
{args: []string{"env", "-json"}, stdoutShouldContain: fmt.Sprintf("\"GNOROOT\": %q", testGnoRootEnv)},
{args: []string{"env", "-json"}, stdoutShouldContain: fmt.Sprintf("\"GNOHOME\": %q", testGnoHomeEnv)},
{
args: []string{"env", "-json", "GNOROOT"},
stdoutShouldBe: fmt.Sprintf("{\n\t\"GNOROOT\": %q\n}\n", testGnoRootEnv),
},
{
args: []string{"env", "-json", "GNOROOT", "storm"},
stdoutShouldBe: fmt.Sprintf("{\n\t\"GNOROOT\": %q,\n\t\"storm\": \"\"\n}\n", testGnoRootEnv),
},
{
args: []string{"env", "-json", "storm"},
stdoutShouldBe: "{\n\t\"storm\": \"\"\n}\n",
},
}

testMainCaseRun(t, tc)
}
3 changes: 2 additions & 1 deletion gnovm/cmd/gno/lint.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"
"path/filepath"

"github.com/gnolang/gno/gnovm/pkg/gnoenv"
"github.com/gnolang/gno/tm2/pkg/commands"
osm "github.com/gnolang/gno/tm2/pkg/os"
)
Expand Down Expand Up @@ -51,7 +52,7 @@ func execLint(cfg *lintCfg, args []string, io commands.IO) error {
rootDir = cfg.rootDir
)
if rootDir == "" {
rootDir = guessRootDir()
rootDir = gnoenv.RootDir()
}

pkgPaths, err := gnoPackagesFromArgs(args)
Expand Down
1 change: 1 addition & 0 deletions gnovm/cmd/gno/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ func newGnocliCmd(io commands.IO) *commands.Command {
newCleanCmd(io),
newReplCmd(),
newDocCmd(io),
newEnvCmd(io),
// fmt -- gofmt
// graph
// vendor -- download deps from the chain in vendor/
Expand Down
Loading

0 comments on commit becc4eb

Please sign in to comment.