func main() { l := termlog.NewLog() testpatt(l) g := l.Group() g.Say("This is a group...") testpatt(g) g.Done() g = l.Group() g.Say("Here are some composed colours...") g.Say( "%s %s %s", color.RedString("red"), color.GreenString("green"), color.BlueString("blue"), ) g.Done() l.Enable("demo") g = l.Group() g.SayAs("disabled", "These don't show...") g.SayAs("demo", "Some named log entries...") g.SayAs("demo", "This is a test") g.SayAs("disabled", "This is a test") g.Done() g = l.Group() g.Say("Disabled colour output...") l.NoColor() testpatt(g) g.Done() }
func TestDevdRouteHandler(t *testing.T) { logger := termlog.NewLog() logger.Quiet() r := Route{"", "/", fsEndpoint("./testdata")} templates := ricetemp.MustMakeTemplates(rice.MustFindBox("templates")) devd := Devd{ Routes: make([]string, 0, 0), OpenBrowser: false, CertFile: "", Address: "", Port: 0, // Shaping Latency: 0, DownKbps: 0, UpKbps: 0, // Livereload LivereloadRoutes: false, Watch: make([]string, 0, 0), Excludes: make([]string, 0, 0), // Logging IgnoreLogs: make([]string, 0, 0), } h := devd.RouteHandler(logger, r, templates, nil) ht := handlerTester{t, h} AssertCode(t, ht.Request("GET", "/", nil), 200) }
func TestDevdRouteHandler(t *testing.T) { logger := termlog.NewLog() logger.Quiet() r := Route{"", "/", fsEndpoint("./testdata")} templates := ricetemp.MustMakeTemplates(rice.MustFindBox("templates")) devd := Devd{LivereloadRoutes: true} h := devd.RouteHandler(logger, r, templates) ht := handlerTester{t, h} AssertCode(t, ht.Request("GET", "/", nil), 200) }
// ServeFile replies to the request with the contents of the named file or directory. func ServeFile(w http.ResponseWriter, r *http.Request, name string) { dir, file := filepath.Split(name) logger := termlog.NewLog() logger.Quiet() fs := FileServer{ http.Dir(dir), inject.CopyInject{}, ricetemp.MustMakeTemplates(rice.MustFindBox("../templates")), } fs.serveFile(logger, w, r, file, false) }
func TestFilterFiles(t *testing.T) { logger := termlog.NewLog() logger.Quiet() for i, tt := range filterFilesTests { result := filterFiles("", tt.files, []string{tt.pattern}, logger) if !reflect.DeepEqual(result, tt.expected) { t.Errorf( "Test %d (pattern %s), expected \"%v\" got \"%v\"", i, tt.pattern, tt.expected, result, ) } } }
func TestDevdHandler(t *testing.T) { logger := termlog.NewLog() logger.Quiet() templates := ricetemp.MustMakeTemplates(rice.MustFindBox("templates")) devd := Devd{LivereloadRoutes: true, WatchPaths: []string{"./"}} devd.AddRoutes([]string{"./"}) h, err := devd.Handler(logger, templates) if err != nil { t.Error(err) } ht := handlerTester{t, h} AssertCode(t, ht.Request("GET", "/", nil), 200) AssertCode(t, ht.Request("GET", "/nonexistent", nil), 404) }
func TestFilterFiles(t *testing.T) { logger := termlog.NewLog() logger.Quiet() for i, tt := range filterFilesTests { result := filterFiles("", tt.files, []string{tt.pattern}, logger) err := false if len(result) != len(tt.expected) { err = true } else { for j := range result { if result[j] != tt.expected[j] { err = true break } } } if err { t.Errorf("Test %d (pattern %s), expected \"%s\" got \"%s\"", i, tt.pattern, tt.expected, result) } } }
func main() { httpIP := kingpin.Flag("address", "Address to listen on"). Short('A'). Default("127.0.0.1"). String() allInterfaces := kingpin.Flag("a", "Listen on all addresses"). Short('a'). Bool() certFile := kingpin.Flag("cert", "Certificate bundle file - enables TLS"). Short('c'). PlaceHolder("PATH"). Default(""). ExistingFile() throttleDownKbps := kingpin.Flag( "down", "Throttle downstream from the client to N kilobytes per second", ). PlaceHolder("N"). Short('d'). Default("0"). Int() logHeaders := kingpin.Flag("logheaders", "Log headers"). Short('H'). Default("false"). Bool() ignoreHeaders := kingpin.Flag( "ignore", "Disable logging matching requests. Regexes are matched over 'host/path'", ). Short('I'). PlaceHolder("REGEX"). Strings() livereloadRoutes := kingpin.Flag("livereload", "Enable livereload for static files"). Short('l'). Default("false"). Bool() latency := kingpin.Flag("latency", "Add N milliseconds of round-trip latency"). PlaceHolder("N"). Short('n'). Default("0"). Int() openBrowser := kingpin.Flag("open", "Open browser window on startup"). Short('o'). Default("false"). Bool() httpPort := kingpin.Flag( "port", "Port to listen on - if not specified, devd will auto-pick a sensible port", ). Short('p'). Int() enableTimer := kingpin.Flag("logtime", "Log timing"). Short('T'). Default("false"). Bool() throttleUpKbps := kingpin.Flag( "up", "Throttle upstream from the client to N kilobytes per second", ). PlaceHolder("N"). Short('u'). Default("0"). Int() watch := kingpin.Flag("watch", "Watch path to trigger livereload"). PlaceHolder("PATH"). Short('w'). Strings() debug := kingpin.Flag("debug", "Debugging for devd development"). Default("false"). Bool() excludes := kingpin.Flag("exclude", "Glob pattern for files to exclude from livereload."). PlaceHolder("PATTERN"). Short('x'). Strings() routes := kingpin.Arg( "route", `Routes have the following forms: [SUBDOMAIN]/<PATH>=<DIR> [SUBDOMAIN]/<PATH>=<URL> <DIR> <URL> `, ).Required().Strings() kingpin.Version(version) kingpin.Parse() logger := termlog.NewLog() if *debug { logger.Enable("debug") } if *enableTimer { logger.Enable("timer") } if *throttleDownKbps == 0 { *throttleDownKbps = slowdown.MaxRate } if *throttleUpKbps == 0 { *throttleUpKbps = slowdown.MaxRate } if *allInterfaces { *httpIP = "0.0.0.0" } tlsEnabled := false if *certFile != "" { tlsEnabled = true } var hl net.Listener var err error if *httpPort > 0 { hl, err = net.Listen("tcp", fmt.Sprintf("%v:%d", *httpIP, *httpPort)) } else { hl, err = pickPort(*httpIP, portLow, portHigh, tlsEnabled) } if err != nil { kingpin.Fatalf("Could not bind to port: %s", err) return } templates := ricetemp.MustMakeTemplates(rice.MustFindBox("templates")) if err != nil { kingpin.Fatalf("Error loading templates: %s", err) return } ignores := make([]*regexp.Regexp, 0, 0) for _, expr := range *ignoreHeaders { v, err := regexp.Compile(expr) if err != nil { kingpin.Fatalf("%s", err) } ignores = append(ignores, v) } routeColl := make(routeCollection) for _, s := range *routes { err := routeColl.Set(s) if err != nil { kingpin.FatalUsage("Invalid route specification: %s", err) } } mux := http.NewServeMux() var livereloadEnabled = false if *livereloadRoutes || len(*watch) > 0 { livereloadEnabled = true } for match, route := range routeColl { handler := devdHandler( logger, route, templates, *logHeaders, ignores, livereloadEnabled, *latency, ) mux.Handle(match, http.StripPrefix(route.Path, handler)) } lr := livereload.NewServer("livereload", logger) if livereloadEnabled { mux.Handle("/livereload", lr) mux.Handle("/livereload.js", http.HandlerFunc(lr.ServeScript)) } if *livereloadRoutes { err = WatchRoutes(routeColl, lr) if err != nil { kingpin.Fatalf("Could not watch routes for livereload: %s", err) } } if len(*watch) > 0 { err = WatchPaths(*watch, *excludes, lr, logger) if err != nil { kingpin.Fatalf("Could not watch path for livereload: %s", err) } } var tlsConfig *tls.Config if *certFile != "" { tlsConfig, err = getTLSConfig(*certFile) if err != nil { kingpin.Fatalf("Could not load certs: %s", err) return } hl = tls.NewListener(hl, tlsConfig) } hl = slowdown.NewSlowListener( hl, float64(*throttleUpKbps)*1024, float64(*throttleDownKbps)*1024, ) url := formatURL(tlsEnabled, *httpIP, hl.Addr().(*net.TCPAddr).Port) logger.Say("Listening on %s (%s)", url, hl.Addr().String()) if *openBrowser { go func() { webbrowser.Open(url) }() } server := &http.Server{ Addr: hl.Addr().String(), Handler: hostPortStrip(mux), } err = server.Serve(hl) logger.Shout("Server stopped: %v", err) }
func main() { address := kingpin.Flag("address", "Address to listen on"). Short('A'). Default("127.0.0.1"). String() allInterfaces := kingpin.Flag("all", "Listen on all addresses"). Short('a'). Bool() certFile := kingpin.Flag("cert", "Certificate bundle file - enables TLS"). Short('c'). PlaceHolder("PATH"). Default(""). ExistingFile() downKbps := kingpin.Flag( "down", "Throttle downstream from the client to N kilobytes per second", ). PlaceHolder("N"). Short('d'). Default("0"). Uint() logHeaders := kingpin.Flag("logheaders", "Log headers"). Short('H'). Default("false"). Bool() ignoreLogs := kingpin.Flag( "ignore", "Disable logging matching requests. Regexes are matched over 'host/path'", ). Short('I'). PlaceHolder("REGEX"). Strings() livereloadRoutes := kingpin.Flag("livereload", "Enable livereload for static files"). Short('l'). Default("false"). Bool() latency := kingpin.Flag("latency", "Add N milliseconds of round-trip latency"). PlaceHolder("N"). Short('n'). Default("0"). Int() openBrowser := kingpin.Flag("open", "Open browser window on startup"). Short('o'). Default("false"). Bool() port := kingpin.Flag( "port", "Port to listen on - if not specified, devd will auto-pick a sensible port", ). Short('p'). Int() credspec := kingpin.Flag( "password", "HTTP basic password protection", ). PlaceHolder("USER:PASS"). Short('P'). String() quiet := kingpin.Flag("quiet", "Silence all logs"). Short('q'). Default("false"). Bool() logTime := kingpin.Flag("logtime", "Log timing"). Short('T'). Default("false"). Bool() upKbps := kingpin.Flag( "up", "Throttle upstream from the client to N kilobytes per second", ). PlaceHolder("N"). Short('u'). Default("0"). Uint() watch := kingpin.Flag("watch", "Watch path to trigger livereload"). PlaceHolder("PATH"). Short('w'). Strings() excludes := kingpin.Flag("exclude", "Glob pattern for files to exclude from livereload"). PlaceHolder("PATTERN"). Short('x'). Strings() debug := kingpin.Flag("debug", "Debugging for devd development"). Default("false"). Bool() routes := kingpin.Arg( "route", `Routes have the following forms: [SUBDOMAIN]/<PATH>=<DIR> [SUBDOMAIN]/<PATH>=<URL> <DIR> <URL> `, ).Required().Strings() kingpin.Version(devd.Version) kingpin.Parse() realAddr := *address if *allInterfaces { realAddr = "0.0.0.0" } var creds *devd.Credentials if *credspec != "" { var err error creds, err = devd.CredentialsFromSpec(*credspec) if err != nil { kingpin.Fatalf("%s", err) return } } dd := devd.Devd{ // Shaping Latency: *latency, DownKbps: *downKbps, UpKbps: *upKbps, // Livereload LivereloadRoutes: *livereloadRoutes, WatchPaths: *watch, Excludes: *excludes, Credentials: creds, } if err := dd.AddRoutes(*routes); err != nil { kingpin.Fatalf("%s", err) } if err := dd.AddIgnores(*ignoreLogs); err != nil { kingpin.Fatalf("%s", err) } logger := termlog.NewLog() if *quiet { logger.Quiet() } if *debug { logger.Enable("debug") } if *logTime { logger.Enable("timer") } if *logHeaders { logger.Enable("headers") } err := dd.Serve( realAddr, *port, *certFile, logger, func(url string) { if *openBrowser { webbrowser.Open(url) } }, ) if err != nil { kingpin.Fatalf("%s", err) } }
// Serve starts the devd server func (dd *Devd) Serve() error { logger := termlog.NewLog() if dd.Debug { logger.Enable("debug") } if dd.EnableTimer { logger.Enable("timer") } if dd.DownKbps == 0 { dd.DownKbps = slowdown.MaxRate } if dd.UpKbps == 0 { dd.UpKbps = slowdown.MaxRate } if dd.AllInterfaces { dd.Address = "0.0.0.0" } tlsEnabled := false if dd.CertFile != "" { tlsEnabled = true } var hl net.Listener var err error if dd.Port > 0 { hl, err = net.Listen("tcp", fmt.Sprintf("%v:%d", dd.Address, dd.Port)) } else { hl, err = pickPort(dd.Address, portLow, portHigh, tlsEnabled) } if err != nil { return fmt.Errorf("Could not bind to port: %s", err) } templates := ricetemp.MustMakeTemplates(rice.MustFindBox("templates")) if err != nil { return fmt.Errorf("Error loading templates: %s", err) } ignores := make([]*regexp.Regexp, 0, 0) for _, expr := range dd.IgnoreLogs { v, err := regexp.Compile(expr) if err != nil { return fmt.Errorf("%s", err) } ignores = append(ignores, v) } routeColl := make(RouteCollection) for _, s := range dd.Routes { err := routeColl.Set(s) if err != nil { return fmt.Errorf("Invalid route specification: %s", err) } } mux := http.NewServeMux() var livereloadEnabled = false if dd.LivereloadRoutes || len(dd.Watch) > 0 { livereloadEnabled = true } for match, route := range routeColl { handler := devdHandler( logger, route, templates, dd.LogHeaders, ignores, livereloadEnabled, dd.Latency, ) mux.Handle(match, http.StripPrefix(route.Path, handler)) } lr := livereload.NewServer("livereload", logger) if livereloadEnabled { mux.Handle("/livereload", lr) mux.Handle("/livereload.js", http.HandlerFunc(lr.ServeScript)) } if dd.LivereloadRoutes { err = WatchRoutes(routeColl, lr) if err != nil { return fmt.Errorf("Could not watch routes for livereload: %s", err) } } if len(dd.Watch) > 0 { err = WatchPaths(dd.Watch, dd.Excludes, lr, logger) if err != nil { return fmt.Errorf("Could not watch path for livereload: %s", err) } } var tlsConfig *tls.Config if dd.CertFile != "" { tlsConfig, err = getTLSConfig(dd.CertFile) if err != nil { return fmt.Errorf("Could not load certs: %s", err) } hl = tls.NewListener(hl, tlsConfig) } hl = slowdown.NewSlowListener( hl, float64(dd.UpKbps)*1024, float64(dd.DownKbps)*1024, ) url := formatURL(tlsEnabled, dd.Address, hl.Addr().(*net.TCPAddr).Port) logger.Say("Listening on %s (%s)", url, hl.Addr().String()) if dd.OpenBrowser { go func() { webbrowser.Open(url) }() } server := &http.Server{ Addr: hl.Addr().String(), Handler: hostPortStrip(mux), } err = server.Serve(hl) logger.Shout("Server stopped: %v", err) return nil }