1
0
mirror of https://github.com/go-micro/go-micro.git synced 2025-02-04 18:21:53 +02:00

[WIP] Add new client cmd (#2243)

* Update greeter references to helloworld

* Add new client command

With this change, Gomu users will be able to generate template projects
for clients to services. Additionally vendor support has been built in
so Gomu users can now generate projects using fully qualified package
names, for example:

```bash
gomu new service github.com/auditemarlow/helloworld
```

This will create a new service project `helloworld` with its module name
already set to `github.com/auditemarlow/helloworld`. Likewise, Gomu
users can then generate client projects in the same manner:

```bash
gomu new client github.com/auditemarlow/helloworld
```

This will create a `helloworld-client` project that uses the protobufs
found in the `github.com/auditemarlow/helloworld` service. This removes
at least some strain in configuring these module dependencies yourself;
you can just scaffold them outright from the start.

Although the default client project is highly opinionated, it works
straight out of the box and has Skaffold in mind. Gomu users should be
able to get going in a matter of seconds.

* Update README
This commit is contained in:
Niek den Breeje 2021-09-03 13:33:10 +02:00 committed by GitHub
parent 80dbe51077
commit 86de031adc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 159 additions and 35 deletions

View File

@ -197,6 +197,38 @@ Skaffold pipeline using the `skaffold` command.
skaffold dev
```
## Creating A Client
To create a new client, use the `gomu new client` command. The name is the
service you'd like to create a client project for.
```bash
$ gomu new client helloworld
creating client helloworld
cd helloworld-client
make tidy
```
You may optionally pass the fully qualified package name of the service you'd
like to create a client project for.
```bash
$ gomu new client github.com/auditemarlow/helloworld
creating client helloworld
cd helloworld-client
make tidy
```
## Running A Client
To run a client, use the `gomu run` command to build and run your client
continuously.
```bash
$ gomu run
2021-09-03 12:52:23 file=helloworld-client/main.go:33 level=info msg:"Hello John"
```
## Listing Services
To list services, use the `gomu services` command.

View File

@ -16,7 +16,7 @@ import (
func NewCommand() *cli.Command {
return &cli.Command{
Name: "call",
Usage: "Call a service, e.g. " + cmd.App().Name + " call greeter Helloworld.Call '{\"name\": \"John\"}'",
Usage: "Call a service, e.g. " + cmd.App().Name + " call helloworld Helloworld.Call '{\"name\": \"John\"}'",
Action: RunCall,
}
}

View File

@ -28,6 +28,7 @@ type config struct {
Alias string
Comments []string
Dir string
Vendor string
Jaeger bool
Skaffold bool
}
@ -43,15 +44,21 @@ func NewCommand() *cli.Command {
Name: "new",
Usage: "Create a project template",
Subcommands: []*cli.Command{
{
Name: "client",
Usage: "Create a client template, e.g. " + cmd.App().Name + " new client [github.com/auditemarlow/]helloworld",
Action: Client,
Flags: flags,
},
{
Name: "function",
Usage: "Create a function template, e.g. " + cmd.App().Name + " new function greeter",
Usage: "Create a function template, e.g. " + cmd.App().Name + " new function [github.com/auditemarlow/]helloworld",
Action: Function,
Flags: flags,
},
{
Name: "service",
Usage: "Create a service template, e.g. " + cmd.App().Name + " new service greeter",
Usage: "Create a service template, e.g. " + cmd.App().Name + " new service [github.com/auditemarlow/]helloworld",
Action: Service,
Flags: flags,
},
@ -59,36 +66,43 @@ func NewCommand() *cli.Command {
}
}
func Client(ctx *cli.Context) error {
return createProject(ctx, "client")
}
// Function creates a new function project template. Exits on error.
func Function(ctx *cli.Context) error {
return createProject(ctx, true)
return createProject(ctx, "function")
}
// Service creates a new service project template. Exits on error.
func Service(ctx *cli.Context) error {
return createProject(ctx, false)
return createProject(ctx, "service")
}
func createProject(ctx *cli.Context, fn bool) error {
name := ctx.Args().First()
if len(name) == 0 {
func createProject(ctx *cli.Context, pt string) error {
arg := ctx.Args().First()
if len(arg) == 0 {
return cli.ShowSubcommandHelp(ctx)
}
if path.IsAbs(name) {
name, vendor := getNameAndVendor(arg)
dir := name
if pt == "client" {
dir += "-client"
}
if path.IsAbs(dir) {
fmt.Println("must provide a relative path as service name")
return nil
}
if _, err := os.Stat(name); !os.IsNotExist(err) {
return fmt.Errorf("%s already exists", name)
if _, err := os.Stat(dir); !os.IsNotExist(err) {
return fmt.Errorf("%s already exists", dir)
}
if fn {
fmt.Printf("creating function %s\n", name)
} else {
fmt.Printf("creating service %s\n", name)
}
fmt.Printf("creating %s %s\n", pt, name)
files := []file{
{".dockerignore", tmpl.DockerIgnore},
@ -97,18 +111,26 @@ func createProject(ctx *cli.Context, fn bool) error {
{"Makefile", tmpl.Makefile},
{"go.mod", tmpl.Module},
}
if fn {
switch pt {
case "client":
files = append(files, []file{
{"main.go", tmpl.MainCLT},
}...)
case "function":
files = append(files, []file{
{"handler/" + name + ".go", tmpl.HandlerFNC},
{"main.go", tmpl.MainFNC},
{"proto/" + name + ".proto", tmpl.ProtoFNC},
}...)
} else {
case "service":
files = append(files, []file{
{"handler/" + name + ".go", tmpl.HandlerSRV},
{"main.go", tmpl.MainSRV},
{"proto/" + name + ".proto", tmpl.ProtoSRV},
}...)
default:
return fmt.Errorf("%s project type not supported", pt)
}
if ctx.Bool("skaffold") {
@ -124,16 +146,29 @@ func createProject(ctx *cli.Context, fn bool) error {
c := config{
Alias: name,
Comments: protoComments(name),
Dir: name,
Dir: dir,
Vendor: vendor,
Jaeger: ctx.Bool("jaeger"),
Skaffold: ctx.Bool("skaffold"),
}
if pt == "client" {
c.Comments = clientComments(name, dir)
} else {
c.Comments = protoComments(name, dir)
}
return create(files, c)
}
func protoComments(alias string) []string {
func clientComments(name, dir string) []string {
return []string{
"cd " + dir,
"make tidy\n",
}
}
func protoComments(name, dir string) []string {
return []string{
"\ndownload protoc zip packages (protoc-$VERSION-$PLATFORM.zip) and install:\n",
"visit https://github.com/protocolbuffers/protobuf/releases/latest",
@ -141,15 +176,15 @@ func protoComments(alias string) []string {
"go get -u google.golang.org/protobuf/proto",
"go install github.com/golang/protobuf/protoc-gen-go@latest",
"go install github.com/asim/go-micro/cmd/protoc-gen-micro/v3@latest",
"\ncompile the proto file " + alias + ".proto:\n",
"cd " + alias,
"\ncompile the proto file " + name + ".proto:\n",
"cd " + dir,
"make proto tidy\n",
}
}
func create(files []file, c config) error {
for _, file := range files {
fp := filepath.Join(c.Alias, file.Path)
fp := filepath.Join(c.Dir, file.Path)
dir := filepath.Dir(fp)
if _, err := os.Stat(dir); os.IsNotExist(err) {
@ -189,3 +224,18 @@ func create(files []file, c config) error {
return nil
}
func getNameAndVendor(s string) (string, string) {
var n string
var v string
if i := strings.LastIndex(s, "/"); i == -1 {
n = s
v = ""
} else {
n = s[i+1:]
v = s[:i+1]
}
return n, v
}

View File

@ -8,7 +8,7 @@ import (
log "github.com/asim/go-micro/v3/logger"
pb "{{.Dir}}/proto"
pb "{{.Vendor}}{{.Dir}}/proto"
)
type {{title .Alias}} struct{}
@ -30,7 +30,7 @@ import (
log "github.com/asim/go-micro/v3/logger"
pb "{{.Dir}}/proto"
pb "{{.Vendor}}{{.Dir}}/proto"
)
type {{title .Alias}} struct{}

View File

@ -1,14 +1,54 @@
package template
// MainCLT is the main template used for new client projects.
var MainCLT = `package main
import (
"context"
"time"
pb "{{.Vendor}}{{lower .Alias}}/proto"
"github.com/asim/go-micro/v3"
log "github.com/asim/go-micro/v3/logger"
)
var (
service = "{{lower .Alias}}"
version = "latest"
)
func main() {
// Create service
srv := micro.NewService()
srv.Init()
// Create client
c := pb.NewHelloworldService(service, srv.Client())
for {
// Call service
rsp, err := c.Call(context.Background(), &pb.CallRequest{Name: "John"})
if err != nil {
log.Fatal(err)
}
log.Info(rsp)
time.Sleep(1 * time.Second)
}
}
`
// MainFNC is the main template used for new function projects.
var MainFNC = `package main
import (
"{{.Dir}}/handler"
"{{.Vendor}}{{.Dir}}/handler"
{{if .Jaeger }} ot "github.com/asim/go-micro/plugins/wrapper/trace/opentracing/v3"
{{if .Jaeger}} ot "github.com/asim/go-micro/plugins/wrapper/trace/opentracing/v3"
{{end}} "github.com/asim/go-micro/v3"
log "github.com/asim/go-micro/v3/logger"{{if .Jaeger }}
log "github.com/asim/go-micro/v3/logger"{{if .Jaeger}}
"github.com/asim/go-micro/cmd/gomu/debug/trace/jaeger"{{end}}
)
@ -55,12 +95,12 @@ func main() {
var MainSRV = `package main
import (
"{{.Dir}}/handler"
pb "{{.Dir}}/proto"
"{{.Vendor}}{{.Dir}}/handler"
pb "{{.Vendor}}{{.Dir}}/proto"
{{if .Jaeger }} ot "github.com/asim/go-micro/plugins/wrapper/trace/opentracing/v3"
{{if .Jaeger}} ot "github.com/asim/go-micro/plugins/wrapper/trace/opentracing/v3"
{{end}} "github.com/asim/go-micro/v3"
log "github.com/asim/go-micro/v3/logger"{{if .Jaeger }}
log "github.com/asim/go-micro/v3/logger"{{if .Jaeger}}
"github.com/asim/go-micro/cmd/gomu/debug/trace/jaeger"{{end}}
)

View File

@ -1,7 +1,7 @@
package template
// Module is the go.mod template used for new projects.
var Module = `module {{.Dir}}
var Module = `module {{.Vendor}}{{.Dir}}
go 1.16
@ -11,5 +11,7 @@ require (
// This can be removed once etcd becomes go gettable, version 3.4 and 3.5 is not,
// see https://github.com/etcd-io/etcd/issues/11154 and https://github.com/etcd-io/etcd/issues/11931.
replace google.golang.org/grpc => google.golang.org/grpc v1.26.0
replace google.golang.org/grpc => google.golang.org/grpc v1.26.0{{if .Vendor}}
replace {{.Vendor}}{{lower .Alias}} => ../{{lower .Alias}}{{end}}
`