mirror of
https://github.com/gohugoio/hugo.git
synced 2025-03-22 18:32:16 +00:00
parent
efc0e05c4e
commit
077005e514
3 changed files with 63 additions and 38 deletions
|
@ -38,7 +38,11 @@ type TemplateNames struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type TemplateLookupDescriptor struct {
|
type TemplateLookupDescriptor struct {
|
||||||
// The full path to the site or theme root.
|
// TemplateDir is the project or theme root of the current template.
|
||||||
|
// This will be the same as WorkingDir for non-theme templates.
|
||||||
|
TemplateDir string
|
||||||
|
|
||||||
|
// The full path to the site root.
|
||||||
WorkingDir string
|
WorkingDir string
|
||||||
|
|
||||||
// Main project layout dir, defaults to "layouts"
|
// Main project layout dir, defaults to "layouts"
|
||||||
|
@ -51,8 +55,8 @@ type TemplateLookupDescriptor struct {
|
||||||
// The template name prefix to look for, i.e. "theme".
|
// The template name prefix to look for, i.e. "theme".
|
||||||
Prefix string
|
Prefix string
|
||||||
|
|
||||||
// The theme name if active.
|
// The theme dir if theme active.
|
||||||
Theme string
|
ThemeDir string
|
||||||
|
|
||||||
// All the output formats in play. This is used to decide if text/template or
|
// All the output formats in play. This is used to decide if text/template or
|
||||||
// html/template.
|
// html/template.
|
||||||
|
@ -64,16 +68,29 @@ type TemplateLookupDescriptor struct {
|
||||||
|
|
||||||
func CreateTemplateNames(d TemplateLookupDescriptor) (TemplateNames, error) {
|
func CreateTemplateNames(d TemplateLookupDescriptor) (TemplateNames, error) {
|
||||||
|
|
||||||
var id TemplateNames
|
|
||||||
|
|
||||||
name := filepath.ToSlash(d.RelPath)
|
name := filepath.ToSlash(d.RelPath)
|
||||||
|
|
||||||
if d.Prefix != "" {
|
if d.Prefix != "" {
|
||||||
name = strings.Trim(d.Prefix, "/") + "/" + name
|
name = strings.Trim(d.Prefix, "/") + "/" + name
|
||||||
}
|
}
|
||||||
|
|
||||||
baseLayoutDir := filepath.Join(d.WorkingDir, d.LayoutDir)
|
var (
|
||||||
fullPath := filepath.Join(baseLayoutDir, d.RelPath)
|
id TemplateNames
|
||||||
|
|
||||||
|
// This is the path to the actual template in process. This may
|
||||||
|
// be in the theme's or the project's /layouts.
|
||||||
|
baseLayoutDir = filepath.Join(d.TemplateDir, d.LayoutDir)
|
||||||
|
fullPath = filepath.Join(baseLayoutDir, d.RelPath)
|
||||||
|
|
||||||
|
// This is always the project's layout dir.
|
||||||
|
baseWorkLayoutDir = filepath.Join(d.WorkingDir, d.LayoutDir)
|
||||||
|
|
||||||
|
baseThemeLayoutDir string
|
||||||
|
)
|
||||||
|
|
||||||
|
if d.ThemeDir != "" {
|
||||||
|
baseThemeLayoutDir = filepath.Join(d.ThemeDir, "layouts")
|
||||||
|
}
|
||||||
|
|
||||||
// The filename will have a suffix with an optional type indicator.
|
// The filename will have a suffix with an optional type indicator.
|
||||||
// Examples:
|
// Examples:
|
||||||
|
@ -140,8 +157,8 @@ func CreateTemplateNames(d TemplateLookupDescriptor) (TemplateNames, error) {
|
||||||
currBaseFilename := fmt.Sprintf("%s-%s", filenameNoSuffix, baseFilename)
|
currBaseFilename := fmt.Sprintf("%s-%s", filenameNoSuffix, baseFilename)
|
||||||
|
|
||||||
templateDir := filepath.Dir(fullPath)
|
templateDir := filepath.Dir(fullPath)
|
||||||
themeDir := filepath.Join(d.WorkingDir, d.Theme)
|
|
||||||
|
|
||||||
|
// Find the base, e.g. "_default".
|
||||||
baseTemplatedDir := strings.TrimPrefix(templateDir, baseLayoutDir)
|
baseTemplatedDir := strings.TrimPrefix(templateDir, baseLayoutDir)
|
||||||
baseTemplatedDir = strings.TrimPrefix(baseTemplatedDir, helpers.FilePathSeparator)
|
baseTemplatedDir = strings.TrimPrefix(baseTemplatedDir, helpers.FilePathSeparator)
|
||||||
|
|
||||||
|
@ -162,7 +179,7 @@ func CreateTemplateNames(d TemplateLookupDescriptor) (TemplateNames, error) {
|
||||||
|
|
||||||
Loop:
|
Loop:
|
||||||
for _, pair := range pairsToCheck {
|
for _, pair := range pairsToCheck {
|
||||||
pathsToCheck := basePathsToCheck(pair, baseLayoutDir, themeDir)
|
pathsToCheck := basePathsToCheck(pair, baseLayoutDir, baseWorkLayoutDir, baseThemeLayoutDir)
|
||||||
|
|
||||||
for _, pathToCheck := range pathsToCheck {
|
for _, pathToCheck := range pathsToCheck {
|
||||||
if ok, err := d.FileExists(pathToCheck); err == nil && ok {
|
if ok, err := d.FileExists(pathToCheck); err == nil && ok {
|
||||||
|
@ -177,13 +194,18 @@ func CreateTemplateNames(d TemplateLookupDescriptor) (TemplateNames, error) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func basePathsToCheck(path []string, layoutDir, themeDir string) []string {
|
func basePathsToCheck(path []string, layoutDir, workLayoutDir, themeLayoutDir string) []string {
|
||||||
// Always look in the project.
|
// workLayoutDir will always be the most specific, so start there.
|
||||||
pathsToCheck := []string{filepath.Join((append([]string{layoutDir}, path...))...)}
|
pathsToCheck := []string{filepath.Join((append([]string{workLayoutDir}, path...))...)}
|
||||||
|
|
||||||
|
if layoutDir != "" && layoutDir != workLayoutDir {
|
||||||
|
pathsToCheck = append(pathsToCheck, filepath.Join((append([]string{layoutDir}, path...))...))
|
||||||
|
}
|
||||||
|
|
||||||
// May have a theme
|
// May have a theme
|
||||||
if themeDir != "" {
|
if themeLayoutDir != "" && themeLayoutDir != layoutDir {
|
||||||
pathsToCheck = append(pathsToCheck, filepath.Join((append([]string{themeDir, "layouts"}, path...))...))
|
pathsToCheck = append(pathsToCheck, filepath.Join((append([]string{themeLayoutDir}, path...))...))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pathsToCheck
|
return pathsToCheck
|
||||||
|
|
|
@ -25,6 +25,7 @@ func TestLayoutBase(t *testing.T) {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
workingDir = "/sites/mysite/"
|
workingDir = "/sites/mysite/"
|
||||||
|
themeDir = "/themes/mytheme/"
|
||||||
layoutBase1 = "layouts"
|
layoutBase1 = "layouts"
|
||||||
layoutPath1 = "_default/single.html"
|
layoutPath1 = "_default/single.html"
|
||||||
layoutPathAmp = "_default/single.amp.html"
|
layoutPathAmp = "_default/single.amp.html"
|
||||||
|
@ -38,76 +39,76 @@ func TestLayoutBase(t *testing.T) {
|
||||||
basePathMatchStrings string
|
basePathMatchStrings string
|
||||||
expect TemplateNames
|
expect TemplateNames
|
||||||
}{
|
}{
|
||||||
{"No base", TemplateLookupDescriptor{WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPath1}, false, "",
|
{"No base", TemplateLookupDescriptor{TemplateDir: workingDir, WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPath1}, false, "",
|
||||||
TemplateNames{
|
TemplateNames{
|
||||||
Name: "_default/single.html",
|
Name: "_default/single.html",
|
||||||
OverlayFilename: "/sites/mysite/layouts/_default/single.html",
|
OverlayFilename: "/sites/mysite/layouts/_default/single.html",
|
||||||
}},
|
}},
|
||||||
{"Base", TemplateLookupDescriptor{WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPath1}, true, "",
|
{"Base", TemplateLookupDescriptor{TemplateDir: workingDir, WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPath1}, true, "",
|
||||||
TemplateNames{
|
TemplateNames{
|
||||||
Name: "_default/single.html",
|
Name: "_default/single.html",
|
||||||
OverlayFilename: "/sites/mysite/layouts/_default/single.html",
|
OverlayFilename: "/sites/mysite/layouts/_default/single.html",
|
||||||
MasterFilename: "/sites/mysite/layouts/_default/single-baseof.html",
|
MasterFilename: "/sites/mysite/layouts/_default/single-baseof.html",
|
||||||
}},
|
}},
|
||||||
{"Base in theme", TemplateLookupDescriptor{WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPath1, Theme: "mytheme"}, true,
|
{"Base in theme", TemplateLookupDescriptor{TemplateDir: workingDir, WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPath1, ThemeDir: themeDir}, true,
|
||||||
"mytheme/layouts/_default/baseof.html",
|
"mytheme/layouts/_default/baseof.html",
|
||||||
TemplateNames{
|
TemplateNames{
|
||||||
Name: "_default/single.html",
|
Name: "_default/single.html",
|
||||||
OverlayFilename: "/sites/mysite/layouts/_default/single.html",
|
OverlayFilename: "/sites/mysite/layouts/_default/single.html",
|
||||||
MasterFilename: "/sites/mysite/mytheme/layouts/_default/baseof.html",
|
MasterFilename: "/themes/mytheme/layouts/_default/baseof.html",
|
||||||
}},
|
}},
|
||||||
{"Template in theme, base in theme", TemplateLookupDescriptor{WorkingDir: filepath.Join(workingDir, "mytheme"), LayoutDir: layoutBase1, RelPath: layoutPath1, Theme: "mytheme"}, true,
|
{"Template in theme, base in theme", TemplateLookupDescriptor{TemplateDir: themeDir, WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPath1, ThemeDir: themeDir}, true,
|
||||||
"mytheme/layouts/_default/baseof.html",
|
"mytheme/layouts/_default/baseof.html",
|
||||||
TemplateNames{
|
TemplateNames{
|
||||||
Name: "_default/single.html",
|
Name: "_default/single.html",
|
||||||
OverlayFilename: "/sites/mysite/mytheme/layouts/_default/single.html",
|
OverlayFilename: "/themes/mytheme/layouts/_default/single.html",
|
||||||
MasterFilename: "/sites/mysite/mytheme/layouts/_default/baseof.html",
|
MasterFilename: "/themes/mytheme/layouts/_default/baseof.html",
|
||||||
}},
|
}},
|
||||||
{"Template in theme, base in site", TemplateLookupDescriptor{WorkingDir: filepath.Join(workingDir, "mytheme"), LayoutDir: layoutBase1, RelPath: layoutPath1, Theme: "mytheme"}, true,
|
{"Template in theme, base in site", TemplateLookupDescriptor{TemplateDir: themeDir, WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPath1, ThemeDir: themeDir}, true,
|
||||||
"mytheme/layouts/_default/baseof.html",
|
"/sites/mysite/layouts/_default/baseof.html",
|
||||||
TemplateNames{
|
TemplateNames{
|
||||||
Name: "_default/single.html",
|
Name: "_default/single.html",
|
||||||
OverlayFilename: "/sites/mysite/mytheme/layouts/_default/single.html",
|
OverlayFilename: "/themes/mytheme/layouts/_default/single.html",
|
||||||
MasterFilename: "/sites/mysite/mytheme/layouts/_default/baseof.html",
|
MasterFilename: "/sites/mysite/layouts/_default/baseof.html",
|
||||||
}},
|
}},
|
||||||
{"Template in site, base in theme", TemplateLookupDescriptor{WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPath1, Theme: "mytheme"}, true,
|
{"Template in site, base in theme", TemplateLookupDescriptor{TemplateDir: workingDir, WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPath1, ThemeDir: themeDir}, true,
|
||||||
"/sites/mysite/mytheme/layouts/_default/baseof.html",
|
"/themes/mytheme",
|
||||||
TemplateNames{
|
TemplateNames{
|
||||||
Name: "_default/single.html",
|
Name: "_default/single.html",
|
||||||
OverlayFilename: "/sites/mysite/layouts/_default/single.html",
|
OverlayFilename: "/sites/mysite/layouts/_default/single.html",
|
||||||
MasterFilename: "/sites/mysite/mytheme/layouts/_default/baseof.html",
|
MasterFilename: "/themes/mytheme/layouts/_default/single-baseof.html",
|
||||||
}},
|
}},
|
||||||
{"With prefix, base in theme", TemplateLookupDescriptor{WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPath1,
|
{"With prefix, base in theme", TemplateLookupDescriptor{TemplateDir: workingDir, WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPath1,
|
||||||
Theme: "mytheme", Prefix: "someprefix"}, true,
|
ThemeDir: themeDir, Prefix: "someprefix"}, true,
|
||||||
"mytheme/layouts/_default/baseof.html",
|
"mytheme/layouts/_default/baseof.html",
|
||||||
TemplateNames{
|
TemplateNames{
|
||||||
Name: "someprefix/_default/single.html",
|
Name: "someprefix/_default/single.html",
|
||||||
OverlayFilename: "/sites/mysite/layouts/_default/single.html",
|
OverlayFilename: "/sites/mysite/layouts/_default/single.html",
|
||||||
MasterFilename: "/sites/mysite/mytheme/layouts/_default/baseof.html",
|
MasterFilename: "/themes/mytheme/layouts/_default/baseof.html",
|
||||||
}},
|
}},
|
||||||
{"Partial", TemplateLookupDescriptor{WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: "partials/menu.html"}, true,
|
{"Partial", TemplateLookupDescriptor{TemplateDir: workingDir, WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: "partials/menu.html"}, true,
|
||||||
"mytheme/layouts/_default/baseof.html",
|
"mytheme/layouts/_default/baseof.html",
|
||||||
TemplateNames{
|
TemplateNames{
|
||||||
Name: "partials/menu.html",
|
Name: "partials/menu.html",
|
||||||
OverlayFilename: "/sites/mysite/layouts/partials/menu.html",
|
OverlayFilename: "/sites/mysite/layouts/partials/menu.html",
|
||||||
}},
|
}},
|
||||||
{"AMP, no base", TemplateLookupDescriptor{WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPathAmp}, false, "",
|
{"AMP, no base", TemplateLookupDescriptor{TemplateDir: workingDir, WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPathAmp}, false, "",
|
||||||
TemplateNames{
|
TemplateNames{
|
||||||
Name: "_default/single.amp.html",
|
Name: "_default/single.amp.html",
|
||||||
OverlayFilename: "/sites/mysite/layouts/_default/single.amp.html",
|
OverlayFilename: "/sites/mysite/layouts/_default/single.amp.html",
|
||||||
}},
|
}},
|
||||||
{"JSON, no base", TemplateLookupDescriptor{WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPathJSON}, false, "",
|
{"JSON, no base", TemplateLookupDescriptor{TemplateDir: workingDir, WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPathJSON}, false, "",
|
||||||
TemplateNames{
|
TemplateNames{
|
||||||
Name: "_default/single.json",
|
Name: "_default/single.json",
|
||||||
OverlayFilename: "/sites/mysite/layouts/_default/single.json",
|
OverlayFilename: "/sites/mysite/layouts/_default/single.json",
|
||||||
}},
|
}},
|
||||||
{"AMP with base", TemplateLookupDescriptor{WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPathAmp}, true, "single-baseof.html|single-baseof.amp.html",
|
{"AMP with base", TemplateLookupDescriptor{TemplateDir: workingDir, WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPathAmp}, true, "single-baseof.html|single-baseof.amp.html",
|
||||||
TemplateNames{
|
TemplateNames{
|
||||||
Name: "_default/single.amp.html",
|
Name: "_default/single.amp.html",
|
||||||
OverlayFilename: "/sites/mysite/layouts/_default/single.amp.html",
|
OverlayFilename: "/sites/mysite/layouts/_default/single.amp.html",
|
||||||
MasterFilename: "/sites/mysite/layouts/_default/single-baseof.amp.html",
|
MasterFilename: "/sites/mysite/layouts/_default/single-baseof.amp.html",
|
||||||
}},
|
}},
|
||||||
{"AMP with no match in base", TemplateLookupDescriptor{WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPathAmp}, true, "single-baseof.html",
|
{"AMP with no match in base", TemplateLookupDescriptor{TemplateDir: workingDir, WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPathAmp}, true, "single-baseof.html",
|
||||||
TemplateNames{
|
TemplateNames{
|
||||||
Name: "_default/single.amp.html",
|
Name: "_default/single.amp.html",
|
||||||
OverlayFilename: "/sites/mysite/layouts/_default/single.amp.html",
|
OverlayFilename: "/sites/mysite/layouts/_default/single.amp.html",
|
||||||
|
@ -115,7 +116,7 @@ func TestLayoutBase(t *testing.T) {
|
||||||
MasterFilename: "",
|
MasterFilename: "",
|
||||||
}},
|
}},
|
||||||
|
|
||||||
{"JSON with base", TemplateLookupDescriptor{WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPathJSON}, true, "single-baseof.json",
|
{"JSON with base", TemplateLookupDescriptor{TemplateDir: workingDir, WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPathJSON}, true, "single-baseof.json",
|
||||||
TemplateNames{
|
TemplateNames{
|
||||||
Name: "_default/single.json",
|
Name: "_default/single.json",
|
||||||
OverlayFilename: "/sites/mysite/layouts/_default/single.json",
|
OverlayFilename: "/sites/mysite/layouts/_default/single.json",
|
||||||
|
|
|
@ -420,13 +420,15 @@ func (t *templateHandler) loadTemplates(absPath string, prefix string) {
|
||||||
|
|
||||||
li := strings.LastIndex(path, layoutDir) + len(layoutDir) + 1
|
li := strings.LastIndex(path, layoutDir) + len(layoutDir) + 1
|
||||||
relPath := path[li:]
|
relPath := path[li:]
|
||||||
|
templateDir := path[:li-len(layoutDir)-1]
|
||||||
|
|
||||||
descriptor := output.TemplateLookupDescriptor{
|
descriptor := output.TemplateLookupDescriptor{
|
||||||
|
TemplateDir: templateDir,
|
||||||
WorkingDir: workingDir,
|
WorkingDir: workingDir,
|
||||||
LayoutDir: layoutDir,
|
LayoutDir: layoutDir,
|
||||||
RelPath: relPath,
|
RelPath: relPath,
|
||||||
Prefix: prefix,
|
Prefix: prefix,
|
||||||
Theme: t.PathSpec.Theme(),
|
ThemeDir: themeDir,
|
||||||
OutputFormats: t.OutputFormatsConfig,
|
OutputFormats: t.OutputFormatsConfig,
|
||||||
FileExists: func(filename string) (bool, error) {
|
FileExists: func(filename string) (bool, error) {
|
||||||
return helpers.Exists(filename, t.Fs.Source)
|
return helpers.Exists(filename, t.Fs.Source)
|
||||||
|
|
Loading…
Reference in a new issue