Skip to content

Commit

Permalink
Generate Gomu files after the fact (micro#2258)
Browse files Browse the repository at this point in the history
* Move file generation to new package

* Use text/template instead of html/template

* Make config variables more consistent

* Combine generate files and print comments there

* Add gomu generate command

* Refactor project templating to file library

* Determine client earlier
  • Loading branch information
AuditeMarlow authored Sep 10, 2021
1 parent 01b7b44 commit e23006b
Show file tree
Hide file tree
Showing 16 changed files with 300 additions and 124 deletions.
1 change: 1 addition & 0 deletions cmd/gomu/cmd/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cli
import (
_ "github.com/asim/go-micro/cmd/gomu/cmd/cli/call"
_ "github.com/asim/go-micro/cmd/gomu/cmd/cli/describe"
_ "github.com/asim/go-micro/cmd/gomu/cmd/cli/generate"
_ "github.com/asim/go-micro/cmd/gomu/cmd/cli/new"
_ "github.com/asim/go-micro/cmd/gomu/cmd/cli/run"
_ "github.com/asim/go-micro/cmd/gomu/cmd/cli/services"
Expand Down
98 changes: 98 additions & 0 deletions cmd/gomu/cmd/cli/generate/generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package generate

import (
"bufio"
"fmt"
"os"
"strings"

"github.com/asim/go-micro/cmd/gomu/cmd"
"github.com/asim/go-micro/cmd/gomu/file"
"github.com/asim/go-micro/cmd/gomu/file/generator"
tmpl "github.com/asim/go-micro/cmd/gomu/file/template"
"github.com/urfave/cli/v2"
)

func init() {
cmd.Register(&cli.Command{
Name: "generate",
Usage: "Generate project template files after the fact",
Subcommands: []*cli.Command{
{
Name: "skaffold",
Usage: "Generate Skaffold project template files",
Action: Skaffold,
},
},
})
}

// Skaffold generates Skaffold project template files in the current directory.
// Exits on error.
func Skaffold(ctx *cli.Context) error {
dir, err := os.Getwd()
if err != nil {
return err
}
service := dir[strings.LastIndex(dir, "/")+1:]

vendor, err := getServiceVendor(service)
if err != nil {
return err
}

g := generator.New(
generator.Service(service),
generator.Vendor(vendor),
generator.Directory("."),
generator.Client(strings.HasSuffix(service, "-client")),
generator.Skaffold(true),
)

files := []file.File{
{".dockerignore", tmpl.DockerIgnore},
{"go.mod", tmpl.Module},
{"plugins.go", tmpl.Plugins},
{"resources/clusterrole.yaml", tmpl.KubernetesClusterRole},
{"resources/configmap.yaml", tmpl.KubernetesEnv},
{"resources/deployment.yaml", tmpl.KubernetesDeployment},
{"resources/rolebinding.yaml", tmpl.KubernetesRoleBinding},
{"skaffold.yaml", tmpl.SkaffoldCFG},
}

if err := g.Generate(files); err != nil {
return err
}

fmt.Println("skaffold project template files generated")

return nil
}

func getServiceVendor(s string) (string, error) {
f, err := os.Open("go.mod")
if err != nil {
return "", err
}
defer f.Close()

line := ""
scanner := bufio.NewScanner(f)
for scanner.Scan() {
if strings.HasPrefix(scanner.Text(), "module ") {
line = scanner.Text()
break

}
}
if line == "" {
return "", nil
}

module := line[strings.LastIndex(line, " ")+1:]
if module == s {
return "", nil
}

return module[:strings.LastIndex(module, "/")] + "/", nil
}
108 changes: 30 additions & 78 deletions cmd/gomu/cmd/cli/new/new.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import (
"fmt"
"os"
"path"
"path/filepath"
"strings"
"text/template"

"github.com/asim/go-micro/cmd/gomu/cmd"
tmpl "github.com/asim/go-micro/cmd/gomu/cmd/cli/new/template"
"github.com/asim/go-micro/cmd/gomu/file"
"github.com/asim/go-micro/cmd/gomu/file/generator"
tmpl "github.com/asim/go-micro/cmd/gomu/file/template"
"github.com/urfave/cli/v2"
)

Expand All @@ -24,21 +24,6 @@ var flags []cli.Flag = []cli.Flag{
},
}

type config struct {
Alias string
Comments []string
Dir string
Vendor string
Client bool
Jaeger bool
Skaffold bool
}

type file struct {
Path string
Tmpl string
}

// NewCommand returns a new new cli command.
func init() {
cmd.Register(&cli.Command{
Expand Down Expand Up @@ -87,10 +72,11 @@ func createProject(ctx *cli.Context, pt string) error {
return cli.ShowSubcommandHelp(ctx)
}

client := pt == "client"
name, vendor := getNameAndVendor(arg)

dir := name
if pt == "client" {
if client {
dir += "-client"
}

Expand All @@ -105,7 +91,16 @@ func createProject(ctx *cli.Context, pt string) error {

fmt.Printf("creating %s %s\n", pt, name)

files := []file{
g := generator.New(
generator.Service(name),
generator.Vendor(vendor),
generator.Directory(dir),
generator.Client(client),
generator.Jaeger(ctx.Bool("jaeger")),
generator.Skaffold(ctx.Bool("skaffold")),
)

files := []file.File{
{".dockerignore", tmpl.DockerIgnore},
{".gitignore", tmpl.GitIgnore},
{"Dockerfile", tmpl.Dockerfile},
Expand All @@ -115,17 +110,17 @@ func createProject(ctx *cli.Context, pt string) error {

switch pt {
case "client":
files = append(files, []file{
files = append(files, []file.File{
{"main.go", tmpl.MainCLT},
}...)
case "function":
files = append(files, []file{
files = append(files, []file.File{
{"handler/" + name + ".go", tmpl.HandlerFNC},
{"main.go", tmpl.MainFNC},
{"proto/" + name + ".proto", tmpl.ProtoFNC},
}...)
case "service":
files = append(files, []file{
files = append(files, []file.File{
{"handler/" + name + ".go", tmpl.HandlerSRV},
{"main.go", tmpl.MainSRV},
{"proto/" + name + ".proto", tmpl.ProtoSRV},
Expand All @@ -135,7 +130,7 @@ func createProject(ctx *cli.Context, pt string) error {
}

if ctx.Bool("skaffold") {
files = append(files, []file{
files = append(files, []file.File{
{"plugins.go", tmpl.Plugins},
{"resources/clusterrole.yaml", tmpl.KubernetesClusterRole},
{"resources/configmap.yaml", tmpl.KubernetesEnv},
Expand All @@ -145,22 +140,22 @@ func createProject(ctx *cli.Context, pt string) error {
}...)
}

c := config{
Alias: name,
Dir: dir,
Vendor: vendor,
Client: pt == "client",
Jaeger: ctx.Bool("jaeger"),
Skaffold: ctx.Bool("skaffold"),
if err := g.Generate(files); err != nil {
return err
}

if pt == "client" {
c.Comments = clientComments(name, dir)
var comments []string
if client {
comments = clientComments(name, dir)
} else {
c.Comments = protoComments(name, dir)
comments = protoComments(name, dir)
}

return create(files, c)
for _, comment := range comments {
fmt.Println(comment)
}

return nil
}

func clientComments(name, dir string) []string {
Expand All @@ -184,49 +179,6 @@ func protoComments(name, dir string) []string {
}
}

func create(files []file, c config) error {
for _, file := range files {
fp := filepath.Join(c.Dir, file.Path)
dir := filepath.Dir(fp)

if _, err := os.Stat(dir); os.IsNotExist(err) {
if err := os.MkdirAll(dir, 0755); err != nil {
return err
}
}

f, err := os.Create(fp)
if err != nil {
return err
}

fn := template.FuncMap{
"dehyphen": func(s string) string {
return strings.ReplaceAll(s, "-", "")
},
"lower": strings.ToLower,
"title": func(s string) string {
return strings.ReplaceAll(strings.Title(s), "-", "")
},
}
t, err := template.New(fp).Funcs(fn).Parse(file.Tmpl)
if err != nil {
return err
}

err = t.Execute(f, c)
if err != nil {
return err
}
}

for _, comment := range c.Comments {
fmt.Println(comment)
}

return nil
}

func getNameAndVendor(s string) (string, string) {
var n string
var v string
Expand Down
6 changes: 6 additions & 0 deletions cmd/gomu/file/file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package file

type File struct {
Path string
Template string
}
70 changes: 70 additions & 0 deletions cmd/gomu/file/generator/generator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package generator

import (
"os"
"path/filepath"
"strings"
"text/template"

"github.com/asim/go-micro/cmd/gomu/file"
)

type Generator interface {
Generate([]file.File) error
}

type generator struct {
opts Options
}

// Generate generates project template files.
func (g *generator) Generate(files []file.File) error {
for _, file := range files {
fp := filepath.Join(g.opts.Directory, file.Path)
dir := filepath.Dir(fp)

if _, err := os.Stat(dir); os.IsNotExist(err) {
if err := os.MkdirAll(dir, 0755); err != nil {
return err
}
}

f, err := os.Create(fp)
if err != nil {
return err
}

fn := template.FuncMap{
"dehyphen": func(s string) string {
return strings.ReplaceAll(s, "-", "")
},
"lower": strings.ToLower,
"title": func(s string) string {
return strings.ReplaceAll(strings.Title(s), "-", "")
},
}
t, err := template.New(fp).Funcs(fn).Parse(file.Template)
if err != nil {
return err
}

err = t.Execute(f, g.opts)
if err != nil {
return err
}
}

return nil
}

// New returns a new generator struct.
func New(opts ...Option) Generator {
var options Options
for _, o := range opts {
o(&options)
}

return &generator{
opts: options,
}
}
Loading

0 comments on commit e23006b

Please sign in to comment.