Example #1
0
// NewDaemonPen creates a new DaemonPen
func NewDaemonPen(block conf.Block, vars map[string]string, log termlog.TermLog) (*DaemonPen, error) {
	d := make([]*daemon, len(block.Daemons))
	for i, dmn := range block.Daemons {
		vcmd := varcmd.VarCmd{Block: nil, Mod: nil, Vars: vars}
		finalcmd, err := vcmd.Render(dmn.Command)
		if err != nil {
			return nil, err
		}
		dmn.Command = finalcmd
		var indir string
		if block.InDir != "" {
			indir = block.InDir
		} else {
			indir, err = os.Getwd()
			if err != nil {
				return nil, err
			}
		}

		d[i] = &daemon{
			conf:  dmn,
			log:   log.Stream(niceHeader("daemon: ", dmn.Command)),
			shell: vars[shellVarName],
			indir: indir,
		}
	}
	return &DaemonPen{daemons: d}, nil
}
Example #2
0
// RunPreps runs all commands in sequence. Stops if any command returns an error.
func RunPreps(b conf.Block, vars map[string]string, mod *watch.Mod, log termlog.TermLog) error {
	vcmd := varcmd.VarCmd{Block: &b, Mod: mod, Vars: vars}
	for _, p := range b.Preps {
		cmd, err := vcmd.Render(p.Command)
		if err != nil {
			return err
		}
		err = RunProc(cmd, log.Stream(niceHeader("prep: ", cmd)))
		if err != nil {
			return err
		}
	}
	return nil
}
Example #3
0
File: proc.go Project: mattn/modd
// Start starts set of daemons, each specified by a command
func (dp *DaemonPen) Start(daemons []conf.Daemon, vars map[string]string, log termlog.TermLog) {
	dp.Lock()
	defer dp.Unlock()
	d := make([]daemon, len(daemons))
	for i, dmn := range daemons {
		d[i] = daemon{
			conf: dmn,
			vars: vars,
			log: log.Stream(
				niceHeader("daemon: ", dmn.Command),
			),
		}
		go d[i].Run()
	}
	dp.daemons = &d
}
Example #4
0
// NewDaemonPen creates a new DaemonPen
func NewDaemonPen(block conf.Block, vars map[string]string, log termlog.TermLog) (*DaemonPen, error) {
	d := make([]*daemon, len(block.Daemons))
	for i, dmn := range block.Daemons {
		vcmd := varcmd.VarCmd{Block: nil, Mod: nil, Vars: vars}
		finalcmd, err := vcmd.Render(dmn.Command)
		if err != nil {
			return nil, err
		}
		dmn.Command = finalcmd
		d[i] = &daemon{
			conf: dmn,
			log:  log.Stream(niceHeader("daemon: ", dmn.Command)),
		}
	}
	return &DaemonPen{daemons: d}, nil
}
Example #5
0
// WrapHandler wraps an httpctx.Handler in the paraphernalia needed by devd for
// logging, latency, and so forth.
func (dd *Devd) WrapHandler(log termlog.TermLog, next httpctx.Handler) http.Handler {
	h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		revertOriginalHost(r)
		timr := timer.Timer{}
		sublog := log.Group()
		defer func() {
			timing := termlog.DefaultPalette.Timestamp.SprintFunc()("timing: ")
			sublog.SayAs("timer", timing+timr.String())
			sublog.Done()
		}()
		if matchStringAny(dd.IgnoreLogs, fmt.Sprintf("%s%s", r.URL.Host, r.RequestURI)) {
			sublog.Quiet()
		}
		timr.RequestHeaders()
		time.Sleep(time.Millisecond * time.Duration(dd.Latency))

		dpath := r.URL.String()
		if !strings.HasPrefix(dpath, "/") {
			dpath = "/" + dpath
		}
		sublog.Say("%s %s", r.Method, dpath)
		LogHeader(sublog, r.Header)
		ctx := timr.NewContext(context.Background())
		ctx = termlog.NewContext(ctx, sublog)
		if dd.AddHeaders != nil {
			for h, vals := range *dd.AddHeaders {
				if strings.ToLower(h) == "host" {
					if len(vals) > 0 {
						r.Host = vals[0]
					}
				} else {
					for _, v := range vals {
						w.Header().Set(h, v)
					}
				}
			}
		}

		next.ServeHTTPContext(
			ctx,
			&ResponseLogWriter{Log: sublog, Resp: w, Timer: &timr},
			r,
		)
	})
	return h
}
Example #6
0
// RunPreps runs all commands in sequence. Stops if any command returns an error.
func RunPreps(b conf.Block, vars map[string]string, mod *watch.Mod, log termlog.TermLog, notifiers []notify.Notifier) error {
	vcmd := varcmd.VarCmd{Block: &b, Mod: mod, Vars: vars}
	for _, p := range b.Preps {
		cmd, err := vcmd.Render(p.Command)
		if err != nil {
			return err
		}
		err = RunProc(cmd, log.Stream(niceHeader("prep: ", cmd)))
		if err != nil {
			if pe, ok := err.(ProcError); ok {
				for _, n := range notifiers {
					n.Push("modd error", pe.Output, "")
				}
			}
			return err
		}
	}
	return nil
}
Example #7
0
File: main.go Project: mattn/modd
// Returns a (continue, error) tuple. If continue is true, execution of the
// remainder of the block should proceed. If error is not nil, modd should
// exit.
func prepsAndNotify(b conf.Block, vars map[string]string, lmod *watch.Mod, log termlog.TermLog) (bool, error) {
	err := modd.RunPreps(b, vars, lmod, log)
	if pe, ok := err.(modd.ProcError); ok {
		if *beep {
			fmt.Print("\a")
		}
		if *doNotify {
			n := notify.NewNotifier()
			if n == nil {
				log.Shout("Could not find a desktop notifier")
			} else {
				n.Push("modd error", pe.Output, "")
			}
		}
		return false, nil
	} else if err != nil {
		return false, err
	}
	return true, nil
}
Example #8
0
// Start starts set of daemons, each specified by a command
func (dp *DaemonPen) Start(daemons []conf.Daemon, vars map[string]string, log termlog.TermLog) {
	dp.Lock()
	defer dp.Unlock()
	d := make([]daemon, len(daemons))
	for i, dmn := range daemons {
		vcmd := varcmd.VarCmd{Block: nil, Mod: nil, Vars: vars}
		finalcmd, err := vcmd.Render(dmn.Command)
		if err != nil {
			log.Shout("%s", err)
			continue
		}
		dmn.Command = finalcmd
		d[i] = daemon{
			conf: dmn,
			log: log.Stream(
				niceHeader("daemon: ", dmn.Command),
			),
		}
		go d[i].Run()
	}
	dp.daemons = &d
}
Example #9
0
File: prep.go Project: cortesi/modd
// RunPreps runs all commands in sequence. Stops if any command returns an error.
func RunPreps(b conf.Block, vars map[string]string, mod *moddwatch.Mod, log termlog.TermLog, notifiers []notify.Notifier, initial bool) error {
	shell := vars[shellVarName]
	vcmd := varcmd.VarCmd{Block: &b, Mod: mod, Vars: vars}
	for _, p := range b.Preps {
		cmd, err := vcmd.Render(p.Command)
		if initial && p.Onchange {
			log.Say(niceHeader("skipping prep: ", cmd))
			continue
		}
		if err != nil {
			return err
		}
		err = RunProc(cmd, shell, log.Stream(niceHeader("prep: ", cmd)))
		if err != nil {
			if pe, ok := err.(ProcError); ok {
				for _, n := range notifiers {
					n.Push("modd error", pe.Output, "")
				}
			}
			return err
		}
	}
	return nil
}
Example #10
0
// Serve starts the devd server. The callback is called with the serving URL
// just before service starts.
func (dd *Devd) Serve(address string, port int, certFile string, logger termlog.TermLog, callback func(string)) error {
	templates, err := ricetemp.MakeTemplates(rice.MustFindBox("templates"))
	if err != nil {
		return fmt.Errorf("Error loading templates: %s", err)
	}
	mux, err := dd.Router(logger, templates)
	if err != nil {
		return err
	}
	var tlsConfig *tls.Config
	var tlsEnabled bool
	if certFile != "" {
		tlsConfig, err = getTLSConfig(certFile)
		if err != nil {
			return fmt.Errorf("Could not load certs: %s", err)
		}
		tlsEnabled = true
	}

	var hl net.Listener
	if port > 0 {
		hl, err = net.Listen("tcp", fmt.Sprintf("%v:%d", address, port))
	} else {
		hl, err = pickPort(address, portLow, portHigh, tlsEnabled)
	}
	if err != nil {
		return err
	}

	if tlsConfig != nil {
		hl = tls.NewListener(hl, tlsConfig)
	}

	hl = slowdown.NewSlowListener(hl, dd.UpKbps*1024, dd.DownKbps*1024)
	url := formatURL(tlsEnabled, address, hl.Addr().(*net.TCPAddr).Port)
	logger.Say("Listening on %s (%s)", url, hl.Addr().String())
	server := &http.Server{Addr: hl.Addr().String(), Handler: mux}
	callback(url)

	if dd.HasLivereload() {
		c := make(chan os.Signal, 1)
		signal.Notify(c, syscall.SIGHUP)
		go func() {
			for {
				<-c
				logger.Say("Received signal - reloading")
				dd.lrserver.Reload([]string{"*"})
			}
		}()
	}

	err = server.Serve(hl)
	logger.Shout("Server stopped: %v", err)
	return nil
}
Example #11
0
// Gives control of chan to caller
func runOnChan(modchan chan *watch.Mod, readyCallback func(), log termlog.TermLog, cnf *conf.Config, watchconf string, notifiers []notify.Notifier) (*conf.Config, error) {
	err := PrepOnly(log, cnf, notifiers)
	if err != nil {
		return nil, err
	}

	dworld, err := NewDaemonWorld(cnf, log)
	if err != nil {
		return nil, err
	}

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	defer signal.Reset(os.Interrupt, os.Kill)
	defer dworld.Shutdown(os.Kill)
	go func() {
		dworld.Shutdown(<-c)
		os.Exit(0)
	}()

	dworld.Start()
	watchpaths := cnf.WatchPatterns()
	if watchconf != "" {
		watchpaths = append(watchpaths, filepath.Dir(watchconf))
	}

	// FIXME: This takes a long time. We could start it in parallel with the
	// first process run in a goroutine
	watcher, err := watch.Watch(watchpaths, lullTime, modchan)
	if err != nil {
		return nil, fmt.Errorf("Error watching: %s", err)
	}
	defer watcher.Stop()
	go readyCallback()

	for mod := range modchan {
		if mod == nil {
			break
		}
		if watchconf != "" && mod.Has(watchconf) {
			ret, err := ioutil.ReadFile(watchconf)
			if err != nil {
				log.Warn("Reloading config - error reading %s: %s", watchconf, err)
				continue
			}
			newcnf, err := conf.Parse(watchconf, string(ret))
			if err != nil {
				log.Warn("Reloading config - error reading %s: %s", watchconf, err)
				continue
			}
			log.Notice("Reloading config %s", watchconf)
			return newcnf, nil
		}
		log.SayAs("debug", "Delta: \n%s", mod.String())
		for i, b := range cnf.Blocks {
			lmod, err := mod.Filter(b.Include, b.Exclude)
			if err != nil {
				log.Shout("Error filtering events: %s", err)
				continue
			}
			if lmod.Empty() {
				continue
			}
			err = RunPreps(b, cnf.GetVariables(), lmod, log, notifiers)
			if err != nil {
				if _, ok := err.(ProcError); ok {
					continue
				} else {
					return nil, err
				}
			}
			dworld.DaemonPens[i].Restart()
		}
	}
	return nil, nil
}
Example #12
0
File: main.go Project: mattn/modd
func run(log termlog.TermLog, cnf *conf.Config, watchconf string) *conf.Config {
	modchan := make(chan *watch.Mod, 1024)
	if *ignores {
		for _, patt := range watch.CommonExcludes {
			fmt.Println(patt)
		}
		os.Exit(0)
	}

	daemonPens := make([]*modd.DaemonPen, len(cnf.Blocks))
	for i, b := range cnf.Blocks {
		if !b.NoCommonFilter {
			b.Exclude = append(b.Exclude, watch.CommonExcludes...)
		}
		cnf.Blocks[i] = b

		_, err := prepsAndNotify(b, cnf.GetVariables(), nil, log)
		if err != nil {
			log.Shout("%s", err)
			return nil
		}

		d := modd.DaemonPen{}
		c := make(chan os.Signal, 1)
		signal.Notify(c, os.Interrupt, os.Kill)
		go func() {
			d.Shutdown(<-c)
			os.Exit(0)
		}()
		if !*prep {
			d.Start(b.Daemons, cnf.GetVariables(), log)
		}
		daemonPens[i] = &d
	}
	if *prep {
		os.Exit(0)
	}

	watchpaths := cnf.WatchPaths()
	if watchconf != "" {
		watchpaths = append(watchpaths, watchconf)
	}

	// FIXME: This takes a long time. We could start it in parallel with the
	// first process run in a goroutine
	watcher, err := watch.Watch(watchpaths, lullTime, modchan)
	defer watcher.Stop()
	if err != nil {
		kingpin.Fatalf("Fatal error: %s", err)
	}

	for mod := range modchan {
		if watchconf != "" && mod.Has(watchconf) {
			ret, err := ioutil.ReadFile(watchconf)
			if err != nil {
				log.Warn("Reloading config - error reading %s: %s", watchconf, err)
				continue
			}
			newcnf, err := conf.Parse(*file, string(ret))
			if err != nil {
				log.Warn("Reloading config - error reading %s: %s", watchconf, err)
				continue
			}
			log.Notice("Reloading config %s", watchconf)
			return newcnf
		}
		if mod == nil {
			break
		}
		log.SayAs("debug", "Delta: \n%s", mod.String())
		for i, b := range cnf.Blocks {
			lmod, err := mod.Filter(b.Include, b.Exclude)
			if err != nil {
				log.Shout("Error filtering events: %s", err)
				continue
			}
			if lmod.Empty() {
				continue
			}

			proceed, err := prepsAndNotify(b, cnf.GetVariables(), lmod, log)
			if err != nil {
				log.Shout("%s", err)
				return nil
			}
			if !proceed {
				continue
			}
			daemonPens[i].Restart()
		}
	}
	return nil
}