Pārlūkot izejas kodu

rewrite main logic to properly stop the process.

e.g. ensure that it's children are also stopped. the code might be
linux-specific at the moment, but i don't quite know how to fix that.
Lucas Stadler 11 gadi atpakaļ
vecāks
revīzija
4c748b257a
1 mainītis faili ar 38 papildinājumiem un 39 dzēšanām
  1. 38 39
      go/qst.go

+ 38 - 39
go/qst.go

@ -1,5 +1,6 @@
1 1
package main
2 2
3
import "errors"
3 4
import "flag"
4 5
import "fmt"
5 6
import "log"
@ -7,7 +8,7 @@ import "os"
7 8
import "os/exec"
8 9
import "path"
9 10
import "strings"
10
import "sync"
11
import "syscall"
11 12
import "time"
12 13
13 14
/*
@ -60,30 +61,23 @@ func main() {
60 61
61 62
	ext := path.Ext(file)
62 63
	fn, found := mappings[ext]
63
	if found {
64
		runAndWatch(file, fn(file))
65
	} else {
66
		fmt.Fprintf(os.Stderr, "Error: No command defined for %s files", ext)
67
		os.Exit(1)
64
	if !found {
65
		log.Fatalf("error: no mapping found for `%s'", file)
68 66
	}
69
}
70 67
71
func runAndWatch(file string, cmdLine string) {
72
	// run command, if file changes (mtime) restart command
68
	runner := MakeRunner(fn(file))
69
	runner.Start()
73 70
	lastMtime := time.Now()
74
	cmd := ShellCmd(cmdLine)
75
	cmd.Start()
76
77 71
	for {
78 72
		info, err := os.Stat(file)
79
		if err != nil {
80
			log.Fatalf("Error: %s disappeared, exiting.", file)
73
		if os.IsNotExist(err) {
74
			log.Fatalf("`%s' disappeared, exiting")
81 75
		}
82 76
83 77
		mtime := info.ModTime()
84 78
		if mtime.After(lastMtime) {
85
			log.Printf("%s changed, rerunning", file)
86
			cmd.Restart()
79
			log.Printf("`%s' changed, trying to restart", file)
80
			runner.Restart()
87 81
		}
88 82
89 83
		lastMtime = mtime
@ -91,38 +85,43 @@ func runAndWatch(file string, cmdLine string) {
91 85
	}
92 86
}
93 87
94
type RestartableCommand struct {
95
	Cmd  *exec.Cmd
96
	Lock sync.Mutex
97
	Name string
98
	Args []string
88
type Runner struct {
89
	cmd      *exec.Cmd
90
	shellCmd string
91
	started  bool
99 92
}
100 93
101
func ShellCmd(cmd string) RestartableCommand {
102
	return RestartableCommand{nil, sync.Mutex{}, "sh", []string{"-c", cmd}}
94
func MakeRunner(shellCmd string) *Runner {
95
	return &Runner{nil, shellCmd, false}
103 96
}
104 97
105
func (c *RestartableCommand) Start() {
106
	c.Cmd = exec.Command(c.Name, c.Args...)
107
	c.Cmd.Stderr = os.Stderr
108
	c.Cmd.Stdout = os.Stdout
109
	c.Lock.Lock()
98
func (r *Runner) Start() error {
99
	if r.started {
100
		return errors.New("already started, use Restart()")
101
	}
102
103
	r.started = true
110 104
	go func() {
111
		c.Cmd.Run()
112
		c.Lock.Unlock()
105
		for {
106
			log.Printf("running %s", r.shellCmd)
107
			r.cmd = exec.Command("sh", "-c", r.shellCmd)
108
			r.cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
109
			err := r.cmd.Run()
110
			log.Printf("%s finished: %s", r.shellCmd, err)
111
112
			time.Sleep(1 * time.Second)
113
		}
113 114
	}()
114
}
115 115
116
func (c *RestartableCommand) Restart() {
117
	c.Cmd.Process.Kill()
118
	c.Start()
116
	return nil
119 117
}
120 118
121
func runShellCmd(cmd string) {
122
	log.Printf("Running: `%s'", cmd)
123
	output, err := exec.Command("sh", "-c", cmd).CombinedOutput()
124
	os.Stderr.Write(output)
125
	log.Printf("Error running command: %s\n", err.Error())
119
func (r *Runner) Restart() error {
120
	pgid, err := syscall.Getpgid(r.cmd.Process.Pid)
121
	if err == nil {
122
		syscall.Kill(-pgid, syscall.SIGTERM)
123
	}
124
	return err
126 125
}
127 126
128 127
func isFile(file string) bool {