Skip to content

Commit

Permalink
Fix builds for windows
Browse files Browse the repository at this point in the history
  • Loading branch information
danawoodman committed Feb 27, 2024
1 parent 327f650 commit fe2a4f8
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 20 deletions.
28 changes: 28 additions & 0 deletions internal/fork.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//go:build !windows

package internal

import (
"os"
"os/exec"
"syscall"
)

func forkProcess(prog string, args []string) *exec.Cmd {
cmd := exec.Command(prog, args...)
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
}
return cmd
}

func killProcess(proc *os.Process) error {
pgid, err := syscall.Getpgid(proc.Pid)
if err == nil {
err = syscall.Kill(-pgid, syscall.SIGINT)
if err != nil {
return err
}
}
return nil
}
25 changes: 25 additions & 0 deletions internal/fork_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package internal

import (
"os"
"os/exec"
"strconv"
"syscall"
)

func forkProcess(prog string, args []string) *exec.Cmd {
cmd := exec.Command(prog, args...)
cmd.SysProcAttr = &syscall.SysProcAttr{
CreationFlags: syscall.CREATE_NEW_PROCESS_GROUP,
}
return cmd
}

func killProcess(proc *os.Process) error {
kill := exec.Command("taskkill", "/T", "/F", "/PID", strconv.Itoa(proc.Pid))
err := kill.Run()
if err != nil {
return err
}
return nil
}
42 changes: 22 additions & 20 deletions internal/watcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"os/exec"
"os/signal"
"path/filepath"
"syscall"
"time"

"github.com/bmatcuk/doublestar/v4"
Expand Down Expand Up @@ -37,7 +36,7 @@ type Watcher struct {
workDir string
}

func NewWatcher(config WatcherConfig) Watcher {
func NewWatcher(config WatcherConfig) *Watcher {
if config.Verbose {
logger.Info("Starting watcher with config:", "config", config)
}
Expand All @@ -47,7 +46,7 @@ func NewWatcher(config WatcherConfig) Watcher {
panic("Could not get working directory: " + err.Error())
}

return Watcher{
return &Watcher{
config: config,
// todo: make this injectable
workDir: workDir,
Expand All @@ -60,7 +59,7 @@ func NewWatcher(config WatcherConfig) Watcher {
}
}

func (w Watcher) Start() {
func (w *Watcher) Start() {
w.log("Command to run:", "cmd", w.config.Command)
w.log("Watched paths:", "paths", w.config.ExcludePaths)

Expand Down Expand Up @@ -115,7 +114,7 @@ func (w Watcher) Start() {
// Watch for a SIGINT signal and call .kill on the current command
// process if we receive one:
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt)
signal.Notify(sig, os.Interrupt, os.Kill)

w.log("Current watchlist:", "watchlist", watcher.WatchList())

Expand Down Expand Up @@ -160,26 +159,27 @@ func (w Watcher) Start() {
}

if w.cmd != nil && w.config.Kill {
w.kill()
w.killProcess()
}

w.runCmd()

case <-sig:
w.log("Received SIGINT, exiting...")
w.kill()
os.Exit(0)
w.killProcess()
os.Exit(1)
}
}
}()

<-done
}

func (w Watcher) runCmd() {
func (w *Watcher) runCmd() {
w.log("Running command...")
cmd := exec.Command(w.config.Command[0], w.config.Command[1:]...)
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
prog := w.config.Command[0]
args := w.config.Command[1:]
cmd := forkProcess(prog, args)

// Attach to current process so we can get color output:
cmd.Stdout = os.Stdout
Expand All @@ -193,31 +193,33 @@ func (w Watcher) runCmd() {
w.cmd = cmd
}

// kill kills the current command process.
// killProcess kills the current command process.
// It sends a SIGINT signal to the process group of cmd.
// We cannot simply call cmd.Process.Kill() because it will not kill
// We cannot simply call cmd.Process.Kill() because it will not killProcess
// the child processes of cmd which, in the case of something like a
// web server, would mean that we can't re-bind to the given port.
// We then wait for the task to exit cleanly before continuing.
func (w Watcher) kill() {
func (w *Watcher) killProcess() {
if w.cmd == nil {
w.log("No command to kill")
return
}
pgid, err := syscall.Getpgid(w.cmd.Process.Pid)
if err == nil {
syscall.Kill(-pgid, syscall.SIGINT)

err := killProcess(w.cmd.Process)
if err != nil {
w.log("Error killing process", "error", err)
}
w.log("Killing current command process:", "cmd", pgid)

w.cmd.Wait()
}

// exit logs a fatal message and exits the program because of
// some invalid condition.
func (w Watcher) exit(msg string, args ...interface{}) {
func (w *Watcher) exit(msg string, args ...interface{}) {
logger.Fatal(msg, args...)
}

func (w Watcher) addFiles(watcher *fsnotify.Watcher, rootPath string) {
func (w *Watcher) addFiles(watcher *fsnotify.Watcher, rootPath string) {
w.log("Adding files in directory to watcher", "path", rootPath)
err := filepath.Walk(rootPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
Expand Down

0 comments on commit fe2a4f8

Please sign in to comment.