mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
Rework the Destination filesystem to make --renderStaticToDisk work
See #9626
This commit is contained in:
parent
b08193971a
commit
d070bdf10f
75 changed files with 651 additions and 566 deletions
2
cache/filecache/filecache_config_test.go
vendored
2
cache/filecache/filecache_config_test.go
vendored
|
@ -184,7 +184,7 @@ dir = "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestConfig() config.Provider {
|
func newTestConfig() config.Provider {
|
||||||
cfg := config.New()
|
cfg := config.NewWithTestDefaults()
|
||||||
cfg.Set("workingDir", filepath.FromSlash("/my/cool/hugoproject"))
|
cfg.Set("workingDir", filepath.FromSlash("/my/cool/hugoproject"))
|
||||||
cfg.Set("contentDir", "content")
|
cfg.Set("contentDir", "content")
|
||||||
cfg.Set("dataDir", "data")
|
cfg.Set("dataDir", "data")
|
||||||
|
|
1
cache/filecache/filecache_test.go
vendored
1
cache/filecache/filecache_test.go
vendored
|
@ -342,6 +342,7 @@ func newPathsSpec(t *testing.T, fs afero.Fs, configStr string) *helpers.PathSpec
|
||||||
cfg, err := config.FromConfigString(configStr, "toml")
|
cfg, err := config.FromConfigString(configStr, "toml")
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
initConfig(fs, cfg)
|
initConfig(fs, cfg)
|
||||||
|
config.SetBaseTestDefaults(cfg)
|
||||||
p, err := helpers.NewPathSpec(hugofs.NewFrom(fs, cfg), cfg, nil)
|
p, err := helpers.NewPathSpec(hugofs.NewFrom(fs, cfg), cfg, nil)
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
return p
|
return p
|
||||||
|
|
|
@ -30,6 +30,7 @@ import (
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/herrors"
|
"github.com/gohugoio/hugo/common/herrors"
|
||||||
"github.com/gohugoio/hugo/common/hugo"
|
"github.com/gohugoio/hugo/common/hugo"
|
||||||
|
"github.com/gohugoio/hugo/common/paths"
|
||||||
|
|
||||||
jww "github.com/spf13/jwalterweatherman"
|
jww "github.com/spf13/jwalterweatherman"
|
||||||
|
|
||||||
|
@ -42,6 +43,7 @@ import (
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
|
||||||
"github.com/bep/debounce"
|
"github.com/bep/debounce"
|
||||||
|
"github.com/bep/overlayfs"
|
||||||
"github.com/gohugoio/hugo/common/types"
|
"github.com/gohugoio/hugo/common/types"
|
||||||
"github.com/gohugoio/hugo/deps"
|
"github.com/gohugoio/hugo/deps"
|
||||||
"github.com/gohugoio/hugo/helpers"
|
"github.com/gohugoio/hugo/helpers"
|
||||||
|
@ -73,8 +75,10 @@ type commandeer struct {
|
||||||
// be fast enough that we could maybe just add it for all server modes.
|
// be fast enough that we could maybe just add it for all server modes.
|
||||||
changeDetector *fileChangeDetector
|
changeDetector *fileChangeDetector
|
||||||
|
|
||||||
// We need to reuse this on server rebuilds.
|
// We need to reuse these on server rebuilds.
|
||||||
destinationFs afero.Fs
|
// These 2 will be different if --renderStaticToDisk is set.
|
||||||
|
publishDirFs afero.Fs
|
||||||
|
publishDirServerFs afero.Fs
|
||||||
|
|
||||||
h *hugoBuilderCommon
|
h *hugoBuilderCommon
|
||||||
ftch flagsToConfigHandler
|
ftch flagsToConfigHandler
|
||||||
|
@ -162,7 +166,8 @@ func (c *commandeer) Set(key string, value any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *commandeer) initFs(fs *hugofs.Fs) error {
|
func (c *commandeer) initFs(fs *hugofs.Fs) error {
|
||||||
c.destinationFs = fs.Destination
|
c.publishDirFs = fs.PublishDir
|
||||||
|
c.publishDirServerFs = fs.PublishDirServer
|
||||||
c.DepsCfg.Fs = fs
|
c.DepsCfg.Fs = fs
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -378,28 +383,63 @@ func (c *commandeer) loadConfig() error {
|
||||||
createMemFs := config.GetBool("renderToMemory")
|
createMemFs := config.GetBool("renderToMemory")
|
||||||
c.renderStaticToDisk = config.GetBool("renderStaticToDisk")
|
c.renderStaticToDisk = config.GetBool("renderStaticToDisk")
|
||||||
|
|
||||||
if createMemFs && !c.renderStaticToDisk {
|
if createMemFs {
|
||||||
// Rendering to memoryFS, publish to Root regardless of publishDir.
|
// Rendering to memoryFS, publish to Root regardless of publishDir.
|
||||||
config.Set("publishDir", "/")
|
config.Set("publishDir", "/")
|
||||||
|
config.Set("publishDirStatic", "/")
|
||||||
|
} else if c.renderStaticToDisk {
|
||||||
|
// Hybrid, render dynamic content to Root.
|
||||||
|
config.Set("publishDirStatic", config.Get("publishDir"))
|
||||||
|
config.Set("publishDir", "/")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c.fsCreate.Do(func() {
|
c.fsCreate.Do(func() {
|
||||||
fs := hugofs.NewFrom(sourceFs, config)
|
fs := hugofs.NewFrom(sourceFs, config)
|
||||||
|
|
||||||
if c.destinationFs != nil {
|
if c.publishDirFs != nil {
|
||||||
// Need to reuse the destination on server rebuilds.
|
// Need to reuse the destination on server rebuilds.
|
||||||
fs.Destination = c.destinationFs
|
fs.PublishDir = c.publishDirFs
|
||||||
} else if createMemFs && c.renderStaticToDisk {
|
fs.PublishDirServer = c.publishDirServerFs
|
||||||
// Writes the dynamic output on memory,
|
} else {
|
||||||
// while serve others directly from publishDir
|
|
||||||
publishDir := config.GetString("publishDir")
|
publishDir := config.GetString("publishDir")
|
||||||
writableFs := afero.NewBasePathFs(afero.NewMemMapFs(), publishDir)
|
publishDirStatic := config.GetString("publishDirStatic")
|
||||||
publicFs := afero.NewOsFs()
|
workingDir := config.GetString("workingDir")
|
||||||
fs.Destination = afero.NewCopyOnWriteFs(afero.NewReadOnlyFs(publicFs), writableFs)
|
absPublishDir := paths.AbsPathify(workingDir, publishDir)
|
||||||
fs.DestinationStatic = publicFs
|
absPublishDirStatic := paths.AbsPathify(workingDir, publishDirStatic)
|
||||||
|
|
||||||
|
if c.renderStaticToDisk {
|
||||||
|
// Writes the dynamic output oton memory,
|
||||||
|
// while serve others directly from /public on disk.
|
||||||
|
dynamicFs := afero.NewMemMapFs()
|
||||||
|
staticFs := afero.NewBasePathFs(afero.NewOsFs(), absPublishDirStatic)
|
||||||
|
|
||||||
|
// Serve from both the static and dynamic fs,
|
||||||
|
// the first will take priority.
|
||||||
|
// THis is a read-only filesystem,
|
||||||
|
// we do all the writes to
|
||||||
|
// fs.Destination and fs.DestinationStatic.
|
||||||
|
fs.PublishDirServer = overlayfs.New(
|
||||||
|
overlayfs.Options{
|
||||||
|
Fss: []afero.Fs{
|
||||||
|
dynamicFs,
|
||||||
|
staticFs,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
fs.PublishDir = dynamicFs
|
||||||
|
fs.PublishDirStatic = staticFs
|
||||||
} else if createMemFs {
|
} else if createMemFs {
|
||||||
// Hugo writes the output to memory instead of the disk.
|
// Hugo writes the output to memory instead of the disk.
|
||||||
fs.Destination = new(afero.MemMapFs)
|
fs.PublishDir = new(afero.MemMapFs)
|
||||||
|
fs.PublishDirServer = fs.PublishDir
|
||||||
|
fs.PublishDirStatic = fs.PublishDir
|
||||||
|
} else {
|
||||||
|
// Write everything to disk.
|
||||||
|
fs.PublishDir = afero.NewBasePathFs(afero.NewOsFs(), absPublishDir)
|
||||||
|
fs.PublishDirServer = fs.PublishDir
|
||||||
|
fs.PublishDirStatic = fs.PublishDir
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.fastRenderMode {
|
if c.fastRenderMode {
|
||||||
|
@ -413,15 +453,15 @@ func (c *commandeer) loadConfig() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
changeDetector.PrepareNew()
|
changeDetector.PrepareNew()
|
||||||
fs.Destination = hugofs.NewHashingFs(fs.Destination, changeDetector)
|
fs.PublishDir = hugofs.NewHashingFs(fs.PublishDir, changeDetector)
|
||||||
fs.DestinationStatic = hugofs.NewHashingFs(fs.DestinationStatic, changeDetector)
|
fs.PublishDirStatic = hugofs.NewHashingFs(fs.PublishDirStatic, changeDetector)
|
||||||
c.changeDetector = changeDetector
|
c.changeDetector = changeDetector
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Cfg.GetBool("logPathWarnings") {
|
if c.Cfg.GetBool("logPathWarnings") {
|
||||||
// Note that we only care about the "dynamic creates" here,
|
// Note that we only care about the "dynamic creates" here,
|
||||||
// so skip the static fs.
|
// so skip the static fs.
|
||||||
fs.Destination = hugofs.NewCreateCountingFs(fs.Destination)
|
fs.PublishDir = hugofs.NewCreateCountingFs(fs.PublishDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
// To debug hard-to-find path issues.
|
// To debug hard-to-find path issues.
|
||||||
|
|
|
@ -18,10 +18,9 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/hugolib/paths"
|
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/hugo"
|
"github.com/gohugoio/hugo/common/hugo"
|
||||||
"github.com/gohugoio/hugo/common/loggers"
|
"github.com/gohugoio/hugo/common/loggers"
|
||||||
|
hpaths "github.com/gohugoio/hugo/common/paths"
|
||||||
"github.com/gohugoio/hugo/config"
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/gohugoio/hugo/helpers"
|
"github.com/gohugoio/hugo/helpers"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
@ -243,14 +242,14 @@ func (cc *hugoBuilderCommon) timeTrack(start time.Time, name string) {
|
||||||
|
|
||||||
func (cc *hugoBuilderCommon) getConfigDir(baseDir string) string {
|
func (cc *hugoBuilderCommon) getConfigDir(baseDir string) string {
|
||||||
if cc.cfgDir != "" {
|
if cc.cfgDir != "" {
|
||||||
return paths.AbsPathify(baseDir, cc.cfgDir)
|
return hpaths.AbsPathify(baseDir, cc.cfgDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, found := os.LookupEnv("HUGO_CONFIGDIR"); found {
|
if v, found := os.LookupEnv("HUGO_CONFIGDIR"); found {
|
||||||
return paths.AbsPathify(baseDir, v)
|
return hpaths.AbsPathify(baseDir, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
return paths.AbsPathify(baseDir, "config")
|
return hpaths.AbsPathify(baseDir, "config")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cc *hugoBuilderCommon) getEnvironment(isServer bool) string {
|
func (cc *hugoBuilderCommon) getEnvironment(isServer bool) string {
|
||||||
|
|
|
@ -22,8 +22,6 @@ import (
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/config"
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/htesting"
|
|
||||||
|
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/hugofs"
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
|
@ -38,15 +36,13 @@ import (
|
||||||
func TestExecute(t *testing.T) {
|
func TestExecute(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
createSite := func(c *qt.C) (string, func()) {
|
createSite := func(c *qt.C) string {
|
||||||
dir, clean, err := createSimpleTestSite(t, testSiteConfig{})
|
dir := createSimpleTestSite(t, testSiteConfig{})
|
||||||
c.Assert(err, qt.IsNil)
|
return dir
|
||||||
return dir, clean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Run("hugo", func(c *qt.C) {
|
c.Run("hugo", func(c *qt.C) {
|
||||||
dir, clean := createSite(c)
|
dir := createSite(c)
|
||||||
defer clean()
|
|
||||||
resp := Execute([]string{"-s=" + dir})
|
resp := Execute([]string{"-s=" + dir})
|
||||||
c.Assert(resp.Err, qt.IsNil)
|
c.Assert(resp.Err, qt.IsNil)
|
||||||
result := resp.Result
|
result := resp.Result
|
||||||
|
@ -56,8 +52,7 @@ func TestExecute(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
c.Run("hugo, set environment", func(c *qt.C) {
|
c.Run("hugo, set environment", func(c *qt.C) {
|
||||||
dir, clean := createSite(c)
|
dir := createSite(c)
|
||||||
defer clean()
|
|
||||||
resp := Execute([]string{"-s=" + dir, "-e=staging"})
|
resp := Execute([]string{"-s=" + dir, "-e=staging"})
|
||||||
c.Assert(resp.Err, qt.IsNil)
|
c.Assert(resp.Err, qt.IsNil)
|
||||||
result := resp.Result
|
result := resp.Result
|
||||||
|
@ -65,9 +60,8 @@ func TestExecute(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
c.Run("convert toJSON", func(c *qt.C) {
|
c.Run("convert toJSON", func(c *qt.C) {
|
||||||
dir, clean := createSite(c)
|
dir := createSite(c)
|
||||||
output := filepath.Join(dir, "myjson")
|
output := filepath.Join(dir, "myjson")
|
||||||
defer clean()
|
|
||||||
resp := Execute([]string{"convert", "toJSON", "-s=" + dir, "-e=staging", "-o=" + output})
|
resp := Execute([]string{"convert", "toJSON", "-s=" + dir, "-e=staging", "-o=" + output})
|
||||||
c.Assert(resp.Err, qt.IsNil)
|
c.Assert(resp.Err, qt.IsNil)
|
||||||
converted := readFileFrom(c, filepath.Join(output, "content", "p1.md"))
|
converted := readFileFrom(c, filepath.Join(output, "content", "p1.md"))
|
||||||
|
@ -75,8 +69,7 @@ func TestExecute(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
c.Run("config, set environment", func(c *qt.C) {
|
c.Run("config, set environment", func(c *qt.C) {
|
||||||
dir, clean := createSite(c)
|
dir := createSite(c)
|
||||||
defer clean()
|
|
||||||
out, err := captureStdout(func() error {
|
out, err := captureStdout(func() error {
|
||||||
resp := Execute([]string{"config", "-s=" + dir, "-e=staging"})
|
resp := Execute([]string{"config", "-s=" + dir, "-e=staging"})
|
||||||
return resp.Err
|
return resp.Err
|
||||||
|
@ -86,16 +79,14 @@ func TestExecute(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
c.Run("deploy, environment set", func(c *qt.C) {
|
c.Run("deploy, environment set", func(c *qt.C) {
|
||||||
dir, clean := createSite(c)
|
dir := createSite(c)
|
||||||
defer clean()
|
|
||||||
resp := Execute([]string{"deploy", "-s=" + dir, "-e=staging", "--target=mydeployment", "--dryRun"})
|
resp := Execute([]string{"deploy", "-s=" + dir, "-e=staging", "--target=mydeployment", "--dryRun"})
|
||||||
c.Assert(resp.Err, qt.Not(qt.IsNil))
|
c.Assert(resp.Err, qt.Not(qt.IsNil))
|
||||||
c.Assert(resp.Err.Error(), qt.Contains, `no driver registered for "hugocloud"`)
|
c.Assert(resp.Err.Error(), qt.Contains, `no driver registered for "hugocloud"`)
|
||||||
})
|
})
|
||||||
|
|
||||||
c.Run("list", func(c *qt.C) {
|
c.Run("list", func(c *qt.C) {
|
||||||
dir, clean := createSite(c)
|
dir := createSite(c)
|
||||||
defer clean()
|
|
||||||
out, err := captureStdout(func() error {
|
out, err := captureStdout(func() error {
|
||||||
resp := Execute([]string{"list", "all", "-s=" + dir, "-e=staging"})
|
resp := Execute([]string{"list", "all", "-s=" + dir, "-e=staging"})
|
||||||
return resp.Err
|
return resp.Err
|
||||||
|
@ -105,8 +96,7 @@ func TestExecute(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
c.Run("new theme", func(c *qt.C) {
|
c.Run("new theme", func(c *qt.C) {
|
||||||
dir, clean := createSite(c)
|
dir := createSite(c)
|
||||||
defer clean()
|
|
||||||
themesDir := filepath.Join(dir, "mythemes")
|
themesDir := filepath.Join(dir, "mythemes")
|
||||||
resp := Execute([]string{"new", "theme", "mytheme", "-s=" + dir, "-e=staging", "--themesDir=" + themesDir})
|
resp := Execute([]string{"new", "theme", "mytheme", "-s=" + dir, "-e=staging", "--themesDir=" + themesDir})
|
||||||
c.Assert(resp.Err, qt.IsNil)
|
c.Assert(resp.Err, qt.IsNil)
|
||||||
|
@ -115,8 +105,7 @@ func TestExecute(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
c.Run("new site", func(c *qt.C) {
|
c.Run("new site", func(c *qt.C) {
|
||||||
dir, clean := createSite(c)
|
dir := createSite(c)
|
||||||
defer clean()
|
|
||||||
siteDir := filepath.Join(dir, "mysite")
|
siteDir := filepath.Join(dir, "mysite")
|
||||||
resp := Execute([]string{"new", "site", siteDir, "-e=staging"})
|
resp := Execute([]string{"new", "site", siteDir, "-e=staging"})
|
||||||
c.Assert(resp.Err, qt.IsNil)
|
c.Assert(resp.Err, qt.IsNil)
|
||||||
|
@ -167,7 +156,7 @@ func TestFlags(t *testing.T) {
|
||||||
name: "ignoreVendorPaths",
|
name: "ignoreVendorPaths",
|
||||||
args: []string{"server", "--ignoreVendorPaths=github.com/**"},
|
args: []string{"server", "--ignoreVendorPaths=github.com/**"},
|
||||||
check: func(c *qt.C, cmd *serverCmd) {
|
check: func(c *qt.C, cmd *serverCmd) {
|
||||||
cfg := config.New()
|
cfg := config.NewWithTestDefaults()
|
||||||
cmd.flagsToConfig(cfg)
|
cmd.flagsToConfig(cfg)
|
||||||
c.Assert(cfg.Get("ignoreVendorPaths"), qt.Equals, "github.com/**")
|
c.Assert(cfg.Get("ignoreVendorPaths"), qt.Equals, "github.com/**")
|
||||||
},
|
},
|
||||||
|
@ -208,7 +197,7 @@ func TestFlags(t *testing.T) {
|
||||||
c.Assert(sc.serverPort, qt.Equals, 1366)
|
c.Assert(sc.serverPort, qt.Equals, 1366)
|
||||||
c.Assert(sc.environment, qt.Equals, "testing")
|
c.Assert(sc.environment, qt.Equals, "testing")
|
||||||
|
|
||||||
cfg := config.New()
|
cfg := config.NewWithTestDefaults()
|
||||||
sc.flagsToConfig(cfg)
|
sc.flagsToConfig(cfg)
|
||||||
c.Assert(cfg.GetString("publishDir"), qt.Equals, "/tmp/mydestination")
|
c.Assert(cfg.GetString("publishDir"), qt.Equals, "/tmp/mydestination")
|
||||||
c.Assert(cfg.GetString("contentDir"), qt.Equals, "mycontent")
|
c.Assert(cfg.GetString("contentDir"), qt.Equals, "mycontent")
|
||||||
|
@ -253,14 +242,8 @@ func TestFlags(t *testing.T) {
|
||||||
func TestCommandsExecute(t *testing.T) {
|
func TestCommandsExecute(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
dir, clean, err := createSimpleTestSite(t, testSiteConfig{})
|
dir := createSimpleTestSite(t, testSiteConfig{})
|
||||||
c.Assert(err, qt.IsNil)
|
dirOut := t.TempDir()
|
||||||
|
|
||||||
dirOut, clean2, err := htesting.CreateTempDir(hugofs.Os, "hugo-cli-out")
|
|
||||||
c.Assert(err, qt.IsNil)
|
|
||||||
|
|
||||||
defer clean()
|
|
||||||
defer clean2()
|
|
||||||
|
|
||||||
sourceFlag := fmt.Sprintf("-s=%s", dir)
|
sourceFlag := fmt.Sprintf("-s=%s", dir)
|
||||||
|
|
||||||
|
@ -297,6 +280,11 @@ func TestCommandsExecute(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
name := "hugo"
|
||||||
|
if len(test.commands) > 0 {
|
||||||
|
name = test.commands[0]
|
||||||
|
}
|
||||||
|
c.Run(name, func(c *qt.C) {
|
||||||
b := newCommandsBuilder().addAll().build()
|
b := newCommandsBuilder().addAll().build()
|
||||||
hugoCmd := b.getCommand()
|
hugoCmd := b.getCommand()
|
||||||
test.flags = append(test.flags, "--quiet")
|
test.flags = append(test.flags, "--quiet")
|
||||||
|
@ -317,9 +305,10 @@ func TestCommandsExecute(t *testing.T) {
|
||||||
// Assert that we have not left any development debug artifacts in
|
// Assert that we have not left any development debug artifacts in
|
||||||
// the code.
|
// the code.
|
||||||
if b.c != nil {
|
if b.c != nil {
|
||||||
_, ok := b.c.destinationFs.(types.DevMarker)
|
_, ok := b.c.publishDirFs.(types.DevMarker)
|
||||||
c.Assert(ok, qt.Equals, false)
|
c.Assert(ok, qt.Equals, false)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -329,11 +318,8 @@ type testSiteConfig struct {
|
||||||
contentDir string
|
contentDir string
|
||||||
}
|
}
|
||||||
|
|
||||||
func createSimpleTestSite(t testing.TB, cfg testSiteConfig) (string, func(), error) {
|
func createSimpleTestSite(t testing.TB, cfg testSiteConfig) string {
|
||||||
d, clean, e := htesting.CreateTempDir(hugofs.Os, "hugo-cli")
|
dir := t.TempDir()
|
||||||
if e != nil {
|
|
||||||
return "", nil, e
|
|
||||||
}
|
|
||||||
|
|
||||||
cfgStr := `
|
cfgStr := `
|
||||||
|
|
||||||
|
@ -352,23 +338,23 @@ title = "Hugo Commands"
|
||||||
contentDir = cfg.contentDir
|
contentDir = cfg.contentDir
|
||||||
}
|
}
|
||||||
|
|
||||||
os.MkdirAll(filepath.Join(d, "public"), 0777)
|
os.MkdirAll(filepath.Join(dir, "public"), 0777)
|
||||||
|
|
||||||
// Just the basic. These are for CLI tests, not site testing.
|
// Just the basic. These are for CLI tests, not site testing.
|
||||||
writeFile(t, filepath.Join(d, "config.toml"), cfgStr)
|
writeFile(t, filepath.Join(dir, "config.toml"), cfgStr)
|
||||||
writeFile(t, filepath.Join(d, "config", "staging", "params.toml"), `myparam="paramstaging"`)
|
writeFile(t, filepath.Join(dir, "config", "staging", "params.toml"), `myparam="paramstaging"`)
|
||||||
writeFile(t, filepath.Join(d, "config", "staging", "deployment.toml"), `
|
writeFile(t, filepath.Join(dir, "config", "staging", "deployment.toml"), `
|
||||||
[[targets]]
|
[[targets]]
|
||||||
name = "mydeployment"
|
name = "mydeployment"
|
||||||
URL = "hugocloud://hugotestbucket"
|
URL = "hugocloud://hugotestbucket"
|
||||||
`)
|
`)
|
||||||
|
|
||||||
writeFile(t, filepath.Join(d, "config", "testing", "params.toml"), `myparam="paramtesting"`)
|
writeFile(t, filepath.Join(dir, "config", "testing", "params.toml"), `myparam="paramtesting"`)
|
||||||
writeFile(t, filepath.Join(d, "config", "production", "params.toml"), `myparam="paramproduction"`)
|
writeFile(t, filepath.Join(dir, "config", "production", "params.toml"), `myparam="paramproduction"`)
|
||||||
|
|
||||||
writeFile(t, filepath.Join(d, "static", "myfile.txt"), `Hello World!`)
|
writeFile(t, filepath.Join(dir, "static", "myfile.txt"), `Hello World!`)
|
||||||
|
|
||||||
writeFile(t, filepath.Join(d, contentDir, "p1.md"), `
|
writeFile(t, filepath.Join(dir, contentDir, "p1.md"), `
|
||||||
---
|
---
|
||||||
title: "P1"
|
title: "P1"
|
||||||
weight: 1
|
weight: 1
|
||||||
|
@ -378,20 +364,20 @@ Content
|
||||||
|
|
||||||
`)
|
`)
|
||||||
|
|
||||||
writeFile(t, filepath.Join(d, "layouts", "_default", "single.html"), `
|
writeFile(t, filepath.Join(dir, "layouts", "_default", "single.html"), `
|
||||||
|
|
||||||
Single: {{ .Title }}
|
Single: {{ .Title }}
|
||||||
|
|
||||||
`)
|
`)
|
||||||
|
|
||||||
writeFile(t, filepath.Join(d, "layouts", "_default", "list.html"), `
|
writeFile(t, filepath.Join(dir, "layouts", "_default", "list.html"), `
|
||||||
|
|
||||||
List: {{ .Title }}
|
List: {{ .Title }}
|
||||||
Environment: {{ hugo.Environment }}
|
Environment: {{ hugo.Environment }}
|
||||||
|
|
||||||
`)
|
`)
|
||||||
|
|
||||||
return d, clean, nil
|
return dir
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeFile(t testing.TB, filename, content string) {
|
func writeFile(t testing.TB, filename, content string) {
|
||||||
|
|
|
@ -508,7 +508,7 @@ func (c *commandeer) build() error {
|
||||||
c.hugo().PrintProcessingStats(os.Stdout)
|
c.hugo().PrintProcessingStats(os.Stdout)
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
|
||||||
if createCounter, ok := c.destinationFs.(hugofs.DuplicatesReporter); ok {
|
if createCounter, ok := c.publishDirFs.(hugofs.DuplicatesReporter); ok {
|
||||||
dupes := createCounter.ReportDuplicates()
|
dupes := createCounter.ReportDuplicates()
|
||||||
if dupes != "" {
|
if dupes != "" {
|
||||||
c.logger.Warnln("Duplicate target paths:", dupes)
|
c.logger.Warnln("Duplicate target paths:", dupes)
|
||||||
|
@ -634,11 +634,7 @@ func chmodFilter(dst, src os.FileInfo) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *commandeer) copyStaticTo(sourceFs *filesystems.SourceFilesystem) (uint64, error) {
|
func (c *commandeer) copyStaticTo(sourceFs *filesystems.SourceFilesystem) (uint64, error) {
|
||||||
publishDir := c.hugo().PathSpec.PublishDir
|
publishDir := helpers.FilePathSeparator
|
||||||
// If root, remove the second '/'
|
|
||||||
if publishDir == "//" {
|
|
||||||
publishDir = helpers.FilePathSeparator
|
|
||||||
}
|
|
||||||
|
|
||||||
if sourceFs.PublishFolder != "" {
|
if sourceFs.PublishFolder != "" {
|
||||||
publishDir = filepath.Join(publishDir, sourceFs.PublishFolder)
|
publishDir = filepath.Join(publishDir, sourceFs.PublishFolder)
|
||||||
|
@ -651,9 +647,9 @@ func (c *commandeer) copyStaticTo(sourceFs *filesystems.SourceFilesystem) (uint6
|
||||||
syncer.NoChmod = c.Cfg.GetBool("noChmod")
|
syncer.NoChmod = c.Cfg.GetBool("noChmod")
|
||||||
syncer.ChmodFilter = chmodFilter
|
syncer.ChmodFilter = chmodFilter
|
||||||
syncer.SrcFs = fs
|
syncer.SrcFs = fs
|
||||||
syncer.DestFs = c.Fs.Destination
|
syncer.DestFs = c.Fs.PublishDir
|
||||||
if c.renderStaticToDisk {
|
if c.renderStaticToDisk {
|
||||||
syncer.DestFs = c.Fs.DestinationStatic
|
syncer.DestFs = c.Fs.PublishDirStatic
|
||||||
}
|
}
|
||||||
// Now that we are using a unionFs for the static directories
|
// Now that we are using a unionFs for the static directories
|
||||||
// We can effectively clean the publishDir on initial sync
|
// We can effectively clean the publishDir on initial sync
|
||||||
|
|
|
@ -36,12 +36,10 @@ title = "Hugo Commands"
|
||||||
contentDir = "thisdoesnotexist"
|
contentDir = "thisdoesnotexist"
|
||||||
|
|
||||||
`
|
`
|
||||||
dir, clean, err := createSimpleTestSite(t, testSiteConfig{configTOML: cfgStr, contentDir: contentDir})
|
dir := createSimpleTestSite(t, testSiteConfig{configTOML: cfgStr, contentDir: contentDir})
|
||||||
c.Assert(err, qt.IsNil)
|
|
||||||
defer clean()
|
|
||||||
|
|
||||||
cmd.SetArgs([]string{"-s=" + dir, "-c=" + contentDir})
|
cmd.SetArgs([]string{"-s=" + dir, "-c=" + contentDir})
|
||||||
|
|
||||||
_, err = cmd.ExecuteC()
|
_, err := cmd.ExecuteC()
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,10 +29,7 @@ func captureStdout(f func() error) (string, error) {
|
||||||
|
|
||||||
func TestListAll(t *testing.T) {
|
func TestListAll(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
dir, clean, err := createSimpleTestSite(t, testSiteConfig{})
|
dir := createSimpleTestSite(t, testSiteConfig{})
|
||||||
defer clean()
|
|
||||||
|
|
||||||
c.Assert(err, qt.IsNil)
|
|
||||||
|
|
||||||
hugoCmd := newCommandsBuilder().addAll().build()
|
hugoCmd := newCommandsBuilder().addAll().build()
|
||||||
cmd := hugoCmd.getCommand()
|
cmd := hugoCmd.getCommand()
|
||||||
|
|
|
@ -122,8 +122,10 @@ func (n *newSiteCmd) newSite(cmd *cobra.Command, args []string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
forceNew, _ := cmd.Flags().GetBool("force")
|
forceNew, _ := cmd.Flags().GetBool("force")
|
||||||
|
cfg := config.New()
|
||||||
return n.doNewSite(hugofs.NewDefault(config.New()), createpath, forceNew)
|
cfg.Set("workingDir", createpath)
|
||||||
|
cfg.Set("publishDir", "public")
|
||||||
|
return n.doNewSite(hugofs.NewDefault(cfg), createpath, forceNew)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createConfig(fs *hugofs.Fs, inpath string, kind string) (err error) {
|
func createConfig(fs *hugofs.Fs, inpath string, kind string) (err error) {
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -148,7 +149,7 @@ func (sc *serverCmd) server(cmd *cobra.Command, args []string) error {
|
||||||
var serverCfgInit sync.Once
|
var serverCfgInit sync.Once
|
||||||
|
|
||||||
cfgInit := func(c *commandeer) (rerr error) {
|
cfgInit := func(c *commandeer) (rerr error) {
|
||||||
c.Set("renderToMemory", !sc.renderToDisk)
|
c.Set("renderToMemory", !(sc.renderToDisk || sc.renderStaticToDisk))
|
||||||
c.Set("renderStaticToDisk", sc.renderStaticToDisk)
|
c.Set("renderStaticToDisk", sc.renderStaticToDisk)
|
||||||
if cmd.Flags().Changed("navigateToChanged") {
|
if cmd.Flags().Changed("navigateToChanged") {
|
||||||
c.Set("navigateToChanged", sc.navigateToChanged)
|
c.Set("navigateToChanged", sc.navigateToChanged)
|
||||||
|
@ -330,13 +331,18 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, net.Listener, string
|
||||||
port := f.c.serverPorts[i].p
|
port := f.c.serverPorts[i].p
|
||||||
listener := f.c.serverPorts[i].ln
|
listener := f.c.serverPorts[i].ln
|
||||||
|
|
||||||
|
// For logging only.
|
||||||
|
// TODO(bep) consolidate.
|
||||||
publishDir := f.c.Cfg.GetString("publishDir")
|
publishDir := f.c.Cfg.GetString("publishDir")
|
||||||
|
publishDirStatic := f.c.Cfg.GetString("publishDirStatic")
|
||||||
|
workingDir := f.c.Cfg.GetString("workingDir")
|
||||||
|
|
||||||
if root != "" {
|
if root != "" {
|
||||||
publishDir = filepath.Join(publishDir, root)
|
publishDir = filepath.Join(publishDir, root)
|
||||||
|
publishDirStatic = filepath.Join(publishDirStatic, root)
|
||||||
}
|
}
|
||||||
|
absPublishDir := paths.AbsPathify(workingDir, publishDir)
|
||||||
absPublishDir := f.c.hugo().PathSpec.AbsPathify(publishDir)
|
absPublishDirStatic := paths.AbsPathify(workingDir, publishDirStatic)
|
||||||
|
|
||||||
jww.FEEDBACK.Printf("Environment: %q", f.c.hugo().Deps.Site.Hugo().Environment)
|
jww.FEEDBACK.Printf("Environment: %q", f.c.hugo().Deps.Site.Hugo().Environment)
|
||||||
|
|
||||||
|
@ -344,14 +350,14 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, net.Listener, string
|
||||||
if f.s.renderToDisk {
|
if f.s.renderToDisk {
|
||||||
jww.FEEDBACK.Println("Serving pages from " + absPublishDir)
|
jww.FEEDBACK.Println("Serving pages from " + absPublishDir)
|
||||||
} else if f.s.renderStaticToDisk {
|
} else if f.s.renderStaticToDisk {
|
||||||
jww.FEEDBACK.Println("Serving pages from memory and static files from " + absPublishDir)
|
jww.FEEDBACK.Println("Serving pages from memory and static files from " + absPublishDirStatic)
|
||||||
} else {
|
} else {
|
||||||
jww.FEEDBACK.Println("Serving pages from memory")
|
jww.FEEDBACK.Println("Serving pages from memory")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
httpFs := afero.NewHttpFs(f.c.destinationFs)
|
httpFs := afero.NewHttpFs(f.c.publishDirServerFs)
|
||||||
fs := filesOnlyFs{httpFs.Dir(absPublishDir)}
|
fs := filesOnlyFs{httpFs.Dir(path.Join("/", root))}
|
||||||
|
|
||||||
if i == 0 && f.c.fastRenderMode {
|
if i == 0 && f.c.fastRenderMode {
|
||||||
jww.FEEDBACK.Println("Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender")
|
jww.FEEDBACK.Println("Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender")
|
||||||
|
|
|
@ -77,6 +77,9 @@ func TestServerFlags(t *testing.T) {
|
||||||
{"--renderToDisk", func(c *qt.C, r serverTestResult) {
|
{"--renderToDisk", func(c *qt.C, r serverTestResult) {
|
||||||
assertPublic(c, r, true)
|
assertPublic(c, r, true)
|
||||||
}},
|
}},
|
||||||
|
{"--renderStaticToDisk", func(c *qt.C, r serverTestResult) {
|
||||||
|
assertPublic(c, r, true)
|
||||||
|
}},
|
||||||
} {
|
} {
|
||||||
c.Run(test.flag, func(c *qt.C) {
|
c.Run(test.flag, func(c *qt.C) {
|
||||||
config := `
|
config := `
|
||||||
|
@ -105,9 +108,7 @@ type serverTestResult struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func runServerTest(c *qt.C, getHome bool, config string, args ...string) (result serverTestResult) {
|
func runServerTest(c *qt.C, getHome bool, config string, args ...string) (result serverTestResult) {
|
||||||
dir, clean, err := createSimpleTestSite(c, testSiteConfig{configTOML: config})
|
dir := createSimpleTestSite(c, testSiteConfig{configTOML: config})
|
||||||
defer clean()
|
|
||||||
c.Assert(err, qt.IsNil)
|
|
||||||
|
|
||||||
sp, err := helpers.FindAvailablePort()
|
sp, err := helpers.FindAvailablePort()
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
|
@ -141,12 +142,15 @@ func runServerTest(c *qt.C, getHome bool, config string, args ...string) (result
|
||||||
time.Sleep(567 * time.Millisecond)
|
time.Sleep(567 * time.Millisecond)
|
||||||
resp, err := http.Get(fmt.Sprintf("http://localhost:%d/", port))
|
resp, err := http.Get(fmt.Sprintf("http://localhost:%d/", port))
|
||||||
c.Check(err, qt.IsNil)
|
c.Check(err, qt.IsNil)
|
||||||
|
c.Check(resp.StatusCode, qt.Equals, http.StatusOK)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
result.homeContent = helpers.ReaderToString(resp.Body)
|
result.homeContent = helpers.ReaderToString(resp.Body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-stop:
|
case <-stop:
|
||||||
case stop <- true:
|
case stop <- true:
|
||||||
|
@ -191,7 +195,7 @@ func TestFixURL(t *testing.T) {
|
||||||
t.Run(test.TestName, func(t *testing.T) {
|
t.Run(test.TestName, func(t *testing.T) {
|
||||||
b := newCommandsBuilder()
|
b := newCommandsBuilder()
|
||||||
s := b.newServerCmd()
|
s := b.newServerCmd()
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
baseURL := test.CLIBaseURL
|
baseURL := test.CLIBaseURL
|
||||||
v.Set("baseURL", test.CfgBaseURL)
|
v.Set("baseURL", test.CfgBaseURL)
|
||||||
s.serverAppend = test.AppendPort
|
s.serverAppend = test.AppendPort
|
||||||
|
|
|
@ -40,11 +40,7 @@ func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
|
||||||
c := s.c
|
c := s.c
|
||||||
|
|
||||||
syncFn := func(sourceFs *filesystems.SourceFilesystem) (uint64, error) {
|
syncFn := func(sourceFs *filesystems.SourceFilesystem) (uint64, error) {
|
||||||
publishDir := c.hugo().PathSpec.PublishDir
|
publishDir := helpers.FilePathSeparator
|
||||||
// If root, remove the second '/'
|
|
||||||
if publishDir == "//" {
|
|
||||||
publishDir = helpers.FilePathSeparator
|
|
||||||
}
|
|
||||||
|
|
||||||
if sourceFs.PublishFolder != "" {
|
if sourceFs.PublishFolder != "" {
|
||||||
publishDir = filepath.Join(publishDir, sourceFs.PublishFolder)
|
publishDir = filepath.Join(publishDir, sourceFs.PublishFolder)
|
||||||
|
@ -55,9 +51,9 @@ func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
|
||||||
syncer.NoChmod = c.Cfg.GetBool("noChmod")
|
syncer.NoChmod = c.Cfg.GetBool("noChmod")
|
||||||
syncer.ChmodFilter = chmodFilter
|
syncer.ChmodFilter = chmodFilter
|
||||||
syncer.SrcFs = sourceFs.Fs
|
syncer.SrcFs = sourceFs.Fs
|
||||||
syncer.DestFs = c.Fs.Destination
|
syncer.DestFs = c.Fs.PublishDir
|
||||||
if c.renderStaticToDisk {
|
if c.renderStaticToDisk {
|
||||||
syncer.DestFs = c.Fs.DestinationStatic
|
syncer.DestFs = c.Fs.PublishDirStatic
|
||||||
}
|
}
|
||||||
|
|
||||||
// prevent spamming the log on changes
|
// prevent spamming the log on changes
|
||||||
|
@ -101,19 +97,14 @@ func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
|
||||||
if ev.Op&fsnotify.Rename == fsnotify.Rename || ev.Op&fsnotify.Remove == fsnotify.Remove {
|
if ev.Op&fsnotify.Rename == fsnotify.Rename || ev.Op&fsnotify.Remove == fsnotify.Remove {
|
||||||
if _, err := sourceFs.Fs.Stat(relPath); os.IsNotExist(err) {
|
if _, err := sourceFs.Fs.Stat(relPath); os.IsNotExist(err) {
|
||||||
// If file doesn't exist in any static dir, remove it
|
// If file doesn't exist in any static dir, remove it
|
||||||
toRemove := filepath.Join(publishDir, relPath)
|
logger.Println("File no longer exists in static dir, removing", relPath)
|
||||||
|
_ = c.Fs.PublishDirStatic.RemoveAll(relPath)
|
||||||
|
|
||||||
logger.Println("File no longer exists in static dir, removing", toRemove)
|
|
||||||
if c.renderStaticToDisk {
|
|
||||||
_ = c.Fs.DestinationStatic.RemoveAll(toRemove)
|
|
||||||
} else {
|
|
||||||
_ = c.Fs.Destination.RemoveAll(toRemove)
|
|
||||||
}
|
|
||||||
} else if err == nil {
|
} else if err == nil {
|
||||||
// If file still exists, sync it
|
// If file still exists, sync it
|
||||||
logger.Println("Syncing", relPath, "to", publishDir)
|
logger.Println("Syncing", relPath, "to", publishDir)
|
||||||
|
|
||||||
if err := syncer.Sync(filepath.Join(publishDir, relPath), relPath); err != nil {
|
if err := syncer.Sync(relPath, relPath); err != nil {
|
||||||
c.logger.Errorln(err)
|
c.logger.Errorln(err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -63,6 +63,15 @@ func (filepathBridge) Separator() string {
|
||||||
|
|
||||||
var fpb filepathBridge
|
var fpb filepathBridge
|
||||||
|
|
||||||
|
// AbsPathify creates an absolute path if given a working dir and a relative path.
|
||||||
|
// If already absolute, the path is just cleaned.
|
||||||
|
func AbsPathify(workingDir, inPath string) string {
|
||||||
|
if filepath.IsAbs(inPath) {
|
||||||
|
return filepath.Clean(inPath)
|
||||||
|
}
|
||||||
|
return filepath.Join(workingDir, inPath)
|
||||||
|
}
|
||||||
|
|
||||||
// MakeTitle converts the path given to a suitable title, trimming whitespace
|
// MakeTitle converts the path given to a suitable title, trimming whitespace
|
||||||
// and replacing hyphens with whitespace.
|
// and replacing hyphens with whitespace.
|
||||||
func MakeTitle(inpath string) string {
|
func MakeTitle(inpath string) string {
|
||||||
|
|
|
@ -45,13 +45,23 @@ func GetStringSlicePreserveString(cfg Provider, key string) []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetBaseTestDefaults provides some common config defaults used in tests.
|
// SetBaseTestDefaults provides some common config defaults used in tests.
|
||||||
func SetBaseTestDefaults(cfg Provider) {
|
func SetBaseTestDefaults(cfg Provider) Provider {
|
||||||
cfg.Set("resourceDir", "resources")
|
setIfNotSet(cfg, "baseURL", "https://example.org")
|
||||||
cfg.Set("contentDir", "content")
|
setIfNotSet(cfg, "resourceDir", "resources")
|
||||||
cfg.Set("dataDir", "data")
|
setIfNotSet(cfg, "contentDir", "content")
|
||||||
cfg.Set("i18nDir", "i18n")
|
setIfNotSet(cfg, "dataDir", "data")
|
||||||
cfg.Set("layoutDir", "layouts")
|
setIfNotSet(cfg, "i18nDir", "i18n")
|
||||||
cfg.Set("assetDir", "assets")
|
setIfNotSet(cfg, "layoutDir", "layouts")
|
||||||
cfg.Set("archetypeDir", "archetypes")
|
setIfNotSet(cfg, "assetDir", "assets")
|
||||||
cfg.Set("publishDir", "public")
|
setIfNotSet(cfg, "archetypeDir", "archetypes")
|
||||||
|
setIfNotSet(cfg, "publishDir", "public")
|
||||||
|
setIfNotSet(cfg, "workingDir", "")
|
||||||
|
setIfNotSet(cfg, "defaultContentLanguage", "en")
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
func setIfNotSet(cfg Provider, key string, value any) {
|
||||||
|
if !cfg.IsSet(key) {
|
||||||
|
cfg.Set(key, value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,11 @@ func NewFrom(params maps.Params) Provider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewWithTestDefaults is used in tests only.
|
||||||
|
func NewWithTestDefaults() Provider {
|
||||||
|
return SetBaseTestDefaults(New())
|
||||||
|
}
|
||||||
|
|
||||||
// defaultConfigProvider is a Provider backed by a map where all keys are lower case.
|
// defaultConfigProvider is a Provider backed by a map where all keys are lower case.
|
||||||
// All methods are thread safe.
|
// All methods are thread safe.
|
||||||
type defaultConfigProvider struct {
|
type defaultConfigProvider struct {
|
||||||
|
|
|
@ -54,7 +54,7 @@ disableInlineCSS = true
|
||||||
func TestUseSettingsFromRootIfSet(t *testing.T) {
|
func TestUseSettingsFromRootIfSet(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
cfg := config.New()
|
cfg := config.NewWithTestDefaults()
|
||||||
cfg.Set("disqusShortname", "root_short")
|
cfg.Set("disqusShortname", "root_short")
|
||||||
cfg.Set("googleAnalytics", "ga_root")
|
cfg.Set("googleAnalytics", "ga_root")
|
||||||
|
|
||||||
|
|
3
go.mod
3
go.mod
|
@ -48,7 +48,7 @@ require (
|
||||||
github.com/russross/blackfriday v1.6.0
|
github.com/russross/blackfriday v1.6.0
|
||||||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd
|
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd
|
||||||
github.com/sanity-io/litter v1.5.4
|
github.com/sanity-io/litter v1.5.4
|
||||||
github.com/spf13/afero v1.8.1
|
github.com/spf13/afero v1.8.2
|
||||||
github.com/spf13/cast v1.4.1
|
github.com/spf13/cast v1.4.1
|
||||||
github.com/spf13/cobra v1.4.0
|
github.com/spf13/cobra v1.4.0
|
||||||
github.com/spf13/fsync v0.9.0
|
github.com/spf13/fsync v0.9.0
|
||||||
|
@ -98,6 +98,7 @@ require (
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.3 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sso v1.11.3 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.16.3 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sts v1.16.3 // indirect
|
||||||
github.com/aws/smithy-go v1.11.2 // indirect
|
github.com/aws/smithy-go v1.11.2 // indirect
|
||||||
|
github.com/bep/overlayfs v0.1.0 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
|
||||||
github.com/dlclark/regexp2 v1.4.0 // indirect
|
github.com/dlclark/regexp2 v1.4.0 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -186,6 +186,8 @@ github.com/bep/golibsass v1.0.0 h1:gNguBMSDi5yZEZzVZP70YpuFQE3qogJIGUlrVILTmOw=
|
||||||
github.com/bep/golibsass v1.0.0/go.mod h1:DL87K8Un/+pWUS75ggYv41bliGiolxzDKWJAq3eJ1MA=
|
github.com/bep/golibsass v1.0.0/go.mod h1:DL87K8Un/+pWUS75ggYv41bliGiolxzDKWJAq3eJ1MA=
|
||||||
github.com/bep/gowebp v0.1.0 h1:4/iQpfnxHyXs3x/aTxMMdOpLEQQhFmF6G7EieWPTQyo=
|
github.com/bep/gowebp v0.1.0 h1:4/iQpfnxHyXs3x/aTxMMdOpLEQQhFmF6G7EieWPTQyo=
|
||||||
github.com/bep/gowebp v0.1.0/go.mod h1:ZhFodwdiFp8ehGJpF4LdPl6unxZm9lLFjxD3z2h2AgI=
|
github.com/bep/gowebp v0.1.0/go.mod h1:ZhFodwdiFp8ehGJpF4LdPl6unxZm9lLFjxD3z2h2AgI=
|
||||||
|
github.com/bep/overlayfs v0.1.0 h1:1hOCrvS4E5Hf0qwxM7m+9oitqClD9mRjQ1d4pECsVcU=
|
||||||
|
github.com/bep/overlayfs v0.1.0/go.mod h1:NFjSmn3kCqG7KX2Lmz8qT8VhPPCwZap3UNogXawoQHM=
|
||||||
github.com/bep/tmc v0.5.1 h1:CsQnSC6MsomH64gw0cT5f+EwQDcvZz4AazKunFwTpuI=
|
github.com/bep/tmc v0.5.1 h1:CsQnSC6MsomH64gw0cT5f+EwQDcvZz4AazKunFwTpuI=
|
||||||
github.com/bep/tmc v0.5.1/go.mod h1:tGYHN8fS85aJPhDLgXETVKp+PR382OvFi2+q2GkGsq0=
|
github.com/bep/tmc v0.5.1/go.mod h1:tGYHN8fS85aJPhDLgXETVKp+PR382OvFi2+q2GkGsq0=
|
||||||
github.com/bep/workers v1.0.0 h1:U+H8YmEaBCEaFZBst7GcRVEoqeRC9dzH2dWOwGmOchg=
|
github.com/bep/workers v1.0.0 h1:U+H8YmEaBCEaFZBst7GcRVEoqeRC9dzH2dWOwGmOchg=
|
||||||
|
@ -564,6 +566,8 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO
|
||||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||||
github.com/spf13/afero v1.8.1 h1:izYHOT71f9iZ7iq37Uqjael60/vYC6vMtzedudZ0zEk=
|
github.com/spf13/afero v1.8.1 h1:izYHOT71f9iZ7iq37Uqjael60/vYC6vMtzedudZ0zEk=
|
||||||
github.com/spf13/afero v1.8.1/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo=
|
github.com/spf13/afero v1.8.1/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo=
|
||||||
|
github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo=
|
||||||
|
github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo=
|
||||||
github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA=
|
github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA=
|
||||||
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
|
github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
|
||||||
|
|
|
@ -19,10 +19,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/config"
|
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/loggers"
|
"github.com/gohugoio/hugo/common/loggers"
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
)
|
)
|
||||||
|
@ -102,7 +102,7 @@ func TestBytesToHTML(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewContentSpec(t *testing.T) {
|
func TestNewContentSpec(t *testing.T) {
|
||||||
cfg := config.New()
|
cfg := config.NewWithTestDefaults()
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
cfg.Set("summaryLength", 32)
|
cfg.Set("summaryLength", 32)
|
||||||
|
|
|
@ -20,9 +20,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/config"
|
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/loggers"
|
"github.com/gohugoio/hugo/common/loggers"
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
@ -30,7 +29,7 @@ import (
|
||||||
|
|
||||||
func TestResolveMarkup(t *testing.T) {
|
func TestResolveMarkup(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
cfg := config.New()
|
cfg := config.NewWithTestDefaults()
|
||||||
spec, err := NewContentSpec(cfg, loggers.NewErrorLogger(), afero.NewMemMapFs(), nil)
|
spec, err := NewContentSpec(cfg, loggers.NewErrorLogger(), afero.NewMemMapFs(), nil)
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
|
|
||||||
|
|
|
@ -459,9 +459,17 @@ func IsDir(path string, fs afero.Fs) (bool, error) {
|
||||||
return afero.IsDir(fs, path)
|
return afero.IsDir(fs, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsEmpty checks if a given path is empty.
|
// IsEmpty checks if a given path is empty, meaning it doesn't contain any regular files.
|
||||||
func IsEmpty(path string, fs afero.Fs) (bool, error) {
|
func IsEmpty(path string, fs afero.Fs) (bool, error) {
|
||||||
return afero.IsEmpty(fs, path)
|
var hasFile bool
|
||||||
|
err := afero.Walk(fs, path, func(path string, info os.FileInfo, err error) error {
|
||||||
|
if info.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
hasFile = true
|
||||||
|
return filepath.SkipDir
|
||||||
|
})
|
||||||
|
return !hasFile, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exists checks if a file or directory exists.
|
// Exists checks if a file or directory exists.
|
||||||
|
|
|
@ -256,55 +256,6 @@ func TestIsDir(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIsEmpty(t *testing.T) {
|
|
||||||
zeroSizedFile, _ := createZeroSizedFileInTempDir()
|
|
||||||
defer deleteFileInTempDir(zeroSizedFile)
|
|
||||||
nonZeroSizedFile, _ := createNonZeroSizedFileInTempDir()
|
|
||||||
defer deleteFileInTempDir(nonZeroSizedFile)
|
|
||||||
emptyDirectory, _ := createEmptyTempDir()
|
|
||||||
defer deleteTempDir(emptyDirectory)
|
|
||||||
nonEmptyZeroLengthFilesDirectory, _ := createTempDirWithZeroLengthFiles()
|
|
||||||
defer deleteTempDir(nonEmptyZeroLengthFilesDirectory)
|
|
||||||
nonEmptyNonZeroLengthFilesDirectory, _ := createTempDirWithNonZeroLengthFiles()
|
|
||||||
defer deleteTempDir(nonEmptyNonZeroLengthFilesDirectory)
|
|
||||||
nonExistentFile := os.TempDir() + "/this-file-does-not-exist.txt"
|
|
||||||
nonExistentDir := os.TempDir() + "/this/directory/does/not/exist/"
|
|
||||||
|
|
||||||
fileDoesNotExist := fmt.Errorf("%q path does not exist", nonExistentFile)
|
|
||||||
dirDoesNotExist := fmt.Errorf("%q path does not exist", nonExistentDir)
|
|
||||||
|
|
||||||
type test struct {
|
|
||||||
input string
|
|
||||||
expectedResult bool
|
|
||||||
expectedErr error
|
|
||||||
}
|
|
||||||
|
|
||||||
data := []test{
|
|
||||||
{zeroSizedFile.Name(), true, nil},
|
|
||||||
{nonZeroSizedFile.Name(), false, nil},
|
|
||||||
{emptyDirectory, true, nil},
|
|
||||||
{nonEmptyZeroLengthFilesDirectory, false, nil},
|
|
||||||
{nonEmptyNonZeroLengthFilesDirectory, false, nil},
|
|
||||||
{nonExistentFile, false, fileDoesNotExist},
|
|
||||||
{nonExistentDir, false, dirDoesNotExist},
|
|
||||||
}
|
|
||||||
for i, d := range data {
|
|
||||||
exists, err := IsEmpty(d.input, new(afero.OsFs))
|
|
||||||
if d.expectedResult != exists {
|
|
||||||
t.Errorf("Test %d failed. Expected result %t got %t", i, d.expectedResult, exists)
|
|
||||||
}
|
|
||||||
if d.expectedErr != nil {
|
|
||||||
if d.expectedErr.Error() != err.Error() {
|
|
||||||
t.Errorf("Test %d failed. Expected %q(%#v) got %q(%#v)", i, d.expectedErr, d.expectedErr, err, err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if d.expectedErr != err {
|
|
||||||
t.Errorf("Test %d failed. Expected %q(%#v) got %q(%#v)", i, d.expectedErr, d.expectedErr, err, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func createZeroSizedFileInTempDir() (*os.File, error) {
|
func createZeroSizedFileInTempDir() (*os.File, error) {
|
||||||
filePrefix := "_path_test_"
|
filePrefix := "_path_test_"
|
||||||
f, e := ioutil.TempFile("", filePrefix) // dir is os.TempDir()
|
f, e := ioutil.TempFile("", filePrefix) // dir is os.TempDir()
|
||||||
|
@ -346,51 +297,6 @@ func createEmptyTempDir() (string, error) {
|
||||||
return d, nil
|
return d, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTempDirWithZeroLengthFiles() (string, error) {
|
|
||||||
d, dirErr := createEmptyTempDir()
|
|
||||||
if dirErr != nil {
|
|
||||||
return "", dirErr
|
|
||||||
}
|
|
||||||
filePrefix := "_path_test_"
|
|
||||||
_, fileErr := ioutil.TempFile(d, filePrefix) // dir is os.TempDir()
|
|
||||||
if fileErr != nil {
|
|
||||||
// if there was an error no file was created.
|
|
||||||
// but we need to remove the directory to clean-up
|
|
||||||
deleteTempDir(d)
|
|
||||||
return "", fileErr
|
|
||||||
}
|
|
||||||
// the dir now has one, zero length file in it
|
|
||||||
return d, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createTempDirWithNonZeroLengthFiles() (string, error) {
|
|
||||||
d, dirErr := createEmptyTempDir()
|
|
||||||
if dirErr != nil {
|
|
||||||
return "", dirErr
|
|
||||||
}
|
|
||||||
filePrefix := "_path_test_"
|
|
||||||
f, fileErr := ioutil.TempFile(d, filePrefix) // dir is os.TempDir()
|
|
||||||
if fileErr != nil {
|
|
||||||
// if there was an error no file was created.
|
|
||||||
// but we need to remove the directory to clean-up
|
|
||||||
deleteTempDir(d)
|
|
||||||
return "", fileErr
|
|
||||||
}
|
|
||||||
byteString := []byte("byteString")
|
|
||||||
|
|
||||||
fileErr = ioutil.WriteFile(f.Name(), byteString, 0644)
|
|
||||||
if fileErr != nil {
|
|
||||||
// delete the file
|
|
||||||
deleteFileInTempDir(f)
|
|
||||||
// also delete the directory
|
|
||||||
deleteTempDir(d)
|
|
||||||
return "", fileErr
|
|
||||||
}
|
|
||||||
|
|
||||||
// the dir now has one, zero length file in it
|
|
||||||
return d, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteTempDir(d string) {
|
func deleteTempDir(d string) {
|
||||||
_ = os.RemoveAll(d)
|
_ = os.RemoveAll(d)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,8 @@ func newTestPathSpec(fs *hugofs.Fs, v config.Provider) *PathSpec {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestDefaultPathSpec(configKeyValues ...any) *PathSpec {
|
func newTestDefaultPathSpec(configKeyValues ...any) *PathSpec {
|
||||||
v := config.New()
|
|
||||||
fs := hugofs.NewMem(v)
|
|
||||||
cfg := newTestCfg()
|
cfg := newTestCfg()
|
||||||
|
fs := hugofs.NewMem(cfg)
|
||||||
|
|
||||||
for i := 0; i < len(configKeyValues); i += 2 {
|
for i := 0; i < len(configKeyValues); i += 2 {
|
||||||
cfg.Set(configKeyValues[i].(string), configKeyValues[i+1])
|
cfg.Set(configKeyValues[i].(string), configKeyValues[i+1])
|
||||||
|
@ -28,15 +27,7 @@ func newTestDefaultPathSpec(configKeyValues ...any) *PathSpec {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestCfg() config.Provider {
|
func newTestCfg() config.Provider {
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
v.Set("contentDir", "content")
|
|
||||||
v.Set("dataDir", "data")
|
|
||||||
v.Set("i18nDir", "i18n")
|
|
||||||
v.Set("layoutDir", "layouts")
|
|
||||||
v.Set("assetDir", "assets")
|
|
||||||
v.Set("resourceDir", "resources")
|
|
||||||
v.Set("publishDir", "public")
|
|
||||||
v.Set("archetypeDir", "archetypes")
|
|
||||||
langs.LoadLanguageSettings(v, nil)
|
langs.LoadLanguageSettings(v, nil)
|
||||||
langs.LoadLanguageSettings(v, nil)
|
langs.LoadLanguageSettings(v, nil)
|
||||||
mod, err := modules.CreateProjectModule(v)
|
mod, err := modules.CreateProjectModule(v)
|
||||||
|
@ -49,7 +40,7 @@ func newTestCfg() config.Provider {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestContentSpec() *ContentSpec {
|
func newTestContentSpec() *ContentSpec {
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
spec, err := NewContentSpec(v, loggers.NewErrorLogger(), afero.NewMemMapFs(), nil)
|
spec, err := NewContentSpec(v, loggers.NewErrorLogger(), afero.NewMemMapFs(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
@ -33,10 +33,18 @@ type DuplicatesReporter interface {
|
||||||
ReportDuplicates() string
|
ReportDuplicates() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ FilesystemUnwrapper = (*createCountingFs)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
func NewCreateCountingFs(fs afero.Fs) afero.Fs {
|
func NewCreateCountingFs(fs afero.Fs) afero.Fs {
|
||||||
return &createCountingFs{Fs: fs, fileCount: make(map[string]int)}
|
return &createCountingFs{Fs: fs, fileCount: make(map[string]int)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fs *createCountingFs) UnwrapFilesystem() afero.Fs {
|
||||||
|
return fs.Fs
|
||||||
|
}
|
||||||
|
|
||||||
// ReportDuplicates reports filenames written more than once.
|
// ReportDuplicates reports filenames written more than once.
|
||||||
func (c *createCountingFs) ReportDuplicates() string {
|
func (c *createCountingFs) ReportDuplicates() string {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
|
|
|
@ -23,6 +23,10 @@ import (
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ FilesystemUnwrapper = (*baseFileDecoratorFs)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
func decorateDirs(fs afero.Fs, meta *FileMeta) afero.Fs {
|
func decorateDirs(fs afero.Fs, meta *FileMeta) afero.Fs {
|
||||||
ffs := &baseFileDecoratorFs{Fs: fs}
|
ffs := &baseFileDecoratorFs{Fs: fs}
|
||||||
|
|
||||||
|
@ -151,6 +155,10 @@ type baseFileDecoratorFs struct {
|
||||||
decorate func(fi os.FileInfo, filename string) (os.FileInfo, error)
|
decorate func(fi os.FileInfo, filename string) (os.FileInfo, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fs *baseFileDecoratorFs) UnwrapFilesystem() afero.Fs {
|
||||||
|
return fs.Fs
|
||||||
|
}
|
||||||
|
|
||||||
func (fs *baseFileDecoratorFs) Stat(name string) (os.FileInfo, error) {
|
func (fs *baseFileDecoratorFs) Stat(name string) (os.FileInfo, error) {
|
||||||
fi, err := fs.Fs.Stat(name)
|
fi, err := fs.Fs.Stat(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -23,6 +23,10 @@ import (
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ FilesystemUnwrapper = (*filenameFilterFs)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
func newFilenameFilterFs(fs afero.Fs, base string, filter *glob.FilenameFilter) afero.Fs {
|
func newFilenameFilterFs(fs afero.Fs, base string, filter *glob.FilenameFilter) afero.Fs {
|
||||||
return &filenameFilterFs{
|
return &filenameFilterFs{
|
||||||
fs: fs,
|
fs: fs,
|
||||||
|
@ -39,6 +43,10 @@ type filenameFilterFs struct {
|
||||||
filter *glob.FilenameFilter
|
filter *glob.FilenameFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fs *filenameFilterFs) UnwrapFilesystem() afero.Fs {
|
||||||
|
return fs.fs
|
||||||
|
}
|
||||||
|
|
||||||
func (fs *filenameFilterFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
|
func (fs *filenameFilterFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
|
||||||
fi, b, err := fs.fs.(afero.Lstater).LstatIfPossible(name)
|
fi, b, err := fs.fs.(afero.Lstater).LstatIfPossible(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -121,6 +121,10 @@ func NewFilterFs(fs afero.Fs) (afero.Fs, error) {
|
||||||
return ffs, nil
|
return ffs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ FilesystemUnwrapper = (*FilterFs)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
// FilterFs is an ordered composite filesystem.
|
// FilterFs is an ordered composite filesystem.
|
||||||
type FilterFs struct {
|
type FilterFs struct {
|
||||||
fs afero.Fs
|
fs afero.Fs
|
||||||
|
@ -141,6 +145,10 @@ func (fs *FilterFs) Chown(n string, uid, gid int) error {
|
||||||
return syscall.EPERM
|
return syscall.EPERM
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fs *FilterFs) UnwrapFilesystem() afero.Fs {
|
||||||
|
return fs.fs
|
||||||
|
}
|
||||||
|
|
||||||
func (fs *FilterFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
|
func (fs *FilterFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
|
||||||
fi, b, err := lstatIfPossible(fs.fs, name)
|
fi, b, err := lstatIfPossible(fs.fs, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
138
hugofs/fs.go
138
hugofs/fs.go
|
@ -19,6 +19,8 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/bep/overlayfs"
|
||||||
|
"github.com/gohugoio/hugo/common/paths"
|
||||||
"github.com/gohugoio/hugo/config"
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
)
|
)
|
||||||
|
@ -26,32 +28,43 @@ import (
|
||||||
// Os points to the (real) Os filesystem.
|
// Os points to the (real) Os filesystem.
|
||||||
var Os = &afero.OsFs{}
|
var Os = &afero.OsFs{}
|
||||||
|
|
||||||
// Fs abstracts the file system to separate source and destination file systems
|
// Fs holds the core filesystems used by Hugo.
|
||||||
// and allows both to be mocked for testing.
|
|
||||||
type Fs struct {
|
type Fs struct {
|
||||||
// Source is Hugo's source file system.
|
// Source is Hugo's source file system.
|
||||||
|
// Note that this will always be a "plain" Afero filesystem:
|
||||||
|
// * afero.OsFs when running in production
|
||||||
|
// * afero.MemMapFs for many of the tests.
|
||||||
Source afero.Fs
|
Source afero.Fs
|
||||||
|
|
||||||
// Destination is Hugo's destination file system.
|
// PublishDir is where Hugo publishes its rendered content.
|
||||||
Destination afero.Fs
|
// It's mounted inside publishDir (default /public).
|
||||||
|
PublishDir afero.Fs
|
||||||
|
|
||||||
// Destination used for `renderStaticToDisk`
|
// PublishDirStatic is the file system used for static files when --renderStaticToDisk is set.
|
||||||
DestinationStatic afero.Fs
|
// When this is set, PublishDir is set to write to memory.
|
||||||
|
PublishDirStatic afero.Fs
|
||||||
|
|
||||||
|
// PublishDirServer is the file system used for serving the public directory with Hugo's development server.
|
||||||
|
// This will typically be the same as PublishDir, but not if --renderStaticToDisk is set.
|
||||||
|
PublishDirServer afero.Fs
|
||||||
|
|
||||||
// Os is an OS file system.
|
// Os is an OS file system.
|
||||||
// NOTE: Field is currently unused.
|
// NOTE: Field is currently unused.
|
||||||
Os afero.Fs
|
Os afero.Fs
|
||||||
|
|
||||||
// WorkingDir is a read-only file system
|
// WorkingDirReadOnly is a read-only file system
|
||||||
// restricted to the project working dir.
|
// restricted to the project working dir.
|
||||||
// TODO(bep) get rid of this (se BaseFs)
|
WorkingDirReadOnly afero.Fs
|
||||||
WorkingDir *afero.BasePathFs
|
|
||||||
|
// WorkingDirWritable is a writable file system
|
||||||
|
// restricted to the project working dir.
|
||||||
|
WorkingDirWritable afero.Fs
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDefault creates a new Fs with the OS file system
|
// NewDefault creates a new Fs with the OS file system
|
||||||
// as source and destination file systems.
|
// as source and destination file systems.
|
||||||
func NewDefault(cfg config.Provider) *Fs {
|
func NewDefault(cfg config.Provider) *Fs {
|
||||||
fs := &afero.OsFs{}
|
fs := Os
|
||||||
return newFs(fs, cfg)
|
return newFs(fs, cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,23 +84,49 @@ func NewFrom(fs afero.Fs, cfg config.Provider) *Fs {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFs(base afero.Fs, cfg config.Provider) *Fs {
|
func newFs(base afero.Fs, cfg config.Provider) *Fs {
|
||||||
|
workingDir := cfg.GetString("workingDir")
|
||||||
|
publishDir := cfg.GetString("publishDir")
|
||||||
|
if publishDir == "" {
|
||||||
|
panic("publishDir is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanity check
|
||||||
|
if IsOsFs(base) && len(workingDir) < 2 {
|
||||||
|
panic("workingDir is too short")
|
||||||
|
}
|
||||||
|
|
||||||
|
absPublishDir := paths.AbsPathify(workingDir, publishDir)
|
||||||
|
|
||||||
|
// Make sure we always have the /public folder ready to use.
|
||||||
|
if err := base.MkdirAll(absPublishDir, 0777); err != nil && !os.IsExist(err) {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pubFs := afero.NewBasePathFs(base, absPublishDir)
|
||||||
|
|
||||||
return &Fs{
|
return &Fs{
|
||||||
Source: base,
|
Source: base,
|
||||||
Destination: base,
|
PublishDir: pubFs,
|
||||||
DestinationStatic: base,
|
PublishDirServer: pubFs,
|
||||||
|
PublishDirStatic: pubFs,
|
||||||
Os: &afero.OsFs{},
|
Os: &afero.OsFs{},
|
||||||
WorkingDir: getWorkingDirFs(base, cfg),
|
WorkingDirReadOnly: getWorkingDirFsReadOnly(base, workingDir),
|
||||||
|
WorkingDirWritable: getWorkingDirFsWritable(base, workingDir),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getWorkingDirFs(base afero.Fs, cfg config.Provider) *afero.BasePathFs {
|
func getWorkingDirFsReadOnly(base afero.Fs, workingDir string) afero.Fs {
|
||||||
workingDir := cfg.GetString("workingDir")
|
if workingDir == "" {
|
||||||
|
return afero.NewReadOnlyFs(base)
|
||||||
if workingDir != "" {
|
}
|
||||||
return afero.NewBasePathFs(afero.NewReadOnlyFs(base), workingDir).(*afero.BasePathFs)
|
return afero.NewBasePathFs(afero.NewReadOnlyFs(base), workingDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
func getWorkingDirFsWritable(base afero.Fs, workingDir string) afero.Fs {
|
||||||
|
if workingDir == "" {
|
||||||
|
return base
|
||||||
|
}
|
||||||
|
return afero.NewBasePathFs(base, workingDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isWrite(flag int) bool {
|
func isWrite(flag int) bool {
|
||||||
|
@ -117,3 +156,64 @@ func MakeReadableAndRemoveAllModulePkgDir(fs afero.Fs, dir string) (int, error)
|
||||||
})
|
})
|
||||||
return counter, fs.RemoveAll(dir)
|
return counter, fs.RemoveAll(dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasOsFs returns whether fs is an OsFs or if it fs wraps an OsFs.
|
||||||
|
// TODO(bep) make this nore robust.
|
||||||
|
func IsOsFs(fs afero.Fs) bool {
|
||||||
|
var isOsFs bool
|
||||||
|
WalkFilesystems(fs, func(fs afero.Fs) bool {
|
||||||
|
switch base := fs.(type) {
|
||||||
|
case *afero.MemMapFs:
|
||||||
|
isOsFs = false
|
||||||
|
case *afero.OsFs:
|
||||||
|
isOsFs = true
|
||||||
|
case *afero.BasePathFs:
|
||||||
|
_, supportsLstat, _ := base.LstatIfPossible("asdfasdfasdf")
|
||||||
|
isOsFs = supportsLstat
|
||||||
|
}
|
||||||
|
return isOsFs
|
||||||
|
})
|
||||||
|
return isOsFs
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilesystemsUnwrapper returns the underlying filesystems.
|
||||||
|
type FilesystemsUnwrapper interface {
|
||||||
|
UnwrapFilesystems() []afero.Fs
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilesystemsProvider returns the underlying filesystem.
|
||||||
|
type FilesystemUnwrapper interface {
|
||||||
|
UnwrapFilesystem() afero.Fs
|
||||||
|
}
|
||||||
|
|
||||||
|
// WalkFn is the walk func for WalkFilesystems.
|
||||||
|
type WalkFn func(fs afero.Fs) bool
|
||||||
|
|
||||||
|
// WalkFilesystems walks fs recursively and calls fn.
|
||||||
|
// If fn returns true, walking is stopped.
|
||||||
|
func WalkFilesystems(fs afero.Fs, fn WalkFn) bool {
|
||||||
|
if fn(fs) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if afs, ok := fs.(FilesystemUnwrapper); ok {
|
||||||
|
if WalkFilesystems(afs.UnwrapFilesystem(), fn) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if bfs, ok := fs.(FilesystemsUnwrapper); ok {
|
||||||
|
for _, sf := range bfs.UnwrapFilesystems() {
|
||||||
|
if WalkFilesystems(sf, fn) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if cfs, ok := fs.(overlayfs.FilesystemIterator); ok {
|
||||||
|
for i := 0; i < cfs.NumFilesystems(); i++ {
|
||||||
|
if WalkFilesystems(cfs.Filesystem(i), fn) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
@ -23,38 +23,46 @@ import (
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestIsOsFs(t *testing.T) {
|
||||||
|
c := qt.New(t)
|
||||||
|
|
||||||
|
c.Assert(IsOsFs(Os), qt.Equals, true)
|
||||||
|
c.Assert(IsOsFs(&afero.MemMapFs{}), qt.Equals, false)
|
||||||
|
c.Assert(IsOsFs(afero.NewBasePathFs(&afero.MemMapFs{}, "/public")), qt.Equals, false)
|
||||||
|
c.Assert(IsOsFs(afero.NewBasePathFs(Os, t.TempDir())), qt.Equals, true)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func TestNewDefault(t *testing.T) {
|
func TestNewDefault(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
|
v.Set("workingDir", t.TempDir())
|
||||||
f := NewDefault(v)
|
f := NewDefault(v)
|
||||||
|
|
||||||
c.Assert(f.Source, qt.Not(qt.IsNil))
|
c.Assert(f.Source, qt.IsNotNil)
|
||||||
c.Assert(f.Source, hqt.IsSameType, new(afero.OsFs))
|
c.Assert(f.Source, hqt.IsSameType, new(afero.OsFs))
|
||||||
c.Assert(f.Os, qt.Not(qt.IsNil))
|
c.Assert(f.Os, qt.IsNotNil)
|
||||||
c.Assert(f.WorkingDir, qt.IsNil)
|
c.Assert(f.WorkingDirReadOnly, qt.IsNotNil)
|
||||||
|
c.Assert(f.WorkingDirReadOnly, hqt.IsSameType, new(afero.BasePathFs))
|
||||||
|
c.Assert(IsOsFs(f.Source), qt.IsTrue)
|
||||||
|
c.Assert(IsOsFs(f.WorkingDirReadOnly), qt.IsTrue)
|
||||||
|
c.Assert(IsOsFs(f.PublishDir), qt.IsTrue)
|
||||||
|
c.Assert(IsOsFs(f.Os), qt.IsTrue)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewMem(t *testing.T) {
|
func TestNewMem(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
f := NewMem(v)
|
f := NewMem(v)
|
||||||
|
|
||||||
c.Assert(f.Source, qt.Not(qt.IsNil))
|
c.Assert(f.Source, qt.Not(qt.IsNil))
|
||||||
c.Assert(f.Source, hqt.IsSameType, new(afero.MemMapFs))
|
c.Assert(f.Source, hqt.IsSameType, new(afero.MemMapFs))
|
||||||
c.Assert(f.Destination, qt.Not(qt.IsNil))
|
c.Assert(f.PublishDir, qt.Not(qt.IsNil))
|
||||||
c.Assert(f.Destination, hqt.IsSameType, new(afero.MemMapFs))
|
c.Assert(f.PublishDir, hqt.IsSameType, new(afero.BasePathFs))
|
||||||
c.Assert(f.Os, hqt.IsSameType, new(afero.OsFs))
|
c.Assert(f.Os, hqt.IsSameType, new(afero.OsFs))
|
||||||
c.Assert(f.WorkingDir, qt.IsNil)
|
c.Assert(f.WorkingDirReadOnly, qt.IsNotNil)
|
||||||
}
|
c.Assert(IsOsFs(f.Source), qt.IsFalse)
|
||||||
|
c.Assert(IsOsFs(f.WorkingDirReadOnly), qt.IsFalse)
|
||||||
func TestWorkingDir(t *testing.T) {
|
c.Assert(IsOsFs(f.PublishDir), qt.IsFalse)
|
||||||
c := qt.New(t)
|
c.Assert(IsOsFs(f.Os), qt.IsTrue)
|
||||||
v := config.New()
|
|
||||||
|
|
||||||
v.Set("workingDir", "/a/b/")
|
|
||||||
|
|
||||||
f := NewMem(v)
|
|
||||||
|
|
||||||
c.Assert(f.WorkingDir, qt.Not(qt.IsNil))
|
|
||||||
c.Assert(f.WorkingDir, hqt.IsSameType, new(afero.BasePathFs))
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,10 @@ import (
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ afero.Fs = (*md5HashingFs)(nil)
|
var (
|
||||||
|
_ afero.Fs = (*md5HashingFs)(nil)
|
||||||
|
_ FilesystemUnwrapper = (*md5HashingFs)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
// FileHashReceiver will receive the filename an the content's MD5 sum on file close.
|
// FileHashReceiver will receive the filename an the content's MD5 sum on file close.
|
||||||
type FileHashReceiver interface {
|
type FileHashReceiver interface {
|
||||||
|
@ -45,6 +48,10 @@ func NewHashingFs(delegate afero.Fs, hashReceiver FileHashReceiver) afero.Fs {
|
||||||
return &md5HashingFs{Fs: delegate, hashReceiver: hashReceiver}
|
return &md5HashingFs{Fs: delegate, hashReceiver: hashReceiver}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fs *md5HashingFs) UnwrapFilesystem() afero.Fs {
|
||||||
|
return fs.Fs
|
||||||
|
}
|
||||||
|
|
||||||
func (fs *md5HashingFs) Create(name string) (afero.File, error) {
|
func (fs *md5HashingFs) Create(name string) (afero.File, error) {
|
||||||
f, err := fs.Fs.Create(name)
|
f, err := fs.Fs.Create(name)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
|
@ -22,9 +22,12 @@ import (
|
||||||
var (
|
var (
|
||||||
_ afero.Fs = (*languageCompositeFs)(nil)
|
_ afero.Fs = (*languageCompositeFs)(nil)
|
||||||
_ afero.Lstater = (*languageCompositeFs)(nil)
|
_ afero.Lstater = (*languageCompositeFs)(nil)
|
||||||
|
_ FilesystemsUnwrapper = (*languageCompositeFs)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
type languageCompositeFs struct {
|
type languageCompositeFs struct {
|
||||||
|
base afero.Fs
|
||||||
|
overlay afero.Fs
|
||||||
*afero.CopyOnWriteFs
|
*afero.CopyOnWriteFs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +36,11 @@ type languageCompositeFs struct {
|
||||||
// to the target filesystem. This information is available in Readdir, Stat etc. via the
|
// to the target filesystem. This information is available in Readdir, Stat etc. via the
|
||||||
// special LanguageFileInfo FileInfo implementation.
|
// special LanguageFileInfo FileInfo implementation.
|
||||||
func NewLanguageCompositeFs(base, overlay afero.Fs) afero.Fs {
|
func NewLanguageCompositeFs(base, overlay afero.Fs) afero.Fs {
|
||||||
return &languageCompositeFs{afero.NewCopyOnWriteFs(base, overlay).(*afero.CopyOnWriteFs)}
|
return &languageCompositeFs{base, overlay, afero.NewCopyOnWriteFs(base, overlay).(*afero.CopyOnWriteFs)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *languageCompositeFs) UnwrapFilesystems() []afero.Fs {
|
||||||
|
return []afero.Fs{fs.base, fs.overlay}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open takes the full path to the file in the target filesystem. If it is a directory, it gets merged
|
// Open takes the full path to the file in the target filesystem. If it is a directory, it gets merged
|
||||||
|
|
|
@ -30,6 +30,10 @@ func NewNoSymlinkFs(fs afero.Fs, logger loggers.Logger, allowFiles bool) afero.F
|
||||||
return &noSymlinkFs{Fs: fs, logger: logger, allowFiles: allowFiles}
|
return &noSymlinkFs{Fs: fs, logger: logger, allowFiles: allowFiles}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ FilesystemUnwrapper = (*noSymlinkFs)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
// noSymlinkFs is a filesystem that prevents symlinking.
|
// noSymlinkFs is a filesystem that prevents symlinking.
|
||||||
type noSymlinkFs struct {
|
type noSymlinkFs struct {
|
||||||
allowFiles bool // block dirs only
|
allowFiles bool // block dirs only
|
||||||
|
@ -67,6 +71,10 @@ func (f *noSymlinkFile) Readdirnames(count int) ([]string, error) {
|
||||||
return fileInfosToNames(dirs), nil
|
return fileInfosToNames(dirs), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fs *noSymlinkFs) UnwrapFilesystem() afero.Fs {
|
||||||
|
return fs.Fs
|
||||||
|
}
|
||||||
|
|
||||||
func (fs *noSymlinkFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
|
func (fs *noSymlinkFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
|
||||||
return fs.stat(name)
|
return fs.stat(name)
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,6 +151,10 @@ func (r RootMapping) trimFrom(name string) string {
|
||||||
return strings.TrimPrefix(name, r.From)
|
return strings.TrimPrefix(name, r.From)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ FilesystemUnwrapper = (*RootMappingFs)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
// A RootMappingFs maps several roots into one. Note that the root of this filesystem
|
// A RootMappingFs maps several roots into one. Note that the root of this filesystem
|
||||||
// is directories only, and they will be returned in Readdir and Readdirnames
|
// is directories only, and they will be returned in Readdir and Readdirnames
|
||||||
// in the order given.
|
// in the order given.
|
||||||
|
@ -200,6 +204,10 @@ func (fs *RootMappingFs) Dirs(base string) ([]FileMetaInfo, error) {
|
||||||
return fss, nil
|
return fss, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fs *RootMappingFs) UnwrapFilesystem() afero.Fs {
|
||||||
|
return fs.Fs
|
||||||
|
}
|
||||||
|
|
||||||
// Filter creates a copy of this filesystem with only mappings matching a filter.
|
// Filter creates a copy of this filesystem with only mappings matching a filter.
|
||||||
func (fs RootMappingFs) Filter(f func(m RootMapping) bool) *RootMappingFs {
|
func (fs RootMappingFs) Filter(f func(m RootMapping) bool) *RootMappingFs {
|
||||||
rootMapToReal := radix.New()
|
rootMapToReal := radix.New()
|
||||||
|
|
|
@ -20,9 +20,8 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/hugofs/glob"
|
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/config"
|
"github.com/gohugoio/hugo/config"
|
||||||
|
"github.com/gohugoio/hugo/hugofs/glob"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/gohugoio/hugo/htesting"
|
"github.com/gohugoio/hugo/htesting"
|
||||||
|
@ -31,7 +30,7 @@ import (
|
||||||
|
|
||||||
func TestLanguageRootMapping(t *testing.T) {
|
func TestLanguageRootMapping(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
v.Set("contentDir", "content")
|
v.Set("contentDir", "content")
|
||||||
|
|
||||||
fs := NewBaseFileDecorator(afero.NewMemMapFs())
|
fs := NewBaseFileDecorator(afero.NewMemMapFs())
|
||||||
|
|
|
@ -26,6 +26,7 @@ import (
|
||||||
var (
|
var (
|
||||||
_ afero.Fs = (*SliceFs)(nil)
|
_ afero.Fs = (*SliceFs)(nil)
|
||||||
_ afero.Lstater = (*SliceFs)(nil)
|
_ afero.Lstater = (*SliceFs)(nil)
|
||||||
|
_ FilesystemsUnwrapper = (*SliceFs)(nil)
|
||||||
_ afero.File = (*sliceDir)(nil)
|
_ afero.File = (*sliceDir)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -52,6 +53,14 @@ type SliceFs struct {
|
||||||
dirs []FileMetaInfo
|
dirs []FileMetaInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fs *SliceFs) UnwrapFilesystems() []afero.Fs {
|
||||||
|
var fss []afero.Fs
|
||||||
|
for _, dir := range fs.dirs {
|
||||||
|
fss = append(fss, dir.Meta().Fs)
|
||||||
|
}
|
||||||
|
return fss
|
||||||
|
}
|
||||||
|
|
||||||
func (fs *SliceFs) Chmod(n string, m os.FileMode) error {
|
func (fs *SliceFs) Chmod(n string, m os.FileMode) error {
|
||||||
return syscall.EPERM
|
return syscall.EPERM
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,11 @@ import (
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
// Make sure we don't accidentally use this in the real Hugo.
|
// Make sure we don't accidentally use this in the real Hugo.
|
||||||
var _ types.DevMarker = (*stacktracerFs)(nil)
|
_ types.DevMarker = (*stacktracerFs)(nil)
|
||||||
|
_ FilesystemUnwrapper = (*stacktracerFs)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
// NewStacktracerFs wraps the given fs printing stack traces for file creates
|
// NewStacktracerFs wraps the given fs printing stack traces for file creates
|
||||||
// matching the given regexp pattern.
|
// matching the given regexp pattern.
|
||||||
|
@ -45,6 +48,10 @@ type stacktracerFs struct {
|
||||||
func (fs *stacktracerFs) DevOnly() {
|
func (fs *stacktracerFs) DevOnly() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fs *stacktracerFs) UnwrapFilesystem() afero.Fs {
|
||||||
|
return fs.Fs
|
||||||
|
}
|
||||||
|
|
||||||
func (fs *stacktracerFs) onCreate(filename string) {
|
func (fs *stacktracerFs) onCreate(filename string) {
|
||||||
if fs.re.MatchString(filename) {
|
if fs.re.MatchString(filename) {
|
||||||
trace := make([]byte, 1500)
|
trace := make([]byte, 1500)
|
||||||
|
|
|
@ -35,7 +35,6 @@ import (
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/herrors"
|
"github.com/gohugoio/hugo/common/herrors"
|
||||||
"github.com/gohugoio/hugo/common/hugo"
|
"github.com/gohugoio/hugo/common/hugo"
|
||||||
"github.com/gohugoio/hugo/hugolib/paths"
|
|
||||||
"github.com/gohugoio/hugo/langs"
|
"github.com/gohugoio/hugo/langs"
|
||||||
"github.com/gohugoio/hugo/modules"
|
"github.com/gohugoio/hugo/modules"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -359,7 +358,7 @@ func (l configLoader) collectModules(modConfig modules.Config, v1 config.Provide
|
||||||
workingDir = v1.GetString("workingDir")
|
workingDir = v1.GetString("workingDir")
|
||||||
}
|
}
|
||||||
|
|
||||||
themesDir := paths.AbsPathify(l.WorkingDir, v1.GetString("themesDir"))
|
themesDir := cpaths.AbsPathify(l.WorkingDir, v1.GetString("themesDir"))
|
||||||
|
|
||||||
var ignoreVendor glob.Glob
|
var ignoreVendor glob.Glob
|
||||||
if s := v1.GetString("ignoreVendorPaths"); s != "" {
|
if s := v1.GetString("ignoreVendorPaths"); s != "" {
|
||||||
|
|
|
@ -38,8 +38,8 @@ import (
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/modules"
|
"github.com/gohugoio/hugo/modules"
|
||||||
|
|
||||||
|
hpaths "github.com/gohugoio/hugo/common/paths"
|
||||||
"github.com/gohugoio/hugo/hugofs"
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/hugolib/paths"
|
"github.com/gohugoio/hugo/hugolib/paths"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
)
|
)
|
||||||
|
@ -68,12 +68,12 @@ type BaseFs struct {
|
||||||
// This usually maps to /my-project/public.
|
// This usually maps to /my-project/public.
|
||||||
PublishFs afero.Fs
|
PublishFs afero.Fs
|
||||||
|
|
||||||
// A read-only filesystem starting from the project workDir.
|
|
||||||
WorkDir afero.Fs
|
|
||||||
|
|
||||||
// The filesystem used for renderStaticToDisk.
|
// The filesystem used for renderStaticToDisk.
|
||||||
PublishFsStatic afero.Fs
|
PublishFsStatic afero.Fs
|
||||||
|
|
||||||
|
// A read-only filesystem starting from the project workDir.
|
||||||
|
WorkDir afero.Fs
|
||||||
|
|
||||||
theBigFs *filesystemsCollector
|
theBigFs *filesystemsCollector
|
||||||
|
|
||||||
// Locks.
|
// Locks.
|
||||||
|
@ -434,21 +434,13 @@ func NewBase(p *paths.Paths, logger loggers.Logger, options ...func(*BaseFs) err
|
||||||
logger = loggers.NewWarningLogger()
|
logger = loggers.NewWarningLogger()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we always have the /public folder ready to use.
|
publishFs := hugofs.NewBaseFileDecorator(fs.PublishDir)
|
||||||
if err := fs.Destination.MkdirAll(p.AbsPublishDir, 0777); err != nil && !os.IsExist(err) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
publishFs := hugofs.NewBaseFileDecorator(afero.NewBasePathFs(fs.Destination, p.AbsPublishDir))
|
|
||||||
sourceFs := hugofs.NewBaseFileDecorator(afero.NewBasePathFs(fs.Source, p.WorkingDir))
|
sourceFs := hugofs.NewBaseFileDecorator(afero.NewBasePathFs(fs.Source, p.WorkingDir))
|
||||||
publishFsStatic := afero.NewBasePathFs(fs.Source, p.AbsPublishDir)
|
publishFsStatic := fs.PublishDirStatic
|
||||||
|
|
||||||
// Same as sourceFs, but no decoration. This is what's used by os.ReadDir etc.
|
|
||||||
workDir := afero.NewBasePathFs(afero.NewReadOnlyFs(fs.Source), p.WorkingDir)
|
|
||||||
|
|
||||||
b := &BaseFs{
|
b := &BaseFs{
|
||||||
SourceFs: sourceFs,
|
SourceFs: sourceFs,
|
||||||
WorkDir: workDir,
|
WorkDir: fs.WorkingDirReadOnly,
|
||||||
PublishFs: publishFs,
|
PublishFs: publishFs,
|
||||||
PublishFsStatic: publishFsStatic,
|
PublishFsStatic: publishFsStatic,
|
||||||
buildMu: lockedfile.MutexAt(filepath.Join(p.WorkingDir, lockFileBuild)),
|
buildMu: lockedfile.MutexAt(filepath.Join(p.WorkingDir, lockFileBuild)),
|
||||||
|
@ -638,7 +630,7 @@ func (b *sourceFilesystemsBuilder) createModFs(
|
||||||
if filepath.IsAbs(path) {
|
if filepath.IsAbs(path) {
|
||||||
return "", path
|
return "", path
|
||||||
}
|
}
|
||||||
return md.dir, paths.AbsPathify(md.dir, path)
|
return md.dir, hpaths.AbsPathify(md.dir, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, mount := range md.Mounts() {
|
for i, mount := range md.Mounts() {
|
||||||
|
|
|
@ -75,7 +75,7 @@ func initConfig(fs afero.Fs, cfg config.Provider) error {
|
||||||
|
|
||||||
func TestNewBaseFs(t *testing.T) {
|
func TestNewBaseFs(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
|
|
||||||
fs := hugofs.NewMem(v)
|
fs := hugofs.NewMem(v)
|
||||||
|
|
||||||
|
@ -181,7 +181,7 @@ theme = ["atheme"]
|
||||||
}
|
}
|
||||||
|
|
||||||
func createConfig() config.Provider {
|
func createConfig() config.Provider {
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
v.Set("contentDir", "mycontent")
|
v.Set("contentDir", "mycontent")
|
||||||
v.Set("i18nDir", "myi18n")
|
v.Set("i18nDir", "myi18n")
|
||||||
v.Set("staticDir", "mystatic")
|
v.Set("staticDir", "mystatic")
|
||||||
|
@ -219,22 +219,19 @@ func TestNewBaseFsEmpty(t *testing.T) {
|
||||||
func TestRealDirs(t *testing.T) {
|
func TestRealDirs(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := createConfig()
|
v := createConfig()
|
||||||
|
root, themesDir := t.TempDir(), t.TempDir()
|
||||||
|
v.Set("workingDir", root)
|
||||||
|
v.Set("themesDir", themesDir)
|
||||||
|
v.Set("theme", "mytheme")
|
||||||
|
|
||||||
fs := hugofs.NewDefault(v)
|
fs := hugofs.NewDefault(v)
|
||||||
sfs := fs.Source
|
sfs := fs.Source
|
||||||
|
|
||||||
root, err := afero.TempDir(sfs, "", "realdir")
|
|
||||||
c.Assert(err, qt.IsNil)
|
|
||||||
themesDir, err := afero.TempDir(sfs, "", "themesDir")
|
|
||||||
c.Assert(err, qt.IsNil)
|
|
||||||
defer func() {
|
defer func() {
|
||||||
os.RemoveAll(root)
|
os.RemoveAll(root)
|
||||||
os.RemoveAll(themesDir)
|
os.RemoveAll(themesDir)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
v.Set("workingDir", root)
|
|
||||||
v.Set("themesDir", themesDir)
|
|
||||||
v.Set("theme", "mytheme")
|
|
||||||
|
|
||||||
c.Assert(sfs.MkdirAll(filepath.Join(root, "myassets", "scss", "sf1"), 0755), qt.IsNil)
|
c.Assert(sfs.MkdirAll(filepath.Join(root, "myassets", "scss", "sf1"), 0755), qt.IsNil)
|
||||||
c.Assert(sfs.MkdirAll(filepath.Join(root, "myassets", "scss", "sf2"), 0755), qt.IsNil)
|
c.Assert(sfs.MkdirAll(filepath.Join(root, "myassets", "scss", "sf2"), 0755), qt.IsNil)
|
||||||
c.Assert(sfs.MkdirAll(filepath.Join(themesDir, "mytheme", "assets", "scss", "sf2"), 0755), qt.IsNil)
|
c.Assert(sfs.MkdirAll(filepath.Join(themesDir, "mytheme", "assets", "scss", "sf2"), 0755), qt.IsNil)
|
||||||
|
|
|
@ -59,13 +59,14 @@ path="github.com/gohugoio/hugoTestModule2"
|
||||||
return fmt.Sprintf(tomlConfig, workingDir, moduleOpts)
|
return fmt.Sprintf(tomlConfig, workingDir, moduleOpts)
|
||||||
}
|
}
|
||||||
|
|
||||||
newTestBuilder := func(t testing.TB, moduleOpts string) (*sitesBuilder, func()) {
|
newTestBuilder := func(t testing.TB, moduleOpts string) *sitesBuilder {
|
||||||
b := newTestSitesBuilder(t)
|
b := newTestSitesBuilder(t)
|
||||||
tempDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugo-modules-variants")
|
tempDir := t.TempDir()
|
||||||
b.Assert(err, qt.IsNil)
|
|
||||||
workingDir := filepath.Join(tempDir, "myhugosite")
|
workingDir := filepath.Join(tempDir, "myhugosite")
|
||||||
b.Assert(os.MkdirAll(workingDir, 0777), qt.IsNil)
|
b.Assert(os.MkdirAll(workingDir, 0777), qt.IsNil)
|
||||||
b.Fs = hugofs.NewDefault(config.New())
|
cfg := config.NewWithTestDefaults()
|
||||||
|
cfg.Set("workingDir", workingDir)
|
||||||
|
b.Fs = hugofs.NewDefault(cfg)
|
||||||
b.WithWorkingDir(workingDir).WithConfigFile("toml", createConfig(workingDir, moduleOpts))
|
b.WithWorkingDir(workingDir).WithConfigFile("toml", createConfig(workingDir, moduleOpts))
|
||||||
b.WithTemplates(
|
b.WithTemplates(
|
||||||
"index.html", `
|
"index.html", `
|
||||||
|
@ -92,22 +93,18 @@ github.com/gohugoio/hugoTestModule2 v0.0.0-20200131160637-9657d7697877 h1:WLM2bQ
|
||||||
github.com/gohugoio/hugoTestModule2 v0.0.0-20200131160637-9657d7697877/go.mod h1:CBFZS3khIAXKxReMwq0le8sEl/D8hcXmixlOHVv+Gd0=
|
github.com/gohugoio/hugoTestModule2 v0.0.0-20200131160637-9657d7697877/go.mod h1:CBFZS3khIAXKxReMwq0le8sEl/D8hcXmixlOHVv+Gd0=
|
||||||
`)
|
`)
|
||||||
|
|
||||||
return b, clean
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("Target in subfolder", func(t *testing.T) {
|
t.Run("Target in subfolder", func(t *testing.T) {
|
||||||
b, clean := newTestBuilder(t, "ignoreImports=true")
|
b := newTestBuilder(t, "ignoreImports=true")
|
||||||
defer clean()
|
|
||||||
|
|
||||||
b.Build(BuildCfg{})
|
b.Build(BuildCfg{})
|
||||||
|
|
||||||
b.AssertFileContent("public/p1/index.html", `<p>Page|https://bep.is|Title: |Text: A link|END</p>`)
|
b.AssertFileContent("public/p1/index.html", `<p>Page|https://bep.is|Title: |Text: A link|END</p>`)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Ignore config", func(t *testing.T) {
|
t.Run("Ignore config", func(t *testing.T) {
|
||||||
b, clean := newTestBuilder(t, "ignoreConfig=true")
|
b := newTestBuilder(t, "ignoreConfig=true")
|
||||||
defer clean()
|
|
||||||
|
|
||||||
b.Build(BuildCfg{})
|
b.Build(BuildCfg{})
|
||||||
|
|
||||||
b.AssertFileContent("public/index.html", `
|
b.AssertFileContent("public/index.html", `
|
||||||
|
@ -117,9 +114,7 @@ JS imported in module: |
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Ignore imports", func(t *testing.T) {
|
t.Run("Ignore imports", func(t *testing.T) {
|
||||||
b, clean := newTestBuilder(t, "ignoreImports=true")
|
b := newTestBuilder(t, "ignoreImports=true")
|
||||||
defer clean()
|
|
||||||
|
|
||||||
b.Build(BuildCfg{})
|
b.Build(BuildCfg{})
|
||||||
|
|
||||||
b.AssertFileContent("public/index.html", `
|
b.AssertFileContent("public/index.html", `
|
||||||
|
@ -129,8 +124,7 @@ JS imported in module: |
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Create package.json", func(t *testing.T) {
|
t.Run("Create package.json", func(t *testing.T) {
|
||||||
b, clean := newTestBuilder(t, "")
|
b := newTestBuilder(t, "")
|
||||||
defer clean()
|
|
||||||
|
|
||||||
b.WithSourceFile("package.json", `{
|
b.WithSourceFile("package.json", `{
|
||||||
"name": "mypack",
|
"name": "mypack",
|
||||||
|
@ -205,8 +199,7 @@ JS imported in module: |
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Create package.json, no default", func(t *testing.T) {
|
t.Run("Create package.json, no default", func(t *testing.T) {
|
||||||
b, clean := newTestBuilder(t, "")
|
b := newTestBuilder(t, "")
|
||||||
defer clean()
|
|
||||||
|
|
||||||
const origPackageJSON = `{
|
const origPackageJSON = `{
|
||||||
"name": "mypack",
|
"name": "mypack",
|
||||||
|
@ -268,8 +261,7 @@ JS imported in module: |
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Create package.json, no default, no package.json", func(t *testing.T) {
|
t.Run("Create package.json, no default, no package.json", func(t *testing.T) {
|
||||||
b, clean := newTestBuilder(t, "")
|
b := newTestBuilder(t, "")
|
||||||
defer clean()
|
|
||||||
|
|
||||||
b.Build(BuildCfg{})
|
b.Build(BuildCfg{})
|
||||||
b.Assert(npm.Pack(b.H.BaseFs.SourceFs, b.H.BaseFs.Assets.Dirs), qt.IsNil)
|
b.Assert(npm.Pack(b.H.BaseFs.SourceFs, b.H.BaseFs.Assets.Dirs), qt.IsNil)
|
||||||
|
@ -333,12 +325,13 @@ func TestHugoModulesMatrix(t *testing.T) {
|
||||||
for _, m := range testmods[:2] {
|
for _, m := range testmods[:2] {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
v := config.New()
|
|
||||||
|
|
||||||
workingDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugo-modules-test")
|
workingDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugo-modules-test")
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
defer clean()
|
defer clean()
|
||||||
|
|
||||||
|
v := config.NewWithTestDefaults()
|
||||||
|
v.Set("workingDir", workingDir)
|
||||||
|
|
||||||
configTemplate := `
|
configTemplate := `
|
||||||
baseURL = "https://example.com"
|
baseURL = "https://example.com"
|
||||||
title = "My Modular Site"
|
title = "My Modular Site"
|
||||||
|
@ -670,13 +663,14 @@ func TestModulesSymlinks(t *testing.T) {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
// We need to use the OS fs for this.
|
workingDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugo-mod-sym")
|
||||||
cfg := config.New()
|
|
||||||
fs := hugofs.NewFrom(hugofs.Os, cfg)
|
|
||||||
|
|
||||||
workDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugo-mod-sym")
|
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
|
|
||||||
|
// We need to use the OS fs for this.
|
||||||
|
cfg := config.NewWithTestDefaults()
|
||||||
|
cfg.Set("workingDir", workingDir)
|
||||||
|
fs := hugofs.NewFrom(hugofs.Os, cfg)
|
||||||
|
|
||||||
defer clean()
|
defer clean()
|
||||||
|
|
||||||
const homeTemplate = `
|
const homeTemplate = `
|
||||||
|
@ -694,9 +688,9 @@ Data: {{ .Site.Data }}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create project dirs and files.
|
// Create project dirs and files.
|
||||||
createDirsAndFiles(workDir)
|
createDirsAndFiles(workingDir)
|
||||||
// Create one module inside the default themes folder.
|
// Create one module inside the default themes folder.
|
||||||
themeDir := filepath.Join(workDir, "themes", "mymod")
|
themeDir := filepath.Join(workingDir, "themes", "mymod")
|
||||||
createDirsAndFiles(themeDir)
|
createDirsAndFiles(themeDir)
|
||||||
|
|
||||||
createSymlinks := func(baseDir, id string) {
|
createSymlinks := func(baseDir, id string) {
|
||||||
|
@ -711,7 +705,7 @@ Data: {{ .Site.Data }}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createSymlinks(workDir, "project")
|
createSymlinks(workingDir, "project")
|
||||||
createSymlinks(themeDir, "mod")
|
createSymlinks(themeDir, "mod")
|
||||||
|
|
||||||
config := `
|
config := `
|
||||||
|
@ -729,12 +723,12 @@ weight = 2
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
b := newTestSitesBuilder(t).WithNothingAdded().WithWorkingDir(workDir)
|
b := newTestSitesBuilder(t).WithNothingAdded().WithWorkingDir(workingDir)
|
||||||
b.WithLogger(loggers.NewErrorLogger())
|
b.WithLogger(loggers.NewErrorLogger())
|
||||||
b.Fs = fs
|
b.Fs = fs
|
||||||
|
|
||||||
b.WithConfigFile("toml", config)
|
b.WithConfigFile("toml", config)
|
||||||
c.Assert(os.Chdir(workDir), qt.IsNil)
|
c.Assert(os.Chdir(workingDir), qt.IsNil)
|
||||||
|
|
||||||
b.Build(BuildCfg{})
|
b.Build(BuildCfg{})
|
||||||
|
|
||||||
|
@ -846,7 +840,10 @@ workingDir = %q
|
||||||
|
|
||||||
b := newTestSitesBuilder(t).Running()
|
b := newTestSitesBuilder(t).Running()
|
||||||
|
|
||||||
b.Fs = hugofs.NewDefault(config.New())
|
cfg := config.NewWithTestDefaults()
|
||||||
|
cfg.Set("workingDir", workingDir)
|
||||||
|
|
||||||
|
b.Fs = hugofs.NewDefault(cfg)
|
||||||
|
|
||||||
b.WithWorkingDir(workingDir).WithConfigFile("toml", tomlConfig)
|
b.WithWorkingDir(workingDir).WithConfigFile("toml", tomlConfig)
|
||||||
b.WithTemplatesAdded("index.html", `
|
b.WithTemplatesAdded("index.html", `
|
||||||
|
@ -968,7 +965,9 @@ workingDir = %q
|
||||||
|
|
||||||
b := newTestSitesBuilder(c).Running()
|
b := newTestSitesBuilder(c).Running()
|
||||||
|
|
||||||
b.Fs = hugofs.NewDefault(config.New())
|
cfg := config.NewWithTestDefaults()
|
||||||
|
cfg.Set("workingDir", workingDir)
|
||||||
|
b.Fs = hugofs.NewDefault(cfg)
|
||||||
|
|
||||||
os.MkdirAll(filepath.Join(workingDir, "content", "blog"), 0777)
|
os.MkdirAll(filepath.Join(workingDir, "content", "blog"), 0777)
|
||||||
|
|
||||||
|
@ -1067,7 +1066,7 @@ func TestSiteWithGoModButNoModules(t *testing.T) {
|
||||||
workDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugo-no-mod")
|
workDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugo-no-mod")
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
|
|
||||||
cfg := config.New()
|
cfg := config.NewWithTestDefaults()
|
||||||
cfg.Set("workingDir", workDir)
|
cfg.Set("workingDir", workDir)
|
||||||
fs := hugofs.NewFrom(hugofs.Os, cfg)
|
fs := hugofs.NewFrom(hugofs.Os, cfg)
|
||||||
|
|
||||||
|
@ -1093,7 +1092,7 @@ func TestModuleAbsMount(t *testing.T) {
|
||||||
absContentDir, clean2, err := htesting.CreateTempDir(hugofs.Os, "hugo-content")
|
absContentDir, clean2, err := htesting.CreateTempDir(hugofs.Os, "hugo-content")
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
|
|
||||||
cfg := config.New()
|
cfg := config.NewWithTestDefaults()
|
||||||
cfg.Set("workingDir", workDir)
|
cfg.Set("workingDir", workDir)
|
||||||
fs := hugofs.NewFrom(hugofs.Os, cfg)
|
fs := hugofs.NewFrom(hugofs.Os, cfg)
|
||||||
|
|
||||||
|
|
|
@ -597,7 +597,7 @@ func (h *HugoSites) reset(config *BuildCfg) {
|
||||||
if config.ResetState {
|
if config.ResetState {
|
||||||
for i, s := range h.Sites {
|
for i, s := range h.Sites {
|
||||||
h.Sites[i] = s.reset()
|
h.Sites[i] = s.reset()
|
||||||
if r, ok := s.Fs.Destination.(hugofs.Reseter); ok {
|
if r, ok := s.Fs.PublishDir.(hugofs.Reseter); ok {
|
||||||
r.Reset()
|
r.Reset()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -496,9 +496,9 @@ func (h *HugoSites) writeBuildStats() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write to the destination, too, if a mem fs is in play.
|
// Write to the destination as well if it's a in-memory fs.
|
||||||
if h.Fs.Source != hugofs.Os {
|
if !hugofs.IsOsFs(h.Fs.Source) {
|
||||||
if err := afero.WriteFile(h.Fs.Destination, filename, js, 0666); err != nil {
|
if err := afero.WriteFile(h.Fs.WorkingDirWritable, filename, js, 0666); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -489,7 +489,7 @@ func TestMultiSitesRebuild(t *testing.T) {
|
||||||
c.Assert(enSite.RegularPages()[0].Title(), qt.Equals, "new_en_2")
|
c.Assert(enSite.RegularPages()[0].Title(), qt.Equals, "new_en_2")
|
||||||
c.Assert(enSite.RegularPages()[1].Title(), qt.Equals, "new_en_1")
|
c.Assert(enSite.RegularPages()[1].Title(), qt.Equals, "new_en_1")
|
||||||
|
|
||||||
rendered := readDestination(t, fs, "public/en/new1/index.html")
|
rendered := readWorkingDir(t, fs, "public/en/new1/index.html")
|
||||||
c.Assert(strings.Contains(rendered, "new_en_1"), qt.Equals, true)
|
c.Assert(strings.Contains(rendered, "new_en_1"), qt.Equals, true)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -503,7 +503,7 @@ func TestMultiSitesRebuild(t *testing.T) {
|
||||||
[]fsnotify.Event{{Name: filepath.FromSlash("content/sect/doc1.en.md"), Op: fsnotify.Write}},
|
[]fsnotify.Event{{Name: filepath.FromSlash("content/sect/doc1.en.md"), Op: fsnotify.Write}},
|
||||||
func(t *testing.T) {
|
func(t *testing.T) {
|
||||||
c.Assert(len(enSite.RegularPages()), qt.Equals, 6)
|
c.Assert(len(enSite.RegularPages()), qt.Equals, 6)
|
||||||
doc1 := readDestination(t, fs, "public/en/sect/doc1-slug/index.html")
|
doc1 := readWorkingDir(t, fs, "public/en/sect/doc1-slug/index.html")
|
||||||
c.Assert(strings.Contains(doc1, "CHANGED"), qt.Equals, true)
|
c.Assert(strings.Contains(doc1, "CHANGED"), qt.Equals, true)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -521,7 +521,7 @@ func TestMultiSitesRebuild(t *testing.T) {
|
||||||
func(t *testing.T) {
|
func(t *testing.T) {
|
||||||
c.Assert(len(enSite.RegularPages()), qt.Equals, 6, qt.Commentf("Rename"))
|
c.Assert(len(enSite.RegularPages()), qt.Equals, 6, qt.Commentf("Rename"))
|
||||||
c.Assert(enSite.RegularPages()[1].Title(), qt.Equals, "new_en_1")
|
c.Assert(enSite.RegularPages()[1].Title(), qt.Equals, "new_en_1")
|
||||||
rendered := readDestination(t, fs, "public/en/new1renamed/index.html")
|
rendered := readWorkingDir(t, fs, "public/en/new1renamed/index.html")
|
||||||
c.Assert(rendered, qt.Contains, "new_en_1")
|
c.Assert(rendered, qt.Contains, "new_en_1")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -538,7 +538,7 @@ func TestMultiSitesRebuild(t *testing.T) {
|
||||||
c.Assert(len(enSite.RegularPages()), qt.Equals, 6)
|
c.Assert(len(enSite.RegularPages()), qt.Equals, 6)
|
||||||
c.Assert(len(enSite.AllPages()), qt.Equals, 34)
|
c.Assert(len(enSite.AllPages()), qt.Equals, 34)
|
||||||
c.Assert(len(frSite.RegularPages()), qt.Equals, 5)
|
c.Assert(len(frSite.RegularPages()), qt.Equals, 5)
|
||||||
doc1 := readDestination(t, fs, "public/en/sect/doc1-slug/index.html")
|
doc1 := readWorkingDir(t, fs, "public/en/sect/doc1-slug/index.html")
|
||||||
c.Assert(strings.Contains(doc1, "Template Changed"), qt.Equals, true)
|
c.Assert(strings.Contains(doc1, "Template Changed"), qt.Equals, true)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -555,9 +555,9 @@ func TestMultiSitesRebuild(t *testing.T) {
|
||||||
c.Assert(len(enSite.RegularPages()), qt.Equals, 6)
|
c.Assert(len(enSite.RegularPages()), qt.Equals, 6)
|
||||||
c.Assert(len(enSite.AllPages()), qt.Equals, 34)
|
c.Assert(len(enSite.AllPages()), qt.Equals, 34)
|
||||||
c.Assert(len(frSite.RegularPages()), qt.Equals, 5)
|
c.Assert(len(frSite.RegularPages()), qt.Equals, 5)
|
||||||
docEn := readDestination(t, fs, "public/en/sect/doc1-slug/index.html")
|
docEn := readWorkingDir(t, fs, "public/en/sect/doc1-slug/index.html")
|
||||||
c.Assert(strings.Contains(docEn, "Hello"), qt.Equals, true)
|
c.Assert(strings.Contains(docEn, "Hello"), qt.Equals, true)
|
||||||
docFr := readDestination(t, fs, "public/fr/sect/doc1/index.html")
|
docFr := readWorkingDir(t, fs, "public/fr/sect/doc1/index.html")
|
||||||
c.Assert(strings.Contains(docFr, "Salut"), qt.Equals, true)
|
c.Assert(strings.Contains(docFr, "Salut"), qt.Equals, true)
|
||||||
|
|
||||||
homeEn := enSite.getPage(page.KindHome)
|
homeEn := enSite.getPage(page.KindHome)
|
||||||
|
@ -700,7 +700,7 @@ END
|
||||||
|
|
||||||
func checkContent(s *sitesBuilder, filename string, matches ...string) {
|
func checkContent(s *sitesBuilder, filename string, matches ...string) {
|
||||||
s.T.Helper()
|
s.T.Helper()
|
||||||
content := readDestination(s.T, s.Fs, filename)
|
content := readWorkingDir(s.T, s.Fs, filename)
|
||||||
for _, match := range matches {
|
for _, match := range matches {
|
||||||
if !strings.Contains(content, match) {
|
if !strings.Contains(content, match) {
|
||||||
s.Fatalf("No match for\n%q\nin content for %s\n%q\nDiff:\n%s", match, filename, content, htesting.DiffStrings(content, match))
|
s.Fatalf("No match for\n%q\nin content for %s\n%q\nDiff:\n%s", match, filename, content, htesting.DiffStrings(content, match))
|
||||||
|
@ -1170,13 +1170,13 @@ func writeToFs(t testing.TB, fs afero.Fs, filename, content string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func readDestination(t testing.TB, fs *hugofs.Fs, filename string) string {
|
func readWorkingDir(t testing.TB, fs *hugofs.Fs, filename string) string {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
return readFileFromFs(t, fs.Destination, filename)
|
return readFileFromFs(t, fs.WorkingDirReadOnly, filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
func destinationExists(fs *hugofs.Fs, filename string) bool {
|
func workingDirExists(fs *hugofs.Fs, filename string) bool {
|
||||||
b, err := helpers.Exists(filename, fs.Destination)
|
b, err := helpers.Exists(filename, fs.WorkingDirReadOnly)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ func TestImageOps(t *testing.T) {
|
||||||
defer clean()
|
defer clean()
|
||||||
|
|
||||||
newBuilder := func(timeout any) *sitesBuilder {
|
newBuilder := func(timeout any) *sitesBuilder {
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
v.Set("workingDir", workDir)
|
v.Set("workingDir", workDir)
|
||||||
v.Set("baseURL", "https://example.org")
|
v.Set("baseURL", "https://example.org")
|
||||||
v.Set("timeout", timeout)
|
v.Set("timeout", timeout)
|
||||||
|
@ -141,7 +141,7 @@ IMG SHORTCODE: /images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_129x239_r
|
||||||
|
|
||||||
assertImages := func() {
|
assertImages := func() {
|
||||||
b.Helper()
|
b.Helper()
|
||||||
b.AssertFileContent(filepath.Join(workDir, "public/index.html"), imgExpect)
|
b.AssertFileContent("public/index.html", imgExpect)
|
||||||
b.AssertImage(350, 219, "public/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_350x0_resize_q75_box.a86fe88d894e5db613f6aa8a80538fefc25b20fa24ba0d782c057adcef616f56.jpg")
|
b.AssertImage(350, 219, "public/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_350x0_resize_q75_box.a86fe88d894e5db613f6aa8a80538fefc25b20fa24ba0d782c057adcef616f56.jpg")
|
||||||
b.AssertImage(129, 239, "public/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_129x239_resize_q75_box.jpg")
|
b.AssertImage(129, 239, "public/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_129x239_resize_q75_box.jpg")
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,8 @@ func NewIntegrationTestBuilder(conf IntegrationTestConfig) *IntegrationTestBuild
|
||||||
if doClean {
|
if doClean {
|
||||||
c.Cleanup(clean)
|
c.Cleanup(clean)
|
||||||
}
|
}
|
||||||
|
} else if conf.WorkingDir == "" {
|
||||||
|
conf.WorkingDir = helpers.FilePathSeparator
|
||||||
}
|
}
|
||||||
|
|
||||||
return &IntegrationTestBuilder{
|
return &IntegrationTestBuilder{
|
||||||
|
@ -157,7 +159,7 @@ func (s *IntegrationTestBuilder) AssertDestinationExists(filename string, b bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *IntegrationTestBuilder) destinationExists(filename string) bool {
|
func (s *IntegrationTestBuilder) destinationExists(filename string) bool {
|
||||||
b, err := helpers.Exists(filename, s.fs.Destination)
|
b, err := helpers.Exists(filename, s.fs.PublishDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -258,11 +260,7 @@ func (s *IntegrationTestBuilder) RenameFile(old, new string) *IntegrationTestBui
|
||||||
|
|
||||||
func (s *IntegrationTestBuilder) FileContent(filename string) string {
|
func (s *IntegrationTestBuilder) FileContent(filename string) string {
|
||||||
s.Helper()
|
s.Helper()
|
||||||
filename = filepath.FromSlash(filename)
|
return s.readWorkingDir(s, s.fs, filepath.FromSlash(filename))
|
||||||
if !strings.HasPrefix(filename, s.Cfg.WorkingDir) {
|
|
||||||
filename = filepath.Join(s.Cfg.WorkingDir, filename)
|
|
||||||
}
|
|
||||||
return s.readDestination(s, s.fs, filename)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *IntegrationTestBuilder) initBuilder() {
|
func (s *IntegrationTestBuilder) initBuilder() {
|
||||||
|
@ -280,8 +278,6 @@ func (s *IntegrationTestBuilder) initBuilder() {
|
||||||
|
|
||||||
logger := loggers.NewBasicLoggerForWriter(s.Cfg.LogLevel, &s.logBuff)
|
logger := loggers.NewBasicLoggerForWriter(s.Cfg.LogLevel, &s.logBuff)
|
||||||
|
|
||||||
fs := hugofs.NewFrom(afs, config.New())
|
|
||||||
|
|
||||||
for _, f := range s.data.Files {
|
for _, f := range s.data.Files {
|
||||||
filename := filepath.Join(s.Cfg.WorkingDir, f.Name)
|
filename := filepath.Join(s.Cfg.WorkingDir, f.Name)
|
||||||
s.Assert(afs.MkdirAll(filepath.Dir(filename), 0777), qt.IsNil)
|
s.Assert(afs.MkdirAll(filepath.Dir(filename), 0777), qt.IsNil)
|
||||||
|
@ -301,10 +297,12 @@ func (s *IntegrationTestBuilder) initBuilder() {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
s.Assert(err, qt.IsNil)
|
|
||||||
|
|
||||||
cfg.Set("workingDir", s.Cfg.WorkingDir)
|
cfg.Set("workingDir", s.Cfg.WorkingDir)
|
||||||
|
|
||||||
|
fs := hugofs.NewFrom(afs, cfg)
|
||||||
|
|
||||||
|
s.Assert(err, qt.IsNil)
|
||||||
|
|
||||||
depsCfg := deps.DepsCfg{Cfg: cfg, Fs: fs, Running: s.Cfg.Running, Logger: logger}
|
depsCfg := deps.DepsCfg{Cfg: cfg, Fs: fs, Running: s.Cfg.Running, Logger: logger}
|
||||||
sites, err := NewHugoSites(depsCfg)
|
sites, err := NewHugoSites(depsCfg)
|
||||||
s.Assert(err, qt.IsNil)
|
s.Assert(err, qt.IsNil)
|
||||||
|
@ -400,9 +398,9 @@ func (s *IntegrationTestBuilder) changeEvents() []fsnotify.Event {
|
||||||
return events
|
return events
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *IntegrationTestBuilder) readDestination(t testing.TB, fs *hugofs.Fs, filename string) string {
|
func (s *IntegrationTestBuilder) readWorkingDir(t testing.TB, fs *hugofs.Fs, filename string) string {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
return s.readFileFromFs(t, fs.Destination, filename)
|
return s.readFileFromFs(t, fs.WorkingDirReadOnly, filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *IntegrationTestBuilder) readFileFromFs(t testing.TB, fs afero.Fs, filename string) string {
|
func (s *IntegrationTestBuilder) readFileFromFs(t testing.TB, fs afero.Fs, filename string) string {
|
||||||
|
|
|
@ -224,8 +224,8 @@ Content.
|
||||||
nnSite := b.H.Sites[1]
|
nnSite := b.H.Sites[1]
|
||||||
svSite := b.H.Sites[2]
|
svSite := b.H.Sites[2]
|
||||||
|
|
||||||
b.AssertFileContent("/my/project/public/en/mystatic/file1.yaml", "en")
|
b.AssertFileContent("public/en/mystatic/file1.yaml", "en")
|
||||||
b.AssertFileContent("/my/project/public/nn/mystatic/file1.yaml", "nn")
|
b.AssertFileContent("public/nn/mystatic/file1.yaml", "nn")
|
||||||
|
|
||||||
// dumpPages(nnSite.RegularPages()...)
|
// dumpPages(nnSite.RegularPages()...)
|
||||||
|
|
||||||
|
@ -300,16 +300,16 @@ Content.
|
||||||
c.Assert(len(bundleSv.Resources()), qt.Equals, 4)
|
c.Assert(len(bundleSv.Resources()), qt.Equals, 4)
|
||||||
c.Assert(len(bundleEn.Resources()), qt.Equals, 4)
|
c.Assert(len(bundleEn.Resources()), qt.Equals, 4)
|
||||||
|
|
||||||
b.AssertFileContent("/my/project/public/en/sect/mybundle/index.html", "image/png: /en/sect/mybundle/logo.png")
|
b.AssertFileContent("public/en/sect/mybundle/index.html", "image/png: /en/sect/mybundle/logo.png")
|
||||||
b.AssertFileContent("/my/project/public/nn/sect/mybundle/index.html", "image/png: /nn/sect/mybundle/logo.png")
|
b.AssertFileContent("public/nn/sect/mybundle/index.html", "image/png: /nn/sect/mybundle/logo.png")
|
||||||
b.AssertFileContent("/my/project/public/sv/sect/mybundle/index.html", "image/png: /sv/sect/mybundle/logo.png")
|
b.AssertFileContent("public/sv/sect/mybundle/index.html", "image/png: /sv/sect/mybundle/logo.png")
|
||||||
|
|
||||||
b.AssertFileContent("/my/project/public/sv/sect/mybundle/featured.png", "PNG Data for sv")
|
b.AssertFileContent("public/sv/sect/mybundle/featured.png", "PNG Data for sv")
|
||||||
b.AssertFileContent("/my/project/public/nn/sect/mybundle/featured.png", "PNG Data for nn")
|
b.AssertFileContent("public/nn/sect/mybundle/featured.png", "PNG Data for nn")
|
||||||
b.AssertFileContent("/my/project/public/en/sect/mybundle/featured.png", "PNG Data for en")
|
b.AssertFileContent("public/en/sect/mybundle/featured.png", "PNG Data for en")
|
||||||
b.AssertFileContent("/my/project/public/en/sect/mybundle/logo.png", "PNG Data")
|
b.AssertFileContent("public/en/sect/mybundle/logo.png", "PNG Data")
|
||||||
b.AssertFileContent("/my/project/public/sv/sect/mybundle/logo.png", "PNG Data")
|
b.AssertFileContent("public/sv/sect/mybundle/logo.png", "PNG Data")
|
||||||
b.AssertFileContent("/my/project/public/nn/sect/mybundle/logo.png", "PNG Data")
|
b.AssertFileContent("public/nn/sect/mybundle/logo.png", "PNG Data")
|
||||||
|
|
||||||
nnSect := nnSite.getPage(page.KindSection, "sect")
|
nnSect := nnSite.getPage(page.KindSection, "sect")
|
||||||
c.Assert(nnSect, qt.Not(qt.IsNil))
|
c.Assert(nnSect, qt.Not(qt.IsNil))
|
||||||
|
|
|
@ -22,7 +22,7 @@ import (
|
||||||
func TestMinifyPublisher(t *testing.T) {
|
func TestMinifyPublisher(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
v.Set("minify", true)
|
v.Set("minify", true)
|
||||||
v.Set("baseURL", "https://example.org/")
|
v.Set("baseURL", "https://example.org/")
|
||||||
|
|
||||||
|
|
|
@ -101,13 +101,13 @@ Resources: {{ resources.Match "**.js" }}
|
||||||
|
|
||||||
assertExists := func(name string, shouldExist bool) {
|
assertExists := func(name string, shouldExist bool) {
|
||||||
b.Helper()
|
b.Helper()
|
||||||
b.Assert(b.CheckExists(filepath.Join(workingDir, name)), qt.Equals, shouldExist)
|
b.Assert(b.CheckExists(name), qt.Equals, shouldExist)
|
||||||
}
|
}
|
||||||
|
|
||||||
assertExists("public/a/b/p1/index.html", true)
|
assertExists("public/a/b/p1/index.html", true)
|
||||||
assertExists("public/a/c/p2/index.html", false)
|
assertExists("public/a/c/p2/index.html", false)
|
||||||
|
|
||||||
b.AssertFileContent(filepath.Join(workingDir, "public", "index.html"), `
|
b.AssertFileContent(filepath.Join("public", "index.html"), `
|
||||||
Data: map[mydata:map[b:map[b1:bval]]]:END
|
Data: map[mydata:map[b:map[b1:bval]]]:END
|
||||||
Template: false
|
Template: false
|
||||||
Resource1: js/include.js:END
|
Resource1: js/include.js:END
|
||||||
|
|
|
@ -23,7 +23,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/htesting"
|
"github.com/gohugoio/hugo/htesting"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/markup/asciidocext"
|
"github.com/gohugoio/hugo/markup/asciidocext"
|
||||||
"github.com/gohugoio/hugo/markup/rst"
|
"github.com/gohugoio/hugo/markup/rst"
|
||||||
|
|
||||||
|
@ -35,7 +34,6 @@ import (
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/resources/page"
|
"github.com/gohugoio/hugo/resources/page"
|
||||||
"github.com/gohugoio/hugo/resources/resource"
|
"github.com/gohugoio/hugo/resources/resource"
|
||||||
"github.com/spf13/afero"
|
|
||||||
"github.com/spf13/jwalterweatherman"
|
"github.com/spf13/jwalterweatherman"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
|
@ -1031,14 +1029,14 @@ func TestPageWithLastmodFromGitInfo(t *testing.T) {
|
||||||
}
|
}
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
// We need to use the OS fs for this.
|
|
||||||
cfg := config.New()
|
|
||||||
fs := hugofs.NewFrom(hugofs.Os, cfg)
|
|
||||||
fs.Destination = &afero.MemMapFs{}
|
|
||||||
|
|
||||||
wd, err := os.Getwd()
|
wd, err := os.Getwd()
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
|
|
||||||
|
// We need to use the OS fs for this.
|
||||||
|
cfg := config.NewWithTestDefaults()
|
||||||
|
cfg.Set("workingDir", filepath.Join(wd, "testsite"))
|
||||||
|
fs := hugofs.NewFrom(hugofs.Os, cfg)
|
||||||
|
|
||||||
cfg.Set("frontmatter", map[string]any{
|
cfg.Set("frontmatter", map[string]any{
|
||||||
"lastmod": []string{":git", "lastmod"},
|
"lastmod": []string{":git", "lastmod"},
|
||||||
})
|
})
|
||||||
|
@ -1060,8 +1058,6 @@ func TestPageWithLastmodFromGitInfo(t *testing.T) {
|
||||||
cfg.Set("languages", langConfig)
|
cfg.Set("languages", langConfig)
|
||||||
cfg.Set("enableGitInfo", true)
|
cfg.Set("enableGitInfo", true)
|
||||||
|
|
||||||
cfg.Set("workingDir", filepath.Join(wd, "testsite"))
|
|
||||||
|
|
||||||
b := newTestSitesBuilderFromDepsCfg(t, deps.DepsCfg{Fs: fs, Cfg: cfg}).WithNothingAdded()
|
b := newTestSitesBuilderFromDepsCfg(t, deps.DepsCfg{Fs: fs, Cfg: cfg}).WithNothingAdded()
|
||||||
|
|
||||||
b.Build(BuildCfg{SkipRender: true})
|
b.Build(BuildCfg{SkipRender: true})
|
||||||
|
@ -1314,7 +1310,7 @@ func TestChompBOM(t *testing.T) {
|
||||||
|
|
||||||
func TestPageWithEmoji(t *testing.T) {
|
func TestPageWithEmoji(t *testing.T) {
|
||||||
for _, enableEmoji := range []bool{true, false} {
|
for _, enableEmoji := range []bool{true, false} {
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
v.Set("enableEmoji", enableEmoji)
|
v.Set("enableEmoji", enableEmoji)
|
||||||
|
|
||||||
b := newTestSitesBuilder(t).WithViper(v)
|
b := newTestSitesBuilder(t).WithViper(v)
|
||||||
|
|
|
@ -127,22 +127,22 @@ func TestPageBundlerSiteRegular(t *testing.T) {
|
||||||
|
|
||||||
// Check both output formats
|
// Check both output formats
|
||||||
rel, filename := relFilename("/a/1/", "index.html")
|
rel, filename := relFilename("/a/1/", "index.html")
|
||||||
b.AssertFileContent(filepath.Join("/work/public", filename),
|
b.AssertFileContent(filepath.Join("public", filename),
|
||||||
"TheContent",
|
"TheContent",
|
||||||
"Single RelPermalink: "+rel,
|
"Single RelPermalink: "+rel,
|
||||||
)
|
)
|
||||||
|
|
||||||
rel, filename = relFilename("/cpath/a/1/", "cindex.html")
|
rel, filename = relFilename("/cpath/a/1/", "cindex.html")
|
||||||
|
|
||||||
b.AssertFileContent(filepath.Join("/work/public", filename),
|
b.AssertFileContent(filepath.Join("public", filename),
|
||||||
"TheContent",
|
"TheContent",
|
||||||
"Single RelPermalink: "+rel,
|
"Single RelPermalink: "+rel,
|
||||||
)
|
)
|
||||||
|
|
||||||
b.AssertFileContent(filepath.FromSlash("/work/public/images/hugo-logo.png"), "content")
|
b.AssertFileContent(filepath.FromSlash("public/images/hugo-logo.png"), "content")
|
||||||
|
|
||||||
// This should be just copied to destination.
|
// This should be just copied to destination.
|
||||||
b.AssertFileContent(filepath.FromSlash("/work/public/assets/pic1.png"), "content")
|
b.AssertFileContent(filepath.FromSlash("public/assets/pic1.png"), "content")
|
||||||
|
|
||||||
leafBundle1 := s.getPage(page.KindPage, "b/my-bundle/index.md")
|
leafBundle1 := s.getPage(page.KindPage, "b/my-bundle/index.md")
|
||||||
c.Assert(leafBundle1, qt.Not(qt.IsNil))
|
c.Assert(leafBundle1, qt.Not(qt.IsNil))
|
||||||
|
@ -159,8 +159,8 @@ func TestPageBundlerSiteRegular(t *testing.T) {
|
||||||
c.Assert(rootBundle, qt.Not(qt.IsNil))
|
c.Assert(rootBundle, qt.Not(qt.IsNil))
|
||||||
c.Assert(rootBundle.Parent().IsHome(), qt.Equals, true)
|
c.Assert(rootBundle.Parent().IsHome(), qt.Equals, true)
|
||||||
if !ugly {
|
if !ugly {
|
||||||
b.AssertFileContent(filepath.FromSlash("/work/public/root/index.html"), "Single RelPermalink: "+relURLBase+"/root/")
|
b.AssertFileContent(filepath.FromSlash("public/root/index.html"), "Single RelPermalink: "+relURLBase+"/root/")
|
||||||
b.AssertFileContent(filepath.FromSlash("/work/public/cpath/root/cindex.html"), "Single RelPermalink: "+relURLBase+"/cpath/root/")
|
b.AssertFileContent(filepath.FromSlash("public/cpath/root/cindex.html"), "Single RelPermalink: "+relURLBase+"/cpath/root/")
|
||||||
}
|
}
|
||||||
|
|
||||||
leafBundle2 := s.getPage(page.KindPage, "a/b/index.md")
|
leafBundle2 := s.getPage(page.KindPage, "a/b/index.md")
|
||||||
|
@ -202,17 +202,17 @@ func TestPageBundlerSiteRegular(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ugly {
|
if ugly {
|
||||||
b.AssertFileContent("/work/public/2017/pageslug.html",
|
b.AssertFileContent("public/2017/pageslug.html",
|
||||||
relPermalinker("Single RelPermalink: %s/2017/pageslug.html"),
|
relPermalinker("Single RelPermalink: %s/2017/pageslug.html"),
|
||||||
permalinker("Single Permalink: %s/2017/pageslug.html"),
|
permalinker("Single Permalink: %s/2017/pageslug.html"),
|
||||||
relPermalinker("Sunset RelPermalink: %s/2017/pageslug/sunset1.jpg"),
|
relPermalinker("Sunset RelPermalink: %s/2017/pageslug/sunset1.jpg"),
|
||||||
permalinker("Sunset Permalink: %s/2017/pageslug/sunset1.jpg"))
|
permalinker("Sunset Permalink: %s/2017/pageslug/sunset1.jpg"))
|
||||||
} else {
|
} else {
|
||||||
b.AssertFileContent("/work/public/2017/pageslug/index.html",
|
b.AssertFileContent("public/2017/pageslug/index.html",
|
||||||
relPermalinker("Sunset RelPermalink: %s/2017/pageslug/sunset1.jpg"),
|
relPermalinker("Sunset RelPermalink: %s/2017/pageslug/sunset1.jpg"),
|
||||||
permalinker("Sunset Permalink: %s/2017/pageslug/sunset1.jpg"))
|
permalinker("Sunset Permalink: %s/2017/pageslug/sunset1.jpg"))
|
||||||
|
|
||||||
b.AssertFileContent("/work/public/cpath/2017/pageslug/cindex.html",
|
b.AssertFileContent("public/cpath/2017/pageslug/cindex.html",
|
||||||
relPermalinker("Single RelPermalink: %s/cpath/2017/pageslug/"),
|
relPermalinker("Single RelPermalink: %s/cpath/2017/pageslug/"),
|
||||||
relPermalinker("Short Sunset RelPermalink: %s/cpath/2017/pageslug/sunset2.jpg"),
|
relPermalinker("Short Sunset RelPermalink: %s/cpath/2017/pageslug/sunset2.jpg"),
|
||||||
relPermalinker("Sunset RelPermalink: %s/cpath/2017/pageslug/sunset1.jpg"),
|
relPermalinker("Sunset RelPermalink: %s/cpath/2017/pageslug/sunset1.jpg"),
|
||||||
|
@ -220,15 +220,15 @@ func TestPageBundlerSiteRegular(t *testing.T) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
b.AssertFileContent(filepath.FromSlash("/work/public/2017/pageslug/c/logo.png"), "content")
|
b.AssertFileContent(filepath.FromSlash("public/2017/pageslug/c/logo.png"), "content")
|
||||||
b.AssertFileContent(filepath.FromSlash("/work/public/cpath/2017/pageslug/c/logo.png"), "content")
|
b.AssertFileContent(filepath.FromSlash("public/cpath/2017/pageslug/c/logo.png"), "content")
|
||||||
c.Assert(b.CheckExists("/work/public/cpath/cpath/2017/pageslug/c/logo.png"), qt.Equals, false)
|
c.Assert(b.CheckExists("public/cpath/cpath/2017/pageslug/c/logo.png"), qt.Equals, false)
|
||||||
|
|
||||||
// Custom media type defined in site config.
|
// Custom media type defined in site config.
|
||||||
c.Assert(len(leafBundle1.Resources().ByType("bepsays")), qt.Equals, 1)
|
c.Assert(len(leafBundle1.Resources().ByType("bepsays")), qt.Equals, 1)
|
||||||
|
|
||||||
if ugly {
|
if ugly {
|
||||||
b.AssertFileContent(filepath.FromSlash("/work/public/2017/pageslug.html"),
|
b.AssertFileContent(filepath.FromSlash("public/2017/pageslug.html"),
|
||||||
"TheContent",
|
"TheContent",
|
||||||
relPermalinker("Sunset RelPermalink: %s/2017/pageslug/sunset1.jpg"),
|
relPermalinker("Sunset RelPermalink: %s/2017/pageslug/sunset1.jpg"),
|
||||||
permalinker("Sunset Permalink: %s/2017/pageslug/sunset1.jpg"),
|
permalinker("Sunset Permalink: %s/2017/pageslug/sunset1.jpg"),
|
||||||
|
@ -247,18 +247,18 @@ func TestPageBundlerSiteRegular(t *testing.T) {
|
||||||
|
|
||||||
// https://github.com/gohugoio/hugo/issues/5882
|
// https://github.com/gohugoio/hugo/issues/5882
|
||||||
b.AssertFileContent(
|
b.AssertFileContent(
|
||||||
filepath.FromSlash("/work/public/2017/pageslug.html"), "0: Page RelPermalink: |")
|
filepath.FromSlash("public/2017/pageslug.html"), "0: Page RelPermalink: |")
|
||||||
|
|
||||||
b.AssertFileContent(filepath.FromSlash("/work/public/cpath/2017/pageslug.html"), "TheContent")
|
b.AssertFileContent(filepath.FromSlash("public/cpath/2017/pageslug.html"), "TheContent")
|
||||||
|
|
||||||
// 은행
|
// 은행
|
||||||
b.AssertFileContent(filepath.FromSlash("/work/public/c/은행/logo-은행.png"), "은행 PNG")
|
b.AssertFileContent(filepath.FromSlash("public/c/은행/logo-은행.png"), "은행 PNG")
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
b.AssertFileContent(filepath.FromSlash("/work/public/2017/pageslug/index.html"), "TheContent")
|
b.AssertFileContent(filepath.FromSlash("public/2017/pageslug/index.html"), "TheContent")
|
||||||
b.AssertFileContent(filepath.FromSlash("/work/public/cpath/2017/pageslug/cindex.html"), "TheContent")
|
b.AssertFileContent(filepath.FromSlash("public/cpath/2017/pageslug/cindex.html"), "TheContent")
|
||||||
b.AssertFileContent(filepath.FromSlash("/work/public/2017/pageslug/index.html"), "Single Title")
|
b.AssertFileContent(filepath.FromSlash("public/2017/pageslug/index.html"), "Single Title")
|
||||||
b.AssertFileContent(filepath.FromSlash("/work/public/root/index.html"), "Single Title")
|
b.AssertFileContent(filepath.FromSlash("public/root/index.html"), "Single Title")
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -397,23 +397,24 @@ func TestPageBundlerSiteWitSymbolicLinksInContent(t *testing.T) {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
// We need to use the OS fs for this.
|
|
||||||
cfg := config.New()
|
|
||||||
fs := hugofs.NewFrom(hugofs.Os, cfg)
|
|
||||||
|
|
||||||
workDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugosym")
|
// We need to use the OS fs for this.
|
||||||
|
workingDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugosym")
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
|
cfg := config.NewWithTestDefaults()
|
||||||
|
cfg.Set("workingDir", workingDir)
|
||||||
|
fs := hugofs.NewFrom(hugofs.Os, cfg)
|
||||||
|
|
||||||
contentDirName := "content"
|
contentDirName := "content"
|
||||||
|
|
||||||
contentDir := filepath.Join(workDir, contentDirName)
|
contentDir := filepath.Join(workingDir, contentDirName)
|
||||||
c.Assert(os.MkdirAll(filepath.Join(contentDir, "a"), 0777), qt.IsNil)
|
c.Assert(os.MkdirAll(filepath.Join(contentDir, "a"), 0777), qt.IsNil)
|
||||||
|
|
||||||
for i := 1; i <= 3; i++ {
|
for i := 1; i <= 3; i++ {
|
||||||
c.Assert(os.MkdirAll(filepath.Join(workDir, fmt.Sprintf("symcontent%d", i)), 0777), qt.IsNil)
|
c.Assert(os.MkdirAll(filepath.Join(workingDir, fmt.Sprintf("symcontent%d", i)), 0777), qt.IsNil)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Assert(os.MkdirAll(filepath.Join(workDir, "symcontent2", "a1"), 0777), qt.IsNil)
|
c.Assert(os.MkdirAll(filepath.Join(workingDir, "symcontent2", "a1"), 0777), qt.IsNil)
|
||||||
|
|
||||||
// Symlinked sections inside content.
|
// Symlinked sections inside content.
|
||||||
os.Chdir(contentDir)
|
os.Chdir(contentDir)
|
||||||
|
@ -431,11 +432,11 @@ func TestPageBundlerSiteWitSymbolicLinksInContent(t *testing.T) {
|
||||||
// Create a circular symlink. Will print some warnings.
|
// Create a circular symlink. Will print some warnings.
|
||||||
c.Assert(os.Symlink(filepath.Join("..", contentDirName), filepath.FromSlash("circus")), qt.IsNil)
|
c.Assert(os.Symlink(filepath.Join("..", contentDirName), filepath.FromSlash("circus")), qt.IsNil)
|
||||||
|
|
||||||
c.Assert(os.Chdir(workDir), qt.IsNil)
|
c.Assert(os.Chdir(workingDir), qt.IsNil)
|
||||||
|
|
||||||
defer clean()
|
defer clean()
|
||||||
|
|
||||||
cfg.Set("workingDir", workDir)
|
cfg.Set("workingDir", workingDir)
|
||||||
cfg.Set("contentDir", contentDirName)
|
cfg.Set("contentDir", contentDirName)
|
||||||
cfg.Set("baseURL", "https://example.com")
|
cfg.Set("baseURL", "https://example.com")
|
||||||
|
|
||||||
|
@ -488,9 +489,9 @@ TheContent.
|
||||||
c.Assert(len(a1Bundle.Resources()), qt.Equals, 2)
|
c.Assert(len(a1Bundle.Resources()), qt.Equals, 2)
|
||||||
c.Assert(len(a1Bundle.Resources().ByType(pageResourceType)), qt.Equals, 1)
|
c.Assert(len(a1Bundle.Resources().ByType(pageResourceType)), qt.Equals, 1)
|
||||||
|
|
||||||
b.AssertFileContent(filepath.FromSlash(workDir+"/public/a/page/index.html"), "TheContent")
|
b.AssertFileContent(filepath.FromSlash("public/a/page/index.html"), "TheContent")
|
||||||
b.AssertFileContent(filepath.FromSlash(workDir+"/public/symbolic1/s1/index.html"), "TheContent")
|
b.AssertFileContent(filepath.FromSlash("public/symbolic1/s1/index.html"), "TheContent")
|
||||||
b.AssertFileContent(filepath.FromSlash(workDir+"/public/symbolic2/a1/index.html"), "TheContent")
|
b.AssertFileContent(filepath.FromSlash("public/symbolic2/a1/index.html"), "TheContent")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPageBundlerHeadless(t *testing.T) {
|
func TestPageBundlerHeadless(t *testing.T) {
|
||||||
|
@ -563,12 +564,12 @@ HEADLESS {{< myShort >}}
|
||||||
|
|
||||||
th := newTestHelper(s.Cfg, s.Fs, t)
|
th := newTestHelper(s.Cfg, s.Fs, t)
|
||||||
|
|
||||||
th.assertFileContent(filepath.FromSlash(workDir+"/public/s1/index.html"), "TheContent")
|
th.assertFileContent(filepath.FromSlash("public/s1/index.html"), "TheContent")
|
||||||
th.assertFileContent(filepath.FromSlash(workDir+"/public/s1/l1.png"), "PNG")
|
th.assertFileContent(filepath.FromSlash("public/s1/l1.png"), "PNG")
|
||||||
|
|
||||||
th.assertFileNotExist(workDir + "/public/s2/index.html")
|
th.assertFileNotExist("public/s2/index.html")
|
||||||
// But the bundled resources needs to be published
|
// But the bundled resources needs to be published
|
||||||
th.assertFileContent(filepath.FromSlash(workDir+"/public/s2/l1.png"), "PNG")
|
th.assertFileContent(filepath.FromSlash("public/s2/l1.png"), "PNG")
|
||||||
|
|
||||||
// No headless bundles here, please.
|
// No headless bundles here, please.
|
||||||
// https://github.com/gohugoio/hugo/issues/6492
|
// https://github.com/gohugoio/hugo/issues/6492
|
||||||
|
@ -1321,7 +1322,7 @@ func TestPageBundlerHome(t *testing.T) {
|
||||||
workDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugo-bundler-home")
|
workDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugo-bundler-home")
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
|
|
||||||
cfg := config.New()
|
cfg := config.NewWithTestDefaults()
|
||||||
cfg.Set("workingDir", workDir)
|
cfg.Set("workingDir", workDir)
|
||||||
fs := hugofs.NewFrom(hugofs.Os, cfg)
|
fs := hugofs.NewFrom(hugofs.Os, cfg)
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
hpaths "github.com/gohugoio/hugo/common/paths"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/config"
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/gohugoio/hugo/langs"
|
"github.com/gohugoio/hugo/langs"
|
||||||
"github.com/gohugoio/hugo/modules"
|
"github.com/gohugoio/hugo/modules"
|
||||||
|
@ -51,6 +53,7 @@ type Paths struct {
|
||||||
// pagination path handling
|
// pagination path handling
|
||||||
PaginatePath string
|
PaginatePath string
|
||||||
|
|
||||||
|
// TODO1 check usage
|
||||||
PublishDir string
|
PublishDir string
|
||||||
|
|
||||||
// When in multihost mode, this returns a list of base paths below PublishDir
|
// When in multihost mode, this returns a list of base paths below PublishDir
|
||||||
|
@ -123,7 +126,7 @@ func New(fs *hugofs.Fs, cfg config.Provider) (*Paths, error) {
|
||||||
languages = langs.Languages{&langs.Language{Lang: "en", Cfg: cfg, ContentDir: contentDir}}
|
languages = langs.Languages{&langs.Language{Lang: "en", Cfg: cfg, ContentDir: contentDir}}
|
||||||
}
|
}
|
||||||
|
|
||||||
absPublishDir := AbsPathify(workingDir, publishDir)
|
absPublishDir := hpaths.AbsPathify(workingDir, publishDir)
|
||||||
if !strings.HasSuffix(absPublishDir, FilePathSeparator) {
|
if !strings.HasSuffix(absPublishDir, FilePathSeparator) {
|
||||||
absPublishDir += FilePathSeparator
|
absPublishDir += FilePathSeparator
|
||||||
}
|
}
|
||||||
|
@ -131,7 +134,7 @@ func New(fs *hugofs.Fs, cfg config.Provider) (*Paths, error) {
|
||||||
if absPublishDir == "//" {
|
if absPublishDir == "//" {
|
||||||
absPublishDir = FilePathSeparator
|
absPublishDir = FilePathSeparator
|
||||||
}
|
}
|
||||||
absResourcesDir := AbsPathify(workingDir, resourceDir)
|
absResourcesDir := hpaths.AbsPathify(workingDir, resourceDir)
|
||||||
if !strings.HasSuffix(absResourcesDir, FilePathSeparator) {
|
if !strings.HasSuffix(absResourcesDir, FilePathSeparator) {
|
||||||
absResourcesDir += FilePathSeparator
|
absResourcesDir += FilePathSeparator
|
||||||
}
|
}
|
||||||
|
@ -254,7 +257,7 @@ func (p *Paths) GetLangSubDir(lang string) string {
|
||||||
// AbsPathify creates an absolute path if given a relative path. If already
|
// AbsPathify creates an absolute path if given a relative path. If already
|
||||||
// absolute, the path is just cleaned.
|
// absolute, the path is just cleaned.
|
||||||
func (p *Paths) AbsPathify(inPath string) string {
|
func (p *Paths) AbsPathify(inPath string) string {
|
||||||
return AbsPathify(p.WorkingDir, inPath)
|
return hpaths.AbsPathify(p.WorkingDir, inPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RelPathify trims any WorkingDir prefix from the given filename. If
|
// RelPathify trims any WorkingDir prefix from the given filename. If
|
||||||
|
@ -267,12 +270,3 @@ func (p *Paths) RelPathify(filename string) string {
|
||||||
|
|
||||||
return strings.TrimPrefix(strings.TrimPrefix(filename, p.WorkingDir), FilePathSeparator)
|
return strings.TrimPrefix(strings.TrimPrefix(filename, p.WorkingDir), FilePathSeparator)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AbsPathify creates an absolute path if given a working dir and a relative path.
|
|
||||||
// If already absolute, the path is just cleaned.
|
|
||||||
func AbsPathify(workingDir, inPath string) string {
|
|
||||||
if filepath.IsAbs(inPath) {
|
|
||||||
return filepath.Clean(inPath)
|
|
||||||
}
|
|
||||||
return filepath.Join(workingDir, inPath)
|
|
||||||
}
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ import (
|
||||||
func TestNewPaths(t *testing.T) {
|
func TestNewPaths(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
fs := hugofs.NewMem(v)
|
fs := hugofs.NewMem(v)
|
||||||
|
|
||||||
v.Set("languages", map[string]any{
|
v.Set("languages", map[string]any{
|
||||||
|
|
|
@ -137,7 +137,7 @@ Edited content.
|
||||||
|
|
||||||
`)
|
`)
|
||||||
|
|
||||||
b.Assert(b.Fs.Destination.Remove("public"), qt.IsNil)
|
b.Assert(b.Fs.WorkingDirWritable.Remove("public"), qt.IsNil)
|
||||||
b.H.ResourceSpec.ClearCaches()
|
b.H.ResourceSpec.ClearCaches()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ const robotTxtTemplate = `User-agent: Googlebot
|
||||||
func TestRobotsTXTOutput(t *testing.T) {
|
func TestRobotsTXTOutput(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cfg := config.New()
|
cfg := config.NewWithTestDefaults()
|
||||||
cfg.Set("baseURL", "http://auth/bub/")
|
cfg.Set("baseURL", "http://auth/bub/")
|
||||||
cfg.Set("enableRobotsTXT", true)
|
cfg.Set("enableRobotsTXT", true)
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ func TestRSSOutput(t *testing.T) {
|
||||||
th.assertFileContent(filepath.Join("public", "categories", "hugo", rssURI), "<?xml", "rss version", "hugo on RSSTest")
|
th.assertFileContent(filepath.Join("public", "categories", "hugo", rssURI), "<?xml", "rss version", "hugo on RSSTest")
|
||||||
|
|
||||||
// RSS Item Limit
|
// RSS Item Limit
|
||||||
content := readDestination(t, fs, filepath.Join("public", rssURI))
|
content := readWorkingDir(t, fs, filepath.Join("public", rssURI))
|
||||||
c := strings.Count(content, "<item>")
|
c := strings.Count(content, "<item>")
|
||||||
if c != rssLimit {
|
if c != rssLimit {
|
||||||
t.Errorf("incorrect RSS item count: expected %d, got %d", rssLimit, c)
|
t.Errorf("incorrect RSS item count: expected %d, got %d", rssLimit, c)
|
||||||
|
|
|
@ -1212,7 +1212,7 @@ title: "Hugo Rocks!"
|
||||||
func TestShortcodeEmoji(t *testing.T) {
|
func TestShortcodeEmoji(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
v.Set("enableEmoji", true)
|
v.Set("enableEmoji", true)
|
||||||
|
|
||||||
builder := newTestSitesBuilder(t).WithViper(v)
|
builder := newTestSitesBuilder(t).WithViper(v)
|
||||||
|
@ -1277,7 +1277,7 @@ func TestShortcodeRef(t *testing.T) {
|
||||||
t.Run(fmt.Sprintf("plainIDAnchors=%t", plainIDAnchors), func(t *testing.T) {
|
t.Run(fmt.Sprintf("plainIDAnchors=%t", plainIDAnchors), func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
v.Set("baseURL", "https://example.org")
|
v.Set("baseURL", "https://example.org")
|
||||||
v.Set("blackfriday", map[string]any{
|
v.Set("blackfriday", map[string]any{
|
||||||
"plainIDAnchors": plainIDAnchors,
|
"plainIDAnchors": plainIDAnchors,
|
||||||
|
|
|
@ -363,7 +363,7 @@ func TestCreateSiteOutputFormats(t *testing.T) {
|
||||||
page.KindSection: []string{"JSON"},
|
page.KindSection: []string{"JSON"},
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := config.New()
|
cfg := config.NewWithTestDefaults()
|
||||||
cfg.Set("outputs", outputsConfig)
|
cfg.Set("outputs", outputsConfig)
|
||||||
|
|
||||||
outputs, err := createSiteOutputFormats(output.DefaultFormats, cfg.GetStringMap("outputs"), false)
|
outputs, err := createSiteOutputFormats(output.DefaultFormats, cfg.GetStringMap("outputs"), false)
|
||||||
|
@ -388,7 +388,7 @@ func TestCreateSiteOutputFormats(t *testing.T) {
|
||||||
// Issue #4528
|
// Issue #4528
|
||||||
t.Run("Mixed case", func(t *testing.T) {
|
t.Run("Mixed case", func(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
cfg := config.New()
|
cfg := config.NewWithTestDefaults()
|
||||||
|
|
||||||
outputsConfig := map[string]any{
|
outputsConfig := map[string]any{
|
||||||
// Note that we in Hugo 0.53.0 renamed this Kind to "taxonomy",
|
// Note that we in Hugo 0.53.0 renamed this Kind to "taxonomy",
|
||||||
|
@ -410,7 +410,7 @@ func TestCreateSiteOutputFormatsInvalidConfig(t *testing.T) {
|
||||||
page.KindHome: []string{"FOO", "JSON"},
|
page.KindHome: []string{"FOO", "JSON"},
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := config.New()
|
cfg := config.NewWithTestDefaults()
|
||||||
cfg.Set("outputs", outputsConfig)
|
cfg.Set("outputs", outputsConfig)
|
||||||
|
|
||||||
_, err := createSiteOutputFormats(output.DefaultFormats, cfg.GetStringMap("outputs"), false)
|
_, err := createSiteOutputFormats(output.DefaultFormats, cfg.GetStringMap("outputs"), false)
|
||||||
|
@ -424,7 +424,7 @@ func TestCreateSiteOutputFormatsEmptyConfig(t *testing.T) {
|
||||||
page.KindHome: []string{},
|
page.KindHome: []string{},
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := config.New()
|
cfg := config.NewWithTestDefaults()
|
||||||
cfg.Set("outputs", outputsConfig)
|
cfg.Set("outputs", outputsConfig)
|
||||||
|
|
||||||
outputs, err := createSiteOutputFormats(output.DefaultFormats, cfg.GetStringMap("outputs"), false)
|
outputs, err := createSiteOutputFormats(output.DefaultFormats, cfg.GetStringMap("outputs"), false)
|
||||||
|
@ -439,7 +439,7 @@ func TestCreateSiteOutputFormatsCustomFormats(t *testing.T) {
|
||||||
page.KindHome: []string{},
|
page.KindHome: []string{},
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := config.New()
|
cfg := config.NewWithTestDefaults()
|
||||||
cfg.Set("outputs", outputsConfig)
|
cfg.Set("outputs", outputsConfig)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -336,7 +336,7 @@ func doTestShouldAlwaysHaveUglyURLs(t *testing.T, uglyURLs bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
content := readDestination(t, fs, test.doc)
|
content := readWorkingDir(t, fs, test.doc)
|
||||||
|
|
||||||
if content != test.expected {
|
if content != test.expected {
|
||||||
t.Errorf("%s content expected:\n%q\ngot:\n%q", test.doc, test.expected, content)
|
t.Errorf("%s content expected:\n%q\ngot:\n%q", test.doc, test.expected, content)
|
||||||
|
@ -362,7 +362,7 @@ func TestMainSections(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
for _, paramSet := range []bool{false, true} {
|
for _, paramSet := range []bool{false, true} {
|
||||||
c.Run(fmt.Sprintf("param-%t", paramSet), func(c *qt.C) {
|
c.Run(fmt.Sprintf("param-%t", paramSet), func(c *qt.C) {
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
if paramSet {
|
if paramSet {
|
||||||
v.Set("params", map[string]any{
|
v.Set("params", map[string]any{
|
||||||
"mainSections": []string{"a1", "a2"},
|
"mainSections": []string{"a1", "a2"},
|
||||||
|
|
|
@ -76,7 +76,7 @@ func TestPageCount(t *testing.T) {
|
||||||
writeSourcesToSource(t, "", fs, urlFakeSource...)
|
writeSourcesToSource(t, "", fs, urlFakeSource...)
|
||||||
s := buildSingleSite(t, deps.DepsCfg{Fs: fs, Cfg: cfg}, BuildCfg{})
|
s := buildSingleSite(t, deps.DepsCfg{Fs: fs, Cfg: cfg}, BuildCfg{})
|
||||||
|
|
||||||
_, err := s.Fs.Destination.Open("public/blue")
|
_, err := s.Fs.WorkingDirReadOnly.Open("public/blue")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("No indexed rendered.")
|
t.Errorf("No indexed rendered.")
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ func TestPageCount(t *testing.T) {
|
||||||
"public/sd3/index.html",
|
"public/sd3/index.html",
|
||||||
"public/sd4.html",
|
"public/sd4.html",
|
||||||
} {
|
} {
|
||||||
if _, err := s.Fs.Destination.Open(filepath.FromSlash(pth)); err != nil {
|
if _, err := s.Fs.WorkingDirReadOnly.Open(filepath.FromSlash(pth)); err != nil {
|
||||||
t.Errorf("No alias rendered: %s", pth)
|
t.Errorf("No alias rendered: %s", pth)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ func doTestSitemapOutput(t *testing.T, internal bool) {
|
||||||
"<loc>http://auth/bub/categories/hugo/</loc>",
|
"<loc>http://auth/bub/categories/hugo/</loc>",
|
||||||
)
|
)
|
||||||
|
|
||||||
content := readDestination(th, th.Fs, outputSitemap)
|
content := readWorkingDir(th, th.Fs, outputSitemap)
|
||||||
c.Assert(content, qt.Not(qt.Contains), "404")
|
c.Assert(content, qt.Not(qt.Contains), "404")
|
||||||
c.Assert(content, qt.Not(qt.Contains), "<loc></loc>")
|
c.Assert(content, qt.Not(qt.Contains), "<loc></loc>")
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,7 @@ type filenameContent struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestSitesBuilder(t testing.TB) *sitesBuilder {
|
func newTestSitesBuilder(t testing.TB) *sitesBuilder {
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
fs := hugofs.NewMem(v)
|
fs := hugofs.NewMem(v)
|
||||||
|
|
||||||
litterOptions := litter.Options{
|
litterOptions := litter.Options{
|
||||||
|
@ -475,6 +475,9 @@ func (s *sitesBuilder) CreateSites() *sitesBuilder {
|
||||||
s.Fatalf("Failed to create sites: %s", err)
|
s.Fatalf("Failed to create sites: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.Assert(s.Fs.PublishDir, qt.IsNotNil)
|
||||||
|
s.Assert(s.Fs.WorkingDirReadOnly, qt.IsNotNil)
|
||||||
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -536,7 +539,7 @@ func (s *sitesBuilder) CreateSitesE() error {
|
||||||
return errors.Wrap(err, "failed to load config")
|
return errors.Wrap(err, "failed to load config")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Fs.Destination = hugofs.NewCreateCountingFs(s.Fs.Destination)
|
s.Fs.PublishDir = hugofs.NewCreateCountingFs(s.Fs.PublishDir)
|
||||||
|
|
||||||
depsCfg := s.depsCfg
|
depsCfg := s.depsCfg
|
||||||
depsCfg.Fs = s.Fs
|
depsCfg.Fs = s.Fs
|
||||||
|
@ -759,8 +762,7 @@ func (s *sitesBuilder) AssertFileDoesNotExist(filename string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sitesBuilder) AssertImage(width, height int, filename string) {
|
func (s *sitesBuilder) AssertImage(width, height int, filename string) {
|
||||||
filename = filepath.Join(s.workingDir, filename)
|
f, err := s.Fs.WorkingDirReadOnly.Open(filename)
|
||||||
f, err := s.Fs.Destination.Open(filename)
|
|
||||||
s.Assert(err, qt.IsNil)
|
s.Assert(err, qt.IsNil)
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
cfg, err := jpeg.DecodeConfig(f)
|
cfg, err := jpeg.DecodeConfig(f)
|
||||||
|
@ -771,17 +773,14 @@ func (s *sitesBuilder) AssertImage(width, height int, filename string) {
|
||||||
|
|
||||||
func (s *sitesBuilder) AssertNoDuplicateWrites() {
|
func (s *sitesBuilder) AssertNoDuplicateWrites() {
|
||||||
s.Helper()
|
s.Helper()
|
||||||
d := s.Fs.Destination.(hugofs.DuplicatesReporter)
|
d := s.Fs.PublishDir.(hugofs.DuplicatesReporter)
|
||||||
s.Assert(d.ReportDuplicates(), qt.Equals, "")
|
s.Assert(d.ReportDuplicates(), qt.Equals, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sitesBuilder) FileContent(filename string) string {
|
func (s *sitesBuilder) FileContent(filename string) string {
|
||||||
s.T.Helper()
|
s.Helper()
|
||||||
filename = filepath.FromSlash(filename)
|
filename = filepath.FromSlash(filename)
|
||||||
if !strings.HasPrefix(filename, s.workingDir) {
|
return readWorkingDir(s.T, s.Fs, filename)
|
||||||
filename = filepath.Join(s.workingDir, filename)
|
|
||||||
}
|
|
||||||
return readDestination(s.T, s.Fs, filename)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sitesBuilder) AssertObject(expected string, object any) {
|
func (s *sitesBuilder) AssertObject(expected string, object any) {
|
||||||
|
@ -797,7 +796,7 @@ func (s *sitesBuilder) AssertObject(expected string, object any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sitesBuilder) AssertFileContentRe(filename string, matches ...string) {
|
func (s *sitesBuilder) AssertFileContentRe(filename string, matches ...string) {
|
||||||
content := readDestination(s.T, s.Fs, filename)
|
content := readWorkingDir(s.T, s.Fs, filename)
|
||||||
for _, match := range matches {
|
for _, match := range matches {
|
||||||
r := regexp.MustCompile("(?s)" + match)
|
r := regexp.MustCompile("(?s)" + match)
|
||||||
if !r.MatchString(content) {
|
if !r.MatchString(content) {
|
||||||
|
@ -807,7 +806,7 @@ func (s *sitesBuilder) AssertFileContentRe(filename string, matches ...string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sitesBuilder) CheckExists(filename string) bool {
|
func (s *sitesBuilder) CheckExists(filename string) bool {
|
||||||
return destinationExists(s.Fs, filepath.Clean(filename))
|
return workingDirExists(s.Fs, filepath.Clean(filename))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sitesBuilder) GetPage(ref string) page.Page {
|
func (s *sitesBuilder) GetPage(ref string) page.Page {
|
||||||
|
@ -848,7 +847,7 @@ type testHelper struct {
|
||||||
func (th testHelper) assertFileContent(filename string, matches ...string) {
|
func (th testHelper) assertFileContent(filename string, matches ...string) {
|
||||||
th.Helper()
|
th.Helper()
|
||||||
filename = th.replaceDefaultContentLanguageValue(filename)
|
filename = th.replaceDefaultContentLanguageValue(filename)
|
||||||
content := readDestination(th, th.Fs, filename)
|
content := readWorkingDir(th, th.Fs, filename)
|
||||||
for _, match := range matches {
|
for _, match := range matches {
|
||||||
match = th.replaceDefaultContentLanguageValue(match)
|
match = th.replaceDefaultContentLanguageValue(match)
|
||||||
th.Assert(strings.Contains(content, match), qt.Equals, true, qt.Commentf(match+" not in: \n"+content))
|
th.Assert(strings.Contains(content, match), qt.Equals, true, qt.Commentf(match+" not in: \n"+content))
|
||||||
|
@ -857,7 +856,7 @@ func (th testHelper) assertFileContent(filename string, matches ...string) {
|
||||||
|
|
||||||
func (th testHelper) assertFileContentRegexp(filename string, matches ...string) {
|
func (th testHelper) assertFileContentRegexp(filename string, matches ...string) {
|
||||||
filename = th.replaceDefaultContentLanguageValue(filename)
|
filename = th.replaceDefaultContentLanguageValue(filename)
|
||||||
content := readDestination(th, th.Fs, filename)
|
content := readWorkingDir(th, th.Fs, filename)
|
||||||
for _, match := range matches {
|
for _, match := range matches {
|
||||||
match = th.replaceDefaultContentLanguageValue(match)
|
match = th.replaceDefaultContentLanguageValue(match)
|
||||||
r := regexp.MustCompile(match)
|
r := regexp.MustCompile(match)
|
||||||
|
@ -870,7 +869,7 @@ func (th testHelper) assertFileContentRegexp(filename string, matches ...string)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (th testHelper) assertFileNotExist(filename string) {
|
func (th testHelper) assertFileNotExist(filename string) {
|
||||||
exists, err := helpers.Exists(filename, th.Fs.Destination)
|
exists, err := helpers.Exists(filename, th.Fs.PublishDir)
|
||||||
th.Assert(err, qt.IsNil)
|
th.Assert(err, qt.IsNil)
|
||||||
th.Assert(exists, qt.Equals, false)
|
th.Assert(exists, qt.Equals, false)
|
||||||
}
|
}
|
||||||
|
@ -892,7 +891,7 @@ func loadTestConfig(fs afero.Fs, withConfig ...func(cfg config.Provider) error)
|
||||||
|
|
||||||
func newTestCfgBasic() (config.Provider, *hugofs.Fs) {
|
func newTestCfgBasic() (config.Provider, *hugofs.Fs) {
|
||||||
mm := afero.NewMemMapFs()
|
mm := afero.NewMemMapFs()
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
v.Set("defaultContentLanguageInSubdir", true)
|
v.Set("defaultContentLanguageInSubdir", true)
|
||||||
|
|
||||||
fs := hugofs.NewFrom(hugofs.NewBaseFileDecorator(mm), v)
|
fs := hugofs.NewFrom(hugofs.NewBaseFileDecorator(mm), v)
|
||||||
|
|
|
@ -500,16 +500,7 @@ func newDepsConfig(tp *TranslationProvider, cfg config.Provider, fs *hugofs.Fs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getConfig() config.Provider {
|
func getConfig() config.Provider {
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
v.Set("defaultContentLanguage", "en")
|
|
||||||
v.Set("contentDir", "content")
|
|
||||||
v.Set("dataDir", "data")
|
|
||||||
v.Set("i18nDir", "i18n")
|
|
||||||
v.Set("layoutDir", "layouts")
|
|
||||||
v.Set("archetypeDir", "archetypes")
|
|
||||||
v.Set("assetDir", "assets")
|
|
||||||
v.Set("resourceDir", "resources")
|
|
||||||
v.Set("publishDir", "public")
|
|
||||||
langs.LoadLanguageSettings(v, nil)
|
langs.LoadLanguageSettings(v, nil)
|
||||||
mod, err := modules.CreateProjectModule(v)
|
mod, err := modules.CreateProjectModule(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -16,14 +16,13 @@ package langs
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/config"
|
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetGlobalOnlySetting(t *testing.T) {
|
func TestGetGlobalOnlySetting(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
v.Set("defaultContentLanguageInSubdir", true)
|
v.Set("defaultContentLanguageInSubdir", true)
|
||||||
v.Set("contentDir", "content")
|
v.Set("contentDir", "content")
|
||||||
v.Set("paginatePath", "page")
|
v.Set("paginatePath", "page")
|
||||||
|
@ -38,7 +37,7 @@ func TestGetGlobalOnlySetting(t *testing.T) {
|
||||||
func TestLanguageParams(t *testing.T) {
|
func TestLanguageParams(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
v.Set("p1", "p1cfg")
|
v.Set("p1", "p1cfg")
|
||||||
v.Set("contentDir", "content")
|
v.Set("contentDir", "content")
|
||||||
|
|
||||||
|
|
|
@ -262,7 +262,7 @@ Position: {{ .Position | safeHTML }}
|
||||||
},
|
},
|
||||||
).Build()
|
).Build()
|
||||||
|
|
||||||
b.AssertFileContent("public/p1/index.html", filepath.FromSlash("Position: \"content/p1.md:7:1\""))
|
b.AssertFileContent("public/p1/index.html", filepath.FromSlash("Position: \"/content/p1.md:7:1\""))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Issue 9571
|
// Issue 9571
|
||||||
|
|
|
@ -16,14 +16,13 @@ package minifiers
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/config"
|
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConfig(t *testing.T) {
|
func TestConfig(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
|
|
||||||
v.Set("minify", map[string]any{
|
v.Set("minify", map[string]any{
|
||||||
"disablexml": true,
|
"disablexml": true,
|
||||||
|
@ -53,7 +52,7 @@ func TestConfig(t *testing.T) {
|
||||||
|
|
||||||
func TestConfigLegacy(t *testing.T) {
|
func TestConfigLegacy(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
|
|
||||||
// This was a bool < Hugo v0.58.
|
// This was a bool < Hugo v0.58.
|
||||||
v.Set("minify", true)
|
v.Set("minify", true)
|
||||||
|
|
|
@ -28,7 +28,7 @@ import (
|
||||||
|
|
||||||
func TestNew(t *testing.T) {
|
func TestNew(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
m, _ := New(media.DefaultTypes, output.DefaultFormats, v)
|
m, _ := New(media.DefaultTypes, output.DefaultFormats, v)
|
||||||
|
|
||||||
var rawJS string
|
var rawJS string
|
||||||
|
@ -76,7 +76,7 @@ func TestNew(t *testing.T) {
|
||||||
|
|
||||||
func TestConfigureMinify(t *testing.T) {
|
func TestConfigureMinify(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
v.Set("minify", map[string]any{
|
v.Set("minify", map[string]any{
|
||||||
"disablexml": true,
|
"disablexml": true,
|
||||||
"tdewolff": map[string]any{
|
"tdewolff": map[string]any{
|
||||||
|
@ -110,7 +110,7 @@ func TestConfigureMinify(t *testing.T) {
|
||||||
|
|
||||||
func TestJSONRoundTrip(t *testing.T) {
|
func TestJSONRoundTrip(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
m, _ := New(media.DefaultTypes, output.DefaultFormats, v)
|
m, _ := New(media.DefaultTypes, output.DefaultFormats, v)
|
||||||
|
|
||||||
for _, test := range []string{`{
|
for _, test := range []string{`{
|
||||||
|
@ -148,7 +148,7 @@ func TestJSONRoundTrip(t *testing.T) {
|
||||||
|
|
||||||
func TestBugs(t *testing.T) {
|
func TestBugs(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
m, _ := New(media.DefaultTypes, output.DefaultFormats, v)
|
m, _ := New(media.DefaultTypes, output.DefaultFormats, v)
|
||||||
|
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
|
@ -171,7 +171,7 @@ func TestBugs(t *testing.T) {
|
||||||
// Renamed to Precision in v2.7.0. Check that we support both.
|
// Renamed to Precision in v2.7.0. Check that we support both.
|
||||||
func TestDecodeConfigDecimalIsNowPrecision(t *testing.T) {
|
func TestDecodeConfigDecimalIsNowPrecision(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
v.Set("minify", map[string]any{
|
v.Set("minify", map[string]any{
|
||||||
"disablexml": true,
|
"disablexml": true,
|
||||||
"tdewolff": map[string]any{
|
"tdewolff": map[string]any{
|
||||||
|
@ -194,7 +194,7 @@ func TestDecodeConfigDecimalIsNowPrecision(t *testing.T) {
|
||||||
// Issue 9456
|
// Issue 9456
|
||||||
func TestDecodeConfigKeepWhitespace(t *testing.T) {
|
func TestDecodeConfigKeepWhitespace(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
v.Set("minify", map[string]any{
|
v.Set("minify", map[string]any{
|
||||||
"tdewolff": map[string]any{
|
"tdewolff": map[string]any{
|
||||||
"html": map[string]any{
|
"html": map[string]any{
|
||||||
|
|
|
@ -23,7 +23,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/config"
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/media"
|
"github.com/gohugoio/hugo/media"
|
||||||
"github.com/gohugoio/hugo/minifiers"
|
"github.com/gohugoio/hugo/minifiers"
|
||||||
"github.com/gohugoio/hugo/output"
|
"github.com/gohugoio/hugo/output"
|
||||||
|
@ -139,7 +138,7 @@ func TestClassCollector(t *testing.T) {
|
||||||
if skipMinifyTest[test.name] {
|
if skipMinifyTest[test.name] {
|
||||||
c.Skip("skip minify test")
|
c.Skip("skip minify test")
|
||||||
}
|
}
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
m, _ := minifiers.New(media.DefaultTypes, output.DefaultFormats, v)
|
m, _ := minifiers.New(media.DefaultTypes, output.DefaultFormats, v)
|
||||||
m.Minify(media.HTMLType, w, strings.NewReader(test.html))
|
m.Minify(media.HTMLType, w, strings.NewReader(test.html))
|
||||||
|
|
||||||
|
|
|
@ -27,9 +27,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewTestResourceSpec() (*resources.Spec, error) {
|
func NewTestResourceSpec() (*resources.Spec, error) {
|
||||||
cfg := config.New()
|
cfg := config.NewWithTestDefaults()
|
||||||
cfg.Set("baseURL", "https://example.org")
|
|
||||||
cfg.Set("publishDir", "public")
|
|
||||||
|
|
||||||
imagingCfg := map[string]any{
|
imagingCfg := map[string]any{
|
||||||
"resampleFilter": "linear",
|
"resampleFilter": "linear",
|
||||||
|
|
|
@ -79,7 +79,7 @@ func newTestResourceSpec(desc specDescriptor) *Spec {
|
||||||
cfg.Set("imaging", imagingCfg)
|
cfg.Set("imaging", imagingCfg)
|
||||||
|
|
||||||
fs := hugofs.NewFrom(afs, cfg)
|
fs := hugofs.NewFrom(afs, cfg)
|
||||||
fs.Destination = hugofs.NewCreateCountingFs(fs.Destination)
|
fs.PublishDir = hugofs.NewCreateCountingFs(fs.PublishDir)
|
||||||
|
|
||||||
s, err := helpers.NewPathSpec(fs, cfg, nil)
|
s, err := helpers.NewPathSpec(fs, cfg, nil)
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
|
@ -118,7 +118,6 @@ func newTestResourceOsFs(c *qt.C) (*Spec, string) {
|
||||||
cfg.Set("workingDir", workDir)
|
cfg.Set("workingDir", workDir)
|
||||||
|
|
||||||
fs := hugofs.NewFrom(hugofs.NewBaseFileDecorator(hugofs.Os), cfg)
|
fs := hugofs.NewFrom(hugofs.NewBaseFileDecorator(hugofs.Os), cfg)
|
||||||
fs.Destination = &afero.MemMapFs{}
|
|
||||||
|
|
||||||
s, err := helpers.NewPathSpec(fs, cfg, nil)
|
s, err := helpers.NewPathSpec(fs, cfg, nil)
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
|
|
|
@ -70,13 +70,13 @@ func TestTransform(t *testing.T) {
|
||||||
// Verify that we publish the same file once only.
|
// Verify that we publish the same file once only.
|
||||||
assertNoDuplicateWrites := func(c *qt.C, spec *Spec) {
|
assertNoDuplicateWrites := func(c *qt.C, spec *Spec) {
|
||||||
c.Helper()
|
c.Helper()
|
||||||
d := spec.Fs.Destination.(hugofs.DuplicatesReporter)
|
d := spec.Fs.PublishDir.(hugofs.DuplicatesReporter)
|
||||||
c.Assert(d.ReportDuplicates(), qt.Equals, "")
|
c.Assert(d.ReportDuplicates(), qt.Equals, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
assertShouldExist := func(c *qt.C, spec *Spec, filename string, should bool) {
|
assertShouldExist := func(c *qt.C, spec *Spec, filename string, should bool) {
|
||||||
c.Helper()
|
c.Helper()
|
||||||
exists, _ := helpers.Exists(filepath.FromSlash(filename), spec.Fs.Destination)
|
exists, _ := helpers.Exists(filepath.FromSlash(filename), spec.Fs.WorkingDirReadOnly)
|
||||||
c.Assert(exists, qt.Equals, should)
|
c.Assert(exists, qt.Equals, should)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,15 +77,7 @@ func TestUnicodeNorm(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestConfig() config.Provider {
|
func newTestConfig() config.Provider {
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
v.Set("contentDir", "content")
|
|
||||||
v.Set("dataDir", "data")
|
|
||||||
v.Set("i18nDir", "i18n")
|
|
||||||
v.Set("layoutDir", "layouts")
|
|
||||||
v.Set("archetypeDir", "archetypes")
|
|
||||||
v.Set("resourceDir", "resources")
|
|
||||||
v.Set("publishDir", "public")
|
|
||||||
v.Set("assetDir", "assets")
|
|
||||||
_, err := langs.LoadLanguageSettings(v, nil)
|
_, err := langs.LoadLanguageSettings(v, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
@ -985,7 +985,5 @@ func newDeps(cfg config.Provider) *deps.Deps {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestNs() *Namespace {
|
func newTestNs() *Namespace {
|
||||||
v := config.New()
|
return New(newDeps(config.NewWithTestDefaults()))
|
||||||
v.Set("contentDir", "content")
|
|
||||||
return New(newDeps(v))
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ import (
|
||||||
|
|
||||||
func TestScpGetLocal(t *testing.T) {
|
func TestScpGetLocal(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
fs := hugofs.NewMem(v)
|
fs := hugofs.NewMem(v)
|
||||||
ps := helpers.FilePathSeparator
|
ps := helpers.FilePathSeparator
|
||||||
|
|
||||||
|
@ -145,9 +145,8 @@ func TestScpGetRemoteParallel(t *testing.T) {
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
|
|
||||||
for _, ignoreCache := range []bool{false} {
|
for _, ignoreCache := range []bool{false} {
|
||||||
cfg := config.New()
|
cfg := config.NewWithTestDefaults()
|
||||||
cfg.Set("ignoreCache", ignoreCache)
|
cfg.Set("ignoreCache", ignoreCache)
|
||||||
cfg.Set("contentDir", "content")
|
|
||||||
|
|
||||||
ns := New(newDeps(cfg))
|
ns := New(newDeps(cfg))
|
||||||
ns.client = cl
|
ns.client = cl
|
||||||
|
@ -227,7 +226,5 @@ func newDeps(cfg config.Provider) *deps.Deps {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestNs() *Namespace {
|
func newTestNs() *Namespace {
|
||||||
v := config.New()
|
return New(newDeps(config.NewWithTestDefaults()))
|
||||||
v.Set("contentDir", "content")
|
|
||||||
return New(newDeps(v))
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ func (ns *Namespace) Config(path any) (image.Config, error) {
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := ns.deps.Fs.WorkingDir.Open(filename)
|
f, err := ns.deps.Fs.WorkingDirReadOnly.Open(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return image.Config{}, err
|
return image.Config{}, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ func TestNSConfig(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
v := config.New()
|
v := config.NewWithTestDefaults()
|
||||||
v.Set("workingDir", "/a/b")
|
v.Set("workingDir", "/a/b")
|
||||||
|
|
||||||
ns := New(&deps.Deps{Fs: hugofs.NewMem(v)})
|
ns := New(&deps.Deps{Fs: hugofs.NewMem(v)})
|
||||||
|
|
Loading…
Reference in a new issue