add proto client/server (#719)

* add proto client/server
pull/727/head v2.0.0-alpha4
Tony Chen 4 years ago committed by GitHub
parent 5b0b39e3df
commit 7cbb0574b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 21
      README.md
  2. 19
      cmd/kratos/internal/base/get.go
  3. 40
      cmd/kratos/internal/base/mod.go
  4. 11
      cmd/kratos/internal/base/mod_test.go
  5. 4
      cmd/kratos/internal/base/repo_test.go
  6. 6
      cmd/kratos/internal/project/new.go
  7. 4
      cmd/kratos/internal/project/project.go
  8. 83
      cmd/kratos/internal/proto/client/client.go
  9. 8
      cmd/kratos/internal/proto/proto.go
  10. 34
      cmd/kratos/internal/proto/server/server.go
  11. 2
      cmd/kratos/internal/proto/server/template.go
  12. 28
      cmd/kratos/internal/proto/source/source.go
  13. 30
      cmd/kratos/internal/upgrade/upgrade.go
  14. 15
      cmd/kratos/main.go
  15. 13
      cmd/kratos/version.go

@ -58,17 +58,16 @@ kratos new helloworld
cd helloworld
# 生成proto模板
kratos proto add api/helloworld/helloworld.proto
# 生成service模板
kratos proto service api/helloworld/helloworld.proto -t internal/service
# 安装生成工具
make init
# 生成api下所有proto文件
make proto
# 编译cmd下所有main文件
make build
# 进行单元测试
make test
# 生成proto源码
kratos proto client api/helloworld/helloworld.proto
# 生成server模板
kratos proto server api/helloworld/helloworld.proto -t internal/service
# 编译成可执行文件
cd /cmd/helloworld
go build
# 运行程序
./helloword
```
### Kratos Boot

@ -0,0 +1,19 @@
package base
import (
"os"
"os/exec"
)
// GoGet go get path.
func GoGet(path ...string) error {
for _, p := range path {
cmd := exec.Command("go", "get", "-u", p)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return err
}
}
return nil
}

@ -1,7 +1,13 @@
package base
import (
"bufio"
"bytes"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"
"golang.org/x/mod/modfile"
)
@ -14,3 +20,37 @@ func ModulePath(filename string) (string, error) {
}
return modfile.ModulePath(modBytes), nil
}
// ModuleVersion returns module version.
func ModuleVersion(path string) (string, error) {
stdout := &bytes.Buffer{}
fd := exec.Command("go", "mod", "graph")
fd.Stdout = stdout
fd.Stderr = stdout
if err := fd.Run(); err != nil {
return "", err
}
rd := bufio.NewReader(stdout)
for {
line, _, err := rd.ReadLine()
if err != nil {
return "", err
}
str := string(line)
i := strings.Index(str, "@")
if strings.Contains(str, path+"@") && i != -1 {
return path + str[i:], nil
}
}
}
// KratosMod returns kratos mod.
func KratosMod() string {
gopath := os.Getenv("GOPATH")
if path, err := ModuleVersion("github.com/go-kratos/kratos/v2"); err == nil {
// $GOPATH/pkg/mod/github.com/go-kratos/kratos@v2
return filepath.Join(gopath, "pkg", "mod", path)
}
// $GOPATH/src/github.com/go-kratos/kratos
return filepath.Join(gopath, "src", "github.com", "go-kratos", "kratos")
}

@ -0,0 +1,11 @@
package base
import "testing"
func TestModuleVersion(t *testing.T) {
v, err := ModuleVersion("golang.org/x/mod")
if err != nil {
t.Fatal(err)
}
t.Log(v)
}

@ -6,11 +6,11 @@ import (
)
func TestRepo(t *testing.T) {
r := NewRepo(RepoURL("https://github.com/go-kratos/service-layout.git"))
r := NewRepo("https://github.com/go-kratos/service-layout.git")
if err := r.Clone(context.Background()); err != nil {
t.Fatal(err)
}
if err := r.CopyTo(context.Background(), "/tmp/test_repo"); err != nil {
if err := r.CopyTo(context.Background(), "/tmp/test_repo", "github.com/go-kratos/kratos-layout", nil); err != nil {
t.Fatal(err)
}
}

@ -1,4 +1,4 @@
package new
package project
import (
"context"
@ -18,8 +18,8 @@ type Project struct {
Name string
}
// Generate generate template project.
func (p *Project) Generate(ctx context.Context, dir string) error {
// New new a project from remote repo.
func (p *Project) New(ctx context.Context, dir string) error {
to := path.Join(dir, p.Name)
if _, err := os.Stat(to); !os.IsNotExist(err) {
return fmt.Errorf("%s already exists", p.Name)

@ -1,4 +1,4 @@
package new
package project
import (
"context"
@ -29,7 +29,7 @@ func run(cmd *cobra.Command, args []string) {
return
}
p := &Project{Name: args[0]}
if err := p.Generate(ctx, wd); err != nil {
if err := p.New(ctx, wd); err != nil {
fmt.Fprintf(os.Stderr, "\033[31mERROR: %s\033[m\n", err)
return
}

@ -0,0 +1,83 @@
package client
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
"github.com/spf13/cobra"
)
var (
// CmdClient represents the source command.
CmdClient = &cobra.Command{
Use: "client",
Short: "Generate the proto client code",
Long: "Generate the proto client code. Example: kratos proto client helloworld.proto",
Run: run,
}
)
func run(cmd *cobra.Command, args []string) {
if len(args) == 0 {
fmt.Println("Please enter the proto file or directory")
return
}
var (
err error
proto = strings.TrimSpace(args[0])
)
if _, err = exec.LookPath("protoc-gen-go-http"); err != nil {
// update the kratos plugins
if err := exec.Command("kratos", "upgrade").Run(); err != nil {
fmt.Println(err)
}
}
if strings.HasSuffix(proto, ".proto") {
err = generate(proto)
} else {
err = walk(proto)
}
if err != nil {
fmt.Println(err)
}
}
func walk(dir string) error {
if dir == "" {
dir = "."
}
return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if ext := filepath.Ext(path); ext != ".proto" {
return nil
}
return generate(path)
})
}
// generate is used to execute the generate command for the specified proto file
func generate(proto string) error {
path, name := filepath.Split(proto)
fd := exec.Command("protoc", []string{
"--proto_path=.",
"--proto_path=" + filepath.Join(base.KratosMod(), "api"),
"--proto_path=" + filepath.Join(base.KratosMod(), "third_party"),
"--proto_path=" + filepath.Join(os.Getenv("GOPATH"), "src"),
"--go_out=paths=source_relative:.",
"--go-grpc_out=paths=source_relative:.",
"--go-http_out=paths=source_relative:.",
"--go-errors_out=paths=source_relative:.",
name,
}...)
fd.Stdout = os.Stdout
fd.Stderr = os.Stderr
fd.Dir = path
if err := fd.Run(); err != nil {
return err
}
fmt.Printf("proto: %s\n", proto)
return nil
}

@ -2,8 +2,8 @@ package proto
import (
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/proto/add"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/proto/service"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/proto/source"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/proto/client"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/proto/server"
"github.com/spf13/cobra"
)
@ -18,8 +18,8 @@ var CmdProto = &cobra.Command{
func init() {
CmdProto.AddCommand(add.CmdAdd)
CmdProto.AddCommand(source.CmdSource)
CmdProto.AddCommand(service.CmdService)
CmdProto.AddCommand(client.CmdClient)
CmdProto.AddCommand(server.CmdServer)
}
func run(cmd *cobra.Command, args []string) {

@ -1,4 +1,4 @@
package service
package server
import (
"fmt"
@ -12,22 +12,22 @@ import (
"github.com/spf13/cobra"
)
// CmdService represents the service command.
var CmdService = &cobra.Command{
Use: "service",
Short: "Generate the proto Service implementations",
Long: "Generate the proto Service implementations. Example: kratos proto service api/xxx.proto -target-dir=internal/service",
// CmdServer the service command.
var CmdServer = &cobra.Command{
Use: "server",
Short: "Generate the proto Server implementations",
Long: "Generate the proto Server implementations. Example: kratos proto server api/xxx.proto -target-dir=internal/service",
Run: run,
}
var targetDir string
func init() {
CmdService.Flags().StringVarP(&targetDir, "-target-dir", "t", "internal/service", "generate target directory")
CmdServer.Flags().StringVarP(&targetDir, "-target-dir", "t", "internal/service", "generate target directory")
}
func run(cmd *cobra.Command, args []string) {
if len(args) == 0 {
fmt.Fprintln(os.Stderr, "Please specify the proto file. Example: kratos proto service api/xxx.proto")
fmt.Fprintln(os.Stderr, "Please specify the proto file. Example: kratos proto server api/xxx.proto")
return
}
reader, err := os.Open(args[0])
@ -66,21 +66,23 @@ func run(cmd *cobra.Command, args []string) {
res = append(res, cs)
}),
)
if _, err := os.Stat(targetDir); os.IsNotExist(err) {
fmt.Printf("Target directory: %s does not exsits\n", targetDir)
return
}
for _, s := range res {
to := path.Join(targetDir, strings.ToLower(s.Service)+".go")
_, err := os.Stat(to)
if !os.IsNotExist(err) {
fmt.Fprintf(os.Stderr, "%s already exists\n", s.Service)
continue
}
if err = os.MkdirAll(targetDir, os.ModeDir); err != nil {
fmt.Fprintf(os.Stderr, "Failed to create file directory: %s\n", targetDir)
if _, err := os.Stat(to); !os.IsNotExist(err) {
fmt.Fprintf(os.Stderr, "%s already exists: %s\n", s.Service, to)
continue
}
b, err := s.execute()
if err != nil {
log.Fatal(err)
}
ioutil.WriteFile(to, b, 0644)
if err := ioutil.WriteFile(to, b, 0644); err != nil {
log.Fatal(err)
}
fmt.Println(to)
}
}

@ -1,28 +0,0 @@
package source
import (
"fmt"
"log"
"os/exec"
"github.com/spf13/cobra"
)
// CmdSource represents the source command.
var CmdSource = &cobra.Command{
Use: "source",
Short: "Generate the proto source code",
Long: "Generate the proto source code. Example: kratos proto source ./**/*.proto",
Run: run,
}
func run(cmd *cobra.Command, args []string) {
input := []string{"--go_out=paths=source_relative:.", "--go-grpc_out=paths=source_relative:."}
input = append(input, args...)
do := exec.Command("protoc", input...)
out, err := do.CombinedOutput()
if err != nil {
log.Fatalf("failed to execute: %s\n", err)
}
fmt.Println(string(out))
}

@ -0,0 +1,30 @@
package upgrade
import (
"fmt"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
"github.com/spf13/cobra"
)
// CmdUpgrade represents the upgrade command.
var CmdUpgrade = &cobra.Command{
Use: "upgrade",
Short: "Upgrade the kratos tools",
Long: "Upgrade the kratos tools. Example: kratos upgrade",
Run: Run,
}
// Run upgrade the kratos tools.
func Run(cmd *cobra.Command, args []string) {
err := base.GoGet(
"github.com/go-kratos/kratos/cmd/kratos/v2",
"github.com/go-kratos/kratos/cmd/protoc-gen-go-http/v2",
"github.com/go-kratos/kratos/cmd/protoc-gen-go-errors/v2",
"google.golang.org/protobuf/cmd/protoc-gen-go",
"google.golang.org/grpc/cmd/protoc-gen-go-grpc",
)
if err != nil {
fmt.Println(err)
}
}

@ -3,21 +3,28 @@ package main
import (
"log"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/new"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/project"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/proto"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/upgrade"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
var (
// Version is the version of the compiled software.
Version string = "v2.0.0-alpha4"
rootCmd = &cobra.Command{
Use: "kratos",
Short: "Kratos: An elegant toolkit for Go microservices.",
Long: `Kratos: An elegant toolkit for Go microservices.`,
Version: Version,
}
}
)
func init() {
rootCmd.AddCommand(new.CmdNew)
rootCmd.AddCommand(project.CmdNew)
rootCmd.AddCommand(proto.CmdProto)
rootCmd.AddCommand(upgrade.CmdUpgrade)
}
func main() {

@ -1,13 +0,0 @@
package main
// go build -ldflags "-X main.Version=x.y.yz"
var (
// Version is the version of the compiled software.
Version string = "v2.0.0"
// Branch is current branch name the code is built off
Branch string
// Revision is the short commit hash of source tree
Revision string
// BuildDate is the date when the binary was built.
BuildDate string
)
Loading…
Cancel
Save