diff --git a/commands/benchmark.go b/commands/benchmark.go index 4f9ab828b..6c42992a0 100644 --- a/commands/benchmark.go +++ b/commands/benchmark.go @@ -54,7 +54,10 @@ func benchmark(cmd *cobra.Command, args []string) error { return err } - c := newCommandeer(cfg) + c, err := newCommandeer(cfg) + if err != nil { + return err + } var memProf *os.File if memProfileFile != "" { diff --git a/commands/commandeer.go b/commands/commandeer.go index e7fd70651..19eadda10 100644 --- a/commands/commandeer.go +++ b/commands/commandeer.go @@ -16,6 +16,7 @@ package commands import ( "github.com/spf13/hugo/deps" "github.com/spf13/hugo/helpers" + "github.com/spf13/hugo/hugofs" ) type commandeer struct { @@ -35,12 +36,14 @@ func (c *commandeer) Set(key string, value interface{}) { // be configured before it is created. func (c *commandeer) PathSpec() *helpers.PathSpec { c.configured = true - if c.pathSpec == nil { - c.pathSpec = helpers.NewPathSpec(c.Fs, c.Cfg) - } return c.pathSpec } -func newCommandeer(cfg *deps.DepsCfg) *commandeer { - return &commandeer{DepsCfg: cfg} +func newCommandeer(cfg *deps.DepsCfg) (*commandeer, error) { + fs := hugofs.NewDefault(cfg.Language) + ps, err := helpers.NewPathSpec(fs, cfg.Cfg) + if err != nil { + return nil, err + } + return &commandeer{DepsCfg: cfg, pathSpec: ps}, nil } diff --git a/commands/hugo.go b/commands/hugo.go index 48d4e0dc1..de5798df9 100644 --- a/commands/hugo.go +++ b/commands/hugo.go @@ -118,7 +118,10 @@ Complete documentation is available at http://gohugo.io/.`, return err } - c := newCommandeer(cfg) + c, err := newCommandeer(cfg) + if err != nil { + return err + } if buildWatch { cfg.Cfg.Set("disableLiveReload", true) @@ -287,7 +290,10 @@ func InitializeConfig(subCmdVs ...*cobra.Command) (*deps.DepsCfg, error) { cfg.Cfg = config - c := newCommandeer(cfg) + c, err := newCommandeer(cfg) + if err != nil { + return nil, err + } for _, cmdV := range append([]*cobra.Command{hugoCmdV}, subCmdVs...) { c.initializeFlags(cmdV) diff --git a/commands/list.go b/commands/list.go index 3f3286f38..97753cc88 100644 --- a/commands/list.go +++ b/commands/list.go @@ -49,7 +49,10 @@ var listDraftsCmd = &cobra.Command{ return err } - c := newCommandeer(cfg) + c, err := newCommandeer(cfg) + if err != nil { + return err + } c.Set("buildDrafts", true) @@ -87,7 +90,10 @@ posted in the future.`, return err } - c := newCommandeer(cfg) + c, err := newCommandeer(cfg) + if err != nil { + return err + } c.Set("buildFuture", true) @@ -125,7 +131,10 @@ expired.`, return err } - c := newCommandeer(cfg) + c, err := newCommandeer(cfg) + if err != nil { + return err + } c.Set("buildExpired", true) diff --git a/commands/new.go b/commands/new.go index e2472af0c..abb234b87 100644 --- a/commands/new.go +++ b/commands/new.go @@ -93,7 +93,10 @@ func NewContent(cmd *cobra.Command, args []string) error { return err } - c := newCommandeer(cfg) + c, err := newCommandeer(cfg) + if err != nil { + return err + } if flagChanged(cmd.Flags(), "format") { c.Set("metaDataFormat", configFormat) @@ -220,7 +223,10 @@ func NewTheme(cmd *cobra.Command, args []string) error { return newUserError("theme name needs to be provided") } - c := newCommandeer(cfg) + c, err := newCommandeer(cfg) + if err != nil { + return err + } createpath := c.PathSpec().AbsPathify(filepath.Join(c.Cfg.GetString("themesDir"), args[0])) jww.INFO.Println("creating theme at", createpath) diff --git a/commands/server.go b/commands/server.go index 3e7673773..ae51d075d 100644 --- a/commands/server.go +++ b/commands/server.go @@ -106,7 +106,10 @@ func server(cmd *cobra.Command, args []string) error { return err } - c := newCommandeer(cfg) + c, err := newCommandeer(cfg) + if err != nil { + return err + } if flagChanged(cmd.Flags(), "disableLiveReload") { c.Set("disableLiveReload", disableLiveReload) diff --git a/deps/deps.go b/deps/deps.go index 3e97ffd93..659f259dd 100644 --- a/deps/deps.go +++ b/deps/deps.go @@ -65,7 +65,7 @@ func (d *Deps) LoadResources() error { return nil } -func New(cfg DepsCfg) *Deps { +func New(cfg DepsCfg) (*Deps, error) { var ( logger = cfg.Logger fs = cfg.Fs @@ -92,26 +92,37 @@ func New(cfg DepsCfg) *Deps { fs = hugofs.NewDefault(cfg.Language) } + ps, err := helpers.NewPathSpec(fs, cfg.Language) + + if err != nil { + return nil, err + } + d := &Deps{ Fs: fs, Log: logger, templateProvider: cfg.TemplateProvider, translationProvider: cfg.TranslationProvider, WithTemplate: cfg.WithTemplate, - PathSpec: helpers.NewPathSpec(fs, cfg.Language), + PathSpec: ps, ContentSpec: helpers.NewContentSpec(cfg.Language), Cfg: cfg.Language, Language: cfg.Language, } - return d + return d, nil } // ForLanguage creates a copy of the Deps with the language dependent // parts switched out. func (d Deps) ForLanguage(l *helpers.Language) (*Deps, error) { + var err error + + d.PathSpec, err = helpers.NewPathSpec(d.Fs, l) + if err != nil { + return nil, err + } - d.PathSpec = helpers.NewPathSpec(d.Fs, l) d.ContentSpec = helpers.NewContentSpec(l) d.Cfg = l d.Language = l diff --git a/helpers/baseURL.go b/helpers/baseURL.go index 9a4b77edd..50265fe36 100644 --- a/helpers/baseURL.go +++ b/helpers/baseURL.go @@ -69,6 +69,5 @@ func newBaseURLFromString(b string) (BaseURL, error) { return result, err } - // TODO(bep) output consider saving original URL? return BaseURL{url: base, urlStr: base.String()}, nil } diff --git a/helpers/baseURL_test.go b/helpers/baseURL_test.go index eaa27ddb9..437152f34 100644 --- a/helpers/baseURL_test.go +++ b/helpers/baseURL_test.go @@ -48,4 +48,14 @@ func TestBaseURL(t *testing.T) { require.NoError(t, err) require.Equal(t, "webcal://hugo@rules.com", p) + // Test with "non-URLs". Some people will try to use these as a way to get + // relative URLs working etc. + b, err = newBaseURLFromString("/") + require.NoError(t, err) + require.Equal(t, "/", b.String()) + + b, err = newBaseURLFromString("") + require.NoError(t, err) + require.Equal(t, "", b.String()) + } diff --git a/helpers/path_test.go b/helpers/path_test.go index 90dd95288..25dbdc543 100644 --- a/helpers/path_test.go +++ b/helpers/path_test.go @@ -59,7 +59,7 @@ func TestMakePath(t *testing.T) { v := viper.New() l := NewDefaultLanguage(v) v.Set("removePathAccents", test.removeAccents) - p := NewPathSpec(hugofs.NewMem(v), l) + p, _ := NewPathSpec(hugofs.NewMem(v), l) output := p.MakePath(test.input) if output != test.expected { @@ -71,7 +71,7 @@ func TestMakePath(t *testing.T) { func TestMakePathSanitized(t *testing.T) { v := viper.New() l := NewDefaultLanguage(v) - p := NewPathSpec(hugofs.NewMem(v), l) + p, _ := NewPathSpec(hugofs.NewMem(v), l) tests := []struct { input string @@ -99,7 +99,7 @@ func TestMakePathSanitizedDisablePathToLower(t *testing.T) { v.Set("disablePathToLower", true) l := NewDefaultLanguage(v) - p := NewPathSpec(hugofs.NewMem(v), l) + p, _ := NewPathSpec(hugofs.NewMem(v), l) tests := []struct { input string diff --git a/helpers/pathspec.go b/helpers/pathspec.go index de7665c87..ff4488020 100644 --- a/helpers/pathspec.go +++ b/helpers/pathspec.go @@ -60,10 +60,14 @@ func (p PathSpec) String() string { } // NewPathSpec creats a new PathSpec from the given filesystems and Language. -func NewPathSpec(fs *hugofs.Fs, cfg config.Provider) *PathSpec { +func NewPathSpec(fs *hugofs.Fs, cfg config.Provider) (*PathSpec, error) { - // TODO(bep) output error handling - baseURL, _ := newBaseURLFromString(cfg.GetString("baseURL")) + baseURLstr := cfg.GetString("baseURL") + baseURL, err := newBaseURLFromString(baseURLstr) + + if err != nil { + return nil, fmt.Errorf("Failed to create baseURL from %q: %s", baseURLstr, err) + } ps := &PathSpec{ fs: fs, @@ -87,7 +91,7 @@ func NewPathSpec(fs *hugofs.Fs, cfg config.Provider) *PathSpec { ps.language = language } - return ps + return ps, nil } // PaginatePath returns the configured root path used for paginator pages. diff --git a/helpers/pathspec_test.go b/helpers/pathspec_test.go index c67c6fbdc..2536b8f24 100644 --- a/helpers/pathspec_test.go +++ b/helpers/pathspec_test.go @@ -40,8 +40,9 @@ func TestNewPathSpecFromConfig(t *testing.T) { v.Set("staticDir", "thestatic") v.Set("theme", "thetheme") - p := NewPathSpec(hugofs.NewMem(v), l) + p, err := NewPathSpec(hugofs.NewMem(v), l) + require.NoError(t, err) require.True(t, p.canonifyURLs) require.True(t, p.defaultContentLanguageInSubdir) require.True(t, p.disablePathToLower) diff --git a/helpers/testhelpers_test.go b/helpers/testhelpers_test.go index 303f9feb6..d5a1b60ed 100644 --- a/helpers/testhelpers_test.go +++ b/helpers/testhelpers_test.go @@ -8,7 +8,8 @@ import ( func newTestPathSpec(fs *hugofs.Fs, v *viper.Viper) *PathSpec { l := NewDefaultLanguage(v) - return NewPathSpec(fs, l) + ps, _ := NewPathSpec(fs, l) + return ps } func newTestDefaultPathSpec(configKeyValues ...interface{}) *PathSpec { diff --git a/helpers/url_test.go b/helpers/url_test.go index b53e2e6cc..499388259 100644 --- a/helpers/url_test.go +++ b/helpers/url_test.go @@ -28,7 +28,7 @@ func TestURLize(t *testing.T) { v := viper.New() l := NewDefaultLanguage(v) - p := NewPathSpec(hugofs.NewMem(v), l) + p, _ := NewPathSpec(hugofs.NewMem(v), l) tests := []struct { input string @@ -89,7 +89,7 @@ func doTestAbsURL(t *testing.T, defaultInSubDir, addLanguage, multilingual bool, for _, test := range tests { v.Set("baseURL", test.baseURL) l := NewLanguage(lang, v) - p := NewPathSpec(hugofs.NewMem(v), l) + p, _ := NewPathSpec(hugofs.NewMem(v), l) output := p.AbsURL(test.input, addLanguage) expected := test.expected @@ -167,7 +167,7 @@ func doTestRelURL(t *testing.T, defaultInSubDir, addLanguage, multilingual bool, v.Set("baseURL", test.baseURL) v.Set("canonifyURLs", test.canonify) l := NewLanguage(lang, v) - p := NewPathSpec(hugofs.NewMem(v), l) + p, _ := NewPathSpec(hugofs.NewMem(v), l) output := p.RelURL(test.input, addLanguage) @@ -255,7 +255,7 @@ func TestURLPrep(t *testing.T) { v := viper.New() v.Set("uglyURLs", d.ugly) l := NewDefaultLanguage(v) - p := NewPathSpec(hugofs.NewMem(v), l) + p, _ := NewPathSpec(hugofs.NewMem(v), l) output := p.URLPrep(d.input) if d.output != output { diff --git a/hugolib/hugo_sites.go b/hugolib/hugo_sites.go index d0ad57525..6c737f65a 100644 --- a/hugolib/hugo_sites.go +++ b/hugolib/hugo_sites.go @@ -92,7 +92,13 @@ func applyDepsIfNeeded(cfg deps.DepsCfg, sites ...*Site) error { if d == nil { cfg.Language = s.Language cfg.WithTemplate = s.withSiteTemplates(cfg.WithTemplate) - d = deps.New(cfg) + + var err error + d, err = deps.New(cfg) + if err != nil { + return err + } + s.Deps = d if err = d.LoadResources(); err != nil { diff --git a/hugolib/testhelpers_test.go b/hugolib/testhelpers_test.go index 1caa97e4e..d50514529 100644 --- a/hugolib/testhelpers_test.go +++ b/hugolib/testhelpers_test.go @@ -74,7 +74,8 @@ func (th testHelper) replaceDefaultContentLanguageValue(value string) string { func newTestPathSpec(fs *hugofs.Fs, v *viper.Viper) *helpers.PathSpec { l := helpers.NewDefaultLanguage(v) - return helpers.NewPathSpec(fs, l) + ps, _ := helpers.NewPathSpec(fs, l) + return ps } func newTestDefaultPathSpec() *helpers.PathSpec { @@ -82,7 +83,8 @@ func newTestDefaultPathSpec() *helpers.PathSpec { // Easier to reason about in tests. v.Set("disablePathToLower", true) fs := hugofs.NewDefault(v) - return helpers.NewPathSpec(fs, v) + ps, _ := helpers.NewPathSpec(fs, v) + return ps } func newTestCfg() (*viper.Viper, *hugofs.Fs) { diff --git a/tpl/tplimpl/template_funcs_test.go b/tpl/tplimpl/template_funcs_test.go index aa322dded..a9cf5e58b 100644 --- a/tpl/tplimpl/template_funcs_test.go +++ b/tpl/tplimpl/template_funcs_test.go @@ -289,12 +289,16 @@ urlize: bat-man } config.Fs = fs - d := deps.New(config) + d, err := deps.New(config) + if err != nil { + t.Fatal(err) + } + if err := d.LoadResources(); err != nil { t.Fatal(err) } - err := d.Tmpl.Lookup("test").Execute(&b, &data) + err = d.Tmpl.Lookup("test").Execute(&b, &data) if err != nil { t.Fatal("Got error on execute", err) @@ -2902,12 +2906,13 @@ func TestPartialCached(t *testing.T) { return nil } - de := deps.New(config) + de, err := deps.New(config) + require.NoError(t, err) require.NoError(t, de.LoadResources()) buf := new(bytes.Buffer) templ := de.Tmpl.Lookup("testroot") - err := templ.Execute(buf, &data) + err = templ.Execute(buf, &data) if err != nil { t.Fatalf("[%d] error executing template: %s", i, err) } @@ -2941,7 +2946,8 @@ func BenchmarkPartial(b *testing.B) { return nil } - de := deps.New(config) + de, err := deps.New(config) + require.NoError(b, err) require.NoError(b, de.LoadResources()) buf := new(bytes.Buffer) @@ -2972,7 +2978,8 @@ func BenchmarkPartialCached(b *testing.B) { return nil } - de := deps.New(config) + de, err := deps.New(config) + require.NoError(b, err) require.NoError(b, de.LoadResources()) buf := new(bytes.Buffer) @@ -2994,7 +3001,10 @@ func newTestFuncster() *templateFuncster { func newTestFuncsterWithViper(v *viper.Viper) *templateFuncster { config := newDepsConfig(v) - d := deps.New(config) + d, err := deps.New(config) + if err != nil { + panic(err) + } if err := d.LoadResources(); err != nil { panic(err) @@ -3013,7 +3023,8 @@ func newTestTemplate(t *testing.T, name, template string) *template.Template { return nil } - de := deps.New(config) + de, err := deps.New(config) + require.NoError(t, err) require.NoError(t, de.LoadResources()) return de.Tmpl.Lookup(name) diff --git a/tpl/tplimpl/template_test.go b/tpl/tplimpl/template_test.go index 08bcab1a7..43b834df2 100644 --- a/tpl/tplimpl/template_test.go +++ b/tpl/tplimpl/template_test.go @@ -79,7 +79,8 @@ html lang=en []byte(this.baseContent), []byte(this.innerContent)) } - a := deps.New(config) + a, err := deps.New(config) + require.NoError(t, err) if err := a.LoadResources(); err != nil { t.Fatal(err) @@ -94,7 +95,7 @@ html lang=en } var buff bytes.Buffer - err := a.Tmpl.ExecuteTemplate(&buff, "mytemplate.html", d) + err = a.Tmpl.ExecuteTemplate(&buff, "mytemplate.html", d) if err != nil && this.expectErr == 0 { t.Errorf("Test %d with root '%s' errored: %s", i, root, err) @@ -288,7 +289,8 @@ func TestTplGoFuzzReports(t *testing.T) { return templ.AddTemplate("fuzz", this.data) } - de := deps.New(config) + de, err := deps.New(config) + require.NoError(t, err) require.NoError(t, de.LoadResources()) templ := de.Tmpl.(*GoHTMLTemplate) @@ -299,7 +301,7 @@ func TestTplGoFuzzReports(t *testing.T) { t.Errorf("#1 Test %d should have errored", i) } - err := de.Tmpl.ExecuteTemplate(ioutil.Discard, "fuzz", d) + err = de.Tmpl.ExecuteTemplate(ioutil.Discard, "fuzz", d) if err != nil && this.expectErr == 0 { t.Fatalf("Test %d errored: %s", i, err)