diff --git a/.gitignore b/.gitignore index 1962ccd..dc2c320 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ bin/ - +tests/ .svn/ .godeps ./build diff --git a/tools/gen/internal/generator/generator.go b/tools/gen/internal/generator/generator.go new file mode 100644 index 0000000..64b44ae --- /dev/null +++ b/tools/gen/internal/generator/generator.go @@ -0,0 +1,113 @@ +package generator + +import ( + "bytes" + "embed" + "html/template" + "io" + "io/fs" + "os" + "path" + "time" + + "git.nobla.cn/golang/aeus/tools/gen/internal/types" +) + +var ( + fileMap = map[string]string{ + "cmd/main.go": MainTemp, + "internal/scope/scope.go": ScopeTemp, + "internal/service/service.go": ServiceLoaderTemp, + "api/v1/pb/greeter.proto": GreeterTemp, + "version/version.go": VersionTemp, + "Makefile": MakefileTemp, + ".gitignore": GitIgnoreTemp, + "README.md": ReadmeTemp, + "go.mod": GoModTemp, + } +) + +var ( + //go:embed third_party + protoDir embed.FS +) + +type ( + TemplateData struct { + ShortName string + PackageName string + Datetime string + Version string + } +) + +func writeFile(file string, buf []byte) (err error) { + dirname := path.Dir(file) + if _, err = os.Stat(dirname); err != nil { + if err = os.MkdirAll(dirname, 0755); err != nil { + return + } + } + err = os.WriteFile(file, buf, 0644) + return +} + +func scanDir(s embed.FS, dirname string, callback func(file string) error) (err error) { + var ( + entities []fs.DirEntry + ) + if entities, err = s.ReadDir(dirname); err != nil { + return nil + } + for _, entity := range entities { + if entity.Name() == "." || entity.Name() == ".." { + continue + } + name := path.Join(dirname, entity.Name()) + if entity.IsDir() { + scanDir(s, name, callback) + } else { + if err = callback(name); err != nil { + break + } + } + } + return +} + +func Geerate(app *types.Applicetion) (err error) { + shortName := app.ShortName() + data := TemplateData{ + ShortName: shortName, + PackageName: app.Package, + Version: "v0.0.1", + Datetime: time.Now().Format(time.DateTime), + } + var t *template.Template + writer := bytes.NewBuffer(nil) + for name, tmpl := range fileMap { + if t, err = template.New(name).Parse(tmpl); err != nil { + return + } + if err = t.Execute(writer, data); err != nil { + return + } + if err = writeFile(path.Join(shortName, name), writer.Bytes()); err != nil { + return + } + writer.Reset() + } + + err = scanDir(protoDir, "third_party", func(filename string) error { + if fp, openerr := protoDir.Open(filename); openerr != nil { + return openerr + } else { + if buf, readerr := io.ReadAll(fp); readerr == nil { + writeFile(path.Join(shortName, filename), buf) + } + fp.Close() + } + return nil + }) + return +} diff --git a/tools/gen/internal/generator/template.go b/tools/gen/internal/generator/template.go new file mode 100644 index 0000000..cb34128 --- /dev/null +++ b/tools/gen/internal/generator/template.go @@ -0,0 +1,230 @@ +package generator + +var ( + MainTemp = ` +package main + +import ( + "fmt" + "os" + "flag" + "git.nobla.cn/golang/aeus" + "git.nobla.cn/golang/aeus/transport/cli" + "git.nobla.cn/golang/aeus/transport/grpc" + "git.nobla.cn/golang/aeus/transport/http" + + "{{.PackageName}}/version" + "{{.PackageName}}/internal/scope" + "{{.PackageName}}/internal/service" +) + +var ( + versionFlag = flag.Bool("version", false, "Show version") +) + +func main() { + var ( + err error + ) + flag.Parse() + if *versionFlag{ + fmt.Println(version.Info()) + os.Exit(0) + } + app := aeus.New( + aeus.WithName("{{.ShortName}}"), + aeus.WithVersion("{{.Version}}"), + aeus.WithServer( + http.New(), + grpc.New(), + cli.New(), + ), + aeus.WithScope(scope.NewScope()), + aeus.WithServiceLoader(service.NewLoader()), + ) + + if err = app.Run(); err != nil { + fmt.Println("app run error:", err) + os.Exit(1) + } +} +` + + ScopeTemp = ` +package scope + +import ( + "context" + + "git.nobla.cn/golang/aeus/transport/cli" + "git.nobla.cn/golang/aeus/transport/grpc" + "git.nobla.cn/golang/aeus/transport/http" +) + +type ScopeContext struct { + ctx context.Context + Http *http.Server + Grpc *grpc.Server + Cli *cli.Server +} + +func (s *ScopeContext) Init(ctx context.Context) (err error) { + s.ctx = ctx + return +} + +func NewScope() *ScopeContext { + return &ScopeContext{} +} +` + + ServiceLoaderTemp = ` +package service + +import ( + "context" + + "{{.PackageName}}/internal/scope" + "git.nobla.cn/golang/aeus/transport/cli" + "git.nobla.cn/golang/aeus/transport/grpc" + "git.nobla.cn/golang/aeus/transport/http" +) + +type serviceLoader struct { + Sope *scope.ScopeContext + Http *http.Server + Grpc *grpc.Server + Cli *cli.Server +} + +func (s *serviceLoader) Init(ctx context.Context) (err error) { + // bind services here + return +} + +func (s *serviceLoader) Run(ctx context.Context) (err error) { + return +} + +func NewLoader() *serviceLoader { + return &serviceLoader{} +} +` + + MakefileTemp = ` +GOHOSTOS:=$(shell go env GOHOSTOS) +GOPATH:=$(shell go env GOPATH) +VERSION=$(shell git describe --tags --always) +DATETIME:=$(shell date "+%Y-%m-%d %H:%M:%S") + + +PROTO_DIR="api/v1/pb" +PROTO_OUT_DIR="api/v1/pb" +PROTO_FILES=$(shell find api -name *.proto) + +.PHONY: proto +proto: + protoc --proto_path=$(PROTO_DIR) \ + --proto_path=./third_party \ + --go_out=paths=source_relative:$(PROTO_OUT_DIR) \ + --go-grpc_out=paths=source_relative:$(PROTO_OUT_DIR) \ + --go-aeus_out=paths=source_relative:$(PROTO_OUT_DIR) \ + --validate_out=paths=source_relative,lang=go:$(PROTO_OUT_DIR) \ + $(PROTO_FILES) + +.PHONY: proto-clean +proto-clean: + rm -rf $(PROTO_OUT_DIR)/*.pb.go + rm -rf $(PROTO_OUT_DIR)/*.pb.validate.go + +.PHONY: build +build: + go mod tidy + go mod vendor + go build -ldflags "-s -w -X '{{.PackageName}}/version.Version=$(VERSION)' -X '{{.PackageName}}/version.BuildDate=$(DATETIME)'" -o bin/{{.ShortName}} cmd/main.go +` + + GreeterTemp = ` +syntax = "proto3"; + +package greeter; + +import "google/api/annotations.proto"; +import "aeus/command.proto"; +import "aeus/rest.proto"; +import "validate/validate.proto"; + +option go_package = "{{.PackageName}}/api/v1/pb;pb"; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) { + option (google.api.http) = { + get: "/helloworld/{name}" + }; + option (aeus.command) = { + path: "/helloworld/:name", + description: "Greeter" + }; + } +} + +// The request message containing the user's name. +message HelloRequest { + option (aeus.rest) = { + table: "users" + }; + int64 id = 1 [(aeus.field)={gorm:"primary_key"},(validate.rules).int64.gt = 999]; + string name = 2; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} +` + VersionTemp = ` +package version + +import "fmt" + +var ( + Version = "{{.Version}}" + BuildDate = "{{.Datetime}}" + ProductName = "{{.ShortName}}" +) + +func Info() string { + return fmt.Sprintf("%s version: %s (built at %s)", ProductName, Version, BuildDate) +} +` + + GitIgnoreTemp = ` +.vscode +.idea + +bin/ +.svn/ +.godeps +./build +.cover/ +*.dat +vendor + +*.o +*.a +*.so + +# Folders +_obj +_test +` + ReadmeTemp = `` + + GoModTemp = ` +module {{.PackageName}} + +go 1.23.0 +` +) diff --git a/tools/gen/internal/types/types.go b/tools/gen/internal/types/types.go new file mode 100644 index 0000000..cfb0352 --- /dev/null +++ b/tools/gen/internal/types/types.go @@ -0,0 +1,15 @@ +package types + +import "strings" + +type Applicetion struct { + Package string +} + +func (app *Applicetion) ShortName() string { + pos := strings.LastIndex(app.Package, "/") + if pos > -1 { + return app.Package[pos+1:] + } + return app.Package +} diff --git a/tools/gen/main.go b/tools/gen/main.go new file mode 100644 index 0000000..c4202e6 --- /dev/null +++ b/tools/gen/main.go @@ -0,0 +1,25 @@ +package main + +import ( + "flag" + "fmt" + "os" + + "git.nobla.cn/golang/aeus/tools/gen/internal/generator" + "git.nobla.cn/golang/aeus/tools/gen/internal/types" +) + +var ( + packageFlag = flag.String("package", "", "package name") +) + +func main() { + flag.Parse() + app := &types.Applicetion{ + Package: *packageFlag, + } + if err := generator.Geerate(app); err != nil { + fmt.Println(err) + os.Exit(1) + } +}