mirror of
https://github.com/go-micro/go-micro.git
synced 2025-03-29 20:39:48 +02:00
Use internal runtime package for gomu run (#2248)
This change refactors the `gomu run` command to use Go Micro's internal runtime package in order to run services. Not only does this clean up duplicate functionality between Go Micro and Gomu, but also adds the feature to Gomu to run remote projects. For example, the following command pulls in a remote project and runs it locally. ```bash gomu run github.com/auditemarlow/helloworld ``` The `gomu run` command remains backwards compatible. By invoking `gomu run` in a Go Micro project directory, Gomu will simply run that project.
This commit is contained in:
parent
270d910b73
commit
a58b8883f8
cmd/gomu
@ -5,17 +5,40 @@ import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"time"
|
||||
"strings"
|
||||
|
||||
"github.com/asim/go-micro/cmd/gomu/cmd"
|
||||
"github.com/asim/go-micro/v3/runtime"
|
||||
"github.com/asim/go-micro/v3/runtime/local/git"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultRetries = 3
|
||||
|
||||
flags []cli.Flag = []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "command",
|
||||
Usage: "command to execute",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "args",
|
||||
Usage: "command arguments",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "type",
|
||||
Usage: "the type of service to operate on",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// NewCommand returns a new run command.
|
||||
func NewCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "run",
|
||||
Usage: "Build and run a service continuously",
|
||||
Usage: "Build and run a service continuously, e.g. gomu run [github.com/auditemarlow/helloworld]",
|
||||
Flags: flags,
|
||||
Action: Run,
|
||||
}
|
||||
}
|
||||
@ -23,76 +46,114 @@ func NewCommand() *cli.Command {
|
||||
// Run runs a service and watches the project directory for change events. On
|
||||
// write, the service is restarted. Exits on error.
|
||||
func Run(ctx *cli.Context) error {
|
||||
service := newService()
|
||||
if err := service.Start(); err != nil {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer service.Stop()
|
||||
|
||||
sig := make(chan os.Signal)
|
||||
done := make(chan bool)
|
||||
signal.Notify(sig, os.Interrupt)
|
||||
go func() {
|
||||
<-sig
|
||||
service.Stop()
|
||||
done <- true
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
service.Wait()
|
||||
fmt.Println("Service has stopped, restarting service")
|
||||
service.Start()
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}()
|
||||
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
source, err := git.ParseSourceLocal(wd, ctx.Args().First())
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return err
|
||||
}
|
||||
defer watcher.Close()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-watcher.Events:
|
||||
if !ok {
|
||||
return
|
||||
svc := &runtime.Service{
|
||||
Name: source.RuntimeName(),
|
||||
Source: source.RuntimeSource(),
|
||||
Version: source.Ref,
|
||||
Metadata: make(map[string]string),
|
||||
}
|
||||
|
||||
typ := ctx.String("type")
|
||||
command := strings.TrimSpace(ctx.String("command"))
|
||||
args := strings.TrimSpace(ctx.String("args"))
|
||||
|
||||
r := *cmd.DefaultCmd.Options().Runtime
|
||||
|
||||
var retries = DefaultRetries
|
||||
if ctx.IsSet("retries") {
|
||||
retries = ctx.Int("retries")
|
||||
}
|
||||
|
||||
opts := []runtime.CreateOption{
|
||||
runtime.WithOutput(os.Stdout),
|
||||
runtime.WithRetries(retries),
|
||||
runtime.CreateType(typ),
|
||||
}
|
||||
|
||||
if len(command) > 0 {
|
||||
opts = append(opts, runtime.WithCommand(command))
|
||||
}
|
||||
|
||||
if len(args) > 0 {
|
||||
opts = append(opts, runtime.WithArgs(args))
|
||||
}
|
||||
|
||||
if err := r.Create(svc, opts...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
done := make(chan bool)
|
||||
if r.String() == "local" {
|
||||
sig := make(chan os.Signal)
|
||||
signal.Notify(sig, os.Interrupt)
|
||||
go func() {
|
||||
<-sig
|
||||
r.Delete(svc)
|
||||
done <- true
|
||||
}()
|
||||
}
|
||||
|
||||
if source.Local {
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
defer watcher.Close()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-watcher.Events:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if event.Op&fsnotify.Write == fsnotify.Write {
|
||||
r.Update(svc)
|
||||
}
|
||||
if event.Op&fsnotify.Create == fsnotify.Create {
|
||||
watcher.Add(event.Name)
|
||||
}
|
||||
if event.Op&fsnotify.Remove == fsnotify.Remove {
|
||||
watcher.Remove(event.Name)
|
||||
}
|
||||
case err, ok := <-watcher.Errors:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
fmt.Println("ERROR", err)
|
||||
}
|
||||
if event.Op&fsnotify.Write == fsnotify.Write {
|
||||
service.Stop()
|
||||
}
|
||||
if event.Op&fsnotify.Create == fsnotify.Create {
|
||||
watcher.Add(event.Name)
|
||||
}
|
||||
if event.Op&fsnotify.Remove == fsnotify.Remove {
|
||||
watcher.Remove(event.Name)
|
||||
}
|
||||
case err, ok := <-watcher.Errors:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
fmt.Println("ERROR", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var files []string
|
||||
filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
files = append(files, path)
|
||||
return nil
|
||||
})
|
||||
|
||||
for _, file := range files {
|
||||
if err := watcher.Add(file); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
var files []string
|
||||
filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
files = append(files, path)
|
||||
return nil
|
||||
})
|
||||
|
||||
for _, file := range files {
|
||||
if err := watcher.Add(file); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
<-done
|
||||
if r.String() == "local" {
|
||||
<-done
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -1,62 +0,0 @@
|
||||
// +build !windows
|
||||
|
||||
package run
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Service is the interface that wraps the service that should run.
|
||||
//
|
||||
// Start starts the service and exits on error.
|
||||
//
|
||||
// Stop stops the service and exits on error.
|
||||
//
|
||||
// Wait waits for the service to exit and exits on error.
|
||||
type Service interface {
|
||||
Start() error
|
||||
Stop() error
|
||||
Wait() error
|
||||
}
|
||||
|
||||
type service struct {
|
||||
cmd *exec.Cmd
|
||||
running bool
|
||||
}
|
||||
|
||||
// Start starts the service and exits on error.
|
||||
func (s *service) Start() error {
|
||||
if s.running {
|
||||
return nil
|
||||
}
|
||||
|
||||
s.cmd = exec.Command("go", "run", ".")
|
||||
s.cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
||||
s.cmd.Stdout = os.Stdout
|
||||
s.cmd.Stderr = os.Stderr
|
||||
s.running = true
|
||||
|
||||
return s.cmd.Start()
|
||||
}
|
||||
|
||||
// Stop stops the service and exits on error.
|
||||
func (s *service) Stop() error {
|
||||
if !s.running {
|
||||
return nil
|
||||
}
|
||||
|
||||
s.running = false
|
||||
return syscall.Kill(-s.cmd.Process.Pid, syscall.SIGTERM)
|
||||
}
|
||||
|
||||
// Wait waits for the service to exit and exits on error.
|
||||
func (s *service) Wait() error {
|
||||
return s.cmd.Wait()
|
||||
}
|
||||
|
||||
func newService() *service {
|
||||
service := new(service)
|
||||
return service
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
// +build windows
|
||||
|
||||
package run
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Service is the interface that wraps the service that should run.
|
||||
//
|
||||
// Start starts the service and exits on error.
|
||||
//
|
||||
// Stop stops the service and exits on error.
|
||||
//
|
||||
// Wait waits for the service to exit and exits on error.
|
||||
type Service interface {
|
||||
Start() error
|
||||
Stop() error
|
||||
Wait() error
|
||||
}
|
||||
|
||||
type service struct {
|
||||
cmd *exec.Cmd
|
||||
running bool
|
||||
}
|
||||
|
||||
// Start starts the service and exits on error.
|
||||
func (s *service) Start() error {
|
||||
if s.running {
|
||||
return nil
|
||||
}
|
||||
|
||||
s.cmd = exec.Command("go", "run", ".")
|
||||
s.cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
s.cmd.Stdout = os.Stdout
|
||||
s.cmd.Stderr = os.Stderr
|
||||
s.running = true
|
||||
|
||||
return s.cmd.Start()
|
||||
}
|
||||
|
||||
// Stop stops the service and exits on error.
|
||||
func (s *service) Stop() error {
|
||||
if !s.running {
|
||||
return nil
|
||||
}
|
||||
|
||||
s.running = false
|
||||
pro, err := os.FindProcess(s.cmd.Process.Pid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return pro.Signal(syscall.SIGTERM)
|
||||
}
|
||||
|
||||
// Wait waits for the service to exit and exits on error.
|
||||
func (s *service) Wait() error {
|
||||
return s.cmd.Wait()
|
||||
}
|
||||
|
||||
func newService() *service {
|
||||
service := new(service)
|
||||
return service
|
||||
}
|
@ -71,8 +71,6 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/asim/go-micro/v3 v3.6.0 h1:I6UVJBpBtWNKCjWf0dRpZznRCW9TR4DXjV4wieyGhK0=
|
||||
github.com/asim/go-micro/v3 v3.6.0/go.mod h1:cNGIIYQcp0qy+taNYmrBdaIHeqMWHV5ZH/FfQzfOyE8=
|
||||
github.com/asim/go-micro/v3 v3.6.1-0.20210831082736-088ccb50019c h1:bwjwOyCBbClb9BwnVo8XohDYzA3Huk/PVpxSfqrx3xg=
|
||||
github.com/asim/go-micro/v3 v3.6.1-0.20210831082736-088ccb50019c/go.mod h1:UQd2JfP/+4goQxddksr2r6ZSaUXNIlVE8hlepbAx/DI=
|
||||
github.com/aws/aws-sdk-go v1.37.27/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
@ -346,8 +344,6 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m
|
||||
github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
|
||||
github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/micro/cli/v2 v2.1.2 h1:43J1lChg/rZCC1rvdqZNFSQDrGT7qfMrtp6/ztpIkEM=
|
||||
github.com/micro/cli/v2 v2.1.2/go.mod h1:EguNh6DAoWKm9nmk+k/Rg0H3lQnDxqzu5x5srOtGtYg=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.40/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
|
||||
|
Loading…
x
Reference in New Issue
Block a user