func (srv *Server) startProcess() error { log.Println("Starting Process: ", srv.addr) srv.setProcessState(created) ev := env.New(os.Environ()) for key, value := range srv.conf.Env { ev.Set(key, value) } cmd := exec.Command(srv.bin, srv.startup...) cmd.Env = ev.Data() cmd.Stderr = srv.stderr cmd.Stdout = srv.stdout err := cmd.Start() if err == nil { srv.setProcessState(running) srv.cmd = cmd go func() { status := cmd.Wait() log.Println(srv.host, "->", status) srv.done <- nil oldState := srv.getProcessState() srv.setProcessState(exited) select { case srv.busy <- true: if oldState == running { // The process crashed or was killed externally // Restart it // TODO: limit the number of consecutive restart if srv.stderr.Len() == 0 || strings.Contains(status.Error(), "terminated") { go srv.restart() } else { go srv.stopAndNotify() } } <-srv.busy default: } }() err = <-srv.testConnection(&url.URL{ Host: srv.addr, Scheme: "http", Path: "/", }, srv.startupTimeout*time.Second) } return err }
func (c *config) UnmarshalJSON(data []byte) error { type cfg config var conf cfg err := json.Unmarshal(data, &conf) if err != nil { return err } if conf.Port == 0 { conf.Port = c.Port } if conf.StartupTimeout == 0 { conf.StartupTimeout = c.StartupTimeout } conf.GoRoot = strings.TrimSpace(conf.GoRoot) if len(conf.GoRoot) == 0 { conf.GoRoot = c.GoRoot } if len(conf.GoPath) == 0 { conf.GoPath = c.GoPath } for i := range conf.Servers { s := &conf.Servers[i] if len(s.GoPath) == 0 { s.GoPath = conf.GoPath } if len(s.GoRoot) == 0 { s.GoRoot = conf.GoRoot } if s.StartupTimeout == 0 { s.StartupTimeout = conf.StartupTimeout } if err := processConfig(s, env.New(os.Environ()), '`'); err != nil { return err } } *c = config(conf) return nil }
{"`$", `$`, true}, {"`", "`", true}, {"", "", true}, {"Hello,$NAME", "Hello,world", true}, {"\\", "\\", true}, {"$KIND${NAME}", "braveworld", true}, {"${UNDEFINED}", "", true}, {"$", "", false}, {"${}", "", false}, {"${NAME", "", false}, {"$ NAME ", "", false}, } var ev = env.New([]string{ "NAME=world", "KIND=brave", }) func TestProcessConfig(t *testing.T) { for _, test := range data { result, err := ProcessConfig([]byte(test.input), ev, escapeChar) if err != nil { t.Log(err) if test.pass { t.Fatal(err, string(result), test.input) } } else if test.pass == false { t.Fatal("Expected failure", string(result), test.input) } else if test.expect != string(result) {
func (srv *Server) build() error { log.Printf("Building...%s", srv.host) // List of file to pass to "go build" var buildFiles []string dep, err := computeDep(&srv.context, srv.target) if err != nil { return err } for f := range srv.dep { srv.unwatch(f) } // Reset the dependency list. srv.dep = make(map[string]struct{}) for _, f := range dep { srv.dep[f] = struct{}{} if err := srv.watch(f); err != nil { return err } if filepath.Dir(f) == srv.targetDir { buildFiles = append(buildFiles, filepath.Base(f)) } } env := env.New(os.Environ()) env.Set("GOPATH", srv.context.GOPATH) command, args := srv.builder[0], srv.builder[1:] args = append(args, buildFiles...) cmd := exec.Command(command, args...) cmd.Env = env.Data() cmd.Dir = srv.conf.WorkingDir if out, err := cmd.CombinedOutput(); err != nil { if len(out) > 0 { r := bufio.NewReader(bytes.NewReader(out)) var lines []string done: for { line, err := r.ReadString('\n') switch { case err != nil: break done case !strings.HasPrefix(line, "#"): lines = append(lines, line) } } return errors.New(strings.Join(lines, "")) } return err } return nil }