Skip to content

Commit

Permalink
fix: fixes watch behaviour, now watches all the commands in a task
Browse files Browse the repository at this point in the history
instead of, just the last command
  • Loading branch information
nxtcoder17 committed Dec 19, 2024
1 parent 4cee317 commit afcd333
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 97 deletions.
9 changes: 1 addition & 8 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/charmbracelet/lipgloss v1.0.0
github.com/joho/godotenv v1.5.1
github.com/muesli/termenv v0.15.2
github.com/nxtcoder17/fwatcher v1.0.3
github.com/nxtcoder17/fwatcher v1.0.4-0.20241218102704-76d04c526fb0
github.com/phuslu/log v1.0.112
github.com/urfave/cli/v3 v3.0.0-beta1
golang.org/x/sync v0.10.0
Expand All @@ -16,20 +16,13 @@ require (

require (
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/charmbracelet/log v0.4.0 // indirect
github.com/charmbracelet/x/ansi v0.6.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
github.com/dlclark/regexp2 v1.11.4 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/urfave/cli/v2 v2.27.5 // indirect
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect
golang.org/x/sys v0.28.0 // indirect
)
20 changes: 2 additions & 18 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,14 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiE
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg=
github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo=
github.com/charmbracelet/log v0.4.0 h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8ZM=
github.com/charmbracelet/log v0.4.0/go.mod h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1KH22MdptM=
github.com/charmbracelet/x/ansi v0.6.0 h1:qOznutrb93gx9oMiGf7caF7bqqubh6YIM0SWKyA08pA=
github.com/charmbracelet/x/ansi v0.6.0/go.mod h1:KBUFw1la39nl0dLl10l5ORDAqGXaeurTQmwyyVKse/Q=
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
Expand All @@ -37,29 +31,19 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
github.com/nxtcoder17/fwatcher v1.0.3-0.20241212071621-beb84ec5b061 h1:bNRVjvghGLiCJ9EOTS/qkrSAyKvz4e2S6CMzL8GnxgI=
github.com/nxtcoder17/fwatcher v1.0.3-0.20241212071621-beb84ec5b061/go.mod h1:MNmSwXYOrqp7U1pUxh0GWB5skpjFTWTQXhAA0+sPJcU=
github.com/nxtcoder17/fwatcher v1.0.3 h1:6oCdh9uMzSSeJLyA6iezc/8WBIZPbD9lx50nxC7cMyQ=
github.com/nxtcoder17/fwatcher v1.0.3/go.mod h1:MNmSwXYOrqp7U1pUxh0GWB5skpjFTWTQXhAA0+sPJcU=
github.com/nxtcoder17/fwatcher v1.0.4-0.20241218102704-76d04c526fb0 h1:k09TYswdqCsFz0fBnO3AjGT5MHfvjPRyBtHbBWuiJLM=
github.com/nxtcoder17/fwatcher v1.0.4-0.20241218102704-76d04c526fb0/go.mod h1:MNmSwXYOrqp7U1pUxh0GWB5skpjFTWTQXhAA0+sPJcU=
github.com/phuslu/log v1.0.112 h1:vQ0ZFd5O+in/0IQAcjuEl6wRkHiQPw7T0sqwmOjpL0U=
github.com/phuslu/log v1.0.112/go.mod h1:F8osGJADo5qLK/0F88djWwdyoZZ9xDJQL1HYRHFEkS0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w=
github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg=
github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU=
golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand Down
1 change: 1 addition & 0 deletions parser/parse-task.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,6 @@ func ParseTask(ctx context.Context, prf *types.ParsedRunfile, task types.Task) (
Interactive: task.Interactive,
Env: taskEnv,
Commands: commands,
Watch: task.Watch,
}, nil
}
223 changes: 155 additions & 68 deletions runner/run-task.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"os/exec"
"path/filepath"
"strings"
"sync"
"time"

"github.com/alecthomas/chroma/v2/quick"
Expand All @@ -17,6 +18,7 @@ import (
"github.com/nxtcoder17/fwatcher/pkg/watcher"
"github.com/nxtcoder17/runfile/errors"
fn "github.com/nxtcoder17/runfile/functions"
"github.com/nxtcoder17/runfile/logging"
"github.com/nxtcoder17/runfile/parser"
"github.com/nxtcoder17/runfile/types"
)
Expand Down Expand Up @@ -53,45 +55,27 @@ func isTTY() bool {
return ((stdout.Mode() & os.ModeCharDevice) == os.ModeCharDevice) && ((stderr.Mode() & os.ModeCharDevice) == os.ModeCharDevice)
}

func runTask(ctx Context, prf *types.ParsedRunfile, args runTaskArgs) error {
runfilePath := prf.Metadata.RunfilePath
task := prf.Tasks[args.taskName]

if task.Metadata.RunfilePath != nil {
runfilePath = *task.Metadata.RunfilePath
}

trail := append(args.taskTrail, args.taskName)

logger := ctx.With("task", args.taskName, "runfile", runfilePath)
logger.Debug("running task")

task, ok := prf.Tasks[args.taskName]
if !ok {
return errors.ErrTaskNotFound
}

task.Name = args.taskName

pt, err := parser.ParseTask(ctx, prf, task)
if err != nil {
return errors.WithErr(err)
}

func runCommand(ctx Context, prf *types.ParsedRunfile, pt *types.ParsedTask, args runTaskArgs) error {
for _, command := range pt.Commands {
logger.Debug("running command task", "command.run", command.Run, "parent.task", args.taskName)
ctx.Debug("running command task", "command.run", command.Run, "parent.task", args.taskName)

if command.If != nil && !*command.If {
logger.Debug("skipping execution for failed `if`", "command", command.Run)
ctx.Debug("skipping execution for failed `if`", "command", command.Run)
continue
}

if command.Run != "" {
if err := runTask(ctx, prf, runTaskArgs{
taskTrail: trail,
taskName: command.Run,
envOverrides: pt.Env,
}); err != nil {
rt, ok := prf.Tasks[command.Run]
if !ok {
return fmt.Errorf("invalid run target")
}

rtp, err := parser.ParseTask(ctx, prf, rt)
if err != nil {
return errors.WithErr(err).KV("env-vars", prf.Env)
}

if err := runCommand(ctx, prf, rtp, args); err != nil {
return errors.WithErr(err).KV("env-vars", prf.Env)
}
continue
Expand Down Expand Up @@ -172,8 +156,14 @@ func runTask(ctx Context, prf *types.ParsedRunfile, args runTaskArgs) error {
fmt.Printf("%s\n", s.Render(padString(hlCode.String(), args.taskName)))
}

logger2 := logging.New(logging.Options{
Prefix: "[runfile]",
Writer: os.Stderr,
SlogKeyAsPrefix: "task",
})

ex := executor.NewExecutor(executor.ExecutorArgs{
Logger: logger,
Logger: logger2,
IsInteractive: pt.Interactive,
Command: func(c context.Context) *exec.Cmd {
return CreateCommand(c, CmdArgs{
Expand All @@ -188,47 +178,144 @@ func runTask(ctx Context, prf *types.ParsedRunfile, args runTaskArgs) error {
},
})

if task.Watch.Enable {
watch, err := watcher.NewWatcher(ctx, watcher.WatcherArgs{
Logger: logger,
WatchDirs: append(task.Watch.Dirs, pt.WorkingDir),
OnlySuffixes: pt.Watch.OnlySuffixes,
IgnoreSuffixes: pt.Watch.IgnoreSuffixes,
ExcludeDirs: pt.Watch.ExcludeDirs,
UseDefaultIgnoreList: true,
})
// if task.Watch != nil && (task.Watch.Enable == nil || *task.Watch.Enable) {
// watch, err := watcher.NewWatcher(ctx, watcher.WatcherArgs{
// Logger: logger,
// WatchDirs: append(task.Watch.Dirs, pt.WorkingDir),
// OnlySuffixes: pt.Watch.OnlySuffixes,
// IgnoreSuffixes: pt.Watch.IgnoreSuffixes,
// ExcludeDirs: pt.Watch.ExcludeDirs,
// UseDefaultIgnoreList: true,
// // CooldownDuration: fn.New(1 * time.Second),
// })
// if err != nil {
// return errors.WithErr(err)
// }
//
// go ex.Exec()
//
// go func() {
// <-ctx.Done()
// logger.Debug("fwatcher is closing ...")
// watch.Close()
// <-time.After(200 * time.Millisecond)
// logger.Info("CLOSING..................")
// os.Exit(0)
// }()
//
// watch.WatchEvents(func(event watcher.Event, fp string) error {
// relPath, err := filepath.Rel(fn.Must(os.Getwd()), fp)
// if err != nil {
// return err
// }
// logger.Info(fmt.Sprintf("[RELOADING] due changes in %s", relPath))
// ex.Kill()
// select {
// case <-time.After(100 * time.Millisecond):
// go ex.Exec()
// return nil
// case <-ctx.Done():
// logger.Info("close signal received")
// watch.Close()
// return nil
// }
// })
//
// return nil
// }

if err := ex.Exec(); err != nil {
return errors.ErrTaskFailed.Wrap(err).KV("task", args.taskName)
}
}

return nil
}

func runTask(ctx Context, prf *types.ParsedRunfile, args runTaskArgs) error {
runfilePath := prf.Metadata.RunfilePath
task := prf.Tasks[args.taskName]

if task.Metadata.RunfilePath != nil {
runfilePath = *task.Metadata.RunfilePath
}

args.taskTrail = append(args.taskTrail, args.taskName)

logger := ctx.With("task", args.taskName, "runfile", runfilePath)
logger.Debug("running task")

task, ok := prf.Tasks[args.taskName]
if !ok {
return errors.ErrTaskNotFound
}

task.Name = args.taskName

pt, err := parser.ParseTask(ctx, prf, task)
if err != nil {
return errors.WithErr(err)
}

nctx, cf := context.WithCancel(ctx)
defer cf()

var wg sync.WaitGroup

wg.Add(1)
go func() {
defer wg.Done()
runCommand(NewContext(nctx, ctx.Logger), prf, pt, args)
}()

if pt.Watch != nil && (pt.Watch.Enable == nil || *pt.Watch.Enable) {
watch, err := watcher.NewWatcher(ctx, watcher.WatcherArgs{
Logger: logger,
WatchDirs: append(task.Watch.Dirs, pt.WorkingDir),
OnlySuffixes: pt.Watch.OnlySuffixes,
IgnoreSuffixes: pt.Watch.IgnoreSuffixes,
ExcludeDirs: pt.Watch.ExcludeDirs,
UseDefaultIgnoreList: true,
// CooldownDuration: fn.New(1 * time.Second),
})
if err != nil {
return errors.WithErr(err)
}

go func() {
<-ctx.Done()
logger.Debug("fwatcher is closing ...")
watch.Close()
<-time.After(200 * time.Millisecond)
logger.Info("CLOSING..................")
os.Exit(0)
}()

watch.WatchEvents(func(event watcher.Event, fp string) error {
relPath, err := filepath.Rel(fn.Must(os.Getwd()), fp)
if err != nil {
return errors.WithErr(err)
return err
}
logger.Info(fmt.Sprintf("[RELOADING] due changes in %s", relPath))
select {
case <-time.After(100 * time.Millisecond):
cf()

go ex.Exec()

go func() {
<-ctx.Done()
logger.Info("fwatcher is closing ...")
<-time.After(200 * time.Millisecond)
os.Exit(0)
}()

watch.WatchEvents(func(event watcher.Event, fp string) error {
relPath, err := filepath.Rel(fn.Must(os.Getwd()), fp)
if err != nil {
return err
}
logger.Info(fmt.Sprintf("[RELOADING] due changes in %s", relPath))
ex.Kill()
<-time.After(100 * time.Millisecond)
go ex.Exec()
return nil
})
nctx, cf = context.WithCancel(ctx)
go runCommand(NewContext(nctx, ctx.Logger), prf, pt, args)

return nil
}
return nil
case <-ctx.Done():
logger.Info("close signal received")
watch.Close()
return nil
}
})

if err := ex.Exec(); err != nil {
return errors.ErrTaskFailed.Wrap(err).KV("task", args.taskName)
}
return nil
}

wg.Wait()

return nil
}
2 changes: 1 addition & 1 deletion types/parsed-types.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type ParsedRunfile struct {
type ParsedTask struct {
Shell []string `json:"shell"`
WorkingDir string `json:"workingDir"`
Watch TaskWatch `json:"watch"`
Watch *TaskWatch `json:"watch,omitempty"`
Env map[string]string `json:"environ"`
Interactive bool `json:"interactive,omitempty"`
Commands []ParsedCommandJson `json:"commands"`
Expand Down
4 changes: 2 additions & 2 deletions types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ type TaskMetadata struct {
}

type TaskWatch struct {
Enable bool `json:"enable"`
Enable *bool `json:"enable,omitempty"`
Dirs []string `json:"dirs"`
OnlySuffixes []string `json:"onlySuffixes"`
IgnoreSuffixes []string `json:"ignoreSuffixes"`
Expand Down Expand Up @@ -66,7 +66,7 @@ type Task struct {

Env EnvVar `json:"env,omitempty"`

Watch TaskWatch `json:"watch"`
Watch *TaskWatch `json:"watch"`

Requires []*Requires `json:"requires,omitempty"`

Expand Down

0 comments on commit afcd333

Please sign in to comment.