Skip to content

Commit

Permalink
Revise the deprecation logging
Browse files Browse the repository at this point in the history
This introduces a more automatic way of increasing the log levels for deprecation log statements based on the version it was deprecated.

The thresholds are a little arbitrary, but

* We log INFO for 6 releases
* We log WARN for another 6 releases
* THen ERROR (failing the build)

This should give theme authors plenty of time to catch up without having the log filled with warnings.
  • Loading branch information
bep committed Oct 26, 2023
1 parent c4a530f commit 71fd79a
Show file tree
Hide file tree
Showing 12 changed files with 93 additions and 68 deletions.
19 changes: 6 additions & 13 deletions commands/commandeer.go
Expand Up @@ -38,6 +38,7 @@ import (

"github.com/gohugoio/hugo/common/hstrings"
"github.com/gohugoio/hugo/common/htime"
"github.com/gohugoio/hugo/common/hugo"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/common/paths"
"github.com/gohugoio/hugo/config"
Expand All @@ -50,9 +51,7 @@ import (
"github.com/spf13/cobra"
)

var (
errHelp = errors.New("help requested")
)
var errHelp = errors.New("help requested")

// Execute executes a command.
func Execute(args []string) error {
Expand Down Expand Up @@ -182,11 +181,9 @@ func (r *rootCommand) ConfigFromConfig(key int32, oldConf *commonConfig) (*commo
cfg: oldConf.cfg,
fs: fs,
}, nil

})

return cc, err

}

func (r *rootCommand) ConfigFromProvider(key int32, cfg config.Provider) (*commonConfig, error) {
Expand All @@ -211,7 +208,7 @@ func (r *rootCommand) ConfigFromProvider(key int32, cfg config.Provider) (*commo
if !cfg.IsSet("workingDir") {
cfg.Set("workingDir", dir)
} else {
if err := os.MkdirAll(cfg.GetString("workingDir"), 0777); err != nil {
if err := os.MkdirAll(cfg.GetString("workingDir"), 0o777); err != nil {
return nil, fmt.Errorf("failed to create workingDir: %w", err)
}
}
Expand Down Expand Up @@ -303,7 +300,6 @@ func (r *rootCommand) ConfigFromProvider(key int32, cfg config.Provider) (*commo
})

return cc, err

}

func (r *rootCommand) HugFromConfig(conf *commonConfig) (*hugolib.HugoSites, error) {
Expand Down Expand Up @@ -348,7 +344,6 @@ func (r *rootCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, args
err := b.build()
return err
}()

if err != nil {
return err
}
Expand Down Expand Up @@ -434,12 +429,13 @@ func (r *rootCommand) createLogger(running bool) (loggers.Logger, error) {
}
} else {
if r.verbose {
helpers.Deprecated("--verbose", "use --logLevel info", false)
hugo.Deprecate("--verbose", "use --logLevel info", "v0.114.0")
hugo.Deprecate("--verbose", "use --logLevel info", "v0.114.0")
level = logg.LevelInfo
}

if r.debug {
helpers.Deprecated("--debug", "use --logLevel debug", false)
hugo.Deprecate("--debug", "use --logLevel debug", "v0.114.0")
level = logg.LevelDebug
}
}
Expand All @@ -453,7 +449,6 @@ func (r *rootCommand) createLogger(running bool) (loggers.Logger, error) {
}

return loggers.New(optsLogger), nil

}

func (r *rootCommand) Reset() {
Expand Down Expand Up @@ -519,7 +514,6 @@ func applyLocalFlagsBuildConfig(cmd *cobra.Command, r *rootCommand) {
_ = cmd.Flags().SetAnnotation("cacheDir", cobra.BashCompSubdirsInDir, []string{})
cmd.Flags().StringP("contentDir", "c", "", "filesystem path to content directory")
_ = cmd.Flags().SetAnnotation("theme", cobra.BashCompSubdirsInDir, []string{"themes"})

}

// Flags needed to do a build (used by hugo and hugo server commands)
Expand Down Expand Up @@ -558,7 +552,6 @@ func applyLocalFlagsBuild(cmd *cobra.Command, r *rootCommand) {
cmd.Flags().StringSlice("disableKinds", []string{}, "disable different kind of pages (home, RSS etc.)")
cmd.Flags().Bool("minify", false, "minify any supported output format (HTML, XML etc.)")
_ = cmd.Flags().SetAnnotation("destination", cobra.BashCompSubdirsInDir, []string{})

}

func (r *rootCommand) timeTrack(start time.Time, name string) {
Expand Down
56 changes: 50 additions & 6 deletions common/hugo/hugo.go
Expand Up @@ -22,14 +22,15 @@ import (
"sort"
"strings"
"sync"
"time"

godartsassv1 "github.com/bep/godartsass"
"github.com/bep/logg"
"github.com/mitchellh/mapstructure"

"time"

"github.com/bep/godartsass/v2"
"github.com/gohugoio/hugo/common/hexec"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/hugofs/files"

"github.com/spf13/afero"
Expand Down Expand Up @@ -183,8 +184,10 @@ type buildInfo struct {
*debug.BuildInfo
}

var bInfo *buildInfo
var bInfoInit sync.Once
var (
bInfo *buildInfo
bInfoInit sync.Once
)

func getBuildInfo() *buildInfo {
bInfoInit.Do(func() {
Expand All @@ -211,7 +214,6 @@ func getBuildInfo() *buildInfo {
bInfo.GoArch = s.Value
}
}

})

return bInfo
Expand Down Expand Up @@ -255,7 +257,7 @@ func GetDependencyListNonGo() []string {
}

if dartSass := dartSassVersion(); dartSass.ProtocolVersion != "" {
var dartSassPath = "github.com/sass/dart-sass-embedded"
dartSassPath := "github.com/sass/dart-sass-embedded"
if IsDartSassV2() {
dartSassPath = "github.com/sass/dart-sass"
}
Expand Down Expand Up @@ -346,3 +348,45 @@ var (
func IsDartSassV2() bool {
return !strings.Contains(DartSassBinaryName, "embedded")
}

// Deprecate informs about a deprecation starting at the given version.
//
// A deprecation typically needs a simple change in the template, but doing so will make the template incompatible with older versions.
// Theme maintainers generally want
// 1. No warnings or errors in the console when building a Hugo site.
// 2. Their theme to work for at least the last few Hugo versions.
func Deprecate(item, alternative string, version string) {
level := deprecationLogLevelFromVersion(version)
DeprecateLevel(item, alternative, version, level)
}

// DeprecateLevel informs about a deprecation logging at the given level.
func DeprecateLevel(item, alternative, version string, level logg.Level) {
var msg string
if level == logg.LevelError {
msg = fmt.Sprintf("%s was deprecated in Hugo %s and will be removed in Hugo %s. %s", item, version, CurrentVersion.Next().ReleaseVersion(), alternative)
} else {
msg = fmt.Sprintf("%s was deprecated in Hugo %s and will be removed in a future release. %s", item, version, alternative)
}

loggers.Log().Logger().WithLevel(level).Logf(msg)
}

// We ususally do about one minor version a month.
// We want people to run at least the current and previous version without any warnings.
// We want people who don't update Hugo that often to see the warnings and errors before we remove the feature.
func deprecationLogLevelFromVersion(ver string) logg.Level {
from := MustParseVersion(ver)
to := CurrentVersion
minorDiff := to.Minor - from.Minor
switch {
case minorDiff >= 12:
// Start failing the build after about a year.
return logg.LevelError
case minorDiff >= 6:
// Start printing warnings after about six months.
return logg.LevelWarn
default:
return logg.LevelInfo
}
}
15 changes: 15 additions & 0 deletions common/hugo/hugo_test.go
Expand Up @@ -17,6 +17,7 @@ import (
"fmt"
"testing"

"github.com/bep/logg"
qt "github.com/frankban/quicktest"
)

Expand Down Expand Up @@ -49,6 +50,20 @@ func TestHugoInfo(t *testing.T) {
c.Assert(devHugoInfo.IsServer(), qt.Equals, true)
}

func TestDeprecationLogLevelFromVersion(t *testing.T) {
c := qt.New(t)

c.Assert(deprecationLogLevelFromVersion("0.55.0"), qt.Equals, logg.LevelError)
ver := CurrentVersion
c.Assert(deprecationLogLevelFromVersion(ver.String()), qt.Equals, logg.LevelInfo)
ver.Minor -= 1
c.Assert(deprecationLogLevelFromVersion(ver.String()), qt.Equals, logg.LevelInfo)
ver.Minor -= 6
c.Assert(deprecationLogLevelFromVersion(ver.String()), qt.Equals, logg.LevelWarn)
ver.Minor -= 6
c.Assert(deprecationLogLevelFromVersion(ver.String()), qt.Equals, logg.LevelError)
}

type testConfig struct {
environment string
running bool
Expand Down
9 changes: 5 additions & 4 deletions common/hugo/version.go
Expand Up @@ -67,8 +67,11 @@ func (h VersionString) String() string {

// Compare implements the compare.Comparer interface.
func (h VersionString) Compare(other any) int {
v := MustParseVersion(h.String())
return compareVersions(v, other)
return compareVersions(h.Version(), other)
}

func (h VersionString) Version() Version {
return MustParseVersion(h.String())
}

// Eq implements the compare.Eqer interface.
Expand Down Expand Up @@ -264,7 +267,6 @@ func compareFloatWithVersion(v1 float64, v2 Version) int {

if v1maj > v2.Major {
return 1

}

if v1maj < v2.Major {
Expand All @@ -276,7 +278,6 @@ func compareFloatWithVersion(v1 float64, v2 Version) int {
}

return -1

}

func GoMinorVersion() int {
Expand Down
3 changes: 2 additions & 1 deletion config/allconfig/allconfig.go
Expand Up @@ -27,6 +27,7 @@ import (
"time"

"github.com/gohugoio/hugo/cache/filecache"
"github.com/gohugoio/hugo/common/hugo"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/common/urls"
Expand Down Expand Up @@ -784,7 +785,7 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
// We accidentally allowed it in the past, so we need to support it a little longer,
// But log a warning.
if _, found := params[kk]; !found {
helpers.Deprecated(fmt.Sprintf("config: languages.%s.%s: custom params on the language top level", k, kk), fmt.Sprintf("Put the value below [languages.%s.params]. See https://gohugo.io/content-management/multilingual/#changes-in-hugo-01120", k), false)
hugo.Deprecate(fmt.Sprintf("config: languages.%s.%s: custom params on the language top level", k, kk), fmt.Sprintf("Put the value below [languages.%s.params]. See https://gohugo.io/content-management/multilingual/#changes-in-hugo-01120", k), "v0.112.0")
params[kk] = vv
}
}
Expand Down
16 changes: 0 additions & 16 deletions helpers/general.go
Expand Up @@ -27,9 +27,6 @@ import (
"unicode"
"unicode/utf8"

"github.com/gohugoio/hugo/common/hugo"
"github.com/gohugoio/hugo/common/loggers"

"github.com/spf13/afero"

"github.com/jdkato/prose/transform"
Expand Down Expand Up @@ -246,19 +243,6 @@ func compareStringSlices(a, b []string) bool {
return true
}

// Deprecated informs about a deprecation, but only once for a given set of arguments' values.
// If the err flag is enabled, it logs as an ERROR (will exit with -1) and the text will
// point at the next Hugo release.
// The idea is two remove an item in two Hugo releases to give users and theme authors
// plenty of time to fix their templates.
func Deprecated(item, alternative string, err bool) {
if err {
loggers.Log().Errorf("%s is deprecated and will be removed in Hugo %s. %s", item, hugo.CurrentVersion.Next().ReleaseVersion(), alternative)
} else {
loggers.Log().Warnf("%s is deprecated and will be removed in a future release. %s", item, alternative)
}
}

// SliceToLower goes through the source slice and lowers all values.
func SliceToLower(s []string) []string {
if s == nil {
Expand Down
7 changes: 0 additions & 7 deletions hugolib/hugo_sites_build.go
Expand Up @@ -25,7 +25,6 @@ import (

"github.com/bep/logg"
"github.com/gohugoio/hugo/hugofs/files"
"github.com/gohugoio/hugo/langs"
"github.com/gohugoio/hugo/publisher"
"github.com/gohugoio/hugo/tpl"

Expand All @@ -40,14 +39,8 @@ import (
"github.com/gohugoio/hugo/output"

"github.com/fsnotify/fsnotify"
"github.com/gohugoio/hugo/helpers"
)

func init() {
// To avoid circular dependencies, we set this here.
langs.DeprecationFunc = helpers.Deprecated
}

// Build builds all sites. If filesystem events are provided,
// this is considered to be a potential partial rebuild.
func (h *HugoSites) Build(config BuildCfg, events ...fsnotify.Event) error {
Expand Down
6 changes: 3 additions & 3 deletions hugolib/page__meta.go
Expand Up @@ -130,7 +130,7 @@ func (p *pageMeta) Aliases() []string {
}

func (p *pageMeta) Author() page.Author {
helpers.Deprecated(".Author", "Use taxonomies.", false)
hugo.Deprecate(".Author", "Use taxonomies.", "v0.98.0")
authors := p.Authors()

for _, author := range authors {
Expand All @@ -140,7 +140,7 @@ func (p *pageMeta) Author() page.Author {
}

func (p *pageMeta) Authors() page.AuthorList {
helpers.Deprecated(".Authors", "Use taxonomies.", true)
hugo.Deprecate(".Author", "Use taxonomies.", "v0.112.0")
return nil
}

Expand Down Expand Up @@ -226,7 +226,7 @@ func (p *pageMeta) Path() string {
{{ $path = .Path }}
{{ end }}
`
helpers.Deprecated(".Path when the page is backed by a file", "We plan to use Path for a canonical source path and you probably want to check the source is a file. To get the current behaviour, you can use a construct similar to the one below:\n"+example, false)
p.s.Log.Warnln(".Path when the page is backed by a file is deprecated. We plan to use Path for a canonical source path and you probably want to check the source is a file. To get the current behaviour, you can use a construct similar to the one below:\n" + example)

}

Expand Down

0 comments on commit 71fd79a

Please sign in to comment.