]> git.maquefel.me Git - brevno-suite/hugo/commitdiff
Add `clock` cli flag
authorsatotake <doublequotation@gmail.com>
Tue, 26 Apr 2022 17:57:04 +0000 (02:57 +0900)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Sun, 8 May 2022 14:56:26 +0000 (16:56 +0200)
Close #8787

26 files changed:
cache/filecache/filecache.go
commands/commandeer.go
commands/commands.go
commands/hugo.go
commands/hugo_test.go
commands/import_jekyll.go
commands/list.go
commands/list_test.go
commands/new_theme.go
commands/server.go
common/htime/time.go
common/loggers/loggers.go
go.mod
go.sum
hugofs/fileinfo.go
hugolib/content_factory.go
hugolib/page_test.go
hugolib/site.go
metrics/metrics.go
modules/collect.go
resources/resource/dates.go
tpl/collections/collections.go
tpl/partials/partials.go
tpl/time/init.go
tpl/time/time.go
tpl/tplimpl/template.go

index 5a87382aeaf3dbde7e1a6520547b69903d656fb8..3104d8ac6dae1f3dcda6277b6af572a173bc350d 100644 (file)
@@ -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
index 5b192c1725033596d07237a94e90624136eebc64..20090cccdae32ba5857649ca00bf2f6f507d1dfc 100644 (file)
@@ -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
index 99b0866e5587d6e188462d5fa59c3658aa083ce3..97e6d21134d154a9ec98363db4d0e028c9080fa5 100644 (file)
@@ -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) {
index 6bd0605db65ddd52d26c4ba27c8bb002d9297cc3..43ec7e5c70875b64b60cc4d9a2f1bd256536134a 100644 (file)
@@ -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")
                        }
index bdad25cfcd239373f2bfbe0859aa5eabe4f2578a..61160b7dd067e212fc8775d42af5dcba62a26425 100644 (file)
@@ -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))
+}
index 4f17b2e39851abedf54b8cff3013cce4a8ac8c7d..232df519c12b60c7ad4c35ae2f57ab15bfa40a18 100644 (file)
@@ -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]
index f4321d031153141ecbb6ab4c53def2db0efc1ae1..4b62c91c53fca85e8324924dc0bdc11aca1f268a 100644 (file)
@@ -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()
 
index 56a3ee9b936425211a2951b988cd8d19cbfb8149..8b25355714e7f3b6ce8c6ce92dc084d02c2d30d9 100644 (file)
@@ -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"})
 
index 9b1a4786c41f0da6b9e60456526bd849eecc49dc..4e2357b55581d91b341c0cf2e22bf32e79447cc1 100644 (file)
@@ -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
index 9857753368b6b06c4fa6a9a9493f26ac32c97ff8..73e5cf073f5aa64ac978b561dbf863ebea739d85 100644 (file)
@@ -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
index 552608b6f9f9d465b82f17bc0e02b5440b2ca18d..d854e9312d82ded6288ff95bbd162697795b95c4 100644 (file)
@@ -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)
+}
index 14c76ae4576d53039b4dc0fd77149601ef72865c..6b73c9f32c1283d8080e0c1383c25c3f43842952 100644 (file)
@@ -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)
 }
diff --git a/go.mod b/go.mod
index 1a59f901db771763e82f1d9fe770e2d574aa6e5e..2637fcc0a73732a2f0a89c94930b50ed1a451462 100644 (file)
--- a/go.mod
+++ b/go.mod
@@ -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
diff --git a/go.sum b/go.sum
index 6c4fd2d725e1f33443ce7eb4c9baa9c8519bd01d..9d0e2b812b91ebc8fa78adc8160a1b0d37ed5328 100644 (file)
--- a/go.sum
+++ b/go.sum
@@ -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=
index af37fce7e66edab1c01a87e3818c45eb04df74f2..d923d632dfa403375d382c9bcf20bc36e6aabef4 100644 (file)
@@ -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,
        )
 }
index e6e82979f02286214a8b157690d63a9ea0e461d3..0a4d0aa0aa851b63b5ea05d1f81ee392e6f31557 100644 (file)
@@ -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(),
        }
index 84e54306a2c783084a46b19edb3b17b7f7499fcb..05a1c3d776f10af81b68466927d747b3e54403d0 100644 (file)
@@ -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) {
index cf7f0ff8249d2143b4b08b7b4c5f577795f9899b..cbfc4d836e0e16be99bd5d365c83435b0ad0eccd 100644 (file)
@@ -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
index 9c46fdf7ee31d068a9747f85a687cc46baf8c5cd..471f48a047150663c47b06172f42ab15d33dfce3 100644 (file)
@@ -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 measurement for key to the metric store.
 func (s *Store) MeasureSince(key string, start time.Time) {
        s.mu.Lock()
-       s.metrics[key] = append(s.metrics[key], time.Since(start))
+       s.metrics[key] = append(s.metrics[key], htime.Since(start))
        s.mu.Unlock()
 }
 
index ff83f9ecca86f28f0dc8b445b2042bbf8aa0aed6..4f5b1c36faa18f9a2cda52ae2fb6f5777c9bf753 100644 (file)
@@ -23,6 +23,7 @@ import (
        "time"
 
        "github.com/bep/debounce"
+       "github.com/gohugoio/hugo/common/htime"
        "github.com/gohugoio/hugo/common/loggers"
 
        "github.com/spf13/cast"
@@ -505,7 +506,7 @@ func (c *collector) applyThemeConfig(tc *moduleAdapter) error {
 }
 
 func (c *collector) collect() {
-       defer c.logger.PrintTimerIfDelayed(time.Now(), "hugo: collected modules")
+       defer c.logger.PrintTimerIfDelayed(htime.Now(), "hugo: collected modules")
        d := debounce.New(2 * time.Second)
        d(func() {
                c.logger.Println("hugo: downloading modules …")
index b43f35c641a79885d028a97d6a38df131edb2b4a..6d19ca7b95f46cf0ebc4d2e8edbdbf56763487d5 100644 (file)
 
 package resource
 
-import "time"
+import (
+       "time"
+
+       "github.com/gohugoio/hugo/common/htime"
+)
 
 var _ Dated = Dates{}
 
@@ -55,7 +59,8 @@ func IsFuture(d Dated) bool {
        if d.PublishDate().IsZero() {
                return false
        }
-       return d.PublishDate().After(time.Now())
+
+       return d.PublishDate().After(htime.Now())
 }
 
 // IsExpired returns whether the argument is expired.
@@ -63,7 +68,7 @@ func IsExpired(d Dated) bool {
        if d.ExpiryDate().IsZero() {
                return false
        }
-       return d.ExpiryDate().Before(time.Now())
+       return d.ExpiryDate().Before(htime.Now())
 }
 
 // IsZeroDates returns true if all of the dates are zero.
index 516e2c272fb841d91f26c08b9cac44dc0398ccce..8fdc85275869ddca00785d9f18d0e753b4922c33 100644 (file)
@@ -35,6 +35,7 @@ import (
 )
 
 func init() {
+       // htime.Now cannot be used here
        rand.Seed(time.Now().UTC().UnixNano())
 }
 
index eb4ebfe321a2301171bcac97ecde55660cf186da..9ded32a7134e98a49e324c9ad887f74d4d3d1ede 100644 (file)
@@ -25,8 +25,8 @@ import (
        "reflect"
        "strings"
        "sync"
-       "time"
 
+       "github.com/gohugoio/hugo/common/htime"
        texttemplate "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate"
 
        "github.com/gohugoio/hugo/helpers"
@@ -222,7 +222,7 @@ func createKey(name string, variants ...any) (partialCacheKey, error) {
 var errUnHashable = errors.New("unhashable")
 
 func (ns *Namespace) getOrCreate(ctx context.Context, key partialCacheKey, context any) (result any, err error) {
-       start := time.Now()
+       start := htime.Now()
        defer func() {
                if r := recover(); r != nil {
                        err = r.(error)
index 4bb2ddf67bfb444d38c365faa4250bec2142ade9..7dd71f2105d7e90d339f9fb35a0def0511366e4e 100644 (file)
@@ -28,6 +28,7 @@ func init() {
                if d.Language == nil {
                        panic("Language must be set")
                }
+
                ctx := New(langs.GetTimeFormatter(d.Language), langs.GetLocation(d.Language))
 
                ns := &internal.TemplateFuncsNamespace{
index 623b7206aa64016148e9a78aafe2a46cfc2a9aeb..cd78b83aaa4d356f6d08670f7a68415e67c58f7b 100644 (file)
@@ -68,9 +68,9 @@ func (ns *Namespace) Format(layout string, v any) (string, error) {
        return ns.timeFormatter.Format(t, layout), nil
 }
 
-// Now returns the current local time.
+// Now returns the current local time or `clock` time
 func (ns *Namespace) Now() _time.Time {
-       return _time.Now()
+       return htime.Now()
 }
 
 // ParseDuration parses the duration string s.
index c092ff638165ea2c766519c245d8701fc7b5a713..d352f02e825d544eb9d50dc08cc626ee5173f548 100644 (file)
@@ -27,10 +27,10 @@ import (
        "sort"
        "strings"
        "sync"
-       "time"
        "unicode"
        "unicode/utf8"
 
+       "github.com/gohugoio/hugo/common/htime"
        "github.com/gohugoio/hugo/common/types"
 
        "github.com/gohugoio/hugo/helpers"
@@ -235,7 +235,7 @@ func (t *templateExec) ExecuteWithContext(ctx context.Context, templ tpl.Templat
                defer rlocker.RUnlock()
        }
        if t.Metrics != nil {
-               defer t.Metrics.MeasureSince(templ.Name(), time.Now())
+               defer t.Metrics.MeasureSince(templ.Name(), htime.Now())
        }
 
        if t.templateUsageTracker != nil {