aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--hugofs/rootmapping_fs.go49
-rw-r--r--hugofs/rootmapping_fs_test.go6
-rw-r--r--hugolib/filesystems/basefs.go34
-rw-r--r--hugolib/hugo_sites_build.go2
-rw-r--r--hugolib/integrationtest_builder.go7
-rw-r--r--resources/resource_transformers/tocss/dartsass/dartsass_integration_test.go37
-rw-r--r--resources/resource_transformers/tocss/scss/scss_integration_test.go37
7 files changed, 135 insertions, 37 deletions
diff --git a/hugofs/rootmapping_fs.go b/hugofs/rootmapping_fs.go
index a5bf9aadf..336c8b4e7 100644
--- a/hugofs/rootmapping_fs.go
+++ b/hugofs/rootmapping_fs.go
@@ -21,6 +21,7 @@ import (
"path"
"path/filepath"
"strings"
+ "sync/atomic"
"github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/common/paths"
@@ -43,6 +44,7 @@ var _ ReverseLookupProvder = (*RootMappingFs)(nil)
func NewRootMappingFs(fs afero.Fs, rms ...RootMapping) (*RootMappingFs, error) {
rootMapToReal := radix.New()
realMapToRoot := radix.New()
+ id := fmt.Sprintf("rfs-%d", rootMappingFsCounter.Add(1))
addMapping := func(key string, rm RootMapping, to *radix.Tree) {
var mappings []RootMapping
@@ -76,6 +78,16 @@ func NewRootMappingFs(fs afero.Fs, rms ...RootMapping) (*RootMappingFs, error) {
rm.Meta = NewFileMeta()
}
+ if rm.FromBase == "" {
+ panic(" rm.FromBase is empty")
+ }
+
+ rm.Meta.Component = rm.FromBase
+ rm.Meta.Module = rm.Module
+ rm.Meta.ModuleOrdinal = rm.ModuleOrdinal
+ rm.Meta.IsProject = rm.IsProject
+ rm.Meta.BaseDir = rm.ToBase
+
if !fi.IsDir() {
// We do allow single file mounts.
// However, the file system logic will be much simpler with just directories.
@@ -122,19 +134,9 @@ func NewRootMappingFs(fs afero.Fs, rms ...RootMapping) (*RootMappingFs, error) {
}
}
- if rm.FromBase == "" {
- panic(" rm.FromBase is empty")
- }
-
// Extract "blog" from "content/blog"
rm.path = strings.TrimPrefix(strings.TrimPrefix(rm.From, rm.FromBase), filepathSeparator)
-
rm.Meta.SourceRoot = fi.(MetaProvider).Meta().Filename
- rm.Meta.BaseDir = rm.ToBase
- rm.Meta.Module = rm.Module
- rm.Meta.ModuleOrdinal = rm.ModuleOrdinal
- rm.Meta.Component = rm.FromBase
- rm.Meta.IsProject = rm.IsProject
meta := rm.Meta.Copy()
@@ -156,6 +158,7 @@ func NewRootMappingFs(fs afero.Fs, rms ...RootMapping) (*RootMappingFs, error) {
}
rfs := &RootMappingFs{
+ id: id,
Fs: fs,
rootMapToReal: rootMapToReal,
realMapToRoot: realMapToRoot,
@@ -227,11 +230,14 @@ var _ FilesystemUnwrapper = (*RootMappingFs)(nil)
// is directories only, and they will be returned in Readdir and Readdirnames
// in the order given.
type RootMappingFs struct {
+ id string
afero.Fs
rootMapToReal *radix.Tree
realMapToRoot *radix.Tree
}
+var rootMappingFsCounter atomic.Int32
+
func (fs *RootMappingFs) Mounts(base string) ([]FileMetaInfo, error) {
base = filepathSeparator + fs.cleanName(base)
roots := fs.getRootsWithPrefix(base)
@@ -263,6 +269,10 @@ func (fs *RootMappingFs) Mounts(base string) ([]FileMetaInfo, error) {
return fss, nil
}
+func (fs *RootMappingFs) Key() string {
+ return fs.id
+}
+
func (fs *RootMappingFs) UnwrapFilesystem() afero.Fs {
return fs.Fs
}
@@ -320,16 +330,16 @@ func (c ComponentPath) ComponentPathJoined() string {
}
type ReverseLookupProvder interface {
- ReverseLookup(filename string, checkExists bool) ([]ComponentPath, error)
- ReverseLookupComponent(component, filename string, checkExists bool) ([]ComponentPath, error)
+ ReverseLookup(filename string) ([]ComponentPath, error)
+ ReverseLookupComponent(component, filename string) ([]ComponentPath, error)
}
// func (fs *RootMappingFs) ReverseStat(filename string) ([]FileMetaInfo, error)
-func (fs *RootMappingFs) ReverseLookup(filename string, checkExists bool) ([]ComponentPath, error) {
- return fs.ReverseLookupComponent("", filename, checkExists)
+func (fs *RootMappingFs) ReverseLookup(filename string) ([]ComponentPath, error) {
+ return fs.ReverseLookupComponent("", filename)
}
-func (fs *RootMappingFs) ReverseLookupComponent(component, filename string, checkExists bool) ([]ComponentPath, error) {
+func (fs *RootMappingFs) ReverseLookupComponent(component, filename string) ([]ComponentPath, error) {
filename = fs.cleanName(filename)
key := filepathSeparator + filename
@@ -360,14 +370,6 @@ func (fs *RootMappingFs) ReverseLookupComponent(component, filename string, chec
} else {
// Now we know that this file _could_ be in this fs.
filename = filepathSeparator + filepath.Join(first.path, dir, name)
-
- if checkExists {
- // Confirm that it exists.
- _, err := fs.Stat(first.FromBase + filename)
- if err != nil {
- continue
- }
- }
}
cps = append(cps, ComponentPath{
@@ -667,6 +669,7 @@ func (fs *RootMappingFs) doStat(name string) ([]FileMetaInfo, error) {
var fis []FileMetaInfo
for _, rm := range roots {
+
var fi FileMetaInfo
fi, err = fs.statRoot(rm, name)
if err == nil {
diff --git a/hugofs/rootmapping_fs_test.go b/hugofs/rootmapping_fs_test.go
index b1ef102d3..83a95d648 100644
--- a/hugofs/rootmapping_fs_test.go
+++ b/hugofs/rootmapping_fs_test.go
@@ -276,20 +276,20 @@ func TestRootMappingFsMount(t *testing.T) {
// Test ReverseLookup.
// Single file mounts.
- cps, err := rfs.ReverseLookup(filepath.FromSlash("singlefiles/no.txt"), true)
+ cps, err := rfs.ReverseLookup(filepath.FromSlash("singlefiles/no.txt"))
c.Assert(err, qt.IsNil)
c.Assert(cps, qt.DeepEquals, []ComponentPath{
{Component: "content", Path: "singles/p1.md", Lang: "no"},
})
- cps, err = rfs.ReverseLookup(filepath.FromSlash("singlefiles/sv.txt"), true)
+ cps, err = rfs.ReverseLookup(filepath.FromSlash("singlefiles/sv.txt"))
c.Assert(err, qt.IsNil)
c.Assert(cps, qt.DeepEquals, []ComponentPath{
{Component: "content", Path: "singles/p1.md", Lang: "sv"},
})
// File inside directory mount.
- cps, err = rfs.ReverseLookup(filepath.FromSlash("mynoblogcontent/test.txt"), true)
+ cps, err = rfs.ReverseLookup(filepath.FromSlash("mynoblogcontent/test.txt"))
c.Assert(err, qt.IsNil)
c.Assert(cps, qt.DeepEquals, []ComponentPath{
{Component: "content", Path: "blog/test.txt", Lang: "no"},
diff --git a/hugolib/filesystems/basefs.go b/hugolib/filesystems/basefs.go
index aa466e0eb..b3e3284d5 100644
--- a/hugolib/filesystems/basefs.go
+++ b/hugolib/filesystems/basefs.go
@@ -265,6 +265,9 @@ type SourceFilesystem struct {
// This is a virtual composite filesystem. It expects path relative to a context.
Fs afero.Fs
+ // The source filesystem (usually the OS filesystem).
+ SourceFs afero.Fs
+
// When syncing a source folder to the target (e.g. /public), this may
// be set to publish into a subfolder. This is used for static syncing
// in multihost mode.
@@ -320,10 +323,10 @@ func (s SourceFilesystems) IsContent(filename string) bool {
}
// ResolvePaths resolves the given filename to a list of paths in the filesystems.
-func (s *SourceFilesystems) ResolvePaths(filename string, checkExists bool) []hugofs.ComponentPath {
+func (s *SourceFilesystems) ResolvePaths(filename string) []hugofs.ComponentPath {
var cpss []hugofs.ComponentPath
for _, rfs := range s.RootFss {
- cps, err := rfs.ReverseLookup(filename, checkExists)
+ cps, err := rfs.ReverseLookup(filename)
if err != nil {
panic(err)
}
@@ -362,7 +365,17 @@ func (d *SourceFilesystem) ReverseLookup(filename string, checkExists bool) ([]h
var cps []hugofs.ComponentPath
hugofs.WalkFilesystems(d.Fs, func(fs afero.Fs) bool {
if rfs, ok := fs.(hugofs.ReverseLookupProvder); ok {
- if c, err := rfs.ReverseLookupComponent(d.Name, filename, checkExists); err == nil {
+ if c, err := rfs.ReverseLookupComponent(d.Name, filename); err == nil {
+ if checkExists {
+ n := 0
+ for _, cp := range c {
+ if _, err := d.Fs.Stat(filepath.FromSlash(cp.Path)); err == nil {
+ c[n] = cp
+ n++
+ }
+ }
+ c = c[:n]
+ }
cps = append(cps, c...)
}
}
@@ -379,11 +392,12 @@ func (d *SourceFilesystem) mounts() []hugofs.FileMetaInfo {
if err == nil {
m = append(m, mounts...)
}
-
}
return false
})
+
// Filter out any mounts not belonging to this filesystem.
+ // TODO(bep) I think this is superflous.
n := 0
for _, mm := range m {
if mm.Meta().Component == d.Name {
@@ -392,6 +406,7 @@ func (d *SourceFilesystem) mounts() []hugofs.FileMetaInfo {
}
}
m = m[:n]
+
return m
}
@@ -428,10 +443,8 @@ func (d *SourceFilesystem) RealDirs(from string) []string {
if !m.IsDir() {
continue
}
- meta := m.Meta()
- _, err := d.Fs.Stat(from)
- if err == nil {
- dirname := filepath.Join(meta.Filename, from)
+ dirname := filepath.Join(m.Meta().Filename, from)
+ if _, err := d.SourceFs.Stat(dirname); err == nil {
dirnames = append(dirnames, dirname)
}
}
@@ -519,8 +532,9 @@ func newSourceFilesystemsBuilder(p *paths.Paths, logger loggers.Logger, b *BaseF
func (b *sourceFilesystemsBuilder) newSourceFilesystem(name string, fs afero.Fs) *SourceFilesystem {
return &SourceFilesystem{
- Name: name,
- Fs: fs,
+ Name: name,
+ Fs: fs,
+ SourceFs: b.sourceFs,
}
}
diff --git a/hugolib/hugo_sites_build.go b/hugolib/hugo_sites_build.go
index 93acdbf6b..382b1eed0 100644
--- a/hugolib/hugo_sites_build.go
+++ b/hugolib/hugo_sites_build.go
@@ -656,7 +656,7 @@ func (h *HugoSites) processPartial(ctx context.Context, l logg.LevelLogger, conf
isChangedDir := statErr == nil && fi.IsDir()
- cpss := h.BaseFs.ResolvePaths(ev.Name, !removed)
+ cpss := h.BaseFs.ResolvePaths(ev.Name)
pss := make([]*paths.Path, len(cpss))
for i, cps := range cpss {
p := cps.Path
diff --git a/hugolib/integrationtest_builder.go b/hugolib/integrationtest_builder.go
index 642bac7ab..be11c18d6 100644
--- a/hugolib/integrationtest_builder.go
+++ b/hugolib/integrationtest_builder.go
@@ -183,6 +183,13 @@ type lockingBuffer struct {
bytes.Buffer
}
+func (b *lockingBuffer) ReadFrom(r io.Reader) (n int64, err error) {
+ b.Lock()
+ n, err = b.Buffer.ReadFrom(r)
+ b.Unlock()
+ return
+}
+
func (b *lockingBuffer) Write(p []byte) (n int, err error) {
b.Lock()
n, err = b.Buffer.Write(p)
diff --git a/resources/resource_transformers/tocss/dartsass/dartsass_integration_test.go b/resources/resource_transformers/tocss/dartsass/dartsass_integration_test.go
index dd4c1e5ca..4d48b3b6a 100644
--- a/resources/resource_transformers/tocss/dartsass/dartsass_integration_test.go
+++ b/resources/resource_transformers/tocss/dartsass/dartsass_integration_test.go
@@ -19,6 +19,7 @@ import (
"github.com/bep/logg"
qt "github.com/frankban/quicktest"
+ "github.com/gohugoio/hugo/htesting"
"github.com/gohugoio/hugo/hugolib"
"github.com/gohugoio/hugo/resources/resource_transformers/tocss/dartsass"
)
@@ -525,3 +526,39 @@ T1: {{ $r.Content }}
b.AssertLogMatches(`Dart Sass: .*assets.*main.scss:13:0: number`)
b.AssertLogMatches(`Dart Sass: .*assets.*main.scss:14:0: number`)
}
+
+// Note: This test is more or less duplicated in both of the SCSS packages (libsass and dartsass).
+func TestBootstrap(t *testing.T) {
+ t.Parallel()
+ if !dartsass.Supports() {
+ t.Skip()
+ }
+ if !htesting.IsCI() {
+ t.Skip("skip (slow) test in non-CI environment")
+ }
+
+ files := `
+-- hugo.toml --
+disableKinds = ["term", "taxonomy", "section", "page"]
+[module]
+[[module.imports]]
+path="github.com/gohugoio/hugo-mod-bootstrap-scss/v5"
+-- go.mod --
+module github.com/gohugoio/tests/testHugoModules
+-- assets/scss/main.scss --
+@import "bootstrap/bootstrap";
+-- layouts/index.html --
+{{ $cssOpts := (dict "transpiler" "dartsass" ) }}
+{{ $r := resources.Get "scss/main.scss" | toCSS $cssOpts }}
+Styles: {{ $r.RelPermalink }}
+ `
+
+ b := hugolib.NewIntegrationTestBuilder(
+ hugolib.IntegrationTestConfig{
+ T: t,
+ TxtarString: files,
+ NeedsOsFS: true,
+ }).Build()
+
+ b.AssertFileContent("public/index.html", "Styles: /scss/main.css")
+}
diff --git a/resources/resource_transformers/tocss/scss/scss_integration_test.go b/resources/resource_transformers/tocss/scss/scss_integration_test.go
index 4d7d9d710..c193ca8af 100644
--- a/resources/resource_transformers/tocss/scss/scss_integration_test.go
+++ b/resources/resource_transformers/tocss/scss/scss_integration_test.go
@@ -20,6 +20,7 @@ import (
qt "github.com/frankban/quicktest"
+ "github.com/gohugoio/hugo/htesting"
"github.com/gohugoio/hugo/hugolib"
"github.com/gohugoio/hugo/resources/resource_transformers/tocss/scss"
)
@@ -290,3 +291,39 @@ T1: {{ $r.Content }}
b.AssertFileContent("public/index.html", `T1: body body{background:url(images/hero.jpg) no-repeat center/cover;font-family:Hugo's New Roman}p{color:blue;font-size:var 24px}b{color:green}`)
}
+
+// Note: This test is more or less duplicated in both of the SCSS packages (libsass and dartsass).
+func TestBootstrap(t *testing.T) {
+ t.Parallel()
+ if !scss.Supports() {
+ t.Skip()
+ }
+ if !htesting.IsCI() {
+ t.Skip("skip (slow) test in non-CI environment")
+ }
+
+ files := `
+-- hugo.toml --
+disableKinds = ["term", "taxonomy", "section", "page"]
+[module]
+[[module.imports]]
+path="github.com/gohugoio/hugo-mod-bootstrap-scss/v5"
+-- go.mod --
+module github.com/gohugoio/tests/testHugoModules
+-- assets/scss/main.scss --
+@import "bootstrap/bootstrap";
+-- layouts/index.html --
+{{ $cssOpts := (dict "transpiler" "libsass" ) }}
+{{ $r := resources.Get "scss/main.scss" | toCSS $cssOpts }}
+Styles: {{ $r.RelPermalink }}
+ `
+
+ b := hugolib.NewIntegrationTestBuilder(
+ hugolib.IntegrationTestConfig{
+ T: t,
+ TxtarString: files,
+ NeedsOsFS: true,
+ }).Build()
+
+ b.AssertFileContent("public/index.html", "Styles: /scss/main.css")
+}