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:
parent
80dbe51077
commit
86de031adc
@ -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.
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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{}
|
||||
|
@ -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}}
|
||||
)
|
||||
|
@ -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}}
|
||||
`
|
||||
|
Loading…
x
Reference in New Issue
Block a user