Skip to content

Commit

Permalink
feat: add -w/--watchPaths for subcommand gf run
Browse files Browse the repository at this point in the history
Live reload supports files specified using the "-w" parameter in addition to Go files.

Usage Example:

1) Watch one file
$ gf run main.go -w manifest/config/config.yaml

2) Watch multiple files, seprated by commas
$ gf run main.go -w manifest/config/config.yaml,otherpath/otherfile

Fixes gogf#2822
  • Loading branch information
windvalley committed Oct 10, 2023
1 parent 00e83fe commit 43337a2
Showing 1 changed file with 48 additions and 28 deletions.
76 changes: 48 additions & 28 deletions cmd/gf/internal/cmd/cmd_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package cmd
import (
"context"
"fmt"
"os"
"runtime"
"strings"

Expand All @@ -19,6 +20,7 @@ import (
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/os/gtimer"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gtag"

"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
Expand All @@ -33,10 +35,11 @@ type cRun struct {
}

type cRunApp struct {
File string // Go run file name.
Path string // Directory storing built binary.
Options string // Extra "go run" options.
Args string // Custom arguments.
File string // Go run file name.
Path string // Directory storing built binary.
Options string // Extra "go run" options.
Args string // Custom arguments.
WatchPaths []string // Watch paths for live reload.
}

const (
Expand All @@ -51,10 +54,11 @@ gf run main.go -mod=vendor
The "run" command is used for running go codes with hot-compiled-like feature,
which compiles and runs the go codes asynchronously when codes change.
`
cRunFileBrief = `building file path.`
cRunPathBrief = `output directory path for built binary file. it's "manifest/output" in default`
cRunExtraBrief = `the same options as "go run"/"go build" except some options as follows defined`
cRunArgsBrief = `custom arguments for your process`
cRunFileBrief = `building file path.`
cRunPathBrief = `output directory path for built binary file. it's "manifest/output" in default`
cRunExtraBrief = `the same options as "go run"/"go build" except some options as follows defined`
cRunArgsBrief = `custom arguments for your process`
cRunWatchPathsBrief = `watch additional paths for live reload, separated by ",". i.e. "manifest/config/config.yaml"`
)

var (
Expand All @@ -63,24 +67,26 @@ var (

func init() {
gtag.Sets(g.MapStrStr{
`cRunUsage`: cRunUsage,
`cRunBrief`: cRunBrief,
`cRunEg`: cRunEg,
`cRunDc`: cRunDc,
`cRunFileBrief`: cRunFileBrief,
`cRunPathBrief`: cRunPathBrief,
`cRunExtraBrief`: cRunExtraBrief,
`cRunArgsBrief`: cRunArgsBrief,
`cRunUsage`: cRunUsage,
`cRunBrief`: cRunBrief,
`cRunEg`: cRunEg,
`cRunDc`: cRunDc,
`cRunFileBrief`: cRunFileBrief,
`cRunPathBrief`: cRunPathBrief,
`cRunExtraBrief`: cRunExtraBrief,
`cRunArgsBrief`: cRunArgsBrief,
`cRunWatchPathsBrief`: cRunWatchPathsBrief,
})
}

type (
cRunInput struct {
g.Meta `name:"run"`
File string `name:"FILE" arg:"true" brief:"{cRunFileBrief}" v:"required"`
Path string `name:"path" short:"p" brief:"{cRunPathBrief}" d:"./"`
Extra string `name:"extra" short:"e" brief:"{cRunExtraBrief}"`
Args string `name:"args" short:"a" brief:"{cRunArgsBrief}"`
g.Meta `name:"run"`
File string `name:"FILE" arg:"true" brief:"{cRunFileBrief}" v:"required"`
Path string `name:"path" short:"p" brief:"{cRunPathBrief}" d:"./"`
Extra string `name:"extra" short:"e" brief:"{cRunExtraBrief}"`
Args string `name:"args" short:"a" brief:"{cRunArgsBrief}"`
WatchPaths string `name:"watchPaths" short:"w" brief:"{cRunWatchPathsBrief}"`
}
cRunOutput struct{}
)
Expand All @@ -92,24 +98,27 @@ func (c cRun) Index(ctx context.Context, in cRunInput) (out *cRunOutput, err err
}

app := &cRunApp{
File: in.File,
Path: in.Path,
Options: in.Extra,
Args: in.Args,
File: in.File,
Path: in.Path,
Options: in.Extra,
Args: in.Args,
WatchPaths: strings.Split(in.WatchPaths, ","),
}
dirty := gtype.NewBool()
_, err = gfsnotify.Add(gfile.RealPath("."), func(event *gfsnotify.Event) {
if gfile.ExtName(event.Path) != "go" {
if gfile.ExtName(event.Path) != "go" && !matchWatchPaths(app.WatchPaths, event.Path) {
return
}

// Variable `dirty` is used for running the changes only one in one second.
if !dirty.Cas(false, true) {
return
}

// With some delay in case of multiple code changes in very short interval.
gtimer.SetTimeout(ctx, 1500*gtime.MS, func(ctx context.Context) {
defer dirty.Set(false)
mlog.Printf(`go file changes: %s`, event.String())
mlog.Printf(`file changes: %s`, event.String())
app.Run(ctx)
})
})
Expand Down Expand Up @@ -152,7 +161,6 @@ func (app *cRunApp) Run(ctx context.Context) {
if process != nil {
if err := process.Kill(); err != nil {
mlog.Debugf("kill process error: %s", err.Error())
//return
}
}
// Run the binary file.
Expand All @@ -171,3 +179,15 @@ func (app *cRunApp) Run(ctx context.Context) {
mlog.Printf("build running pid: %d", pid)
}
}

func matchWatchPaths(watchPaths []string, eventPath string) bool {
pathSeparator := string(os.PathSeparator)
for _, path := range watchPaths {
path = gstr.TrimLeftStr(path, pathSeparator)
path = gstr.TrimLeftStr(path, "."+pathSeparator)
if gstr.HasSuffix(eventPath, pathSeparator+path) {
return true
}
}
return false
}

0 comments on commit 43337a2

Please sign in to comment.