mirror of
https://github.com/cubixle/tuugen.git
synced 2026-04-24 21:24:42 +01:00
wip
This commit is contained in:
46
README.md
Normal file
46
README.md
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# Tuugen
|
||||||
|
|
||||||
|
Tuugen takes a tuugen.yml and a grpc proto definition to generate common boiler plate logic. Some of the common boiler plate it generates is http routes, grpc service, data model structs and a main file with some default plumbing.
|
||||||
|
|
||||||
|
Tuugen adds an interactor package which the http and grpc transport layers use for business logic.
|
||||||
|
|
||||||
|
Feel free to pull the repo and play around with the example_project.
|
||||||
|
|
||||||
|
## Using Tuugen.
|
||||||
|
|
||||||
|
```
|
||||||
|
go install github.com/cubixle/tuugen
|
||||||
|
```
|
||||||
|
|
||||||
|
And the run `tuugen` in the root dir of your project or wherever you have your tuugen and proto file.
|
||||||
|
|
||||||
|
## Example tuugen file
|
||||||
|
```yaml
|
||||||
|
project: tuugen_test_project
|
||||||
|
import_path: github.com/cubixle/tuugen/example_project
|
||||||
|
proto_file: service.proto
|
||||||
|
grpc_file: internal/pb/service/service_grpc.pb.go
|
||||||
|
service_name: Service
|
||||||
|
data_models:
|
||||||
|
- name: User
|
||||||
|
properties:
|
||||||
|
- name: id
|
||||||
|
type: varchar
|
||||||
|
autoinc: true
|
||||||
|
- name: team_id
|
||||||
|
type: varchar
|
||||||
|
- name: name
|
||||||
|
type: varchar
|
||||||
|
- name: email
|
||||||
|
type: varchar
|
||||||
|
- name: created_at
|
||||||
|
type: timestamp
|
||||||
|
- name: updated_at
|
||||||
|
type: timestamp
|
||||||
|
- name: Team
|
||||||
|
properties:
|
||||||
|
- name: id
|
||||||
|
type: varchar
|
||||||
|
- name: name
|
||||||
|
type: varchar
|
||||||
|
```
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package tuugen
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s := grpc.NewServer()
|
s := grpc.NewServer()
|
||||||
pb.RegisterServiceServer(s, service.New(store))
|
pb.RegisterServiceServer(s, service.New())
|
||||||
if err := s.Serve(lis); err != nil {
|
if err := s.Serve(lis); err != nil {
|
||||||
log.Fatalf("failed to serve: %v", err)
|
log.Fatalf("failed to serve: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import (
|
|||||||
"embed"
|
"embed"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/cubixle/tuugen"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed templates/*
|
//go:embed templates/*
|
||||||
@@ -17,47 +15,47 @@ func main() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to find tuugen.yaml, %v", err)
|
log.Fatalf("failed to find tuugen.yaml, %v", err)
|
||||||
}
|
}
|
||||||
cfg, err := tuugen.YamlToConfig(d)
|
cfg, err := YamlToConfig(d)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to load config, %v", err)
|
log.Fatalf("failed to load config, %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Generating protos from %s\n", cfg.ProtoFile)
|
log.Printf("Generating protos from %s\n", cfg.ProtoFile)
|
||||||
err = tuugen.GenerateProtos(cfg.ProtoFile)
|
err = GenerateProtos(cfg.ProtoFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("Generating service implementation")
|
log.Println("Generating service implementation")
|
||||||
err = tuugen.GenerateService(FS, cfg)
|
err = GenerateService(FS, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to generate service: %v", err)
|
log.Fatalf("failed to generate service: %v", err)
|
||||||
}
|
}
|
||||||
log.Println("Generating interactor stubs")
|
log.Println("Generating interactor stubs")
|
||||||
err = tuugen.GenerateInteractor(FS, cfg)
|
err = GenerateInteractor(FS, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to generate interactor: %v", err)
|
log.Fatalf("failed to generate interactor: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("Generating data models")
|
log.Println("Generating data models")
|
||||||
if err := tuugen.GenerateDataModels(FS, cfg); err != nil {
|
if err := GenerateDataModels(FS, cfg); err != nil {
|
||||||
log.Fatalf("failed to generate data models: %v", err)
|
log.Fatalf("failed to generate data models: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("Generate main.go")
|
log.Println("Generate main.go")
|
||||||
if err := tuugen.GenerateMain(FS, cfg); err != nil {
|
if err := GenerateMain(FS, cfg); err != nil {
|
||||||
log.Fatalf("failed to generate main file: %v", err)
|
log.Fatalf("failed to generate main file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Running 'go mod init %s' \n", cfg.ImportPath)
|
log.Printf("Running 'go mod init %s' \n", cfg.ImportPath)
|
||||||
if err := tuugen.GoModInit(cfg.ImportPath); err != nil {
|
if err := GoModInit(cfg.ImportPath); err != nil {
|
||||||
log.Fatalf("failed to run 'go mod init': %v", err)
|
log.Fatalf("failed to run 'go mod init': %v", err)
|
||||||
}
|
}
|
||||||
log.Println("Running clean up")
|
log.Println("Running clean up")
|
||||||
if err := tuugen.GoFmt(); err != nil {
|
if err := GoFmt(); err != nil {
|
||||||
log.Fatalf("failed to run gofmt: %v", err)
|
log.Fatalf("failed to run gofmt: %v", err)
|
||||||
}
|
}
|
||||||
if err := tuugen.GoImports(); err != nil {
|
if err := GoImports(); err != nil {
|
||||||
log.Fatalf("failed to run 'goimports': %v", err)
|
log.Fatalf("failed to run 'goimports': %v", err)
|
||||||
}
|
}
|
||||||
log.Println("------")
|
log.Println("------")
|
||||||
27
service.go
27
service.go
@@ -1,4 +1,4 @@
|
|||||||
package tuugen
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
@@ -67,20 +67,24 @@ func createFileFromProto(FS embed.FS, cfg Config, templateFile, outputFile strin
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
funcs, err := methodsFromProto(cfg)
|
def, err := parseProto(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := t.Execute(f, funcs); err != nil {
|
// dirty check to see if we need to import the interactors.
|
||||||
|
if strings.Contains(templateFile, "service") {
|
||||||
|
def.Imports = append(def.Imports, cfg.ImportPath+"/internal/interactors")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := t.Execute(f, def); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return f.Close()
|
return f.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func methodsFromProto(cfg Config) (serviceDef, error) {
|
func parseProto(cfg Config) (serviceDef, error) {
|
||||||
funcs := []serviceFuncDef{}
|
|
||||||
fset := token.NewFileSet()
|
fset := token.NewFileSet()
|
||||||
f, err := parser.ParseFile(fset, cfg.GRPCFile, nil, 0)
|
f, err := parser.ParseFile(fset, cfg.GRPCFile, nil, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -90,10 +94,17 @@ func methodsFromProto(cfg Config) (serviceDef, error) {
|
|||||||
importStrs := []string{}
|
importStrs := []string{}
|
||||||
servicePath := filepath.Dir(cfg.GRPCFile)
|
servicePath := filepath.Dir(cfg.GRPCFile)
|
||||||
for _, i := range f.Imports {
|
for _, i := range f.Imports {
|
||||||
importStrs = append(importStrs, i.Name.Name)
|
importStrs = append(importStrs, i.Path.Value)
|
||||||
}
|
}
|
||||||
importStrs = append(importStrs, strings.Join([]string{cfg.ImportPath, strings.TrimLeft(servicePath, "/")}, "/"), cfg.ImportPath+"/internal/interactors")
|
importStrs = append(importStrs, strings.Join([]string{cfg.ImportPath, strings.TrimLeft(servicePath, "/")}, "/"))
|
||||||
|
|
||||||
|
funcs := parseFuncs(cfg, f)
|
||||||
|
|
||||||
|
return serviceDef{Funcs: funcs, Imports: importStrs}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseFuncs(cfg Config, f *ast.File) []serviceFuncDef {
|
||||||
|
funcs := []serviceFuncDef{}
|
||||||
for _, m := range f.Scope.Objects {
|
for _, m := range f.Scope.Objects {
|
||||||
if m.Name != cfg.ServiceName+"Server" {
|
if m.Name != cfg.ServiceName+"Server" {
|
||||||
continue
|
continue
|
||||||
@@ -118,7 +129,7 @@ func methodsFromProto(cfg Config) (serviceDef, error) {
|
|||||||
funcs = append(funcs, f)
|
funcs = append(funcs, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return serviceDef{Funcs: funcs, Imports: importStrs}, nil
|
return funcs
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseFieldList(fl *ast.FieldList) []string {
|
func parseFieldList(fl *ast.FieldList) []string {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s := grpc.NewServer()
|
s := grpc.NewServer()
|
||||||
pb.Register{{.ServiceName}}Server(s, service.New(store))
|
pb.Register{{.ServiceName}}Server(s, service.New())
|
||||||
if err := s.Serve(lis); err != nil {
|
if err := s.Serve(lis); err != nil {
|
||||||
log.Fatalf("failed to serve: %v", err)
|
log.Fatalf("failed to serve: %v", err)
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,10 @@ import ({{ range .Imports }}
|
|||||||
"{{ . }}"{{ end }}
|
"{{ . }}"{{ end }}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func New() *Service {
|
||||||
|
return &Service{}
|
||||||
|
}
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
interactor *interactors.Interactor
|
interactor *interactors.Interactor
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user