output: Fix base theme vs project base template logic - hugo - [fork] hugo port for 9front
 (HTM) git clone git@git.drkhsh.at/hugo.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 077005e514b1ed50d84ceb90c7c72f184cb04521
 (DIR) parent efc0e05c4ef974414b010b3fba5e40dab0d43876
 (HTM) Author: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
       Date:   Wed, 12 Apr 2017 20:40:36 +0200
       
       output: Fix base theme vs project base template logic
       
       Fixes #3323
       
       Diffstat:
         M output/layout_base.go               |      50 ++++++++++++++++++++++---------
         M output/layout_base_test.go          |      47 ++++++++++++++++---------------
         M tpl/tplimpl/template.go             |       4 +++-
       
       3 files changed, 63 insertions(+), 38 deletions(-)
       ---
 (DIR) diff --git a/output/layout_base.go b/output/layout_base.go
       @@ -38,7 +38,11 @@ type TemplateNames 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
        
                // Main project layout dir, defaults to "layouts"
       @@ -51,8 +55,8 @@ type TemplateLookupDescriptor struct {
                // The template name prefix to look for, i.e. "theme".
                Prefix string
        
       -        // The theme name if active.
       -        Theme string
       +        // The theme dir if theme active.
       +        ThemeDir string
        
                // All the output formats in play. This is used to decide if text/template or
                // html/template.
       @@ -64,16 +68,29 @@ type TemplateLookupDescriptor struct {
        
        func CreateTemplateNames(d TemplateLookupDescriptor) (TemplateNames, error) {
        
       -        var id TemplateNames
       -
                name := filepath.ToSlash(d.RelPath)
        
                if d.Prefix != "" {
                        name = strings.Trim(d.Prefix, "/") + "/" + name
                }
        
       -        baseLayoutDir := filepath.Join(d.WorkingDir, d.LayoutDir)
       -        fullPath := filepath.Join(baseLayoutDir, d.RelPath)
       +        var (
       +                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.
                // Examples:
       @@ -140,8 +157,8 @@ func CreateTemplateNames(d TemplateLookupDescriptor) (TemplateNames, error) {
                        currBaseFilename := fmt.Sprintf("%s-%s", filenameNoSuffix, baseFilename)
        
                        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(baseTemplatedDir, helpers.FilePathSeparator)
        
       @@ -162,7 +179,7 @@ func CreateTemplateNames(d TemplateLookupDescriptor) (TemplateNames, error) {
        
                Loop:
                        for _, pair := range pairsToCheck {
       -                        pathsToCheck := basePathsToCheck(pair, baseLayoutDir, themeDir)
       +                        pathsToCheck := basePathsToCheck(pair, baseLayoutDir, baseWorkLayoutDir, baseThemeLayoutDir)
        
                                for _, pathToCheck := range pathsToCheck {
                                        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 {
       -        // Always look in the project.
       -        pathsToCheck := []string{filepath.Join((append([]string{layoutDir}, path...))...)}
       +func basePathsToCheck(path []string, layoutDir, workLayoutDir, themeLayoutDir string) []string {
       +        // workLayoutDir will always be the most specific, so start there.
       +        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
       -        if themeDir != "" {
       -                pathsToCheck = append(pathsToCheck, filepath.Join((append([]string{themeDir, "layouts"}, path...))...))
       +        if themeLayoutDir != "" && themeLayoutDir != layoutDir {
       +                pathsToCheck = append(pathsToCheck, filepath.Join((append([]string{themeLayoutDir}, path...))...))
       +
                }
        
                return pathsToCheck
 (DIR) diff --git a/output/layout_base_test.go b/output/layout_base_test.go
       @@ -25,6 +25,7 @@ func TestLayoutBase(t *testing.T) {
        
                var (
                        workingDir     = "/sites/mysite/"
       +                themeDir       = "/themes/mytheme/"
                        layoutBase1    = "layouts"
                        layoutPath1    = "_default/single.html"
                        layoutPathAmp  = "_default/single.amp.html"
       @@ -38,76 +39,76 @@ func TestLayoutBase(t *testing.T) {
                        basePathMatchStrings string
                        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{
                                        Name:            "_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{
                                        Name:            "_default/single.html",
                                        OverlayFilename: "/sites/mysite/layouts/_default/single.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",
                                TemplateNames{
                                        Name:            "_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",
                                TemplateNames{
                                        Name:            "_default/single.html",
       -                                OverlayFilename: "/sites/mysite/mytheme/layouts/_default/single.html",
       -                                MasterFilename:  "/sites/mysite/mytheme/layouts/_default/baseof.html",
       +                                OverlayFilename: "/themes/mytheme/layouts/_default/single.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,
       -                        "mytheme/layouts/_default/baseof.html",
       +                {"Template in theme, base in site", TemplateLookupDescriptor{TemplateDir: themeDir, WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPath1, ThemeDir: themeDir}, true,
       +                        "/sites/mysite/layouts/_default/baseof.html",
                                TemplateNames{
                                        Name:            "_default/single.html",
       -                                OverlayFilename: "/sites/mysite/mytheme/layouts/_default/single.html",
       -                                MasterFilename:  "/sites/mysite/mytheme/layouts/_default/baseof.html",
       +                                OverlayFilename: "/themes/mytheme/layouts/_default/single.html",
       +                                MasterFilename:  "/sites/mysite/layouts/_default/baseof.html",
                                }},
       -                {"Template in site, base in theme", TemplateLookupDescriptor{WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPath1, Theme: "mytheme"}, true,
       -                        "/sites/mysite/mytheme/layouts/_default/baseof.html",
       +                {"Template in site, base in theme", TemplateLookupDescriptor{TemplateDir: workingDir, WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPath1, ThemeDir: themeDir}, true,
       +                        "/themes/mytheme",
                                TemplateNames{
                                        Name:            "_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,
       -                        Theme: "mytheme", Prefix: "someprefix"}, true,
       +                {"With prefix, base in theme", TemplateLookupDescriptor{TemplateDir: workingDir, WorkingDir: workingDir, LayoutDir: layoutBase1, RelPath: layoutPath1,
       +                        ThemeDir: themeDir, Prefix: "someprefix"}, true,
                                "mytheme/layouts/_default/baseof.html",
                                TemplateNames{
                                        Name:            "someprefix/_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",
                                TemplateNames{
                                        Name:            "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{
                                        Name:            "_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{
                                        Name:            "_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{
                                        Name:            "_default/single.amp.html",
                                        OverlayFilename: "/sites/mysite/layouts/_default/single.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{
                                        Name:            "_default/single.amp.html",
                                        OverlayFilename: "/sites/mysite/layouts/_default/single.amp.html",
       @@ -115,7 +116,7 @@ func TestLayoutBase(t *testing.T) {
                                        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{
                                        Name:            "_default/single.json",
                                        OverlayFilename: "/sites/mysite/layouts/_default/single.json",
 (DIR) diff --git a/tpl/tplimpl/template.go b/tpl/tplimpl/template.go
       @@ -420,13 +420,15 @@ func (t *templateHandler) loadTemplates(absPath string, prefix string) {
        
                                li := strings.LastIndex(path, layoutDir) + len(layoutDir) + 1
                                relPath := path[li:]
       +                        templateDir := path[:li-len(layoutDir)-1]
        
                                descriptor := output.TemplateLookupDescriptor{
       +                                TemplateDir:   templateDir,
                                        WorkingDir:    workingDir,
                                        LayoutDir:     layoutDir,
                                        RelPath:       relPath,
                                        Prefix:        prefix,
       -                                Theme:         t.PathSpec.Theme(),
       +                                ThemeDir:      themeDir,
                                        OutputFormats: t.OutputFormatsConfig,
                                        FileExists: func(filename string) (bool, error) {
                                                return helpers.Exists(filename, t.Fs.Source)