From: Bjørn Erik Pedersen Date: Mon, 26 Nov 2018 09:11:22 +0000 (+0100) Subject: Add tpl/site and tpl/hugo X-Git-Tag: v0.53~40 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=831d23cb4d1ca99cdc15ed31c8ee1f981497be8f;p=brevno-suite%2Fhugo Add tpl/site and tpl/hugo This means that the current `.Site` and ´.Hugo` is available as a globals, so you can do `site.IsServer`, `hugo.Version` etc. Fixes #5470 Fixes #5467 Fixes #5503 --- diff --git a/.gitignore b/.gitignore index 568492d8..89244f12 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -hugo +/hugo docs/public* /.idea hugo.exe diff --git a/commands/commandeer.go b/commands/commandeer.go index cd2866a2..b722991a 100644 --- a/commands/commandeer.go +++ b/commands/commandeer.go @@ -17,10 +17,11 @@ import ( "bytes" "errors" - "github.com/gohugoio/hugo/common/herrors" - "io/ioutil" + "github.com/gohugoio/hugo/common/herrors" + "github.com/gohugoio/hugo/common/hugo" + jww "github.com/spf13/jwalterweatherman" "os" @@ -105,7 +106,7 @@ func (c *commandeer) getErrorWithContext() interface{} { m := make(map[string]interface{}) m["Error"] = errors.New(removeErrorPrefixFromLog(c.logger.Errors())) - m["Version"] = hugoVersionString() + m["Version"] = hugo.BuildVersionString() fe := herrors.UnwrapErrorWithFileContext(c.buildErr) if fe != nil { @@ -379,7 +380,7 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error { if themeVersionMismatch { name := filepath.Base(dir) cfg.Logger.ERROR.Printf("%s theme does not support Hugo version %s. Minimum version required is %s\n", - strings.ToUpper(name), helpers.CurrentHugoVersion.ReleaseVersion(), minVersion) + strings.ToUpper(name), hugo.CurrentVersion.ReleaseVersion(), minVersion) } return nil diff --git a/commands/genman.go b/commands/genman.go index ac4eaf8d..72004628 100644 --- a/commands/genman.go +++ b/commands/genman.go @@ -17,6 +17,7 @@ import ( "fmt" "strings" + "github.com/gohugoio/hugo/common/hugo" "github.com/gohugoio/hugo/helpers" "github.com/gohugoio/hugo/hugofs" "github.com/spf13/cobra" @@ -45,7 +46,7 @@ in the "man" directory under the current directory.`, header := &doc.GenManHeader{ Section: "1", Manual: "Hugo Manual", - Source: fmt.Sprintf("Hugo %s", helpers.CurrentHugoVersion), + Source: fmt.Sprintf("Hugo %s", hugo.CurrentVersion), } if !strings.HasSuffix(cc.genmandir, helpers.FilePathSeparator) { cc.genmandir += helpers.FilePathSeparator diff --git a/commands/hugo.go b/commands/hugo.go index 0bb15c3d..759efc17 100644 --- a/commands/hugo.go +++ b/commands/hugo.go @@ -23,6 +23,7 @@ import ( "sort" "sync/atomic" + "github.com/gohugoio/hugo/common/hugo" "github.com/pkg/errors" "github.com/gohugoio/hugo/common/herrors" @@ -1041,7 +1042,7 @@ func (c *commandeer) isThemeVsHugoVersionMismatch(fs afero.Fs) (dir string, mism } if minVersion, ok := tomlMeta["min_version"]; ok { - if helpers.CompareVersion(minVersion) > 0 { + if hugo.CompareVersion(minVersion) > 0 { return absThemeDir, true, fmt.Sprint(minVersion) } } diff --git a/commands/version.go b/commands/version.go index b85f5372..287950a2 100644 --- a/commands/version.go +++ b/commands/version.go @@ -14,16 +14,9 @@ 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/gohugoio/hugo/common/hugo" "github.com/spf13/cobra" + jww "github.com/spf13/jwalterweatherman" ) var _ cmder = (*versionCmd)(nil) @@ -47,29 +40,5 @@ func newVersionCmd() *versionCmd { } func printHugoVersion() { - jww.FEEDBACK.Println(hugoVersionString()) -} - -func hugoVersionString() string { - program := "Hugo Static Site Generator" - - version := "v" + helpers.CurrentHugoVersion.String() - if hugolib.CommitHash != "" { - version += "-" + strings.ToUpper(hugolib.CommitHash) - } - if scss.Supports() { - version += "/extended" - } - - osArch := runtime.GOOS + "/" + runtime.GOARCH - - var buildDate string - if hugolib.BuildDate != "" { - buildDate = hugolib.BuildDate - } else { - buildDate = "unknown" - } - - return fmt.Sprintf("%s %s %s BuildDate: %s", program, version, osArch, buildDate) - + jww.FEEDBACK.Println(hugo.BuildVersionString()) } diff --git a/common/hugo/hugo.go b/common/hugo/hugo.go new file mode 100644 index 00000000..b93b10bf --- /dev/null +++ b/common/hugo/hugo.go @@ -0,0 +1,45 @@ +// 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 hugo + +import ( + "fmt" + "html/template" +) + +var ( + // CommitHash contains the current Git revision. Use make to build to make + // sure this gets set. + CommitHash string + + // BuildDate contains the date of the current build. + BuildDate string +) + +// Info contains information about the current Hugo environment +type Info struct { + Version VersionString + Generator template.HTML + CommitHash string + BuildDate string +} + +func NewInfo() Info { + return Info{ + Version: CurrentVersion.Version(), + CommitHash: CommitHash, + BuildDate: BuildDate, + Generator: template.HTML(fmt.Sprintf(``, CurrentVersion.String())), + } +} diff --git a/common/hugo/hugo_test.go b/common/hugo/hugo_test.go new file mode 100644 index 00000000..18a9b594 --- /dev/null +++ b/common/hugo/hugo_test.go @@ -0,0 +1,34 @@ +// 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 hugo + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestHugoInfo(t *testing.T) { + assert := require.New(t) + + hugoInfo := NewInfo() + + assert.Equal(CurrentVersion.Version(), hugoInfo.Version) + assert.IsType(VersionString(""), hugoInfo.Version) + assert.Equal(CommitHash, hugoInfo.CommitHash) + assert.Equal(BuildDate, hugoInfo.BuildDate) + assert.Contains(hugoInfo.Generator, fmt.Sprintf("Hugo %s", hugoInfo.Version)) + +} diff --git a/common/hugo/site.go b/common/hugo/site.go new file mode 100644 index 00000000..08391858 --- /dev/null +++ b/common/hugo/site.go @@ -0,0 +1,24 @@ +// 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 hugo + +import "github.com/gohugoio/hugo/langs" + +// Site represents a site in the build. This is currently a very narrow interface, +// but the actual implementation will be richer, see hugolib.SiteInfo. +type Site interface { + Language() *langs.Language + IsServer() bool + Hugo() Info +} diff --git a/common/hugo/vars_extended.go b/common/hugo/vars_extended.go new file mode 100644 index 00000000..20683b80 --- /dev/null +++ b/common/hugo/vars_extended.go @@ -0,0 +1,18 @@ +// 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. + +// +build extended + +package hugo + +var isExtended = true diff --git a/common/hugo/vars_regular.go b/common/hugo/vars_regular.go new file mode 100644 index 00000000..e1ece83f --- /dev/null +++ b/common/hugo/vars_regular.go @@ -0,0 +1,18 @@ +// 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. + +// +build !extended + +package hugo + +var isExtended = false diff --git a/common/hugo/version.go b/common/hugo/version.go new file mode 100644 index 00000000..204f8f74 --- /dev/null +++ b/common/hugo/version.go @@ -0,0 +1,239 @@ +// 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 hugo + +import ( + "fmt" + + "runtime" + "strings" + + "github.com/gohugoio/hugo/compare" + "github.com/spf13/cast" +) + +// Version represents the Hugo build version. +type Version struct { + // Major and minor version. + Number float32 + + // Increment this for bug releases + PatchLevel int + + // HugoVersionSuffix is the suffix used in the Hugo version string. + // It will be blank for release versions. + Suffix string +} + +var ( + _ compare.Eqer = (*VersionString)(nil) + _ compare.Comparer = (*VersionString)(nil) +) + +func (v Version) String() string { + return version(v.Number, v.PatchLevel, v.Suffix) +} + +// Version returns the Hugo version. +func (v Version) Version() VersionString { + return VersionString(v.String()) +} + +// VersionString represents a Hugo version string. +type VersionString string + +func (h VersionString) String() string { + return string(h) +} + +// Compare implements the compare.Comparer interface. +func (h VersionString) Compare(other interface{}) int { + v := MustParseVersion(h.String()) + return compareVersionsWithSuffix(v.Number, v.PatchLevel, v.Suffix, other) +} + +// Eq implements the compare.Eqer interface. +func (h VersionString) Eq(other interface{}) bool { + s, err := cast.ToStringE(other) + if err != nil { + return false + } + return s == h.String() +} + +var versionSuffixes = []string{"-test", "-DEV"} + +// ParseVersion parses a version string. +func ParseVersion(s string) (Version, error) { + var vv Version + for _, suffix := range versionSuffixes { + if strings.HasSuffix(s, suffix) { + vv.Suffix = suffix + s = strings.TrimSuffix(s, suffix) + } + } + + v, p := parseVersion(s) + + vv.Number = v + vv.PatchLevel = p + + return vv, nil +} + +// MustParseVersion parses a version string +// and panics if any error occurs. +func MustParseVersion(s string) Version { + vv, err := ParseVersion(s) + if err != nil { + panic(err) + } + return vv +} + +// ReleaseVersion represents the release version. +func (v Version) ReleaseVersion() Version { + v.Suffix = "" + return v +} + +// Next returns the next Hugo release version. +func (v Version) Next() Version { + return Version{Number: v.Number + 0.01} +} + +// Prev returns the previous Hugo release version. +func (v Version) Prev() Version { + return Version{Number: v.Number - 0.01} +} + +// NextPatchLevel returns the next patch/bugfix Hugo version. +// This will be a patch increment on the previous Hugo version. +func (v Version) NextPatchLevel(level int) Version { + return Version{Number: v.Number - 0.01, PatchLevel: level} +} + +// BuildVersionString creates a version string. This is what you see when +// running "hugo version". +func BuildVersionString() string { + program := "Hugo Static Site Generator" + + version := "v" + CurrentVersion.String() + if CommitHash != "" { + version += "-" + strings.ToUpper(CommitHash) + } + if isExtended { + version += "/extended" + } + + osArch := runtime.GOOS + "/" + runtime.GOARCH + + var buildDate string + if BuildDate != "" { + buildDate = BuildDate + } else { + buildDate = "unknown" + } + + return fmt.Sprintf("%s %s %s BuildDate: %s", program, version, osArch, buildDate) + +} + +func version(version float32, patchVersion int, suffix string) string { + if patchVersion > 0 { + return fmt.Sprintf("%.2f.%d%s", version, patchVersion, suffix) + } + return fmt.Sprintf("%.2f%s", version, suffix) +} + +// CompareVersion compares the given version string or number against the +// running Hugo version. +// It returns -1 if the given version is less than, 0 if equal and 1 if greater than +// the running version. +func CompareVersion(version interface{}) int { + return compareVersionsWithSuffix(CurrentVersion.Number, CurrentVersion.PatchLevel, CurrentVersion.Suffix, version) +} + +func compareVersions(inVersion float32, inPatchVersion int, in interface{}) int { + return compareVersionsWithSuffix(inVersion, inPatchVersion, "", in) +} + +func compareVersionsWithSuffix(inVersion float32, inPatchVersion int, suffix string, in interface{}) int { + var c int + switch d := in.(type) { + case float64: + c = compareFloatVersions(inVersion, float32(d)) + case float32: + c = compareFloatVersions(inVersion, d) + case int: + c = compareFloatVersions(inVersion, float32(d)) + case int32: + c = compareFloatVersions(inVersion, float32(d)) + case int64: + c = compareFloatVersions(inVersion, float32(d)) + default: + s, err := cast.ToStringE(in) + if err != nil { + return -1 + } + + v, err := ParseVersion(s) + if err != nil { + return -1 + } + + if v.Number == inVersion && v.PatchLevel == inPatchVersion { + return strings.Compare(suffix, v.Suffix) + } + + if v.Number < inVersion || (v.Number == inVersion && v.PatchLevel < inPatchVersion) { + return -1 + } + + return 1 + } + + if c == 0 && suffix != "" { + return 1 + } + + return c +} + +func parseVersion(s string) (float32, int) { + var ( + v float32 + p int + ) + + if strings.Count(s, ".") == 2 { + li := strings.LastIndex(s, ".") + p = cast.ToInt(s[li+1:]) + s = s[:li] + } + + v = float32(cast.ToFloat64(s)) + + return v, p +} + +func compareFloatVersions(version float32, v float32) int { + if v == version { + return 0 + } + if v < version { + return -1 + } + return 1 +} diff --git a/common/hugo/version_current.go b/common/hugo/version_current.go new file mode 100644 index 00000000..0a42f302 --- /dev/null +++ b/common/hugo/version_current.go @@ -0,0 +1,22 @@ +// 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 hugo + +// CurrentVersion represents the current build version. +// This should be the only one. +var CurrentVersion = Version{ + Number: 0.53, + PatchLevel: 0, + Suffix: "-DEV", +} diff --git a/common/hugo/version_test.go b/common/hugo/version_test.go new file mode 100644 index 00000000..fb28750e --- /dev/null +++ b/common/hugo/version_test.go @@ -0,0 +1,70 @@ +// Copyright 2015 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 hugo + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestHugoVersion(t *testing.T) { + assert.Equal(t, "0.15-DEV", version(0.15, 0, "-DEV")) + assert.Equal(t, "0.15.2-DEV", version(0.15, 2, "-DEV")) + + v := Version{Number: 0.21, PatchLevel: 0, Suffix: "-DEV"} + + require.Equal(t, v.ReleaseVersion().String(), "0.21") + require.Equal(t, "0.21-DEV", v.String()) + require.Equal(t, "0.22", v.Next().String()) + nextVersionString := v.Next().Version() + require.Equal(t, "0.22", nextVersionString.String()) + require.True(t, nextVersionString.Eq("0.22")) + require.False(t, nextVersionString.Eq("0.21")) + require.True(t, nextVersionString.Eq(nextVersionString)) + require.Equal(t, "0.20.3", v.NextPatchLevel(3).String()) +} + +func TestCompareVersions(t *testing.T) { + require.Equal(t, 0, compareVersions(0.20, 0, 0.20)) + require.Equal(t, 0, compareVersions(0.20, 0, float32(0.20))) + require.Equal(t, 0, compareVersions(0.20, 0, float64(0.20))) + require.Equal(t, 1, compareVersions(0.19, 1, 0.20)) + require.Equal(t, 1, compareVersions(0.19, 3, "0.20.2")) + require.Equal(t, -1, compareVersions(0.19, 1, 0.01)) + require.Equal(t, 1, compareVersions(0, 1, 3)) + require.Equal(t, 1, compareVersions(0, 1, int32(3))) + require.Equal(t, 1, compareVersions(0, 1, int64(3))) + require.Equal(t, 0, compareVersions(0.20, 0, "0.20")) + require.Equal(t, 0, compareVersions(0.20, 1, "0.20.1")) + require.Equal(t, -1, compareVersions(0.20, 1, "0.20")) + require.Equal(t, 1, compareVersions(0.20, 0, "0.20.1")) + require.Equal(t, 1, compareVersions(0.20, 1, "0.20.2")) + require.Equal(t, 1, compareVersions(0.21, 1, "0.22.1")) + require.Equal(t, -1, compareVersions(0.22, 0, "0.22-DEV")) + require.Equal(t, 1, compareVersions(0.22, 0, "0.22.1-DEV")) + require.Equal(t, 1, compareVersionsWithSuffix(0.22, 0, "-DEV", "0.22")) + require.Equal(t, -1, compareVersionsWithSuffix(0.22, 1, "-DEV", "0.22")) + require.Equal(t, 0, compareVersionsWithSuffix(0.22, 1, "-DEV", "0.22.1-DEV")) + +} + +func TestParseHugoVersion(t *testing.T) { + require.Equal(t, "0.25", MustParseVersion("0.25").String()) + require.Equal(t, "0.25.2", MustParseVersion("0.25.2").String()) + require.Equal(t, "0.25-test", MustParseVersion("0.25-test").String()) + require.Equal(t, "0.25-DEV", MustParseVersion("0.25-DEV").String()) + +} diff --git a/deps/deps.go b/deps/deps.go index de6d8b52..46f4f773 100644 --- a/deps/deps.go +++ b/deps/deps.go @@ -7,6 +7,7 @@ import ( "github.com/pkg/errors" "github.com/gohugoio/hugo/cache/filecache" + "github.com/gohugoio/hugo/common/hugo" "github.com/gohugoio/hugo/common/loggers" "github.com/gohugoio/hugo/config" "github.com/gohugoio/hugo/helpers" @@ -62,8 +63,12 @@ type Deps struct { // The translation func to use Translate func(translationID string, args ...interface{}) string `json:"-"` + // The language in use. TODO(bep) consolidate with site Language *langs.Language + // The site building. + Site hugo.Site + // All the output formats available for the current site. OutputFormatsConfig output.Formats @@ -230,6 +235,7 @@ func New(cfg DepsCfg) (*Deps, error) { ResourceSpec: resourceSpec, Cfg: cfg.Language, Language: cfg.Language, + Site: cfg.Site, FileCaches: fileCaches, BuildStartListeners: &Listeners{}, Timeout: time.Duration(timeoutms) * time.Millisecond, @@ -245,7 +251,7 @@ func New(cfg DepsCfg) (*Deps, error) { // ForLanguage creates a copy of the Deps with the language dependent // parts switched out. -func (d Deps) ForLanguage(cfg DepsCfg) (*Deps, error) { +func (d Deps) ForLanguage(cfg DepsCfg, onCreated func(d *Deps) error) (*Deps, error) { l := cfg.Language var err error @@ -259,6 +265,8 @@ func (d Deps) ForLanguage(cfg DepsCfg) (*Deps, error) { return nil, err } + d.Site = cfg.Site + // The resource cache is global so reuse. // TODO(bep) clean up these inits. resourceCache := d.ResourceSpec.ResourceCache @@ -271,6 +279,12 @@ func (d Deps) ForLanguage(cfg DepsCfg) (*Deps, error) { d.Cfg = l d.Language = l + if onCreated != nil { + if err = onCreated(&d); err != nil { + return nil, err + } + } + if err := d.translationProvider.Clone(&d); err != nil { return nil, err } @@ -299,6 +313,9 @@ type DepsCfg struct { // The language to use. Language *langs.Language + // The Site in use + Site hugo.Site + // The configuration to use. Cfg config.Provider diff --git a/goreleaser-extended.yml b/goreleaser-extended.yml index 31b52d7b..004e9495 100644 --- a/goreleaser-extended.yml +++ b/goreleaser-extended.yml @@ -2,7 +2,7 @@ project_name: hugo_extended builds: - binary: hugo ldflags: - - -s -w -X github.com/gohugoio/hugo/hugolib.BuildDate={{.Date}} + - -s -w -X github.com/gohugoio/hugo/common/hugo.BuildDate={{.Date}} -X github.com/gohugoio/hugo/common/hugo.CommitHash={{ .ShortCommit }} - "-extldflags '-static'" env: - CGO_ENABLED=1 diff --git a/goreleaser.yml b/goreleaser.yml index d2cdf720..0e900601 100644 --- a/goreleaser.yml +++ b/goreleaser.yml @@ -2,7 +2,7 @@ project_name: hugo build: main: main.go binary: hugo - ldflags: -s -w -X github.com/gohugoio/hugo/hugolib.BuildDate={{.Date}} + ldflags: -s -w -X github.com/gohugoio/hugo/common/hugo.BuildDate={{.Date}} -X github.com/gohugoio/hugo/common/hugo.CommitHash={{ .ShortCommit }} env: - CGO_ENABLED=0 goos: diff --git a/helpers/general.go b/helpers/general.go index 43a92131..cfabab5a 100644 --- a/helpers/general.go +++ b/helpers/general.go @@ -27,6 +27,8 @@ import ( "unicode" "unicode/utf8" + "github.com/gohugoio/hugo/common/hugo" + "github.com/gohugoio/hugo/hugofs" "github.com/spf13/afero" @@ -324,7 +326,7 @@ func InitLoggers() { // plenty of time to fix their templates. func Deprecated(object, item, alternative string, err bool) { if err { - DistinctErrorLog.Printf("%s's %s is deprecated and will be removed in Hugo %s. %s", object, item, CurrentHugoVersion.Next().ReleaseVersion(), alternative) + DistinctErrorLog.Printf("%s's %s is deprecated and will be removed in Hugo %s. %s", object, item, hugo.CurrentVersion.Next().ReleaseVersion(), alternative) } else { // Make sure the users see this while avoiding build breakage. This will not lead to an os.Exit(-1) diff --git a/helpers/hugo.go b/helpers/hugo.go deleted file mode 100644 index 3ad4f937..00000000 --- a/helpers/hugo.go +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright 2015 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 helpers - -import ( - "fmt" - "strings" - - "github.com/gohugoio/hugo/compare" - "github.com/spf13/cast" -) - -// HugoVersion represents the Hugo build version. -type HugoVersion struct { - // Major and minor version. - Number float32 - - // Increment this for bug releases - PatchLevel int - - // HugoVersionSuffix is the suffix used in the Hugo version string. - // It will be blank for release versions. - Suffix string -} - -var ( - _ compare.Eqer = (*HugoVersionString)(nil) - _ compare.Comparer = (*HugoVersionString)(nil) -) - -func (v HugoVersion) String() string { - return hugoVersion(v.Number, v.PatchLevel, v.Suffix) -} - -// Version returns the Hugo version. -func (v HugoVersion) Version() HugoVersionString { - return HugoVersionString(v.String()) -} - -// HugoVersionString represents a Hugo version string. -type HugoVersionString string - -func (h HugoVersionString) String() string { - return string(h) -} - -// Compare implements the compare.Comparer interface. -func (h HugoVersionString) Compare(other interface{}) int { - v := MustParseHugoVersion(h.String()) - return compareVersionsWithSuffix(v.Number, v.PatchLevel, v.Suffix, other) -} - -// Eq implements the compare.Eqer interface. -func (h HugoVersionString) Eq(other interface{}) bool { - s, err := cast.ToStringE(other) - if err != nil { - return false - } - return s == h.String() -} - -var versionSuffixes = []string{"-test", "-DEV"} - -// ParseHugoVersion parses a version string. -func ParseHugoVersion(s string) (HugoVersion, error) { - var vv HugoVersion - for _, suffix := range versionSuffixes { - if strings.HasSuffix(s, suffix) { - vv.Suffix = suffix - s = strings.TrimSuffix(s, suffix) - } - } - - v, p := parseVersion(s) - - vv.Number = v - vv.PatchLevel = p - - return vv, nil -} - -// MustParseHugoVersion parses a version string -// and panics if any error occurs. -func MustParseHugoVersion(s string) HugoVersion { - vv, err := ParseHugoVersion(s) - if err != nil { - panic(err) - } - return vv -} - -// ReleaseVersion represents the release version. -func (v HugoVersion) ReleaseVersion() HugoVersion { - v.Suffix = "" - return v -} - -// Next returns the next Hugo release version. -func (v HugoVersion) Next() HugoVersion { - return HugoVersion{Number: v.Number + 0.01} -} - -// Prev returns the previous Hugo release version. -func (v HugoVersion) Prev() HugoVersion { - return HugoVersion{Number: v.Number - 0.01} -} - -// NextPatchLevel returns the next patch/bugfix Hugo version. -// This will be a patch increment on the previous Hugo version. -func (v HugoVersion) NextPatchLevel(level int) HugoVersion { - return HugoVersion{Number: v.Number - 0.01, PatchLevel: level} -} - -// CurrentHugoVersion represents the current build version. -// This should be the only one. -var CurrentHugoVersion = HugoVersion{ - Number: 0.53, - PatchLevel: 0, - Suffix: "-DEV", -} - -func hugoVersion(version float32, patchVersion int, suffix string) string { - if patchVersion > 0 { - return fmt.Sprintf("%.2f.%d%s", version, patchVersion, suffix) - } - return fmt.Sprintf("%.2f%s", version, suffix) -} - -// CompareVersion compares the given version string or number against the -// running Hugo version. -// It returns -1 if the given version is less than, 0 if equal and 1 if greater than -// the running version. -func CompareVersion(version interface{}) int { - return compareVersionsWithSuffix(CurrentHugoVersion.Number, CurrentHugoVersion.PatchLevel, CurrentHugoVersion.Suffix, version) -} - -func compareVersions(inVersion float32, inPatchVersion int, in interface{}) int { - return compareVersionsWithSuffix(inVersion, inPatchVersion, "", in) -} - -func compareVersionsWithSuffix(inVersion float32, inPatchVersion int, suffix string, in interface{}) int { - var c int - switch d := in.(type) { - case float64: - c = compareFloatVersions(inVersion, float32(d)) - case float32: - c = compareFloatVersions(inVersion, d) - case int: - c = compareFloatVersions(inVersion, float32(d)) - case int32: - c = compareFloatVersions(inVersion, float32(d)) - case int64: - c = compareFloatVersions(inVersion, float32(d)) - default: - s, err := cast.ToStringE(in) - if err != nil { - return -1 - } - - v, err := ParseHugoVersion(s) - if err != nil { - return -1 - } - - if v.Number == inVersion && v.PatchLevel == inPatchVersion { - return strings.Compare(suffix, v.Suffix) - } - - if v.Number < inVersion || (v.Number == inVersion && v.PatchLevel < inPatchVersion) { - return -1 - } - - return 1 - } - - if c == 0 && suffix != "" { - return 1 - } - - return c -} - -func parseVersion(s string) (float32, int) { - var ( - v float32 - p int - ) - - if strings.Count(s, ".") == 2 { - li := strings.LastIndex(s, ".") - p = cast.ToInt(s[li+1:]) - s = s[:li] - } - - v = float32(cast.ToFloat64(s)) - - return v, p -} - -func compareFloatVersions(version float32, v float32) int { - if v == version { - return 0 - } - if v < version { - return -1 - } - return 1 -} diff --git a/helpers/hugo_test.go b/helpers/hugo_test.go deleted file mode 100644 index 1c2d8961..00000000 --- a/helpers/hugo_test.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2015 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 helpers - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestHugoVersion(t *testing.T) { - assert.Equal(t, "0.15-DEV", hugoVersion(0.15, 0, "-DEV")) - assert.Equal(t, "0.15.2-DEV", hugoVersion(0.15, 2, "-DEV")) - - v := HugoVersion{Number: 0.21, PatchLevel: 0, Suffix: "-DEV"} - - require.Equal(t, v.ReleaseVersion().String(), "0.21") - require.Equal(t, "0.21-DEV", v.String()) - require.Equal(t, "0.22", v.Next().String()) - nextVersionString := v.Next().Version() - require.Equal(t, "0.22", nextVersionString.String()) - require.True(t, nextVersionString.Eq("0.22")) - require.False(t, nextVersionString.Eq("0.21")) - require.True(t, nextVersionString.Eq(nextVersionString)) - require.Equal(t, "0.20.3", v.NextPatchLevel(3).String()) -} - -func TestCompareVersions(t *testing.T) { - require.Equal(t, 0, compareVersions(0.20, 0, 0.20)) - require.Equal(t, 0, compareVersions(0.20, 0, float32(0.20))) - require.Equal(t, 0, compareVersions(0.20, 0, float64(0.20))) - require.Equal(t, 1, compareVersions(0.19, 1, 0.20)) - require.Equal(t, 1, compareVersions(0.19, 3, "0.20.2")) - require.Equal(t, -1, compareVersions(0.19, 1, 0.01)) - require.Equal(t, 1, compareVersions(0, 1, 3)) - require.Equal(t, 1, compareVersions(0, 1, int32(3))) - require.Equal(t, 1, compareVersions(0, 1, int64(3))) - require.Equal(t, 0, compareVersions(0.20, 0, "0.20")) - require.Equal(t, 0, compareVersions(0.20, 1, "0.20.1")) - require.Equal(t, -1, compareVersions(0.20, 1, "0.20")) - require.Equal(t, 1, compareVersions(0.20, 0, "0.20.1")) - require.Equal(t, 1, compareVersions(0.20, 1, "0.20.2")) - require.Equal(t, 1, compareVersions(0.21, 1, "0.22.1")) - require.Equal(t, -1, compareVersions(0.22, 0, "0.22-DEV")) - require.Equal(t, 1, compareVersions(0.22, 0, "0.22.1-DEV")) - require.Equal(t, 1, compareVersionsWithSuffix(0.22, 0, "-DEV", "0.22")) - require.Equal(t, -1, compareVersionsWithSuffix(0.22, 1, "-DEV", "0.22")) - require.Equal(t, 0, compareVersionsWithSuffix(0.22, 1, "-DEV", "0.22.1-DEV")) - -} - -func TestParseHugoVersion(t *testing.T) { - require.Equal(t, "0.25", MustParseHugoVersion("0.25").String()) - require.Equal(t, "0.25.2", MustParseHugoVersion("0.25.2").String()) - require.Equal(t, "0.25-test", MustParseHugoVersion("0.25-test").String()) - require.Equal(t, "0.25-DEV", MustParseHugoVersion("0.25-DEV").String()) - -} diff --git a/htesting/test_structs.go b/htesting/test_structs.go new file mode 100644 index 00000000..168c848a --- /dev/null +++ b/htesting/test_structs.go @@ -0,0 +1,51 @@ +// 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 htesting + +import ( + "github.com/gohugoio/hugo/common/hugo" + "github.com/gohugoio/hugo/langs" + "github.com/spf13/viper" +) + +type testSite struct { + h hugo.Info + l *langs.Language +} + +func (t testSite) Hugo() hugo.Info { + return t.h +} + +func (t testSite) IsServer() bool { + return false +} + +func (t testSite) Language() *langs.Language { + return t.l +} + +// NewTestHugoSite creates a new minimal test site. +func NewTestHugoSite() hugo.Site { + return testSite{ + h: hugo.NewInfo(), + l: langs.NewLanguage("en", newTestConfig()), + } +} + +func newTestConfig() *viper.Viper { + v := viper.New() + v.Set("contentDir", "content") + return v +} diff --git a/hugolib/hugo_info.go b/hugolib/hugo_info.go deleted file mode 100644 index 303231ed..00000000 --- a/hugolib/hugo_info.go +++ /dev/null @@ -1,49 +0,0 @@ -// 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 hugolib - -import ( - "fmt" - "html/template" - - "github.com/gohugoio/hugo/helpers" -) - -var ( - // CommitHash contains the current Git revision. Use make to build to make - // sure this gets set. - CommitHash string - - // BuildDate contains the date of the current build. - BuildDate string -) - -var hugoInfo *HugoInfo - -// HugoInfo contains information about the current Hugo environment -type HugoInfo struct { - Version helpers.HugoVersionString - Generator template.HTML - CommitHash string - BuildDate string -} - -func init() { - hugoInfo = &HugoInfo{ - Version: helpers.CurrentHugoVersion.Version(), - CommitHash: CommitHash, - BuildDate: BuildDate, - Generator: template.HTML(fmt.Sprintf(``, helpers.CurrentHugoVersion.String())), - } -} diff --git a/hugolib/hugo_info_test.go b/hugolib/hugo_info_test.go deleted file mode 100644 index 0a34330a..00000000 --- a/hugolib/hugo_info_test.go +++ /dev/null @@ -1,33 +0,0 @@ -// 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 hugolib - -import ( - "fmt" - "testing" - - "github.com/gohugoio/hugo/helpers" - "github.com/stretchr/testify/require" -) - -func TestHugoInfo(t *testing.T) { - assert := require.New(t) - - assert.Equal(helpers.CurrentHugoVersion.Version(), hugoInfo.Version) - assert.IsType(helpers.HugoVersionString(""), hugoInfo.Version) - assert.Equal(CommitHash, hugoInfo.CommitHash) - assert.Equal(BuildDate, hugoInfo.BuildDate) - assert.Contains(hugoInfo.Generator, fmt.Sprintf("Hugo %s", hugoInfo.Version)) - -} diff --git a/hugolib/hugo_sites.go b/hugolib/hugo_sites.go index 9cc09192..043e049d 100644 --- a/hugolib/hugo_sites.go +++ b/hugolib/hugo_sites.go @@ -21,12 +21,13 @@ import ( "strings" "sync" + "github.com/gohugoio/hugo/publisher" + "github.com/gohugoio/hugo/common/herrors" "github.com/gohugoio/hugo/common/loggers" "github.com/gohugoio/hugo/deps" "github.com/gohugoio/hugo/helpers" "github.com/gohugoio/hugo/langs" - "github.com/gohugoio/hugo/publisher" "github.com/gohugoio/hugo/i18n" "github.com/gohugoio/hugo/tpl" @@ -224,6 +225,27 @@ func applyDeps(cfg deps.DepsCfg, sites ...*Site) error { continue } + onCreated := func(d *deps.Deps) error { + s.Deps = d + + // Set up the main publishing chain. + s.publisher = publisher.NewDestinationPublisher(d.PathSpec.BaseFs.PublishFs, s.outputFormatsConfig, s.mediaTypesConfig, cfg.Cfg.GetBool("minify")) + + if err := s.initializeSiteInfo(); err != nil { + return err + } + + d.Site = &s.Info + + siteConfig, err := loadSiteConfig(s.Language) + if err != nil { + return err + } + s.siteConfig = siteConfig + s.siteRefLinker, err = newSiteRefLinker(s.Language, s) + return err + } + cfg.Language = s.Language cfg.MediaTypes = s.mediaTypesConfig cfg.OutputFormats = s.outputFormatsConfig @@ -238,37 +260,23 @@ func applyDeps(cfg deps.DepsCfg, sites ...*Site) error { } d.OutputFormatsConfig = s.outputFormatsConfig - s.Deps = d + + if err := onCreated(d); err != nil { + return err + } if err = d.LoadResources(); err != nil { return err } } else { - d, err = d.ForLanguage(cfg) + d, err = d.ForLanguage(cfg, onCreated) if err != nil { return err } d.OutputFormatsConfig = s.outputFormatsConfig - s.Deps = d } - // Set up the main publishing chain. - s.publisher = publisher.NewDestinationPublisher(d.PathSpec.BaseFs.PublishFs, s.outputFormatsConfig, s.mediaTypesConfig, cfg.Cfg.GetBool("minify")) - - if err := s.initializeSiteInfo(); err != nil { - return err - } - - siteConfig, err := loadSiteConfig(s.Language) - if err != nil { - return err - } - s.siteConfig = siteConfig - s.siteRefLinker, err = newSiteRefLinker(s.Language, s) - if err != nil { - return err - } } return nil diff --git a/hugolib/page.go b/hugolib/page.go index f3e87be7..4c48a606 100644 --- a/hugolib/page.go +++ b/hugolib/page.go @@ -21,6 +21,8 @@ import ( "math/rand" "reflect" + "github.com/gohugoio/hugo/common/hugo" + "github.com/gohugoio/hugo/common/maps" "github.com/gohugoio/hugo/common/urls" "github.com/gohugoio/hugo/media" @@ -1873,8 +1875,8 @@ func (p *Page) copy(initContent bool) *Page { return &c } -func (p *Page) Hugo() *HugoInfo { - return hugoInfo +func (p *Page) Hugo() hugo.Info { + return p.s.Info.hugoInfo } // GetPage looks up a page for the given ref. diff --git a/hugolib/page_test.go b/hugolib/page_test.go index cd8bd8ff..177ed7fb 100644 --- a/hugolib/page_test.go +++ b/hugolib/page_test.go @@ -1436,7 +1436,7 @@ func TestIndexPageSimpleMethods(t *testing.T) { {func(n *Page) bool { return n.IsNode() }}, {func(n *Page) bool { return !n.IsPage() }}, {func(n *Page) bool { return n.Scratch() != nil }}, - {func(n *Page) bool { return n.Hugo() != nil }}, + {func(n *Page) bool { return n.Hugo().Version != "" }}, } { n := s.newHomePage() diff --git a/hugolib/pages_language_merge_test.go b/hugolib/pages_language_merge_test.go index 8a4688f1..6706af3b 100644 --- a/hugolib/pages_language_merge_test.go +++ b/hugolib/pages_language_merge_test.go @@ -66,7 +66,7 @@ func TestMergeLanguages(t *testing.T) { firstNN := nnSite.RegularPages[0] assert.Equal(4, len(firstNN.Sites())) - assert.Equal("en", firstNN.Sites().First().Language.Lang) + assert.Equal("en", firstNN.Sites().First().Language().Lang) nnBundle := nnSite.getPage("page", "bundle") enBundle := enSite.getPage("page", "bundle") diff --git a/hugolib/site.go b/hugolib/site.go index 25eb34f0..d0e6c301 100644 --- a/hugolib/site.go +++ b/hugolib/site.go @@ -36,11 +36,11 @@ import ( "github.com/gohugoio/hugo/common/herrors" - _errors "github.com/pkg/errors" - + "github.com/gohugoio/hugo/common/hugo" "github.com/gohugoio/hugo/common/maps" "github.com/gohugoio/hugo/publisher" "github.com/gohugoio/hugo/resource" + _errors "github.com/pkg/errors" "github.com/gohugoio/hugo/langs" @@ -388,7 +388,7 @@ type SiteInfo struct { Social SiteSocial *PageCollections Menus *Menus - Hugo *HugoInfo + hugoInfo hugo.Info Title string RSSLink string Author map[string]interface{} @@ -405,17 +405,25 @@ type SiteInfo struct { Data *map[string]interface{} owner *HugoSites s *Site - Language *langs.Language + language *langs.Language LanguagePrefix string Languages langs.Languages defaultContentLanguageInSubdir bool sectionPagesMenu string } +func (s *SiteInfo) Language() *langs.Language { + return s.language +} + func (s *SiteInfo) Config() SiteConfig { return s.s.siteConfig } +func (s *SiteInfo) Hugo() hugo.Info { + return s.hugoInfo +} + func (s *SiteInfo) String() string { return fmt.Sprintf("Site(%q)", s.Title) } @@ -797,7 +805,10 @@ func (s *Site) processPartial(events []fsnotify.Event) (whatChanged, error) { MediaTypes: site.mediaTypesConfig, OutputFormats: site.outputFormatsConfig, } - site.Deps, err = first.Deps.ForLanguage(depsCfg) + site.Deps, err = first.Deps.ForLanguage(depsCfg, func(d *deps.Deps) error { + d.Site = &site.Info + return nil + }) if err != nil { return whatChanged{}, err } @@ -1122,7 +1133,7 @@ func (s *Site) initialize() (err error) { func (s *SiteInfo) HomeAbsURL() string { base := "" if s.IsMultiLingual() { - base = s.Language.Lang + base = s.Language().Lang } return s.owner.AbsURL(base, false) } @@ -1194,7 +1205,7 @@ func (s *Site) initializeSiteInfo() error { Social: lang.GetStringMapString("social"), LanguageCode: lang.GetString("languageCode"), Copyright: lang.GetString("copyright"), - Language: lang, + language: lang, LanguagePrefix: languagePrefix, Languages: languages, defaultContentLanguageInSubdir: defaultContentInSubDir, @@ -1211,6 +1222,7 @@ func (s *Site) initializeSiteInfo() error { Data: &s.Data, owner: s.owner, s: s, + hugoInfo: hugo.NewInfo(), // TODO(bep) make this Menu and similar into delegate methods on SiteInfo Taxonomies: s.Taxonomies, } diff --git a/hugolib/template_test.go b/hugolib/template_test.go index 9cc523cb..32ede563 100644 --- a/hugolib/template_test.go +++ b/hugolib/template_test.go @@ -236,3 +236,24 @@ Page Content b.AssertFileContent("public/page/index.html", "Base: Hi!?") } + +func TestTemplateFuncs(t *testing.T) { + + b := newTestSitesBuilder(t).WithDefaultMultiSiteConfig() + + homeTpl := `Site: {{ site.Language.Lang }} / {{ .Site.Language.Lang }} / {{ site.BaseURL }} +Hugo: {{ hugo.Generator }} +` + + b.WithTemplatesAdded( + "index.html", homeTpl, + "index.fr.html", homeTpl, + ) + + b.CreateSites().Build(BuildCfg{}) + + b.AssertFileContent("public/en/index.html", "Site: en / en / http://example.com/blog", + "Hugo: `, helpers.CurrentHugoVersion) +var hugoGeneratorTag = fmt.Sprintf(``, hugo.CurrentVersion) // HugoGenerator injects a meta generator tag for Hugo if none present. func HugoGenerator(ft transform.FromTo) error {