jww "github.com/spf13/jwalterweatherman"
)
-var (
+var _ cmder = (*serverCmd)(nil)
+
+type serverCmd struct {
disableLiveReload bool
navigateToChanged bool
renderToDisk bool
noHTTPCache bool
disableFastRender bool
-)
-var serverCmd = &cobra.Command{
- Use: "server",
- Aliases: []string{"serve"},
- Short: "A high performance webserver",
- Long: `Hugo provides its own webserver which builds and serves the site.
+ cmd *cobra.Command
+}
+
+func (c *serverCmd) getCommand() *cobra.Command {
+ return c.cmd
+}
+
+func newServerCmd() *serverCmd {
+ cc := &serverCmd{}
+
+ cc.cmd = &cobra.Command{
+ Use: "server",
+ Aliases: []string{"serve"},
+ Short: "A high performance webserver",
+ Long: `Hugo provides its own webserver which builds and serves the site.
While hugo server is high performance, it is a webserver with limited options.
Many run it in production, but the standard behavior is for people to use it
in development and use a more full featured server such as Nginx or Caddy.
automatically rebuild the site. It will then live reload any open browser pages
and push the latest content to them. As most Hugo sites are built in a fraction
of a second, you will be able to save and see your changes nearly instantly.`,
- //RunE: server,
+ RunE: cc.server,
+ }
+
+ initHugoBuilderFlags(cc.cmd)
+
+ // TODO(bep) cli refactor fields vs strings
+ cc.cmd.Flags().IntVarP(&cc.serverPort, "port", "p", 1313, "port on which the server will listen")
+ cc.cmd.Flags().IntVar(&cc.liveReloadPort, "liveReloadPort", -1, "port for live reloading (i.e. 443 in HTTPS proxy situations)")
+ cc.cmd.Flags().StringVarP(&cc.serverInterface, "bind", "", "127.0.0.1", "interface to which the server will bind")
+ cc.cmd.Flags().BoolVarP(&cc.serverWatch, "watch", "w", true, "watch filesystem for changes and recreate as needed")
+ cc.cmd.Flags().BoolVar(&cc.noHTTPCache, "noHTTPCache", false, "prevent HTTP caching")
+ cc.cmd.Flags().BoolVarP(&cc.serverAppend, "appendPort", "", true, "append port to baseURL")
+ cc.cmd.Flags().BoolVar(&cc.disableLiveReload, "disableLiveReload", false, "watch without enabling live browser reload on rebuild")
+ cc.cmd.Flags().BoolVar(&cc.navigateToChanged, "navigateToChanged", false, "navigate to changed content file on live browser reload")
+ cc.cmd.Flags().BoolVar(&cc.renderToDisk, "renderToDisk", false, "render to Destination path (default is render to memory & serve from there)")
+ cc.cmd.Flags().BoolVar(&cc.disableFastRender, "disableFastRender", false, "enables full re-renders on changes")
+
+ cc.cmd.Flags().String("memstats", "", "log memory usage to this file")
+ cc.cmd.Flags().String("meminterval", "100ms", "interval to poll memory usage (requires --memstats), valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".")
+
+ return cc
}
type filesOnlyFs struct {
}
func init() {
- initHugoBuilderFlags(serverCmd)
-
- serverCmd.Flags().IntVarP(&serverPort, "port", "p", 1313, "port on which the server will listen")
- serverCmd.Flags().IntVar(&liveReloadPort, "liveReloadPort", -1, "port for live reloading (i.e. 443 in HTTPS proxy situations)")
- serverCmd.Flags().StringVarP(&serverInterface, "bind", "", "127.0.0.1", "interface to which the server will bind")
- serverCmd.Flags().BoolVarP(&serverWatch, "watch", "w", true, "watch filesystem for changes and recreate as needed")
- serverCmd.Flags().BoolVar(&noHTTPCache, "noHTTPCache", false, "prevent HTTP caching")
- serverCmd.Flags().BoolVarP(&serverAppend, "appendPort", "", true, "append port to baseURL")
- serverCmd.Flags().BoolVar(&disableLiveReload, "disableLiveReload", false, "watch without enabling live browser reload on rebuild")
- serverCmd.Flags().BoolVar(&navigateToChanged, "navigateToChanged", false, "navigate to changed content file on live browser reload")
- serverCmd.Flags().BoolVar(&renderToDisk, "renderToDisk", false, "render to Destination path (default is render to memory & serve from there)")
- serverCmd.Flags().BoolVar(&disableFastRender, "disableFastRender", false, "enables full re-renders on changes")
-
- serverCmd.Flags().String("memstats", "", "log memory usage to this file")
- serverCmd.Flags().String("meminterval", "100ms", "interval to poll memory usage (requires --memstats), valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".")
-
- serverCmd.RunE = server
}
var serverPorts []int
-func server(cmd *cobra.Command, args []string) error {
+func (s *serverCmd) server(cmd *cobra.Command, args []string) error {
// If a Destination is provided via flag write to disk
destination, _ := cmd.Flags().GetString("destination")
if destination != "" {
- renderToDisk = true
+ s.renderToDisk = true
}
var serverCfgInit sync.Once
cfgInit := func(c *commandeer) error {
- c.Set("renderToMemory", !renderToDisk)
+ c.Set("renderToMemory", !s.renderToDisk)
if cmd.Flags().Changed("navigateToChanged") {
- c.Set("navigateToChanged", navigateToChanged)
+ c.Set("navigateToChanged", s.navigateToChanged)
}
if cmd.Flags().Changed("disableLiveReload") {
- c.Set("disableLiveReload", disableLiveReload)
+ c.Set("disableLiveReload", s.disableLiveReload)
}
if cmd.Flags().Changed("disableFastRender") {
- c.Set("disableFastRender", disableFastRender)
+ c.Set("disableFastRender", s.disableFastRender)
}
- if serverWatch {
+ if s.serverWatch {
c.Set("watch", true)
}
serverPorts = make([]int, 1)
if c.languages.IsMultihost() {
- if !serverAppend {
+ if !s.serverAppend {
err = newSystemError("--appendPort=false not supported when in multihost mode")
}
serverPorts = make([]int, len(c.languages))
}
- currentServerPort := serverPort
+ currentServerPort := s.serverPort
for i := 0; i < len(serverPorts); i++ {
- l, err := net.Listen("tcp", net.JoinHostPort(serverInterface, strconv.Itoa(currentServerPort)))
+ l, err := net.Listen("tcp", net.JoinHostPort(s.serverInterface, strconv.Itoa(currentServerPort)))
if err == nil {
l.Close()
serverPorts[i] = currentServerPort
} else {
- if i == 0 && serverCmd.Flags().Changed("port") {
+ if i == 0 && s.cmd.Flags().Changed("port") {
// port set explicitly by user -- he/she probably meant it!
err = newSystemErrorF("Server startup failed: %s", err)
}
- jww.ERROR.Println("port", serverPort, "already in use, attempting to use an available port")
+ jww.ERROR.Println("port", s.serverPort, "already in use, attempting to use an available port")
sp, err := helpers.FindAvailablePort()
if err != nil {
err = newSystemError("Unable to find alternative port to use:", err)
c.serverPorts = serverPorts
- c.Set("port", serverPort)
- if liveReloadPort != -1 {
- c.Set("liveReloadPort", liveReloadPort)
+ c.Set("port", s.serverPort)
+ if s.liveReloadPort != -1 {
+ c.Set("liveReloadPort", s.liveReloadPort)
} else {
c.Set("liveReloadPort", serverPorts[0])
}
serverPort = serverPorts[0]
}
- baseURL, err := fixURL(language, baseURL, serverPort)
+ baseURL, err := s.fixURL(language, baseURL, serverPort)
if err != nil {
return nil
}
jww.ERROR.Println("memstats error:", err)
}
- c, err := InitializeConfig(true, cfgInit, serverCmd)
+ c, err := InitializeConfig(true, cfgInit, s.cmd)
+ // TODO(bep) cli refactor
if err != nil {
return err
}
}
// Watch runs its own server as part of the routine
- if serverWatch {
+ if s.serverWatch {
watchDirs, err := c.getDirList()
if err != nil {
}
- return c.serve()
+ return c.serve(s)
}
baseURLs []string
roots []string
c *commandeer
+ s *serverCmd
}
func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, error) {
absPublishDir := f.c.PathSpec().AbsPathify(publishDir)
if i == 0 {
- if renderToDisk {
+ if f.s.renderToDisk {
jww.FEEDBACK.Println("Serving pages from " + absPublishDir)
} else {
jww.FEEDBACK.Println("Serving pages from memory")
decorate := func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if noHTTPCache {
+ if f.s.noHTTPCache {
w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0")
w.Header().Set("Pragma", "no-cache")
}
mu.Handle(u.Path, http.StripPrefix(u.Path, fileserver))
}
- endpoint := net.JoinHostPort(serverInterface, strconv.Itoa(port))
+ endpoint := net.JoinHostPort(f.s.serverInterface, strconv.Itoa(port))
return mu, u.String(), endpoint, nil
}
-func (c *commandeer) serve() error {
+// TODO(bep) cli refactor
+func (c *commandeer) serve(s *serverCmd) error {
isMultiHost := Hugo.IsMultihost()
baseURLs: baseURLs,
roots: roots,
c: c,
+ s: s,
}
doLiveReload := !c.Cfg.GetBool("disableLiveReload")
mu.HandleFunc("/livereload.js", livereload.ServeJS)
mu.HandleFunc("/livereload", livereload.Handler)
}
- jww.FEEDBACK.Printf("Web Server is available at %s (bind address %s)\n", serverURL, serverInterface)
+ jww.FEEDBACK.Printf("Web Server is available at %s (bind address %s)\n", serverURL, s.serverInterface)
go func() {
err = http.ListenAndServe(endpoint, mu)
if err != nil {
// fixURL massages the baseURL into a form needed for serving
// all pages correctly.
-func fixURL(cfg config.Provider, s string, port int) (string, error) {
+func (sc *serverCmd) fixURL(cfg config.Provider, s string, port int) (string, error) {
useLocalhost := false
if s == "" {
s = cfg.GetString("baseURL")
u.Host = "localhost"
}
- if serverAppend {
+ if sc.serverAppend {
if strings.Contains(u.Host, ":") {
u.Host, _, err = net.SplitHostPort(u.Host)
if err != nil {
}
func memStats() error {
- memstats := serverCmd.Flags().Lookup("memstats").Value.String()
+ sc := newServerCmd().getCommand()
+ memstats := sc.Flags().Lookup("memstats").Value.String()
if memstats != "" {
- interval, err := time.ParseDuration(serverCmd.Flags().Lookup("meminterval").Value.String())
+ interval, err := time.ParseDuration(sc.Flags().Lookup("meminterval").Value.String())
if err != nil {
interval, _ = time.ParseDuration("100ms")
}