Skip to content

Commit

Permalink
feat: add watchman integration
Browse files Browse the repository at this point in the history
  • Loading branch information
cdmistman committed May 22, 2024
1 parent f4bce67 commit df33507
Show file tree
Hide file tree
Showing 7 changed files with 391 additions and 25 deletions.
121 changes: 121 additions & 0 deletions '
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package app

import (
"fmt"
"os"

"github.com/cdmistman/watchman"
"github.com/cdmistman/watchman/protocol"
"github.com/cdmistman/watchman/protocol/query"
"github.com/rs/zerolog/log"
)

type watchmanState int

const (
uninit watchmanState = iota
initing
errored
ready
)

type Watchman struct {
subscriptions []Subscription
}

type Subscription struct {
updates chan []string
glob string
}

func (w *Watchman) MaybeStart() error {
// TODO: proper error handling
if len(w.subscriptions) == 0 {
return nil
}

globs := []string{}
for _, sub := range w.subscriptions {
globs = append(globs, sub.glob)
}

q := query.Query{
Generators: query.Generators{query.GGlob: globs},
Fields: query.Fields{query.FName},
}

client, err := watchman.Connect()
if err != nil {
return err
}

if !client.HasCapability("glob_generator") {
return fmt.Errorf("watchman does not have the glob_generator capability")
}

cwd, err := os.Getwd()
if err != nil {
return err
}

watch, err := client.AddWatch(cwd)
if err != nil {
return err
}

if watch.RelativePath() != "" {
if !client.HasCapability("relative_root") {
return fmt.Errorf("watchman does not have the relative_root capability but gave a relative root")
}

q.RelativeRoot = watch.RelativePath()
}

if _, err = watch.Subscribe("process-compose", &q); err != nil {
return err
}

go loop(client, w.subscriptions, watch.Root(), watch.RelativePath())
return nil
}

// assumes that all subscriptions have already been created
func loop(client *watchman.Client, subs []Subscription, root, rel string) {
for {
rawNotif, ok := <-client.Notifications()
if !ok {
log.Warn().Msg("watchman client shut down, exiting watch loop")
return
}

notif, ok := rawNotif.(*protocol.Subscription)
if !ok {
log.Debug().Msg("got a non-subscription notification, ignoring")
}

if notif.IsFreshInstance() {
log.Debug().Msg("fresh instance notification, ignoring")
}

files := []string{}
for _, rawFile := range notif.Files() {
// if the query fields change, this will need to be a map[string]any
file := rawFile.(string)
files = append(files, file)
}

for _, sub := range subs {
sub.updates <- files
}
}
}

func (w *Watchman) Subscribe(glob string) <-chan []string {
ch := make(chan []string)
w.subscriptions = append(w.subscriptions, Subscription{
updates: ch,
glob: glob,
})

return ch
}
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/InVisionApp/go-health/v2 v2.1.4
github.com/adrg/xdg v0.4.0
github.com/cakturk/go-netstat v0.0.0-20200220111822-e5b49efee7a5
github.com/cdmistman/watchman v0.2.1-0.20240521013409-16b1ae353832
github.com/creack/pty v1.1.21
github.com/f1bonacc1/glippy v0.0.0-20230614190937-e7ca07f99f6f
github.com/fatih/color v1.16.0
Expand All @@ -31,9 +32,8 @@ replace github.com/cakturk/go-netstat => github.com/f1bonacc1/netstat v0.0.0-202
require (
github.com/InVisionApp/go-logger v1.0.1 // indirect
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/bytedance/sonic v1.10.2 // indirect
github.com/cdmistman/watchman v0.2.1-0.20240520005913-d8783be7f453 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
Expand Down Expand Up @@ -76,5 +76,5 @@ require (
github.com/rs/zerolog v1.32.0
github.com/swaggo/files v1.0.1
github.com/swaggo/gin-swagger v1.6.0
golang.org/x/sys v0.19.0 // indirect
golang.org/x/sys v0.20.0 // indirect
)
14 changes: 11 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
Expand All @@ -21,6 +23,8 @@ github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZF
github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
github.com/cdmistman/watchman v0.2.1-0.20240520005913-d8783be7f453 h1:5kwNOesBL08pw4GurjnaLfXik1Vh7lq4aVZro61+/vM=
github.com/cdmistman/watchman v0.2.1-0.20240520005913-d8783be7f453/go.mod h1:6Vf499nk4H8euH9INguY3dux8DWPmTkGnn1Un/yj+ek=
github.com/cdmistman/watchman v0.2.1-0.20240521013409-16b1ae353832 h1:Ax/3QlycSW6UV2Gcl1cWB0xfvHej85JhZYPJuQBD1gs=
github.com/cdmistman/watchman v0.2.1-0.20240521013409-16b1ae353832/go.mod h1:dWMrnZS+cSIn+wGnWneps2bPUWvwvFLKq2/iS4yJOa4=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
Expand All @@ -46,6 +50,8 @@ github.com/f1bonacc1/netstat v0.0.0-20230714090734-adb3fa07cab7 h1:CNJScrucGEDyO
github.com/f1bonacc1/netstat v0.0.0-20230714090734-adb3fa07cab7/go.mod h1:jtAfVaU/2cu1+wdSRPWE2c1N2qeAA3K4RH9pYgqwets=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
Expand Down Expand Up @@ -104,7 +110,6 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
Expand Down Expand Up @@ -151,8 +156,8 @@ github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0=
github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shirou/gopsutil v2.18.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
Expand All @@ -169,8 +174,9 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
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/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M=
Expand Down Expand Up @@ -227,6 +233,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
Expand Down
58 changes: 49 additions & 9 deletions src/app/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import (
"context"
"errors"
"fmt"
"github.com/cakturk/go-netstat/netstat"
"github.com/f1bonacc1/process-compose/src/types"
"io"
"math/rand"
"os"
Expand All @@ -17,6 +15,9 @@ import (
"syscall"
"time"

"github.com/cakturk/go-netstat/netstat"
"github.com/f1bonacc1/process-compose/src/types"

"github.com/f1bonacc1/process-compose/src/command"
"github.com/f1bonacc1/process-compose/src/health"
"github.com/f1bonacc1/process-compose/src/pclog"
Expand Down Expand Up @@ -65,6 +66,13 @@ type Process struct {
isMain bool
extraArgs []string
isStopped atomic.Bool
isDevRestart atomic.Bool
devWatchers []devWatch
}

type devWatch struct {
sub *WatchmanSub
config *types.Watch
}

func NewProcess(
Expand All @@ -77,6 +85,7 @@ func NewProcess(
printLogs bool,
isMain bool,
extraArgs []string,
watchman *Watchman,
) *Process {
colNumeric := rand.Intn(int(color.FgHiWhite)-int(color.FgHiBlack)) + int(color.FgHiBlack)

Expand Down Expand Up @@ -104,6 +113,7 @@ func NewProcess(
proc.setUpProbes()
proc.procCond = *sync.NewCond(proc)
proc.procStartedCond = *sync.NewCond(proc)
proc.setUpWatchman(watchman)
return proc
}

Expand Down Expand Up @@ -139,9 +149,9 @@ func (p *Process) run() int {

p.startProbes()

//Wait should wait for I/O consumption, but if the execution is too fast
//e.g. echo 'hello world' the output will not reach the pipe
//TODO Fix this
// Wait should wait for I/O consumption, but if the execution is too fast
// e.g. echo 'hello world' the output will not reach the pipe
// TODO Fix this
time.Sleep(50 * time.Millisecond)
_ = p.command.Wait()
p.Lock()
Expand Down Expand Up @@ -212,7 +222,6 @@ func (p *Process) getCommander() command.Commander {
p.mergeExtraArgs(),
)
}

}

func (p *Process) mergeExtraArgs() []string {
Expand Down Expand Up @@ -254,6 +263,11 @@ func (p *Process) isRestartable() bool {
p.Lock()
exitCode := p.getExitCode()
p.Unlock()

if p.isDevRestart.Swap(false) {
return true
}

if p.isStopped.Swap(false) {
return false
}
Expand Down Expand Up @@ -381,16 +395,35 @@ func (p *Process) isRunning() bool {

func (p *Process) prepareForShutDown() {
// prevent restart during global shutdown or scale down
//p.procConf.RestartPolicy.Restart = types.RestartPolicyNo
// p.procConf.RestartPolicy.Restart = types.RestartPolicyNo
p.isStopped.Store(true)

}

func (p *Process) onProcessStart() {
if isStringDefined(p.procConf.LogLocation) {
p.logger.Open(p.getLogPath(), p.procConf.LoggerConfig)
}

for _, watch := range p.devWatchers {
go func() {
for {
files, ok := watch.sub.Recv()
if !ok {
log.
Debug().
Msg("watchman sub closed, exiting")
return
}

if len(files) == 0 {
continue
}

p.isDevRestart.Store(true)
}
}()
}

p.Lock()
p.started = true
p.Unlock()
Expand Down Expand Up @@ -457,8 +490,8 @@ func (p *Process) updateProcState() {
p.procState.Name = p.getName()
}
p.procState.IsRunning = isRunning

}

func (p *Process) setStartTime(startTime time.Time) {
p.timeMutex.Lock()
defer p.timeMutex.Unlock()
Expand Down Expand Up @@ -663,6 +696,13 @@ func (p *Process) onReadinessCheckEnd(isOk, isFatal bool, err string) {
}
}

func (p *Process) setUpWatchman(watchman *Watchman) {
for _, config := range p.procConf.Watch {
recv := watchman.Subscribe(config)
p.devWatchers = append(p.devWatchers, devWatch{recv, config})
}
}

func (p *Process) validateProcess() error {
if isStringDefined(p.procConf.WorkingDir) {
stat, err := os.Stat(p.procConf.WorkingDir)
Expand Down
Loading

0 comments on commit df33507

Please sign in to comment.