Skip to content

Commit

Permalink
Initial spec for an alternative cli
Browse files Browse the repository at this point in the history
  • Loading branch information
ferranbt committed Sep 22, 2021
1 parent 3283fb9 commit a54cec4
Show file tree
Hide file tree
Showing 7 changed files with 467 additions and 1 deletion.
95 changes: 95 additions & 0 deletions command/flagset/flagset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package flagset

import (
"flag"
"fmt"
"strings"
)

type Flagset struct {
flags []*FlagVar
set *flag.FlagSet
}

func NewFlagSet(name string) *Flagset {
f := &Flagset{
flags: []*FlagVar{},
set: flag.NewFlagSet(name, flag.ContinueOnError),
}
return f
}

type FlagVar struct {
Name string
Usage string
}

func (f *Flagset) addFlag(fl *FlagVar) {
f.flags = append(f.flags, fl)
}

func (f *Flagset) Help() string {
str := "Options:\n\n"
items := []string{}
for _, item := range f.flags {
items = append(items, fmt.Sprintf(" -%s\n %s", item.Name, item.Usage))
}
return str + strings.Join(items, "\n\n")
}

func (f *Flagset) Parse(args []string) error {
return f.set.Parse(args)
}

func (f *Flagset) Args() []string {
return f.set.Args()
}

func (f *Flagset) BoolVar() {

}

type BoolFlag struct {
Name string
Usage string
Default bool
Value *bool
}

func (f *Flagset) BoolFlag(b *BoolFlag) {
f.addFlag(&FlagVar{
Name: b.Name,
Usage: b.Usage,
})
f.set.BoolVar(b.Value, b.Name, b.Default, b.Usage)
}

type StringFlag struct {
Name string
Usage string
Default string
Value *string
}

func (f *Flagset) StringFlag(b *StringFlag) {
f.addFlag(&FlagVar{
Name: b.Name,
Usage: b.Usage,
})
f.set.StringVar(b.Value, b.Name, b.Default, b.Usage)
}

type IntFlag struct {
Name string
Usage string
Default int
Value *int
}

func (f *Flagset) IntFlag(i *IntFlag) {
f.addFlag(&FlagVar{
Name: i.Name,
Usage: i.Usage,
})
f.set.IntVar(i.Value, i.Name, i.Default, i.Usage)
}
45 changes: 45 additions & 0 deletions command/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package main

import (
"fmt"
"os"

"github.com/ethereum/go-ethereum/command/server"
"github.com/mitchellh/cli"
)

func main() {
os.Exit(Run(os.Args[1:]))
}

func Run(args []string) int {
commands := commands()

cli := &cli.CLI{
Name: "bor",
Args: args,
Commands: commands,
}

exitCode, err := cli.Run()
if err != nil {
fmt.Fprintf(os.Stderr, "Error executing CLI: %s\n", err.Error())
return 1
}
return exitCode
}

func commands() map[string]cli.CommandFactory {
ui := &cli.BasicUi{
Reader: os.Stdin,
Writer: os.Stdout,
ErrorWriter: os.Stderr,
}
return map[string]cli.CommandFactory{
"server": func() (cli.Command, error) {
return &server.Command{
UI: ui,
}, nil
},
}
}
137 changes: 137 additions & 0 deletions command/server/command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package server

import (
"fmt"
"io"
"os"
"os/signal"
"strings"
"syscall"
"time"

"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/eth/tracers"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/mattn/go-colorable"
"github.com/mattn/go-isatty"
"github.com/mitchellh/cli"
)

// Command is the command to start the sever
type Command struct {
UI cli.Ui

// cli configuration
cliConfig *Config

configFile string

// bor node
node *node.Node
}

// Help implements the cli.Command interface
func (c *Command) Help() string {
return ""
}

// Synopsis implements the cli.Command interface
func (c *Command) Synopsis() string {
return ""
}

// Run implements the cli.Command interface
func (c *Command) Run(args []string) int {
flags := c.Flags()
if err := flags.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}

// read config file
config := DefaultConfig()
if c.configFile != "" {
c, err := readConfigFile(c.configFile)
if err != nil {
panic(err)
}
config.Merge(c)
}
config.Merge(c.cliConfig)

// start the logger
setupLogger(*config.LogLevel)

// create the node
nodeCfg, err := config.buildNode()
if err != nil {
panic(err)
}
stack, err := node.New(nodeCfg)
if err != nil {
panic(err)
}
c.node = stack

// register the ethereum backend
ethCfg, err := config.buildEth()
if err != nil {
panic(err)
}
backend, err := eth.New(stack, ethCfg)
if err != nil {
panic(err)
}
c.node.RegisterAPIs(tracers.APIs(backend.APIBackend))

// start the node
if err := c.node.Start(); err != nil {
panic(err)
}
return c.handleSignals()
}

func (c *Command) handleSignals() int {
signalCh := make(chan os.Signal, 4)
signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP)

sig := <-signalCh

c.UI.Output(fmt.Sprintf("Caught signal: %v", sig))
c.UI.Output("Gracefully shutting down agent...")

gracefulCh := make(chan struct{})
go func() {
c.node.Close()
close(gracefulCh)
}()

select {
case <-signalCh:
return 1
case <-time.After(5 * time.Second):
return 1
case <-gracefulCh:
return 0
}
}

func setupLogger(logLevel string) {
output := io.Writer(os.Stderr)
usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
if usecolor {
output = colorable.NewColorableStderr()
}
ostream := log.StreamHandler(output, log.TerminalFormat(usecolor))
glogger := log.NewGlogHandler(ostream)

// logging
lvl, err := log.LvlFromString(strings.ToLower(logLevel))
if err == nil {
glogger.Verbosity(lvl)
} else {
glogger.Verbosity(log.LvlInfo)
}
log.Root().SetHandler(glogger)
}
Loading

0 comments on commit a54cec4

Please sign in to comment.