Skip to content

Commit

Permalink
commands: Show server error info in browser
Browse files Browse the repository at this point in the history
  • Loading branch information
bep committed Oct 4, 2018
1 parent fae48d7 commit 27d90da
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 35 deletions.
82 changes: 80 additions & 2 deletions commands/commandeer.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,24 @@
package commands

import (
"fmt"
"log"
"os"
"path/filepath"
"regexp"
"strings"
"sync"
"time"

"github.com/gohugoio/hugo/livereload"

"github.com/gohugoio/hugo/config"

"github.com/spf13/cobra"

"github.com/spf13/afero"

"github.com/gohugoio/hugo/hugolib"
"github.com/spf13/afero"
jww "github.com/spf13/jwalterweatherman"

"github.com/bep/debounce"
"github.com/gohugoio/hugo/common/types"
Expand Down Expand Up @@ -72,6 +76,70 @@ type commandeer struct {

configured bool
paused bool

errorHandler *errorHandler
}

type errorHandler struct {
logger *log.Logger
sync.RWMutex
err *buildError
}

type buildError struct {
logger *log.Logger
What string
Err error
}

func (b buildError) log() {
b.logger.Println(b.Error())
}

func (b buildError) Error() string {
return fmt.Sprintf("%s: %s", b.What, b.Err)
}

func (c *commandeer) getError() *buildError {
h := c.errorHandler
h.RLock()
defer h.RUnlock()
return h.err
}

func (c *commandeer) getErrorWithContext() interface{} {
h := c.errorHandler
h.RLock()
defer h.RUnlock()
if h.err == nil {
return nil
}
m := make(map[string]interface{})

m["Error"] = h.err
m["Version"] = hugoVersionString()

return m
}

func (c *commandeer) handleError(what string, err error) error {
h := c.errorHandler
h.Lock()
defer h.Unlock()

if err == nil {
h.err = nil
return nil
}

h.err = &buildError{logger: h.logger, What: what, Err: err}
h.err.log()

// TODO(bep) server error config
// Need to refresh the browser to show the error page.
livereload.ForceRefresh()

return h.err
}

func (c *commandeer) Set(key string, value interface{}) {
Expand All @@ -98,13 +166,23 @@ func newCommandeer(mustHaveConfigFile, running bool, h *hugoBuilderCommon, f fla
rebuildDebouncer, _, _ = debounce.New(4 * time.Second)
}

/*var logger *log.Logger
if c.Logger != nil {
logger = c.Logger.ERROR
} else {
logger = jww.ERROR
}*/
// TODO(bep) server error
logger := jww.ERROR

c := &commandeer{
h: h,
ftch: f,
commandeerHugoState: &commandeerHugoState{},
doWithCommandeer: doWithCommandeer,
visitedURLs: types.NewEvictingStringQueue(10),
debounce: rebuildDebouncer,
errorHandler: &errorHandler{logger: logger},
}

return c, c.loadConfig(mustHaveConfigFile, running)
Expand Down
24 changes: 0 additions & 24 deletions commands/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
package commands

import (
"os"

"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/helpers"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -255,25 +253,3 @@ func checkErr(logger *jww.Notepad, err error, s ...string) {
}
logger.ERROR.Println(err)
}

func stopOnErr(logger *jww.Notepad, err error, s ...string) {
if err == nil {
return
}

defer os.Exit(-1)

if len(s) == 0 {
newMessage := err.Error()
// Printing an empty string results in a error with
// no message, no bueno.
if newMessage != "" {
logger.CRITICAL.Println(newMessage)
}
}
for _, message := range s {
if message != "" {
logger.CRITICAL.Println(message)
}
}
}
16 changes: 9 additions & 7 deletions commands/hugo.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"syscall"

"github.com/gohugoio/hugo/hugolib/filesystems"
"github.com/pkg/errors"

"golang.org/x/sync/errgroup"

Expand Down Expand Up @@ -637,17 +638,17 @@ func (c *commandeer) fullRebuild() {
c.commandeerHugoState = &commandeerHugoState{}
err := c.loadConfig(true, true)
if err != nil {
jww.ERROR.Println("Failed to reload config:", err)
c.handleError("Failed to reload config", errors.WithStack(err))
// Set the processing on pause until the state is recovered.
c.paused = true
} else {
c.paused = false
}

if !c.paused {
if err := c.buildSites(); err != nil {
jww.ERROR.Println(err)
} else if !c.h.buildWatch && !c.Cfg.GetBool("disableLiveReload") {
err := c.buildSites()
c.handleError("Build failed", errors.WithStack(err))
if err == nil && !c.h.buildWatch && !c.Cfg.GetBool("disableLiveReload") {
livereload.ForceRefresh()
}
}
Expand Down Expand Up @@ -839,11 +840,12 @@ func (c *commandeer) newWatcher(dirList ...string) (*watcher.Batcher, error) {
c.Logger.FEEDBACK.Printf("Syncing all static files\n")
_, err := c.copyStatic()
if err != nil {
stopOnErr(c.Logger, err, "Error copying static files to publish dir")
c.handleError("Error copying static files to publish dir", errors.WithStack(err))
break
}
} else {
if err := staticSyncer.syncsStaticEvents(staticEvents); err != nil {
c.Logger.ERROR.Println(err)
c.handleError("Error syncing static files to publish dir", errors.WithStack(err))
continue
}
}
Expand Down Expand Up @@ -917,7 +919,7 @@ func (c *commandeer) newWatcher(dirList ...string) (*watcher.Batcher, error) {
}
case err := <-watcher.Errors:
if err != nil {
c.Logger.ERROR.Println(err)
c.handleError("Error while watching", errors.WithStack(err))
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions commands/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,16 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro

decorate := func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

// First check the error state
err := f.c.getErrorWithContext()
if err != nil {
errTemplate := defaultBuildErrorTemplate
w.WriteHeader(errTemplate.statusCode) // TODO(bep) error server improve
errTemplate.buildErrorPage(err, w)
return
}

if f.s.noHTTPCache {
w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0")
w.Header().Set("Pragma", "no-cache")
Expand Down
50 changes: 50 additions & 0 deletions commands/server_errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package commands

import (
"html/template"
"io"
)

type errorTemplate struct {
// To text template to produce a nice looking error page in the browser.
templ string

// The default HTTP status code shown for this error.
statusCode int
}

var defaultBuildErrorTemplate = errorTemplate{
templ: `<h1>{{ .Error.What }}</h1>
<pre>{{ .Error.Err }}</pre>
<pre>{{ .Error.Err.StackTrace }}</pre>
<small>{{ .Version }}</small>
`,
statusCode: 500,
}

func (templ errorTemplate) buildErrorPage(data interface{}, w io.Writer) error {
t, err := template.New("").Parse(templ.templ)
if err != nil {
return err
}

return t.Execute(w, data)
}
11 changes: 9 additions & 2 deletions commands/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@
package commands

import (
"fmt"
"runtime"
"strings"

jww "github.com/spf13/jwalterweatherman"

"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/hugolib"
"github.com/gohugoio/hugo/resource/tocss/scss"
"github.com/spf13/cobra"
jww "github.com/spf13/jwalterweatherman"
)

var _ cmder = (*versionCmd)(nil)
Expand All @@ -45,6 +47,10 @@ func newVersionCmd() *versionCmd {
}

func printHugoVersion() {
jww.FEEDBACK.Println(hugoVersionString())
}

func hugoVersionString() string {
program := "Hugo Static Site Generator"

version := "v" + helpers.CurrentHugoVersion.String()
Expand All @@ -64,5 +70,6 @@ func printHugoVersion() {
buildDate = "unknown"
}

jww.FEEDBACK.Println(program, version, osArch, "BuildDate:", buildDate)
return fmt.Sprintf("%s %s %s BuildDate: %s", program, version, osArch, buildDate)

}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ require (
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/nicksnyder/go-i18n v1.10.0
github.com/olekukonko/tablewriter v0.0.0-20180506121414-d4647c9c7a84
github.com/pkg/errors v0.8.0
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/russross/blackfriday v0.0.0-20180804101149-46c73eb196ba
github.com/sanity-io/litter v1.1.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ github.com/olekukonko/tablewriter v0.0.0-20180506121414-d4647c9c7a84 h1:fiKJgB4J
github.com/olekukonko/tablewriter v0.0.0-20180506121414-d4647c9c7a84/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday v0.0.0-20180804101149-46c73eb196ba h1:8Vzt8HxRjy7hp1eqPKVoAEPK9npQFW2510qlobGzvi0=
Expand Down

0 comments on commit 27d90da

Please sign in to comment.