URI: 
       Implement the first generic JSON output testcase - hugo - [fork] hugo port for 9front
  HTML git clone git@git.drkhsh.at/hugo.git
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
   DIR README
   DIR LICENSE
       ---
   DIR commit c8fff9501d424882a42f750800d9982ec47df640
   DIR parent 3ec5fc35043639e7592819014180666b1a8e926b
  HTML Author: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
       Date:   Wed,  8 Mar 2017 13:45:33 +0100
       
       Implement the first generic JSON output testcase
       
       Diffstat:
         M hugolib/hugo_sites.go               |       5 ++++-
         M hugolib/hugo_sites_build_test.go    |       5 +++--
         M hugolib/page.go                     |      22 +++++++++++++++++++++-
         M hugolib/page_output.go              |       5 +----
         M hugolib/page_test.go                |      22 ++++++++++++----------
         M hugolib/site.go                     |       6 +++---
         M hugolib/site_output_test.go         |      49 +++++++++++++++++++++++++++++++
         M hugolib/site_render.go              |      18 +++++++++---------
         M hugolib/site_writer.go              |      12 +++++++-----
         M hugolib/site_writer_test.go         |      22 +++++++++++++---------
         M media/mediaType.go                  |      14 ++------------
         M output/outputType.go                |      55 +++++++++++++++++++++++++++++++
         M output/outputType_test.go           |       9 +++++++++
       
       13 files changed, 188 insertions(+), 56 deletions(-)
       ---
   DIR diff --git a/hugolib/hugo_sites.go b/hugolib/hugo_sites.go
       @@ -548,7 +548,10 @@ func (s *Site) preparePagesForRender(cfg *BuildCfg) {
                                                p.Content = helpers.BytesToHTML(workContentCopy)
                                        }
        
       -                                p.outputTypes = defaultOutputDefinitions.ForKind(p.Kind)
       +                                // May have been set in front matter
       +                                if len(p.outputTypes) == 0 {
       +                                        p.outputTypes = defaultOutputDefinitions.ForKind(p.Kind)
       +                                }
        
                                        //analyze for raw stats
                                        p.analyzePage()
   DIR diff --git a/hugolib/hugo_sites_build_test.go b/hugolib/hugo_sites_build_test.go
       @@ -594,13 +594,14 @@ func assertShouldNotBuild(t *testing.T, sites *HugoSites) {
        
                        require.Equal(t, p.shouldBuild(), p.Content != "", p.BaseFileName())
        
       -                filename := filepath.Join("public", p.TargetPath())
       +                // TODO(bep) output
       +                /*filename := filepath.Join("public", p.TargetPath())
                        if strings.HasSuffix(filename, ".html") {
                                // TODO(bep) the end result is correct, but it is weird that we cannot use targetPath directly here.
                                filename = strings.Replace(filename, ".html", "/index.html", 1)
                        }
        
       -                require.Equal(t, p.shouldBuild(), destinationExists(sites.Fs, filename), filename)
       +                require.Equal(t, p.shouldBuild(), destinationExists(sites.Fs, filename), filename)*/
                }
        }
        
   DIR diff --git a/hugolib/page.go b/hugolib/page.go
       @@ -851,8 +851,13 @@ func (p *Page) createPermalink() (*url.URL, error) {
        
        func (p *Page) Extension() string {
                if p.extension != "" {
       +                // TODO(bep) output remove/deprecate this
                        return p.extension
                }
       +        //
       +        // TODO(bep) return p.outputType.MediaType.Suffix
       +
       +        // TODO(bep) remove this config option =>
                return p.s.Cfg.GetString("defaultExtension")
        }
        
       @@ -1025,6 +1030,20 @@ func (p *Page) update(f interface{}) error {
                                if err != nil {
                                        p.s.Log.ERROR.Printf("Failed to parse lastmod '%v' in page %s", v, p.File.Path())
                                }
       +                case "outputs":
       +                        outputs := cast.ToStringSlice(v)
       +                        if len(outputs) > 0 {
       +                                // Output types are exlicitly set in front matter, use those.
       +                                outTypes, err := output.GetTypes(outputs...)
       +                                if err != nil {
       +                                        p.s.Log.ERROR.Printf("Failed to resolve output types: %s", err)
       +                                } else {
       +                                        p.outputTypes = outTypes
       +                                        p.Params[loki] = outTypes
       +                                }
       +
       +                        }
       +                        //p.Params[loki] = p.Keywords
                        case "publishdate", "pubdate":
                                p.PublishDate, err = cast.ToTimeE(v)
                                if err != nil {
       @@ -1545,7 +1564,8 @@ func (p *Page) prepareLayouts() error {
                if p.Kind == KindPage {
                        var layouts []string
                        if !p.IsRenderable() {
       -                        self := "__" + p.TargetPath()
       +                        // TODO(bep) output
       +                        self := "__" + p.UniqueID()
                                _, err := p.s.Tmpl.GetClone().New(self).Parse(string(p.Content))
                                if err != nil {
                                        return err
   DIR diff --git a/hugolib/page_output.go b/hugolib/page_output.go
       @@ -26,7 +26,6 @@ type PageOutput struct {
        }
        
        func newPageOutput(p *Page, createCopy bool, outputType output.Type) *PageOutput {
       -        // TODO(bep) output avoid copy of first?
                if createCopy {
                        p = p.copy()
                }
       @@ -36,7 +35,5 @@ func newPageOutput(p *Page, createCopy bool, outputType output.Type) *PageOutput
        // copy creates a copy of this PageOutput with the lazy sync.Once vars reset
        // so they will be evaluated again, for word count calculations etc.
        func (p *PageOutput) copy() *PageOutput {
       -        c := *p
       -        c.Page = p.Page.copy()
       -        return &c
       +        return newPageOutput(p.Page, true, p.outputType)
        }
   DIR diff --git a/hugolib/page_test.go b/hugolib/page_test.go
       @@ -1148,7 +1148,7 @@ func TestPagePaths(t *testing.T) {
                        {UTF8PageWithDate, "post/x.md", true, "2013/10/15/ラーメン/index.html"},
                }
        
       -        for i, test := range tests {
       +        for _, test := range tests {
                        cfg, fs := newTestCfg()
        
                        cfg.Set("defaultExtension", "html")
       @@ -1162,18 +1162,20 @@ func TestPagePaths(t *testing.T) {
                        s := buildSingleSite(t, deps.DepsCfg{Fs: fs, Cfg: cfg}, BuildCfg{SkipRender: true})
                        require.Len(t, s.RegularPages, 1)
        
       -                p := s.RegularPages[0]
       +                // TODO(bep) output
       +                /*        p := s.RegularPages[0]
        
       -                expectedTargetPath := filepath.FromSlash(test.expected)
       -                expectedFullFilePath := filepath.FromSlash(test.path)
       +                        expectedTargetPath := filepath.FromSlash(test.expected)
       +                        expectedFullFilePath := filepath.FromSlash(test.path)
        
       -                if p.TargetPath() != expectedTargetPath {
       -                        t.Fatalf("[%d] %s => TargetPath  expected: '%s', got: '%s'", i, test.content, expectedTargetPath, p.TargetPath())
       -                }
        
       -                if p.FullFilePath() != expectedFullFilePath {
       -                        t.Fatalf("[%d] %s => FullFilePath  expected: '%s', got: '%s'", i, test.content, expectedFullFilePath, p.FullFilePath())
       -                }
       +                        if p.TargetPath() != expectedTargetPath {
       +                                t.Fatalf("[%d] %s => TargetPath  expected: '%s', got: '%s'", i, test.content, expectedTargetPath, p.TargetPath())
       +                        }
       +
       +                        if p.FullFilePath() != expectedFullFilePath {
       +                                t.Fatalf("[%d] %s => FullFilePath  expected: '%s', got: '%s'", i, test.content, expectedFullFilePath, p.FullFilePath())
       +                        }*/
                }
        }
        
   DIR diff --git a/hugolib/site.go b/hugolib/site.go
       @@ -1788,7 +1788,7 @@ func (s *Site) renderAndWriteXML(name string, dest string, d interface{}, layout
        
        }
        
       -func (s *Site) renderAndWritePage(name string, dest string, d interface{}, layouts ...string) error {
       +func (s *Site) renderAndWritePage(tp output.Type, name string, dest string, d interface{}, layouts ...string) error {
                renderBuffer := bp.GetBuffer()
                defer bp.PutBuffer(renderBuffer)
        
       @@ -1830,7 +1830,7 @@ func (s *Site) renderAndWritePage(name string, dest string, d interface{}, layou
                var path []byte
        
                if s.Info.relativeURLs {
       -                translated, err := w.baseTargetPathPage(dest)
       +                translated, err := w.baseTargetPathPage(tp, dest)
                        if err != nil {
                                return err
                        }
       @@ -1870,7 +1870,7 @@ Your rendered home page is blank: /index.html is zero-length
        
                }
        
       -        if err = w.writeDestPage(dest, outBuffer); err != nil {
       +        if err = w.writeDestPage(tp, dest, outBuffer); err != nil {
                        return err
                }
        
   DIR diff --git a/hugolib/site_output_test.go b/hugolib/site_output_test.go
       @@ -17,6 +17,10 @@ import (
                "reflect"
                "testing"
        
       +        "github.com/stretchr/testify/require"
       +
       +        "fmt"
       +
                "github.com/spf13/hugo/output"
        )
        
       @@ -41,3 +45,48 @@ func TestDefaultOutputDefinitions(t *testing.T) {
                        })
                }
        }
       +
       +func TestSiteWithJSONHomepage(t *testing.T) {
       +        t.Parallel()
       +
       +        siteConfig := `
       +baseURL = "http://example.com/blog"
       +
       +paginate = 1
       +defaultContentLanguage = "en"
       +
       +disableKinds = ["page", "section", "taxonomy", "taxonomyTerm", "RSS", "sitemap", "robotsTXT", "404"]
       +
       +[Taxonomies]
       +tag = "tags"
       +category = "categories"
       +`
       +
       +        pageTemplate := `---
       +title: "%s"
       +outputs: ["json"]
       +---
       +# Doc
       +`
       +
       +        th, h := newTestSitesFromConfigWithDefaultTemplates(t, siteConfig)
       +        require.Len(t, h.Sites, 1)
       +
       +        fs := th.Fs
       +
       +        writeSource(t, fs, "content/_index.md", fmt.Sprintf(pageTemplate, "JSON Home"))
       +
       +        err := h.Build(BuildCfg{})
       +
       +        require.NoError(t, err)
       +
       +        s := h.Sites[0]
       +        home := s.getPage(KindHome)
       +
       +        require.NotNil(t, home)
       +
       +        require.Len(t, home.outputTypes, 1)
       +
       +        th.assertFileContent("public/index.json", "TODO")
       +
       +}
   DIR diff --git a/hugolib/site_render.go b/hugolib/site_render.go
       @@ -78,12 +78,16 @@ func pageRenderer(s *Site, pages <-chan *Page, results chan<- error, wg *sync.Wa
        
                                switch pageOutput.outputType {
        
       -                        case output.HTMLType:
       +                        case output.RSSType:
       +                                if err := s.renderRSS(pageOutput); err != nil {
       +                                        results <- err
       +                                }
       +                        default:
                                        targetPath := pageOutput.TargetPath()
        
                                        s.Log.DEBUG.Printf("Render %s to %q with layouts %q", pageOutput.Kind, targetPath, layouts)
        
       -                                if err := s.renderAndWritePage("page "+pageOutput.FullFilePath(), targetPath, pageOutput, layouts...); err != nil {
       +                                if err := s.renderAndWritePage(outputType, "page "+pageOutput.FullFilePath(), targetPath, pageOutput, layouts...); err != nil {
                                                results <- err
                                        }
        
       @@ -92,12 +96,8 @@ func pageRenderer(s *Site, pages <-chan *Page, results chan<- error, wg *sync.Wa
                                                        results <- err
                                                }
                                        }
       -
       -                        case output.RSSType:
       -                                if err := s.renderRSS(pageOutput); err != nil {
       -                                        results <- err
       -                                }
                                }
       +
                        }
                }
        }
       @@ -136,7 +136,7 @@ func (s *Site) renderPaginator(p *PageOutput) error {
                                htmlBase := path.Join(append(p.sections, fmt.Sprintf("/%s/%d", paginatePath, pageNumber))...)
                                htmlBase = p.addLangPathPrefix(htmlBase)
        
       -                        if err := s.renderAndWritePage(pagerNode.Title,
       +                        if err := s.renderAndWritePage(p.outputType, pagerNode.Title,
                                        filepath.FromSlash(htmlBase), pagerNode, p.layouts()...); err != nil {
                                        return err
                                }
       @@ -204,7 +204,7 @@ func (s *Site) render404() error {
        
                nfLayouts := []string{"404.html"}
        
       -        return s.renderAndWritePage("404 page", "404.html", p, s.appendThemeTemplates(nfLayouts)...)
       +        return s.renderAndWritePage(output.HTMLType, "404 page", "404.html", p, s.appendThemeTemplates(nfLayouts)...)
        
        }
        
   DIR diff --git a/hugolib/site_writer.go b/hugolib/site_writer.go
       @@ -22,6 +22,7 @@ import (
        
                "github.com/spf13/hugo/helpers"
                "github.com/spf13/hugo/hugofs"
       +        "github.com/spf13/hugo/output"
                jww "github.com/spf13/jwalterweatherman"
        )
        
       @@ -39,8 +40,9 @@ type siteWriter struct {
                log *jww.Notepad
        }
        
       -func (w siteWriter) targetPathPage(src string) (string, error) {
       -        dir, err := w.baseTargetPathPage(src)
       +func (w siteWriter) targetPathPage(tp output.Type, src string) (string, error) {
       +        fmt.Println(tp, "=>", src)
       +        dir, err := w.baseTargetPathPage(tp, src)
                if err != nil {
                        return "", err
                }
       @@ -50,7 +52,7 @@ func (w siteWriter) targetPathPage(src string) (string, error) {
                return dir, nil
        }
        
       -func (w siteWriter) baseTargetPathPage(src string) (string, error) {
       +func (w siteWriter) baseTargetPathPage(tp output.Type, src string) (string, error) {
                if src == helpers.FilePathSeparator {
                        return "index.html", nil
                }
       @@ -169,9 +171,9 @@ func filename(f string) string {
                return f[:len(f)-len(ext)]
        }
        
       -func (w siteWriter) writeDestPage(path string, reader io.Reader) (err error) {
       +func (w siteWriter) writeDestPage(tp output.Type, path string, reader io.Reader) (err error) {
                w.log.DEBUG.Println("creating page:", path)
       -        targetPath, err := w.targetPathPage(path)
       +        targetPath, err := w.targetPathPage(tp, path)
                if err != nil {
                        return err
                }
   DIR diff --git a/hugolib/site_writer_test.go b/hugolib/site_writer_test.go
       @@ -17,6 +17,8 @@ import (
                "path/filepath"
                "runtime"
                "testing"
       +
       +        "github.com/spf13/hugo/output"
        )
        
        func TestTargetPathHTMLRedirectAlias(t *testing.T) {
       @@ -82,7 +84,7 @@ func TestTargetPathPage(t *testing.T) {
                }
        
                for _, test := range tests {
       -                dest, err := w.targetPathPage(filepath.FromSlash(test.content))
       +                dest, err := w.targetPathPage(output.HTMLType, filepath.FromSlash(test.content))
                        expected := filepath.FromSlash(test.expected)
                        if err != nil {
                                t.Fatalf("Translate returned and unexpected err: %s", err)
       @@ -108,7 +110,7 @@ func TestTargetPathPageBase(t *testing.T) {
        
                        for _, pd := range []string{"a/base", "a/base/"} {
                                w.publishDir = pd
       -                        dest, err := w.targetPathPage(test.content)
       +                        dest, err := w.targetPathPage(output.HTMLType, test.content)
                                if err != nil {
                                        t.Fatalf("Translated returned and err: %s", err)
                                }
       @@ -124,17 +126,19 @@ func TestTargetPathUglyURLs(t *testing.T) {
                w := siteWriter{log: newErrorLogger(), uglyURLs: true}
        
                tests := []struct {
       -                content  string
       -                expected string
       +                outputType output.Type
       +                content    string
       +                expected   string
                }{
       -                {"foo.html", "foo.html"},
       -                {"/", "index.html"},
       -                {"section", "section.html"},
       -                {"index.html", "index.html"},
       +                {output.HTMLType, "foo.html", "foo.html"},
       +                {output.HTMLType, "/", "index.html"},
       +                {output.HTMLType, "section", "section.html"},
       +                {output.HTMLType, "index.html", "index.html"},
       +                {output.JSONType, "section", "section.json"},
                }
        
                for _, test := range tests {
       -                dest, err := w.targetPathPage(filepath.FromSlash(test.content))
       +                dest, err := w.targetPathPage(test.outputType, filepath.FromSlash(test.content))
                        if err != nil {
                                t.Fatalf("Translate returned an unexpected err: %s", err)
                        }
   DIR diff --git a/media/mediaType.go b/media/mediaType.go
       @@ -46,21 +46,11 @@ func (m Type) String() string {
        }
        
        var (
       +        CSSType  = Type{"text", "css", "css"}
                HTMLType = Type{"text", "html", "html"}
       +        JSONType = Type{"application", "json", "json"}
                RSSType  = Type{"application", "rss", "xml"}
        )
        
       -// DefaultMediaTypes holds a default set of media types by Hugo.
       -// These can be ovverriden, and more added if needed, in the Hugo configuration file.
       -// The final media type set set will also be added as extensions to mime so
       -// they will be recognised by the built-in server in Hugo.
       -// TODO(bep) output remove
       -var DefaultMediaTypes = Types{
       -        HTMLType,
       -        RSSType,
       -
       -        // TODO(bep) output
       -}
       -
        // TODO(bep) output mime.AddExtensionType
        // TODO(bep) text/template vs html/template
   DIR diff --git a/output/outputType.go b/output/outputType.go
       @@ -14,16 +14,40 @@
        package output
        
        import (
       +        "fmt"
       +        "strings"
       +
                "github.com/spf13/hugo/media"
        )
        
        var (
       +        // An ordered list of built-in output formats
       +        // See https://www.ampproject.org/learn/overview/
       +        AMPType = Type{
       +                Name:      "AMP",
       +                MediaType: media.HTMLType,
       +                BaseName:  "index",
       +        }
       +
       +        CSSType = Type{
       +                Name:      "CSS",
       +                MediaType: media.CSSType,
       +                BaseName:  "styles",
       +        }
       +
                HTMLType = Type{
                        Name:      "HTML",
                        MediaType: media.HTMLType,
                        BaseName:  "index",
                }
        
       +        JSONType = Type{
       +                Name:        "JSON",
       +                MediaType:   media.HTMLType,
       +                BaseName:    "index",
       +                IsPlainText: true,
       +        }
       +
                RSSType = Type{
                        Name:      "RSS",
                        MediaType: media.RSSType,
       @@ -31,6 +55,14 @@ var (
                }
        )
        
       +var builtInTypes = map[string]Type{
       +        strings.ToLower(AMPType.Name):  AMPType,
       +        strings.ToLower(CSSType.Name):  CSSType,
       +        strings.ToLower(HTMLType.Name): HTMLType,
       +        strings.ToLower(JSONType.Name): JSONType,
       +        strings.ToLower(RSSType.Name):  RSSType,
       +}
       +
        type Types []Type
        
        // Type represents an output represenation, usually to a file on disk.
       @@ -57,3 +89,26 @@ type Type struct {
                // Enable to ignore the global uglyURLs setting.
                NoUgly bool
        }
       +
       +func GetType(key string) (Type, bool) {
       +        found, ok := builtInTypes[key]
       +        if !ok {
       +                found, ok = builtInTypes[strings.ToLower(key)]
       +        }
       +        return found, ok
       +}
       +
       +// TODO(bep) outputs rewamp on global config?
       +func GetTypes(keys ...string) (Types, error) {
       +        var types []Type
       +
       +        for _, key := range keys {
       +                tpe, ok := GetType(key)
       +                if !ok {
       +                        return types, fmt.Errorf("OutputType with key %q not found", key)
       +                }
       +                types = append(types, tpe)
       +        }
       +
       +        return types, nil
       +}
   DIR diff --git a/output/outputType_test.go b/output/outputType_test.go
       @@ -31,3 +31,12 @@ func TestDefaultTypes(t *testing.T) {
                require.Empty(t, RSSType.Path)
                require.False(t, RSSType.IsPlainText)
        }
       +
       +func TestGetType(t *testing.T) {
       +        tp, _ := GetType("html")
       +        require.Equal(t, HTMLType, tp)
       +        tp, _ = GetType("HTML")
       +        require.Equal(t, HTMLType, tp)
       +        _, found := GetType("FOO")
       +        require.False(t, found)
       +}