mirror of
https://github.com/gohugoio/hugo.git
synced 2025-08-31 22:41:53 +02:00
Support files in content mounts
This commit is a general improvement of handling if single file mounts. Fixes #6684 Fixes #6696
This commit is contained in:
@@ -18,6 +18,7 @@ package filesystems
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -55,6 +56,8 @@ type BaseFs struct {
|
||||
theBigFs *filesystemsCollector
|
||||
}
|
||||
|
||||
// TODO(bep) we can get regular files in here and that is fine, but
|
||||
// we need to clean up the naming.
|
||||
func (fs *BaseFs) WatchDirs() []hugofs.FileMetaInfo {
|
||||
var dirs []hugofs.FileMetaInfo
|
||||
for _, dir := range fs.AllDirs() {
|
||||
@@ -62,7 +65,6 @@ func (fs *BaseFs) WatchDirs() []hugofs.FileMetaInfo {
|
||||
dirs = append(dirs, dir)
|
||||
}
|
||||
}
|
||||
|
||||
return dirs
|
||||
}
|
||||
|
||||
@@ -90,7 +92,7 @@ func (b *BaseFs) RelContentDir(filename string) string {
|
||||
for _, dir := range b.SourceFilesystems.Content.Dirs {
|
||||
dirname := dir.Meta().Filename()
|
||||
if strings.HasPrefix(filename, dirname) {
|
||||
rel := strings.TrimPrefix(filename, dirname)
|
||||
rel := path.Join(dir.Meta().Path(), strings.TrimPrefix(filename, dirname))
|
||||
return strings.TrimPrefix(rel, filePathSeparator)
|
||||
}
|
||||
}
|
||||
@@ -298,8 +300,16 @@ func (d *SourceFilesystem) Contains(filename string) bool {
|
||||
func (d *SourceFilesystem) Path(filename string) string {
|
||||
for _, dir := range d.Dirs {
|
||||
meta := dir.Meta()
|
||||
if !dir.IsDir() {
|
||||
if filename == meta.Filename() {
|
||||
return meta.PathFile()
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasPrefix(filename, meta.Filename()) {
|
||||
p := strings.TrimPrefix(strings.TrimPrefix(filename, meta.Filename()), filePathSeparator)
|
||||
p = path.Join(meta.PathFile(), p)
|
||||
return p
|
||||
}
|
||||
}
|
||||
@@ -530,11 +540,11 @@ func (b *sourceFilesystemsBuilder) createModFs(
|
||||
fromToStatic []hugofs.RootMapping
|
||||
)
|
||||
|
||||
absPathify := func(path string) string {
|
||||
absPathify := func(path string) (string, string) {
|
||||
if filepath.IsAbs(path) {
|
||||
return path
|
||||
return "", path
|
||||
}
|
||||
return paths.AbsPathify(md.dir, path)
|
||||
return md.dir, paths.AbsPathify(md.dir, path)
|
||||
}
|
||||
|
||||
for _, mount := range md.Mounts() {
|
||||
@@ -544,9 +554,12 @@ func (b *sourceFilesystemsBuilder) createModFs(
|
||||
mountWeight++
|
||||
}
|
||||
|
||||
base, filename := absPathify(mount.Source)
|
||||
|
||||
rm := hugofs.RootMapping{
|
||||
From: mount.Target,
|
||||
To: absPathify(mount.Source),
|
||||
From: mount.Target,
|
||||
To: filename,
|
||||
ToBasedir: base,
|
||||
Meta: hugofs.FileMeta{
|
||||
"watch": md.Watch(),
|
||||
"mountWeight": mountWeight,
|
||||
@@ -621,7 +634,8 @@ func (b *sourceFilesystemsBuilder) createModFs(
|
||||
if md.isMainProject {
|
||||
return b.p.AbsResourcesDir
|
||||
}
|
||||
return absPathify(files.FolderResources)
|
||||
_, filename := absPathify(files.FolderResources)
|
||||
return filename
|
||||
}
|
||||
|
||||
if collector.overlayMounts == nil {
|
||||
|
@@ -545,6 +545,85 @@ title: "My Page"
|
||||
b.AssertFileContent("public/mypage/index.html", "Permalink: https://example.org/mypage/")
|
||||
}
|
||||
|
||||
// https://github.com/gohugoio/hugo/issues/6684
|
||||
func TestMountsContentFile(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
workingDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugo-modules-content-file")
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer clean()
|
||||
|
||||
configTemplate := `
|
||||
baseURL = "https://example.com"
|
||||
title = "My Modular Site"
|
||||
workingDir = %q
|
||||
|
||||
[module]
|
||||
[[module.mounts]]
|
||||
source = "README.md"
|
||||
target = "content/_index.md"
|
||||
[[module.mounts]]
|
||||
source = "mycontent"
|
||||
target = "content/blog"
|
||||
|
||||
`
|
||||
|
||||
config := fmt.Sprintf(configTemplate, workingDir)
|
||||
|
||||
b := newTestSitesBuilder(t).Running()
|
||||
|
||||
b.Fs = hugofs.NewDefault(viper.New())
|
||||
|
||||
b.WithWorkingDir(workingDir).WithConfigFile("toml", config)
|
||||
b.WithTemplatesAdded("index.html", `
|
||||
{{ .Title }}
|
||||
{{ .Content }}
|
||||
|
||||
{{ $readme := .Site.GetPage "/README.md" }}
|
||||
{{ with $readme }}README: {{ .Title }}|Filename: {{ path.Join .File.Filename }}|Path: {{ path.Join .File.Path }}|FilePath: {{ path.Join .File.FileInfo.Meta.PathFile }}|{{ end }}
|
||||
|
||||
|
||||
{{ $mypage := .Site.GetPage "/blog/mypage.md" }}
|
||||
{{ with $mypage }}MYPAGE: {{ .Title }}|Path: {{ path.Join .File.Path }}|FilePath: {{ path.Join .File.FileInfo.Meta.PathFile }}|{{ end }}
|
||||
|
||||
`)
|
||||
|
||||
os.Mkdir(filepath.Join(workingDir, "mycontent"), 0777)
|
||||
|
||||
b.WithSourceFile("README.md", `---
|
||||
title: "Readme Title"
|
||||
---
|
||||
|
||||
Readme Content.
|
||||
`,
|
||||
filepath.Join("mycontent", "mypage.md"), `
|
||||
---
|
||||
title: "My Page"
|
||||
---
|
||||
|
||||
`)
|
||||
|
||||
b.Build(BuildCfg{})
|
||||
|
||||
b.AssertFileContent("public/index.html", `
|
||||
README: Readme Title
|
||||
/README.md|Path: _index.md|FilePath: README.md
|
||||
Readme Content.
|
||||
MYPAGE: My Page|Path: blog/mypage.md|FilePath: mycontent/mypage.md|
|
||||
`)
|
||||
b.AssertFileContent("public/blog/mypage/index.html", "Single: My Page")
|
||||
|
||||
b.EditFiles("README.md", `---
|
||||
title: "Readme Edit"
|
||||
---
|
||||
`)
|
||||
|
||||
b.Build(BuildCfg{})
|
||||
|
||||
b.AssertFileContent("public/index.html", `
|
||||
Readme Edit
|
||||
`)
|
||||
}
|
||||
|
||||
// https://github.com/gohugoio/hugo/issues/6299
|
||||
func TestSiteWithGoModButNoModules(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
@@ -895,7 +895,7 @@ func (m *contentChangeMap) add(dirname string, tp bundleDirType) {
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
func (m *contentChangeMap) resolveAndRemove(filename string) (string, string, bundleDirType) {
|
||||
func (m *contentChangeMap) resolveAndRemove(filename string) (string, bundleDirType) {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
|
||||
@@ -908,22 +908,22 @@ func (m *contentChangeMap) resolveAndRemove(filename string) (string, string, bu
|
||||
|
||||
if _, found := m.branchBundles[dir]; found {
|
||||
delete(m.branchBundles, dir)
|
||||
return dir, dir, bundleBranch
|
||||
return dir, bundleBranch
|
||||
}
|
||||
|
||||
if key, _, found := m.leafBundles.LongestPrefix(dir); found {
|
||||
m.leafBundles.Delete(key)
|
||||
dir = string(key)
|
||||
return dir, dir, bundleLeaf
|
||||
return dir, bundleLeaf
|
||||
}
|
||||
|
||||
fileTp, isContent := classifyBundledFile(name)
|
||||
if isContent && fileTp != bundleNot {
|
||||
// A new bundle.
|
||||
return dir, dir, fileTp
|
||||
return dir, fileTp
|
||||
}
|
||||
|
||||
return dir, filename, bundleNot
|
||||
return dir, bundleNot
|
||||
|
||||
}
|
||||
|
||||
|
@@ -946,6 +946,24 @@ func (p *pageState) sourceRef() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *pageState) sourceRefs() []string {
|
||||
refs := []string{p.sourceRef()}
|
||||
|
||||
if !p.File().IsZero() {
|
||||
meta := p.File().FileInfo().Meta()
|
||||
path := meta.PathFile()
|
||||
|
||||
if path != "" {
|
||||
ref := "/" + path
|
||||
if ref != refs[0] {
|
||||
refs = append(refs, ref)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return refs
|
||||
}
|
||||
|
||||
type pageStatePages []*pageState
|
||||
|
||||
// Implement sorting.
|
||||
|
@@ -151,12 +151,11 @@ func newPageCollectionsFromPages(pages pageStatePages) *PageCollections {
|
||||
for _, pageCollection := range []pageStatePages{c.workAllPages, c.headlessPages} {
|
||||
for _, p := range pageCollection {
|
||||
if p.IsPage() {
|
||||
sourceRef := p.sourceRef()
|
||||
if sourceRef != "" {
|
||||
// index the canonical ref
|
||||
// e.g. /section/article.md
|
||||
add(sourceRef, p)
|
||||
sourceRefs := p.sourceRefs()
|
||||
for _, ref := range sourceRefs {
|
||||
add(ref, p)
|
||||
}
|
||||
sourceRef := sourceRefs[0]
|
||||
|
||||
// Ref/Relref supports this potentially ambiguous lookup.
|
||||
add(p.File().LogicalName(), p)
|
||||
@@ -177,11 +176,9 @@ func newPageCollectionsFromPages(pages pageStatePages) *PageCollections {
|
||||
pathWithNoExtensions := path.Join(dir, translationBaseName)
|
||||
add(pathWithNoExtensions, p)
|
||||
} else {
|
||||
// index the canonical, unambiguous ref for any backing file
|
||||
// e.g. /section/_index.md
|
||||
sourceRef := p.sourceRef()
|
||||
if sourceRef != "" {
|
||||
add(sourceRef, p)
|
||||
sourceRefs := p.sourceRefs()
|
||||
for _, ref := range sourceRefs {
|
||||
add(ref, p)
|
||||
}
|
||||
|
||||
ref := p.SectionsPath()
|
||||
|
@@ -116,7 +116,7 @@ func (c *pagesCollector) Collect() error {
|
||||
} else {
|
||||
dirs := make(map[contentDirKey]bool)
|
||||
for _, filename := range c.filenames {
|
||||
dir, filename, btype := c.tracker.resolveAndRemove(filename)
|
||||
dir, btype := c.tracker.resolveAndRemove(filename)
|
||||
dirs[contentDirKey{dir, filename, btype}] = true
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ func (c *pagesCollector) Collect() error {
|
||||
default:
|
||||
// We always start from a directory.
|
||||
collectErr = c.collectDir(dir.dirname, true, func(fim hugofs.FileMetaInfo) bool {
|
||||
return strings.HasSuffix(dir.filename, fim.Meta().Path())
|
||||
return dir.filename == fim.Meta().Filename()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -211,6 +211,7 @@ func (c *pagesCollector) collectDir(dirname string, partial bool, inFilter func(
|
||||
for _, fi := range readdir {
|
||||
if filter(fi) {
|
||||
filtered = append(filtered, fi)
|
||||
|
||||
if c.tracker != nil {
|
||||
// Track symlinks.
|
||||
c.tracker.addSymbolicLinkMapping(fi)
|
||||
|
Reference in New Issue
Block a user