From 496730840e388d7187149503f6e6e4648a8f65c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Mon, 21 Apr 2025 16:15:21 +0200 Subject: [PATCH] Revert the breaking change from 0.146.0 with dots in content filenames Closes #13632 --- common/paths/pathparser.go | 96 ++++++++++++------- common/paths/pathparser_test.go | 93 +++++++++++++++--- common/paths/paths_integration_test.go | 23 +++++ hugolib/collections_test.go | 2 + hugolib/content_render_hooks_test.go | 2 - hugolib/site_test.go | 2 +- tpl/tplimpl/templatestore.go | 24 ++--- tpl/tplimpl/templatestore_integration_test.go | 2 +- 8 files changed, 175 insertions(+), 69 deletions(-) diff --git a/common/paths/pathparser.go b/common/paths/pathparser.go index c04f2022e..b0a2f9fc4 100644 --- a/common/paths/pathparser.go +++ b/common/paths/pathparser.go @@ -124,14 +124,15 @@ func (pp *PathParser) parseIdentifier(component, s string, p *Path, i, lastDot i if p.posContainerHigh != -1 { return } - mayHaveLang := pp.LanguageIndex != nil + mayHaveLang := p.posIdentifierLanguage == -1 && pp.LanguageIndex != nil mayHaveLang = mayHaveLang && (component == files.ComponentFolderContent || component == files.ComponentFolderLayouts) mayHaveOutputFormat := component == files.ComponentFolderLayouts - mayHaveKind := mayHaveOutputFormat + mayHaveKind := p.posIdentifierKind == -1 && mayHaveOutputFormat + mayHaveLayout := component == files.ComponentFolderLayouts var found bool var high int - if len(p.identifiers) > 0 { + if len(p.identifiersKnown) > 0 { high = lastDot } else { high = len(p.s) @@ -139,9 +140,9 @@ func (pp *PathParser) parseIdentifier(component, s string, p *Path, i, lastDot i id := types.LowHigh[string]{Low: i + 1, High: high} sid := p.s[id.Low:id.High] - if len(p.identifiers) == 0 { + if len(p.identifiersKnown) == 0 { // The first is always the extension. - p.identifiers = append(p.identifiers, id) + p.identifiersKnown = append(p.identifiersKnown, id) found = true // May also be the output format. @@ -164,8 +165,8 @@ func (pp *PathParser) parseIdentifier(component, s string, p *Path, i, lastDot i } found = langFound if langFound { - p.identifiers = append(p.identifiers, id) - p.posIdentifierLanguage = len(p.identifiers) - 1 + p.identifiersKnown = append(p.identifiersKnown, id) + p.posIdentifierLanguage = len(p.identifiersKnown) - 1 } } @@ -177,28 +178,33 @@ func (pp *PathParser) parseIdentifier(component, s string, p *Path, i, lastDot i // false positives on the form css.html. if pp.IsOutputFormat(sid, p.Ext()) { found = true - p.identifiers = append(p.identifiers, id) - p.posIdentifierOutputFormat = len(p.identifiers) - 1 + p.identifiersKnown = append(p.identifiersKnown, id) + p.posIdentifierOutputFormat = len(p.identifiersKnown) - 1 } } if !found && mayHaveKind { if kinds.GetKindMain(sid) != "" { found = true - p.identifiers = append(p.identifiers, id) - p.posIdentifierKind = len(p.identifiers) - 1 + p.identifiersKnown = append(p.identifiersKnown, id) + p.posIdentifierKind = len(p.identifiersKnown) - 1 } } if !found && sid == identifierBaseof { found = true - p.identifiers = append(p.identifiers, id) - p.posIdentifierBaseof = len(p.identifiers) - 1 + p.identifiersKnown = append(p.identifiersKnown, id) + p.posIdentifierBaseof = len(p.identifiersKnown) - 1 + } + + if !found && mayHaveLayout { + p.identifiersKnown = append(p.identifiersKnown, id) + p.posIdentifierLayout = len(p.identifiersKnown) - 1 + found = true } if !found { - p.identifiers = append(p.identifiers, id) - p.identifiersUnknown = append(p.identifiersUnknown, len(p.identifiers)-1) + p.identifiersUnknown = append(p.identifiersUnknown, id) } } @@ -252,13 +258,13 @@ func (pp *PathParser) doParse(component, s string, p *Path) (*Path, error) { } } - if len(p.identifiers) > 0 { + if len(p.identifiersKnown) > 0 { isContentComponent := p.component == files.ComponentFolderContent || p.component == files.ComponentFolderArchetypes isContent := isContentComponent && pp.IsContentExt(p.Ext()) - id := p.identifiers[len(p.identifiers)-1] + id := p.identifiersKnown[len(p.identifiersKnown)-1] - if id.High > p.posContainerHigh { - b := p.s[p.posContainerHigh:id.High] + if id.Low > p.posContainerHigh { + b := p.s[p.posContainerHigh : id.Low-1] if isContent { switch b { case "index": @@ -294,6 +300,16 @@ func (pp *PathParser) doParse(component, s string, p *Path) (*Path, error) { } } + if p.pathType == TypeShortcode && p.posIdentifierLayout != -1 { + // myshortcode or myshortcode.html, no layout. + if len(p.identifiersKnown) <= 2 { + p.posIdentifierLayout = -1 + } else { + // First is always the name. + p.posIdentifierLayout-- + } + } + return p, nil } @@ -350,13 +366,14 @@ type Path struct { component string pathType Type - identifiers []types.LowHigh[string] + identifiersKnown []types.LowHigh[string] + identifiersUnknown []types.LowHigh[string] posIdentifierLanguage int posIdentifierOutputFormat int posIdentifierKind int + posIdentifierLayout int posIdentifierBaseof int - identifiersUnknown []int disabled bool trimLeadingSlash bool @@ -388,10 +405,11 @@ func (p *Path) reset() { p.posSectionHigh = -1 p.component = "" p.pathType = 0 - p.identifiers = p.identifiers[:0] + p.identifiersKnown = p.identifiersKnown[:0] p.posIdentifierLanguage = -1 p.posIdentifierOutputFormat = -1 p.posIdentifierKind = -1 + p.posIdentifierLayout = -1 p.posIdentifierBaseof = -1 p.disabled = false p.trimLeadingSlash = false @@ -479,7 +497,7 @@ func (p *Path) Name() string { // Name returns the last element of path without any extension. func (p *Path) NameNoExt() string { if i := p.identifierIndex(0); i != -1 { - return p.s[p.posContainerHigh : p.identifiers[i].Low-1] + return p.s[p.posContainerHigh : p.identifiersKnown[i].Low-1] } return p.s[p.posContainerHigh:] } @@ -491,7 +509,7 @@ func (p *Path) NameNoLang() string { return p.Name() } - return p.s[p.posContainerHigh:p.identifiers[i].Low-1] + p.s[p.identifiers[i].High:] + return p.s[p.posContainerHigh:p.identifiersKnown[i].Low-1] + p.s[p.identifiersKnown[i].High:] } // BaseNameNoIdentifier returns the logical base name for a resource without any identifier (e.g. no extension). @@ -510,15 +528,15 @@ func (p *Path) NameNoIdentifier() string { } func (p *Path) nameLowHigh() types.LowHigh[string] { - if len(p.identifiers) > 0 { - lastID := p.identifiers[len(p.identifiers)-1] + if len(p.identifiersKnown) > 0 { + lastID := p.identifiersKnown[len(p.identifiersKnown)-1] if p.posContainerHigh == lastID.Low { // The last identifier is the name. return lastID } return types.LowHigh[string]{ Low: p.posContainerHigh, - High: p.identifiers[len(p.identifiers)-1].Low - 1, + High: p.identifiersKnown[len(p.identifiersKnown)-1].Low - 1, } } return types.LowHigh[string]{ @@ -566,7 +584,7 @@ func (p *Path) PathNoIdentifier() string { // PathBeforeLangAndOutputFormatAndExt returns the path up to the first identifier that is not a language or output format. func (p *Path) PathBeforeLangAndOutputFormatAndExt() string { - if len(p.identifiers) == 0 { + if len(p.identifiersKnown) == 0 { return p.norm(p.s) } i := p.identifierIndex(0) @@ -582,7 +600,7 @@ func (p *Path) PathBeforeLangAndOutputFormatAndExt() string { return p.norm(p.s) } - id := p.identifiers[i] + id := p.identifiersKnown[i] return p.norm(p.s[:id.Low-1]) } @@ -633,11 +651,11 @@ func (p *Path) BaseNoLeadingSlash() string { } func (p *Path) base(preserveExt, isBundle bool) string { - if len(p.identifiers) == 0 { + if len(p.identifiersKnown) == 0 { return p.norm(p.s) } - if preserveExt && len(p.identifiers) == 1 { + if preserveExt && len(p.identifiersKnown) == 1 { // Preserve extension. return p.norm(p.s) } @@ -659,7 +677,7 @@ func (p *Path) base(preserveExt, isBundle bool) string { } // For txt files etc. we want to preserve the extension. - id := p.identifiers[0] + id := p.identifiersKnown[0] return p.norm(p.s[:high] + p.s[id.Low-1:id.High]) } @@ -676,6 +694,10 @@ func (p *Path) Kind() string { return p.identifierAsString(p.posIdentifierKind) } +func (p *Path) Layout() string { + return p.identifierAsString(p.posIdentifierLayout) +} + func (p *Path) Lang() string { return p.identifierAsString(p.posIdentifierLanguage) } @@ -689,8 +711,8 @@ func (p *Path) Disabled() bool { } func (p *Path) Identifiers() []string { - ids := make([]string, len(p.identifiers)) - for i, id := range p.identifiers { + ids := make([]string, len(p.identifiersKnown)) + for i, id := range p.identifiersKnown { ids[i] = p.s[id.Low:id.High] } return ids @@ -699,7 +721,7 @@ func (p *Path) Identifiers() []string { func (p *Path) IdentifiersUnknown() []string { ids := make([]string, len(p.identifiersUnknown)) for i, id := range p.identifiersUnknown { - ids[i] = p.s[p.identifiers[id].Low:p.identifiers[id].High] + ids[i] = p.s[id.Low:id.High] } return ids } @@ -735,12 +757,12 @@ func (p *Path) identifierAsString(i int) string { return "" } - id := p.identifiers[i] + id := p.identifiersKnown[i] return p.s[id.Low:id.High] } func (p *Path) identifierIndex(i int) int { - if i < 0 || i >= len(p.identifiers) { + if i < 0 || i >= len(p.identifiersKnown) { return -1 } return i diff --git a/common/paths/pathparser_test.go b/common/paths/pathparser_test.go index fd1590c73..a6194e756 100644 --- a/common/paths/pathparser_test.go +++ b/common/paths/pathparser_test.go @@ -171,22 +171,25 @@ func TestParse(t *testing.T) { "/a/b.a.b.no.txt", func(c *qt.C, p *Path) { c.Assert(p.Name(), qt.Equals, "b.a.b.no.txt") - c.Assert(p.NameNoIdentifier(), qt.Equals, "b") + c.Assert(p.NameNoIdentifier(), qt.Equals, "b.a.b") c.Assert(p.NameNoLang(), qt.Equals, "b.a.b.txt") - c.Assert(p.Identifiers(), qt.DeepEquals, []string{"txt", "no", "b", "a", "b"}) + c.Assert(p.Identifiers(), qt.DeepEquals, []string{"txt", "no"}) c.Assert(p.IdentifiersUnknown(), qt.DeepEquals, []string{"b", "a", "b"}) - c.Assert(p.Base(), qt.Equals, "/a/b.txt") - c.Assert(p.BaseNoLeadingSlash(), qt.Equals, "a/b.txt") + c.Assert(p.Base(), qt.Equals, "/a/b.a.b.txt") + c.Assert(p.BaseNoLeadingSlash(), qt.Equals, "a/b.a.b.txt") c.Assert(p.Path(), qt.Equals, "/a/b.a.b.no.txt") - c.Assert(p.PathNoLang(), qt.Equals, "/a/b.txt") + c.Assert(p.PathNoLang(), qt.Equals, "/a/b.a.b.txt") c.Assert(p.Ext(), qt.Equals, "txt") - c.Assert(p.PathNoIdentifier(), qt.Equals, "/a/b") + c.Assert(p.PathNoIdentifier(), qt.Equals, "/a/b.a.b") }, }, { "Home branch cundle", "/_index.md", func(c *qt.C, p *Path) { + c.Assert(p.Identifiers(), qt.DeepEquals, []string{"md"}) + c.Assert(p.IsBranchBundle(), qt.IsTrue) + c.Assert(p.IsBundle(), qt.IsTrue) c.Assert(p.Base(), qt.Equals, "/") c.Assert(p.BaseReTyped("foo"), qt.Equals, "/foo") c.Assert(p.Path(), qt.Equals, "/_index.md") @@ -206,7 +209,8 @@ func TestParse(t *testing.T) { c.Assert(p.ContainerDir(), qt.Equals, "") c.Assert(p.Dir(), qt.Equals, "/a") c.Assert(p.Ext(), qt.Equals, "md") - c.Assert(p.Identifiers(), qt.DeepEquals, []string{"md", "index"}) + c.Assert(p.IdentifiersUnknown(), qt.DeepEquals, []string{"index"}) + c.Assert(p.Identifiers(), qt.DeepEquals, []string{"md"}) c.Assert(p.IsBranchBundle(), qt.IsFalse) c.Assert(p.IsBundle(), qt.IsTrue) c.Assert(p.IsLeafBundle(), qt.IsTrue) @@ -228,7 +232,7 @@ func TestParse(t *testing.T) { c.Assert(p.ContainerDir(), qt.Equals, "/a") c.Assert(p.Dir(), qt.Equals, "/a/b") c.Assert(p.Ext(), qt.Equals, "md") - c.Assert(p.Identifiers(), qt.DeepEquals, []string{"md", "no", "index"}) + c.Assert(p.Identifiers(), qt.DeepEquals, []string{"md", "no"}) c.Assert(p.IsBranchBundle(), qt.IsFalse) c.Assert(p.IsBundle(), qt.IsTrue) c.Assert(p.IsLeafBundle(), qt.IsTrue) @@ -250,7 +254,7 @@ func TestParse(t *testing.T) { c.Assert(p.Container(), qt.Equals, "b") c.Assert(p.ContainerDir(), qt.Equals, "/a") c.Assert(p.Ext(), qt.Equals, "md") - c.Assert(p.Identifiers(), qt.DeepEquals, []string{"md", "no", "_index"}) + c.Assert(p.Identifiers(), qt.DeepEquals, []string{"md", "no"}) c.Assert(p.IsBranchBundle(), qt.IsTrue) c.Assert(p.IsBundle(), qt.IsTrue) c.Assert(p.IsLeafBundle(), qt.IsFalse) @@ -289,7 +293,7 @@ func TestParse(t *testing.T) { func(c *qt.C, p *Path) { c.Assert(p.Base(), qt.Equals, "/a/b/index.txt") c.Assert(p.Ext(), qt.Equals, "txt") - c.Assert(p.Identifiers(), qt.DeepEquals, []string{"txt", "no", "index"}) + c.Assert(p.Identifiers(), qt.DeepEquals, []string{"txt", "no"}) c.Assert(p.IsLeafBundle(), qt.IsFalse) c.Assert(p.PathNoIdentifier(), qt.Equals, "/a/b/index") }, @@ -372,7 +376,7 @@ func TestParse(t *testing.T) { } for _, test := range tests { c.Run(test.name, func(c *qt.C) { - if test.name != "Basic Markdown file" { + if test.name != "Home branch cundle" { // return } test.assert(c, testParser.Parse(files.ComponentFolderContent, test.path)) @@ -401,10 +405,58 @@ func TestParseLayouts(t *testing.T) { "/list.no.html", func(c *qt.C, p *Path) { c.Assert(p.Identifiers(), qt.DeepEquals, []string{"html", "no", "list"}) + c.Assert(p.IdentifiersUnknown(), qt.DeepEquals, []string{}) c.Assert(p.Base(), qt.Equals, "/list.html") c.Assert(p.Lang(), qt.Equals, "no") }, }, + { + "Kind", + "/section.no.html", + func(c *qt.C, p *Path) { + c.Assert(p.Kind(), qt.Equals, kinds.KindSection) + c.Assert(p.Identifiers(), qt.DeepEquals, []string{"html", "no", "section"}) + c.Assert(p.IdentifiersUnknown(), qt.DeepEquals, []string{}) + c.Assert(p.Base(), qt.Equals, "/section.html") + c.Assert(p.Lang(), qt.Equals, "no") + }, + }, + { + "Layout", + "/list.section.no.html", + func(c *qt.C, p *Path) { + c.Assert(p.Layout(), qt.Equals, "list") + c.Assert(p.Identifiers(), qt.DeepEquals, []string{"html", "no", "section", "list"}) + c.Assert(p.IdentifiersUnknown(), qt.DeepEquals, []string{}) + c.Assert(p.Base(), qt.Equals, "/list.html") + c.Assert(p.Lang(), qt.Equals, "no") + }, + }, + { + "Layout multiple", + "/maylayout.list.section.no.html", + func(c *qt.C, p *Path) { + c.Assert(p.Layout(), qt.Equals, "maylayout") + c.Assert(p.Identifiers(), qt.DeepEquals, []string{"html", "no", "section", "list", "maylayout"}) + c.Assert(p.IdentifiersUnknown(), qt.DeepEquals, []string{}) + c.Assert(p.Base(), qt.Equals, "/maylayout.html") + c.Assert(p.Lang(), qt.Equals, "no") + }, + }, + { + "Layout shortcode", + "/_shortcodes/myshort.list.no.html", + func(c *qt.C, p *Path) { + c.Assert(p.Layout(), qt.Equals, "list") + }, + }, + { + "Layout baseof", + "/baseof.list.no.html", + func(c *qt.C, p *Path) { + c.Assert(p.Layout(), qt.Equals, "list") + }, + }, { "Lang and output format", "/list.no.amp.not.html", @@ -429,6 +481,20 @@ func TestParseLayouts(t *testing.T) { c.Assert(p.OutputFormat(), qt.Equals, "html") }, }, + { + "Shortcode with layout", + "/_shortcodes/myshortcode.list.html", + func(c *qt.C, p *Path) { + c.Assert(p.Base(), qt.Equals, "/_shortcodes/myshortcode.html") + c.Assert(p.Type(), qt.Equals, TypeShortcode) + c.Assert(p.Identifiers(), qt.DeepEquals, []string{"html", "list", "myshortcode"}) + c.Assert(p.PathNoIdentifier(), qt.Equals, "/_shortcodes/myshortcode") + c.Assert(p.PathBeforeLangAndOutputFormatAndExt(), qt.Equals, "/_shortcodes/myshortcode.list") + c.Assert(p.Lang(), qt.Equals, "") + c.Assert(p.Kind(), qt.Equals, "") + c.Assert(p.OutputFormat(), qt.Equals, "html") + }, + }, { "Sub dir", "/pages/home.html", @@ -445,7 +511,7 @@ func TestParseLayouts(t *testing.T) { "/pages/baseof.list.section.fr.amp.html", func(c *qt.C, p *Path) { c.Assert(p.Identifiers(), qt.DeepEquals, []string{"html", "amp", "fr", "section", "list", "baseof"}) - c.Assert(p.IdentifiersUnknown(), qt.DeepEquals, []string{"list"}) + c.Assert(p.IdentifiersUnknown(), qt.DeepEquals, []string{}) c.Assert(p.Kind(), qt.Equals, kinds.KindSection) c.Assert(p.Lang(), qt.Equals, "fr") c.Assert(p.OutputFormat(), qt.Equals, "amp") @@ -501,6 +567,9 @@ func TestParseLayouts(t *testing.T) { for _, test := range tests { c.Run(test.name, func(c *qt.C) { + if test.name != "Baseof" { + // return + } test.assert(c, testParser.Parse(files.ComponentFolderLayouts, test.path)) }) } diff --git a/common/paths/paths_integration_test.go b/common/paths/paths_integration_test.go index 62d40f527..f5ea3066a 100644 --- a/common/paths/paths_integration_test.go +++ b/common/paths/paths_integration_test.go @@ -78,3 +78,26 @@ disablePathToLower = true b.AssertFileContent("public/en/mysection/mybundle/index.html", "en|Single") b.AssertFileContent("public/fr/MySection/MyBundle/index.html", "fr|Single") } + +func TestIssue13596(t *testing.T) { + t.Parallel() + + files := ` +-- hugo.toml -- +disableKinds = ['home','rss','section','sitemap','taxonomy','term'] +-- content/p1/index.md -- +--- +title: p1 +--- +-- content/p1/a.1.txt -- +-- content/p1/a.2.txt -- +-- layouts/all.html -- +{{ range .Resources.Match "*" }}{{ .Name }}|{{ end }} +` + + b := hugolib.Test(t, files) + + b.AssertFileContent("public/p1/index.html", "a.1.txt|a.2.txt|") + b.AssertFileExists("public/p1/a.1.txt", true) + b.AssertFileExists("public/p1/a.2.txt", true) // fails +} diff --git a/hugolib/collections_test.go b/hugolib/collections_test.go index a8c817bec..f62d4c604 100644 --- a/hugolib/collections_test.go +++ b/hugolib/collections_test.go @@ -39,6 +39,8 @@ title: "Page" `) b.CreateSites().Build(BuildCfg{}) + // b.H.TemplateStore.PrintDebug("", tplimpl.CategoryLayout, os.Stdout) + c.Assert(len(b.H.Sites), qt.Equals, 1) c.Assert(len(b.H.Sites[0].RegularPages()), qt.Equals, 2) diff --git a/hugolib/content_render_hooks_test.go b/hugolib/content_render_hooks_test.go index 56ae0a052..c4e15a5c6 100644 --- a/hugolib/content_render_hooks_test.go +++ b/hugolib/content_render_hooks_test.go @@ -464,8 +464,6 @@ title: "Home" ` b := Test(t, files) - // b.DebugPrint("", tplimpl.CategoryShortcode) - b.AssertFileContentExact("public/index.xml", "My shortcode XML.") b.AssertFileContentExact("public/index.html", "My shortcode HTML.") s := b.H.Sites[0] diff --git a/hugolib/site_test.go b/hugolib/site_test.go index a9fe977cf..4d68602e5 100644 --- a/hugolib/site_test.go +++ b/hugolib/site_test.go @@ -978,7 +978,7 @@ func TestRefLinking(t *testing.T) { {".", "", true, "/level2/level3/"}, {"./", "", true, "/level2/level3/"}, - {"embedded.dot.md", "", true, "/level2/level3/embedded/"}, + {"embedded.dot.md", "", true, "/level2/level3/embedded.dot/"}, // test empty link, as well as fragment only link {"", "", true, ""}, diff --git a/tpl/tplimpl/templatestore.go b/tpl/tplimpl/templatestore.go index 5be65f874..dba897608 100644 --- a/tpl/tplimpl/templatestore.go +++ b/tpl/tplimpl/templatestore.go @@ -654,7 +654,7 @@ func (s *TemplateStore) PrintDebug(prefix string, category Category, w io.Writer return } s := strings.ReplaceAll(strings.TrimSpace(vv.content), "\n", " ") - ts := fmt.Sprintf("kind: %q layout: %q content: %.30s", vv.D.Kind, vv.D.LayoutFromTemplate, s) + ts := fmt.Sprintf("kind: %q layout: %q lang: %q content: %.30s", vv.D.Kind, vv.D.LayoutFromTemplate, vv.D.Lang, s) fmt.Fprintf(w, "%s%s %s\n", strings.Repeat(" ", level), key, ts) } s.treeMain.WalkPrefix(prefix, func(key string, v map[nodeKey]*TemplInfo) (bool, error) { @@ -1126,7 +1126,7 @@ func (s *TemplateStore) insertTemplate2( if !replace { if v, found := m[nk]; found { - if len(pi.IdentifiersUnknown()) >= len(v.PathInfo.IdentifiersUnknown()) { + if len(pi.Identifiers()) >= len(v.PathInfo.Identifiers()) { // e.g. /pages/home.foo.html and /pages/home.html where foo may be a valid language name in another site. return nil, nil } @@ -1261,7 +1261,10 @@ func (s *TemplateStore) insertTemplates(include func(fi hugofs.FileMetaInfo) boo ) base := piOrig.PathBeforeLangAndOutputFormatAndExt() - identifiers := pi.IdentifiersUnknown() + identifiers := []string{} + if pi.Layout() != "" { + identifiers = append(identifiers, pi.Layout()) + } if pi.Kind() != "" { identifiers = append(identifiers, pi.Kind()) } @@ -1576,24 +1579,12 @@ func (s *TemplateStore) toKeyCategoryAndDescriptor(p *paths.Path) (string, strin outputFormat, mediaType := s.resolveOutputFormatAndOrMediaType(p.OutputFormat(), p.Ext()) nameNoIdentifier := p.NameNoIdentifier() - var layout string - unknownids := p.IdentifiersUnknown() - if p.Type() == paths.TypeShortcode { - if len(unknownids) > 1 { - // The name is the last identifier. - layout = unknownids[len(unknownids)-2] - } - } else if len(unknownids) > 0 { - // Pick the last, closest to the base name. - layout = unknownids[len(unknownids)-1] - } - d := TemplateDescriptor{ Lang: p.Lang(), OutputFormat: p.OutputFormat(), MediaType: mediaType.Type, Kind: p.Kind(), - LayoutFromTemplate: layout, + LayoutFromTemplate: p.Layout(), IsPlainText: outputFormat.IsPlainText, } @@ -1633,6 +1624,7 @@ func (s *TemplateStore) toKeyCategoryAndDescriptor(p *paths.Path) (string, strin if category == CategoryShortcode { k1 = p.PathNoIdentifier() + parts := strings.Split(k1, "/"+containerShortcodes+"/") k1 = parts[0] if len(parts) > 1 { diff --git a/tpl/tplimpl/templatestore_integration_test.go b/tpl/tplimpl/templatestore_integration_test.go index 06cb00212..bd00f82b7 100644 --- a/tpl/tplimpl/templatestore_integration_test.go +++ b/tpl/tplimpl/templatestore_integration_test.go @@ -1056,7 +1056,7 @@ All. b := hugolib.Test(t, files, hugolib.TestOptWarn()) - b.AssertLogContains("Duplicate content path") + b.AssertLogContains("! Duplicate content path") } // Issue #13577.