Skip to content

Commit

Permalink
bootstrap cmd and more tests for gofire driver
Browse files Browse the repository at this point in the history
  • Loading branch information
1pkg committed Oct 22, 2021
1 parent 3dd6147 commit e91e1e6
Show file tree
Hide file tree
Showing 16 changed files with 303 additions and 21 deletions.
22 changes: 22 additions & 0 deletions cmd/bootstrap/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package main

import (
"context"
"log"

"github.com/1pkg/gofire/cmd"
"github.com/1pkg/gofire/generators"
_ "github.com/1pkg/gofire/generators/gofire"
)

func main() {
if err := cmd.Run(
context.Background(),
generators.DriverNameGofire,
"../gofire",
"main",
"run",
); err != nil {
log.Fatalln(err)
}
}
182 changes: 182 additions & 0 deletions cmd/gofire/gofire.gen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
// THIS IS AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
// Generated using github.com/1pkg/gofire 🔥 2021-10-22T23:15:29+02:00.
package main

import (
"context"
"errors"
"flag"
"fmt"
"os"
"os/signal"
"strings"
"unicode"

"github.com/1pkg/gofire"
"github.com/1pkg/gofire/parsers"
"github.com/mitchellh/mapstructure"
)

// Commandrun is autogenerated cli interface for run function.
func Commandrun(ctx context.Context) (o0 error, err error) {
var a0 string
var a1 string
var a2 string
var a3 string
if err = func(ctx context.Context) (err error) {
help := func() {
doc, usage, list := "run wraps cmd run for cli generators.", "run arg0 arg1 arg2 arg3 [--help]", "func run(ctx context.Context, name, dir, pckg, function string) error, arg 0 string arg 1 string arg 2 string arg 3 string"
if doc != "" {
_, _ = fmt.Fprintln(flag.CommandLine.Output(), doc)
}
if usage != "" {
_, _ = fmt.Fprintln(flag.CommandLine.Output(), usage)
}
if list != "" {
_, _ = fmt.Fprintln(flag.CommandLine.Output(), list)
}
}
defer func() {
if err != nil {
help()
}
}()
var tokenize = func(tokens []string) (args []string, flags map[string]string, err error) {
var flname = func(token string) (string, error) {
fln := strings.Replace(token, "--", "", 1)
for _, r := range fln {
if r != '.' && !(unicode.IsLetter(r) || unicode.IsDigit(r)) {
return "", fmt.Errorf("flag name %s is not alphanumeric and can't be tokenized", fln)
}
}
if _, ok := flags[fln]; ok {
return "", fmt.Errorf("flag name %s used multiple times and can't be tokenized", fln)
}
return fln, nil
}
ltkns := len(tokens)
args, flags = make([]string, 0, ltkns), make(map[string]string, ltkns)
var fln, prevToken string
for i := 0; i < ltkns; i++ {
token := strings.TrimSpace(tokens[i])
if token == "" {
continue
}
iflag, iflagPrev := strings.HasPrefix(token, "--"), strings.HasPrefix(prevToken, "--")
f, _ := flname(token)
switch {
case !iflag && !iflagPrev:
if strings.HasPrefix(token, "-") {
err = fmt.Errorf("short flag name %s can't be tokenized", token)
} else {
args = append(args, token)
prevToken = ""
}
case iflag && strings.Contains(token, "="):
parts := strings.SplitN(token, "=", 2)
fln, err = flname(parts[0])
flags[fln] = parts[1]
prevToken = ""
case !iflag && iflagPrev:
fln, err = flname(prevToken)
flags[fln] = token
prevToken = ""
case f == "help":
args, flags = nil, map[string]string{"help": "true"}
return
case iflag && i != ltkns-1:
prevToken = token
default:
err = fmt.Errorf("provided cli parameters %v can't be tokenized near token %s %s", tokens, prevToken, token)
}
if err != nil {
args, flags = nil, nil
return
}
}
return
}
args, flags, err := tokenize(os.Args[1:])
if err != nil {
return err
}
if args == nil {
args = nil
}
if flags == nil {
flags = nil
}
if flags["help"] == "true" {
return errors.New("help requested")
}
{
i := 0
if len(args) <= i {
return fmt.Errorf("argument %d-th is required", i)
}
v, _, err := parsers.ParseTypeValue(gofire.TPrimitive{TKind: 0x10}, args[i])
if err != nil {
return fmt.Errorf("argument a0 value %v can't be parsed %v", args[i], err)
}
if err := mapstructure.Decode(v, &a0); err != nil {
return fmt.Errorf("argument a0 value %v can't be decoded %v", v, err)
}
}
{
i := 1
if len(args) <= i {
return fmt.Errorf("argument %d-th is required", i)
}
v, _, err := parsers.ParseTypeValue(gofire.TPrimitive{TKind: 0x10}, args[i])
if err != nil {
return fmt.Errorf("argument a1 value %v can't be parsed %v", args[i], err)
}
if err := mapstructure.Decode(v, &a1); err != nil {
return fmt.Errorf("argument a1 value %v can't be decoded %v", v, err)
}
}
{
i := 2
if len(args) <= i {
return fmt.Errorf("argument %d-th is required", i)
}
v, _, err := parsers.ParseTypeValue(gofire.TPrimitive{TKind: 0x10}, args[i])
if err != nil {
return fmt.Errorf("argument a2 value %v can't be parsed %v", args[i], err)
}
if err := mapstructure.Decode(v, &a2); err != nil {
return fmt.Errorf("argument a2 value %v can't be decoded %v", v, err)
}
}
{
i := 3
if len(args) <= i {
return fmt.Errorf("argument %d-th is required", i)
}
v, _, err := parsers.ParseTypeValue(gofire.TPrimitive{TKind: 0x10}, args[i])
if err != nil {
return fmt.Errorf("argument a3 value %v can't be parsed %v", args[i], err)
}
if err := mapstructure.Decode(v, &a3); err != nil {
return fmt.Errorf("argument a3 value %v can't be decoded %v", v, err)
}
}
return
}(ctx); err != nil {
return
}
o0 = run(ctx, a0, a1, a2, a3)
return
}

// auto generated main entrypoint.
func main() {
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()
func(o0 error, err error) {
if err != nil {
fmt.Println(err)
os.Exit(2)
}
}(Commandrun(ctx))
}
13 changes: 13 additions & 0 deletions cmd/gofire/run.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package main

import (
"context"

"github.com/1pkg/gofire/cmd"
"github.com/1pkg/gofire/generators"
)

// run wraps cmd run for cli generators.
func run(ctx context.Context, name, dir, pckg, function string) error {
return cmd.Run(ctx, generators.DriverName(name), dir, pckg, function)
}
4 changes: 3 additions & 1 deletion cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"github.com/1pkg/gofire/parsers"
)

// Run first parse provided package function, then
// generates relevant cli boilerplate and writes it to a file.
func Run(ctx context.Context, name generators.DriverName, dir, pckg, function string) error {
cmd, err := parsers.Parse(ctx, os.DirFS(dir), pckg, function)
if err != nil {
Expand All @@ -20,7 +22,7 @@ func Run(ctx context.Context, name generators.DriverName, dir, pckg, function st
if err := generators.Generate(ctx, name, *cmd, &b); err != nil {
return err
}
f, err := os.Create(filepath.Join(dir, fmt.Sprintf("%s.go", name)))
f, err := os.Create(filepath.Join(dir, fmt.Sprintf("%s.gen.go", name)))
if err != nil {
return err
}
Expand Down
11 changes: 11 additions & 0 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ type Visitor interface {
VisitFlag(Flag, *Group) error
}

// Parameter defines an abstraction for cmd parameter.
type Parameter interface {
Accept(Visitor) error
}

// Placeholder is a cmd parameter implementation
// that just hold parameter slot.
type Placeholder struct {
Type Typ
}
Expand All @@ -18,6 +21,8 @@ func (p Placeholder) Accept(v Visitor) error {
return v.VisitPlaceholder(p)
}

// Argument is a cmd parameter implementation
// that represents cmd positional argument.
type Argument struct {
Index uint64
Ellipsis bool
Expand All @@ -28,6 +33,8 @@ func (a Argument) Accept(v Visitor) error {
return v.VisitArgument(a)
}

// Flag is a cmd parameter implementation
// that represents cmd flag.
type Flag struct {
Full string
Short string
Expand All @@ -42,6 +49,8 @@ func (f Flag) Accept(v Visitor) error {
return v.VisitFlag(f, nil)
}

// Group is a cmd parameter implementation
// that groups multiple cmd flags together.
type Group struct {
Name string
Doc string
Expand All @@ -58,6 +67,8 @@ func (g Group) Accept(v Visitor) error {
return nil
}

// Group is a cmd composite parameter implementation
// that represent function as a command.
type Command struct {
Package string
Function string
Expand Down
2 changes: 2 additions & 0 deletions generators/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/1pkg/gofire"
)

// DriverName holds names of drivers implementations.
type DriverName string

const (
Expand All @@ -17,6 +18,7 @@ const (
DriverNameBubbleTea DriverName = "bubbletea"
)

// Reference helps to represent full qualified group name.
type Reference string

func NewReference(typ, g, f string) *Reference {
Expand Down
6 changes: 3 additions & 3 deletions generators/generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func TestGeneratorGenerate(t *testing.T) {
return "{{"
}
err := generators.Generate(context.TODO(), generators.DriverName("test_generate"), gofire.Command{}, nil)
if fmt.Sprintf("%v", err) != `template: gen:4: unexpected "{" in command` {
if fmt.Sprintf("%v", err) != `template: gen:5: unexpected "{" in command` {
t.Fatalf("generate should fail on driver broken template error with message %q", err)
}
})
Expand All @@ -120,7 +120,7 @@ func TestGeneratorGenerate(t *testing.T) {
return "{{.Error}}"
}
err := generators.Generate(context.TODO(), generators.DriverName("test_generate"), gofire.Command{}, nil)
if fmt.Sprintf("%v", err) != `template: gen:3:3: executing "gen" at <.Error>: can't evaluate field Error in type generators.proxy` {
if fmt.Sprintf("%v", err) != `template: gen:4:3: executing "gen" at <.Error>: can't evaluate field Error in type generators.proxy` {
t.Fatalf("generate should fail on driver template expanding error with message %q", err)
}
})
Expand All @@ -135,7 +135,7 @@ func TestGeneratorGenerate(t *testing.T) {
return "func {{.Import}}"
}
err := generators.Generate(context.TODO(), generators.DriverName("test_generate"), gofire.Command{}, nil)
if fmt.Sprintf("%v", err) != "2:2: expected 'package', found 'func'" {
if fmt.Sprintf("%v", err) != "3:2: expected 'package', found 'func'" {
t.Fatalf("generate should fail on driver code formating error with message %q", err)
}
})
Expand Down
6 changes: 4 additions & 2 deletions generators/gofire/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"sort"
"strings"

Expand Down Expand Up @@ -133,7 +135,6 @@ func (d *driver) VisitArgument(a gofire.Argument) error {
case gofire.Float32, gofire.Float64:
case gofire.Complex64, gofire.Complex128:
case gofire.String:
case gofire.Array:
case gofire.Slice:
case gofire.Map:
default:
Expand Down Expand Up @@ -194,7 +195,6 @@ func (d *driver) VisitFlag(f gofire.Flag, g *gofire.Group) error {
case gofire.Float32, gofire.Float64:
case gofire.Complex64, gofire.Complex128:
case gofire.String:
case gofire.Array:
case gofire.Slice:
case gofire.Map:
default:
Expand Down Expand Up @@ -245,6 +245,8 @@ func (d *driver) VisitFlag(f gofire.Flag, g *gofire.Group) error {
}

func include(buf *bytes.Buffer, path string) error {
_, p, _, _ := runtime.Caller(0)
path = filepath.Join(filepath.Dir(p), path)
f, err := os.Open(path)
if err != nil {
return err
Expand Down
14 changes: 14 additions & 0 deletions generators/gofire/drvier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,27 @@ argument 1-th is required
exit status 2
`,
},
"echo complex params types should produce expected output on valid params": {
dir: "echo_complex_params",
pckg: "main",
function: "echo",
params: []string{`--a="{1,2,3,4,5}"`, `--b="{{1},{2},{3}}"`, `"{test1:{'aaa', 'bbb'}, test2:{bbb, aaa}}"`},
out: "[1 2 3 4 5] [[1] [2] [3]] map[test1:['aaa' 'bbb'] test2:[bbb aaa]]\n",
},
"echo group params types should produce expected output on valid params": {
dir: "echo_group_params",
pckg: "main",
function: "echo",
params: []string{"--g1.a=100"},
out: "1:100 2:10\n",
},
"echo complex group params types should produce expected output on valid params": {
dir: "echo_complex_group_params",
pckg: "main",
function: "echo",
params: []string{`--g.b="{1:2}"`},
out: "{map[key:value] map[1:2]}\n",
},
"echo group params types should produce expected error on invalid params": {
dir: "echo_group_params",
pckg: "main",
Expand Down
Loading

0 comments on commit e91e1e6

Please sign in to comment.