diff options
-rw-r--r-- | cache/filecache/filecache.go | 3 | ||||
-rw-r--r-- | commands/commandeer.go | 23 | ||||
-rw-r--r-- | commands/commands.go | 7 | ||||
-rw-r--r-- | commands/hugo.go | 10 | ||||
-rw-r--r-- | commands/hugo_test.go | 45 | ||||
-rw-r--r-- | commands/import_jekyll.go | 5 | ||||
-rw-r--r-- | commands/list.go | 8 | ||||
-rw-r--r-- | commands/list_test.go | 4 | ||||
-rw-r--r-- | commands/new_theme.go | 4 | ||||
-rw-r--r-- | commands/server.go | 7 | ||||
-rw-r--r-- | common/htime/time.go | 12 | ||||
-rw-r--r-- | common/loggers/loggers.go | 5 | ||||
-rw-r--r-- | go.mod | 1 | ||||
-rw-r--r-- | go.sum | 2 | ||||
-rw-r--r-- | hugofs/fileinfo.go | 3 | ||||
-rw-r--r-- | hugolib/content_factory.go | 3 | ||||
-rw-r--r-- | hugolib/page_test.go | 51 | ||||
-rw-r--r-- | hugolib/site.go | 6 | ||||
-rw-r--r-- | metrics/metrics.go | 3 | ||||
-rw-r--r-- | modules/collect.go | 3 | ||||
-rw-r--r-- | resources/resource/dates.go | 11 | ||||
-rw-r--r-- | tpl/collections/collections.go | 1 | ||||
-rw-r--r-- | tpl/partials/partials.go | 4 | ||||
-rw-r--r-- | tpl/time/init.go | 1 | ||||
-rw-r--r-- | tpl/time/time.go | 4 | ||||
-rw-r--r-- | tpl/tplimpl/template.go | 4 |
26 files changed, 193 insertions, 37 deletions
diff --git a/cache/filecache/filecache.go b/cache/filecache/filecache.go index 5a87382ae..3104d8ac6 100644 --- a/cache/filecache/filecache.go +++ b/cache/filecache/filecache.go @@ -24,6 +24,7 @@ import ( "sync" "time" + "github.com/gohugoio/hugo/common/htime" "github.com/gohugoio/hugo/common/hugio" "github.com/gohugoio/hugo/helpers" @@ -295,7 +296,7 @@ func (c *Cache) isExpired(modTime time.Time) bool { if c.maxAge < 0 { return false } - return c.maxAge == 0 || time.Since(modTime) > c.maxAge + return c.maxAge == 0 || htime.Since(modTime) > c.maxAge } // For testing diff --git a/commands/commandeer.go b/commands/commandeer.go index 5b192c172..20090cccd 100644 --- a/commands/commandeer.go +++ b/commands/commandeer.go @@ -15,6 +15,7 @@ package commands import ( "errors" + "fmt" "io/ioutil" "net" "os" @@ -28,9 +29,11 @@ import ( "golang.org/x/sync/semaphore" "github.com/gohugoio/hugo/common/herrors" + "github.com/gohugoio/hugo/common/htime" "github.com/gohugoio/hugo/common/hugo" "github.com/gohugoio/hugo/common/paths" + "github.com/spf13/cast" jww "github.com/spf13/jwalterweatherman" "github.com/gohugoio/hugo/common/loggers" @@ -41,6 +44,7 @@ import ( "github.com/gohugoio/hugo/hugolib" "github.com/spf13/afero" + "github.com/bep/clock" "github.com/bep/debounce" "github.com/bep/overlayfs" "github.com/gohugoio/hugo/common/types" @@ -164,6 +168,20 @@ func (c *commandeer) initFs(fs *hugofs.Fs) error { return nil } +func (c *commandeer) initClock() error { + bt := c.Cfg.GetString("clock") + if bt == "" { + return nil + } + + t, err := cast.StringToDateInDefaultLocation(bt, nil) + if err != nil { + return fmt.Errorf(`failed to parse "clock" flag: %s`, err) + } + htime.Clock = clock.Start(t) + return nil +} + func newCommandeer(mustHaveConfigFile, failOnInitErr, running bool, h *hugoBuilderCommon, f flagsToConfigHandler, cfgInit func(c *commandeer) error, subCmdVs ...*cobra.Command) (*commandeer, error) { var rebuildDebouncer func(f func()) if running { @@ -341,6 +359,11 @@ func (c *commandeer) loadConfig() error { c.configFiles = configFiles + err = c.initClock() + if err != nil { + return err + } + if l, ok := c.Cfg.Get("languagesSorted").(langs.Languages); ok { c.languagesConfigured = true c.languages = l diff --git a/commands/commands.go b/commands/commands.go index 99b0866e5..97e6d2113 100644 --- a/commands/commands.go +++ b/commands/commands.go @@ -18,6 +18,7 @@ import ( "os" "time" + "github.com/gohugoio/hugo/common/htime" "github.com/gohugoio/hugo/common/hugo" "github.com/gohugoio/hugo/common/loggers" hpaths "github.com/gohugoio/hugo/common/paths" @@ -151,7 +152,7 @@ built with love by spf13 and friends in Go. Complete documentation is available at https://gohugo.io/.`, RunE: func(cmd *cobra.Command, args []string) error { - defer cc.timeTrack(time.Now(), "Total") + defer cc.timeTrack(htime.Now(), "Total") cfgInit := func(c *commandeer) error { if cc.buildWatch { c.Set("disableLiveReload", true) @@ -210,6 +211,7 @@ type hugoBuilderCommon struct { buildWatch bool poll string + clock string gc bool @@ -236,7 +238,7 @@ func (cc *hugoBuilderCommon) timeTrack(start time.Time, name string) { if cc.quiet { return } - elapsed := time.Since(start) + elapsed := htime.Since(start) fmt.Printf("%s in %v ms\n", name, int(1000*elapsed.Seconds())) } @@ -279,6 +281,7 @@ func (cc *hugoBuilderCommon) handleCommonBuilderFlags(cmd *cobra.Command) { cmd.PersistentFlags().StringVarP(&cc.environment, "environment", "e", "", "build environment") cmd.PersistentFlags().StringP("themesDir", "", "", "filesystem path to themes directory") cmd.PersistentFlags().StringP("ignoreVendorPaths", "", "", "ignores any _vendor for module paths matching the given Glob pattern") + cmd.PersistentFlags().StringVar(&cc.clock, "clock", "", "set clock inside hugo, e.g. --clock 2021-11-06T22:30:00.00+09:00") } func (cc *hugoBuilderCommon) handleFlags(cmd *cobra.Command) { diff --git a/commands/hugo.go b/commands/hugo.go index 6bd0605db..43ec7e5c7 100644 --- a/commands/hugo.go +++ b/commands/hugo.go @@ -33,6 +33,7 @@ import ( "github.com/gohugoio/hugo/hugofs/files" "github.com/gohugoio/hugo/tpl" + "github.com/gohugoio/hugo/common/htime" "github.com/gohugoio/hugo/common/types" "github.com/gohugoio/hugo/hugofs" @@ -187,6 +188,7 @@ func initializeFlags(cmd *cobra.Command, cfg config.Provider) { "buildDrafts", "buildFuture", "buildExpired", + "clock", "uglyURLs", "canonifyURLs", "enableRobotsTXT", @@ -679,7 +681,7 @@ func (c *commandeer) firstPathSpec() *helpers.PathSpec { } func (c *commandeer) timeTrack(start time.Time, name string) { - elapsed := time.Since(start) + elapsed := htime.Since(start) c.logger.Printf("%s in %v ms", name, int(1000*elapsed.Seconds())) } @@ -790,7 +792,7 @@ func (c *commandeer) fullRebuild(changeType string) { time.Sleep(2 * time.Second) }() - defer c.timeTrack(time.Now(), "Rebuilt") + defer c.timeTrack(htime.Now(), "Rebuilt") c.commandeerHugoState = newCommandeerHugoState() err := c.loadConfig() @@ -900,7 +902,7 @@ func (c *commandeer) printChangeDetected(typ string) { c.logger.Println(msg) const layout = "2006-01-02 15:04:05.000 -0700" - c.logger.Println(time.Now().Format(layout)) + c.logger.Println(htime.Now().Format(layout)) } const ( @@ -1135,7 +1137,7 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher, c.changeDetector.PrepareNew() func() { - defer c.timeTrack(time.Now(), "Total") + defer c.timeTrack(htime.Now(), "Total") if err := c.rebuildSites(dynamicEvents); err != nil { c.handleBuildErr(err, "Rebuild failed") } diff --git a/commands/hugo_test.go b/commands/hugo_test.go index bdad25cfc..61160b7dd 100644 --- a/commands/hugo_test.go +++ b/commands/hugo_test.go @@ -29,7 +29,6 @@ import ( // Issue #5662 func TestHugoWithContentDirOverride(t *testing.T) { - t.Parallel() c := qt.New(t) files := ` @@ -51,7 +50,6 @@ Page: {{ .Title }}| // Issue #9794 func TestHugoStaticFilesMultipleStaticAndManyFolders(t *testing.T) { - t.Parallel() c := qt.New(t) files := ` @@ -95,6 +93,36 @@ Home. } +// Issue #8787 +func TestHugoListCommandsWithClockFlag(t *testing.T) { + c := qt.New(t) + + files := ` +-- config.toml -- +baseURL = "https://example.org" +title = "Hugo Commands" +-- content/past.md -- +--- +title: "Past" +date: 2000-11-06 +--- +-- content/future.md -- +--- +title: "Future" +date: 2200-11-06 +--- +-- layouts/_default/single.html -- +Page: {{ .Title }}| + +` + s := newTestHugoCmdBuilder(c, files, []string{"list", "future"}).Build() + p := filepath.Join("content", "future.md") + s.AssertStdout(p + ",2200-11-06T00:00:00Z") + + s = newTestHugoCmdBuilder(c, files, []string{"list", "future", "--clock", "2300-11-06"}).Build() + s.AssertStdout("") +} + type testHugoCmdBuilder struct { *qt.C @@ -102,6 +130,7 @@ type testHugoCmdBuilder struct { dir string files string args []string + out string } func newTestHugoCmdBuilder(c *qt.C, files string, args []string) *testHugoCmdBuilder { @@ -127,8 +156,12 @@ func (s *testHugoCmdBuilder) Build() *testHugoCmdBuilder { args := append(s.args, "-s="+s.dir, "--quiet") cmd.SetArgs(args) - _, err := cmd.ExecuteC() + out, err := captureStdout(func() error { + _, err := cmd.ExecuteC() + return err + }) s.Assert(err, qt.IsNil) + s.out = out return s } @@ -149,3 +182,9 @@ func (s *testHugoCmdBuilder) AssertFileContent(filename string, matches ...strin } } } + +func (s *testHugoCmdBuilder) AssertStdout(match string) { + s.Helper() + content := strings.TrimSpace(s.out) + s.Assert(content, qt.Contains, strings.TrimSpace(match)) +} diff --git a/commands/import_jekyll.go b/commands/import_jekyll.go index 4f17b2e39..232df519c 100644 --- a/commands/import_jekyll.go +++ b/commands/import_jekyll.go @@ -28,6 +28,7 @@ import ( "github.com/gohugoio/hugo/parser/pageparser" + "github.com/gohugoio/hugo/common/htime" "github.com/gohugoio/hugo/common/hugio" "github.com/gohugoio/hugo/parser/metadecoders" @@ -362,12 +363,12 @@ func parseJekyllFilename(filename string) (time.Time, string, error) { re := regexp.MustCompile(`(\d+-\d+-\d+)-(.+)\..*`) r := re.FindAllStringSubmatch(filename, -1) if len(r) == 0 { - return time.Now(), "", errors.New("filename not match") + return htime.Now(), "", errors.New("filename not match") } postDate, err := time.Parse("2006-1-2", r[0][1]) if err != nil { - return time.Now(), "", err + return htime.Now(), "", err } postName := r[0][2] diff --git a/commands/list.go b/commands/list.go index f4321d031..4b62c91c5 100644 --- a/commands/list.go +++ b/commands/list.go @@ -99,6 +99,10 @@ List requires a subcommand, e.g. ` + "`hugo list drafts`.", return newSystemError("Error building sites", err) } + if err != nil { + return newSystemError("Error building sites", err) + } + writer := csv.NewWriter(os.Stdout) defer writer.Flush() @@ -127,6 +131,10 @@ List requires a subcommand, e.g. ` + "`hugo list drafts`.", return newSystemError("Error building sites", err) } + if err != nil { + return newSystemError("Error building sites", err) + } + writer := csv.NewWriter(os.Stdout) defer writer.Flush() diff --git a/commands/list_test.go b/commands/list_test.go index 56a3ee9b9..8b2535571 100644 --- a/commands/list_test.go +++ b/commands/list_test.go @@ -34,9 +34,9 @@ func TestListAll(t *testing.T) { hugoCmd := newCommandsBuilder().addAll().build() cmd := hugoCmd.getCommand() - defer func() { + t.Cleanup(func() { os.RemoveAll(dir) - }() + }) cmd.SetArgs([]string{"-s=" + dir, "list", "all"}) diff --git a/commands/new_theme.go b/commands/new_theme.go index 9b1a4786c..4e2357b55 100644 --- a/commands/new_theme.go +++ b/commands/new_theme.go @@ -18,8 +18,8 @@ import ( "errors" "path/filepath" "strings" - "time" + "github.com/gohugoio/hugo/common/htime" "github.com/gohugoio/hugo/helpers" "github.com/gohugoio/hugo/hugofs" "github.com/spf13/cobra" @@ -113,7 +113,7 @@ func (n *newThemeCmd) newTheme(cmd *cobra.Command, args []string) error { by := []byte(`The MIT License (MIT) -Copyright (c) ` + time.Now().Format("2006") + ` YOUR_NAME_HERE +Copyright (c) ` + htime.Now().Format("2006") + ` YOUR_NAME_HERE Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/commands/server.go b/commands/server.go index 985775336..73e5cf073 100644 --- a/commands/server.go +++ b/commands/server.go @@ -33,6 +33,7 @@ import ( "syscall" "time" + "github.com/gohugoio/hugo/common/htime" "github.com/gohugoio/hugo/common/paths" "golang.org/x/sync/errgroup" @@ -255,7 +256,7 @@ func (sc *serverCmd) server(cmd *cobra.Command, args []string) error { } err = func() error { - defer c.timeTrack(time.Now(), "Built") + defer c.timeTrack(htime.Now(), "Built") err := c.serverBuild() if err != nil { cmd.PrintErrln("Error:", err.Error()) @@ -668,13 +669,13 @@ func memStats() error { go func() { var stats runtime.MemStats - start := time.Now().UnixNano() + start := htime.Now().UnixNano() for { runtime.ReadMemStats(&stats) if fileMemStats != nil { fileMemStats.WriteString(fmt.Sprintf("%d\t%d\t%d\t%d\t%d\n", - (time.Now().UnixNano()-start)/1000000, stats.HeapSys, stats.HeapAlloc, stats.HeapIdle, stats.HeapReleased)) + (htime.Now().UnixNano()-start)/1000000, stats.HeapSys, stats.HeapAlloc, stats.HeapIdle, stats.HeapReleased)) time.Sleep(interval) } else { break diff --git a/common/htime/time.go b/common/htime/time.go index 552608b6f..d854e9312 100644 --- a/common/htime/time.go +++ b/common/htime/time.go @@ -17,6 +17,7 @@ import ( "strings" "time" + "github.com/bep/clock" "github.com/spf13/cast" toml "github.com/pelletier/go-toml/v2" @@ -74,6 +75,7 @@ var ( "November", "December", } + Clock = clock.Start(time.Now()) ) func NewTimeFormatter(ltr locales.Translator) TimeFormatter { @@ -148,3 +150,13 @@ func ToTimeInDefaultLocationE(i any, location *time.Location) (tim time.Time, er } return cast.ToTimeInDefaultLocationE(i, location) } + +// Now returns time.Now() or time value based on`clock` flag. +// Use this function to fake time inside hugo. +func Now() time.Time { + return Clock.Now() +} + +func Since(t time.Time) time.Duration { + return Clock.Now().Sub(t) +} diff --git a/common/loggers/loggers.go b/common/loggers/loggers.go index 14c76ae45..6b73c9f32 100644 --- a/common/loggers/loggers.go +++ b/common/loggers/loggers.go @@ -24,6 +24,7 @@ import ( "runtime" "time" + "github.com/gohugoio/hugo/common/htime" "github.com/gohugoio/hugo/common/terminal" jww "github.com/spf13/jwalterweatherman" @@ -176,7 +177,7 @@ func (l *logger) Out() io.Writer { // PrintTimerIfDelayed prints a time statement to the FEEDBACK logger // if considerable time is spent. func (l *logger) PrintTimerIfDelayed(start time.Time, name string) { - elapsed := time.Since(start) + elapsed := htime.Since(start) milli := int(1000 * elapsed.Seconds()) if milli < 500 { return @@ -185,7 +186,7 @@ func (l *logger) PrintTimerIfDelayed(start time.Time, name string) { } func (l *logger) PrintTimer(start time.Time, name string) { - elapsed := time.Since(start) + elapsed := htime.Since(start) milli := int(1000 * elapsed.Seconds()) l.Printf("%s in %v ms", name, milli) } @@ -91,6 +91,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/sso v1.4.0 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.7.0 // indirect github.com/aws/smithy-go v1.8.0 // indirect + github.com/bep/clock v0.1.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect github.com/dlclark/regexp2 v1.4.0 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect @@ -212,6 +212,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.7.0/go.mod h1:0qcSMCyASQPN2sk/1KQLQ2 github.com/aws/smithy-go v1.8.0 h1:AEwwwXQZtUwP5Mz506FeXXrKBe0jA8gVM+1gEcSRooc= github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/bep/clock v0.1.0 h1:sdvJ08SsgwTY/ejA705YKBlktFfj2uVpmQSSQspZJ2c= +github.com/bep/clock v0.1.0/go.mod h1:shVP9tZ3cXpbVj60SnlU1pMwKjFxECBRm9vZfpoA0Gs= github.com/bep/debounce v1.2.0 h1:wXds8Kq8qRfwAOpAxHrJDbCXgC5aHSzgQb/0gKsHQqo= github.com/bep/debounce v1.2.0/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= github.com/bep/gitmap v1.1.2 h1:zk04w1qc1COTZPPYWDQHvns3y1afOsdRfraFQ3qI840= diff --git a/hugofs/fileinfo.go b/hugofs/fileinfo.go index af37fce7e..d923d632d 100644 --- a/hugofs/fileinfo.go +++ b/hugofs/fileinfo.go @@ -31,6 +31,7 @@ import ( "errors" "github.com/gohugoio/hugo/common/hreflect" + "github.com/gohugoio/hugo/common/htime" "github.com/spf13/afero" ) @@ -203,7 +204,7 @@ func newDirNameOnlyFileInfo(name string, meta *FileMeta, fileOpener func() (afer m.IsOrdered = false return NewFileMetaInfo( - &dirNameOnlyFileInfo{name: base, modTime: time.Now()}, + &dirNameOnlyFileInfo{name: base, modTime: htime.Now()}, m, ) } diff --git a/hugolib/content_factory.go b/hugolib/content_factory.go index e6e82979f..0a4d0aa0a 100644 --- a/hugolib/content_factory.go +++ b/hugolib/content_factory.go @@ -20,6 +20,7 @@ import ( "strings" "time" + "github.com/gohugoio/hugo/common/htime" "github.com/gohugoio/hugo/helpers" "github.com/gohugoio/hugo/source" @@ -70,7 +71,7 @@ func (f ContentFactory) ApplyArchetypeTemplate(w io.Writer, p page.Page, archety d := &archetypeFileData{ Type: archetypeKind, - Date: time.Now().Format(time.RFC3339), + Date: htime.Now().Format(time.RFC3339), Page: p, File: p.File(), } diff --git a/hugolib/page_test.go b/hugolib/page_test.go index 84e54306a..05a1c3d77 100644 --- a/hugolib/page_test.go +++ b/hugolib/page_test.go @@ -22,12 +22,14 @@ import ( "testing" "time" + "github.com/bep/clock" "github.com/gohugoio/hugo/htesting" "github.com/gohugoio/hugo/markup/asciidocext" "github.com/gohugoio/hugo/markup/rst" "github.com/gohugoio/hugo/config" + "github.com/gohugoio/hugo/common/htime" "github.com/gohugoio/hugo/common/loggers" "github.com/gohugoio/hugo/hugofs" @@ -1536,7 +1538,6 @@ Content. } func TestShouldBuild(t *testing.T) { - t.Parallel() past := time.Date(2009, 11, 17, 20, 34, 58, 651387237, time.UTC) future := time.Date(2037, 11, 17, 20, 34, 58, 651387237, time.UTC) zero := time.Time{} @@ -1582,6 +1583,54 @@ func TestShouldBuild(t *testing.T) { } } +func TestShouldBuildWithClock(t *testing.T) { + htime.Clock = clock.Start(time.Date(2021, 11, 17, 20, 34, 58, 651387237, time.UTC)) + t.Cleanup(func() { htime.Clock = clock.Start(time.Now()) }) + past := time.Date(2009, 11, 17, 20, 34, 58, 651387237, time.UTC) + future := time.Date(2037, 11, 17, 20, 34, 58, 651387237, time.UTC) + zero := time.Time{} + + publishSettings := []struct { + buildFuture bool + buildExpired bool + buildDrafts bool + draft bool + publishDate time.Time + expiryDate time.Time + out bool + }{ + // publishDate and expiryDate + {false, false, false, false, zero, zero, true}, + {false, false, false, false, zero, future, true}, + {false, false, false, false, past, zero, true}, + {false, false, false, false, past, future, true}, + {false, false, false, false, past, past, false}, + {false, false, false, false, future, future, false}, + {false, false, false, false, future, past, false}, + + // buildFuture and buildExpired + {false, true, false, false, past, past, true}, + {true, true, false, false, past, past, true}, + {true, false, false, false, past, past, false}, + {true, false, false, false, future, future, true}, + {true, true, false, false, future, future, true}, + {false, true, false, false, future, past, false}, + + // buildDrafts and draft + {true, true, false, true, past, future, false}, + {true, true, true, true, past, future, true}, + {true, true, true, true, past, future, true}, + } + + for _, ps := range publishSettings { + s := shouldBuild(ps.buildFuture, ps.buildExpired, ps.buildDrafts, ps.draft, + ps.publishDate, ps.expiryDate) + if s != ps.out { + t.Errorf("AssertShouldBuildWithClock unexpected output with params: %+v", ps) + } + } +} + // "dot" in path: #1885 and #2110 // disablePathToLower regression: #3374 func TestPathIssues(t *testing.T) { diff --git a/hugolib/site.go b/hugolib/site.go index cf7f0ff82..cbfc4d836 100644 --- a/hugolib/site.go +++ b/hugolib/site.go @@ -30,6 +30,7 @@ import ( "strings" "time" + "github.com/gohugoio/hugo/common/htime" "github.com/gohugoio/hugo/common/hugio" "github.com/gohugoio/hugo/common/types" "github.com/gohugoio/hugo/modules" @@ -1910,10 +1911,11 @@ func shouldBuild(buildFuture bool, buildExpired bool, buildDrafts bool, Draft bo if !(buildDrafts || !Draft) { return false } - if !buildFuture && !publishDate.IsZero() && publishDate.After(time.Now()) { + hnow := htime.Now() + if !buildFuture && !publishDate.IsZero() && publishDate.After(hnow) { return false } - if !buildExpired && !expiryDate.IsZero() && expiryDate.Before(time.Now()) { + if !buildExpired && !expiryDate.IsZero() && expiryDate.Before(hnow) { return false } return true diff --git a/metrics/metrics.go b/metrics/metrics.go index 9c46fdf7e..471f48a04 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -25,6 +25,7 @@ import ( "sync" "time" + "github.com/gohugoio/hugo/common/htime" "github.com/gohugoio/hugo/common/types" "github.com/gohugoio/hugo/compare" "github.com/gohugoio/hugo/helpers" @@ -129,7 +130,7 @@ func (s *Store) TrackValue(key string, value any, cached bool) { // MeasureSince adds a measuremen |