URI: 
       create: Use archetype template as-is as a Go template - 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 422057f60709696bbbd1c38c9ead2bf114d47e31
   DIR parent 4aa1239070bb9d4324d3582f3e809b702a59d3ac
  HTML Author: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
       Date:   Sun, 18 Jun 2017 19:06:28 +0200
       
       create: Use archetype template as-is as a Go template
       
       This commit removes the fragile front matter decoding, and takes the provided archetype file as-is and processes it as a template.
       
       This also means that we no longer will attempt to fill in default values for `title` and `date`.
       
       The upside is that it is now easy to create these values in a dynamic way:
       
       ```toml
       +++
       title = {{ .BaseFileName | title }}
       date = {{ .Date }}
       draft = true
       +++
       ```
       
       You can currently use all of Hugo's template funcs, but the data context is currently very shallow:
       
       * `.Type` gives the archetype kind provided
       * `.Name` gives the target file name without extension.
       * `.Path` gives the target file name
       * `.Date` gives the current time as RFC3339 formatted string
       
       The above  will probably be extended in #1629.
       
       Fixes #452
       Updates #1629
       
       Diffstat:
         M commands/new.go                     |       5 -----
         M create/content.go                   |     101 ++++---------------------------
         A create/content_template_handler.go  |      94 +++++++++++++++++++++++++++++++
         M create/content_test.go              |      12 +++++++-----
         M parser/frontmatter.go               |       2 ++
       
       5 files changed, 115 insertions(+), 99 deletions(-)
       ---
   DIR diff --git a/commands/new.go b/commands/new.go
       @@ -42,7 +42,6 @@ var (
        func init() {
                newSiteCmd.Flags().StringVarP(&configFormat, "format", "f", "toml", "config & frontmatter format")
                newSiteCmd.Flags().Bool("force", false, "init inside non-empty directory")
       -        newCmd.Flags().StringVarP(&configFormat, "format", "f", "toml", "frontmatter format")
                newCmd.Flags().StringVarP(&contentType, "kind", "k", "", "content type to create")
                newCmd.PersistentFlags().StringVarP(&source, "source", "s", "", "filesystem path to read files relative from")
                newCmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
       @@ -98,10 +97,6 @@ func NewContent(cmd *cobra.Command, args []string) error {
                        return err
                }
        
       -        if cmd.Flags().Changed("format") {
       -                c.Set("metaDataFormat", configFormat)
       -        }
       -
                if cmd.Flags().Changed("editor") {
                        c.Set("newContentEditor", contentEditor)
                }
   DIR diff --git a/create/content.go b/create/content.go
       @@ -19,68 +19,40 @@ import (
                "os"
                "os/exec"
                "path/filepath"
       -        "strings"
       -        "time"
        
                "github.com/gohugoio/hugo/helpers"
                "github.com/gohugoio/hugo/hugolib"
       -        "github.com/gohugoio/hugo/parser"
       -        "github.com/spf13/afero"
       -        "github.com/spf13/cast"
                jww "github.com/spf13/jwalterweatherman"
        )
        
        // NewContent creates a new content file in the content directory based upon the
        // given kind, which is used to lookup an archetype.
       -func NewContent(s *hugolib.Site, kind, name string) (err error) {
       -        jww.INFO.Println("attempting to create ", name, "of", kind)
       +func NewContent(s *hugolib.Site, kind, targetPath string) error {
       +        jww.INFO.Println("attempting to create ", targetPath, "of", kind)
        
       -        location := FindArchetype(s, kind)
       +        archetypeFilename := findArchetype(s, kind)
        
       -        var by []byte
       +        var (
       +                content []byte
       +                err     error
       +        )
        
       -        if location != "" {
       -                by, err = afero.ReadFile(s.Fs.Source, location)
       -                if err != nil {
       -                        jww.ERROR.Println(err)
       -                }
       -        }
       -        if location == "" || err != nil {
       -                by = []byte("+++\ndraft = true \n+++\n")
       -        }
       -
       -        psr, err := parser.ReadFrom(bytes.NewReader(by))
       +        content, err = executeArcheTypeAsTemplate(s, kind, targetPath, archetypeFilename)
                if err != nil {
                        return err
                }
        
       -        metadata, err := createMetadata(psr, name)
       -        if err != nil {
       -                jww.ERROR.Printf("Error processing archetype file %s: %s\n", location, err)
       -                return err
       -        }
       +        contentPath := s.PathSpec.AbsPathify(filepath.Join(s.Cfg.GetString("contentDir"), targetPath))
        
       -        page, err := s.NewPage(name)
       -        if err != nil {
       +        if err := helpers.SafeWriteToDisk(contentPath, bytes.NewReader(content), s.Fs.Source); err != nil {
                        return err
                }
        
       -        if err = page.SetSourceMetaData(metadata, parser.FormatToLeadRune(s.Cfg.GetString("metaDataFormat"))); err != nil {
       -                return
       -        }
       -
       -        page.SetSourceContent(psr.Content())
       -
       -        contentPath := s.PathSpec.AbsPathify(filepath.Join(s.Cfg.GetString("contentDir"), name))
       -
       -        if err = page.SafeSaveSourceAs(contentPath); err != nil {
       -                return
       -        }
                jww.FEEDBACK.Println(contentPath, "created")
        
                editor := s.Cfg.GetString("newContentEditor")
                if editor != "" {
       -                jww.FEEDBACK.Printf("Editing %s with %q ...\n", name, editor)
       +                jww.FEEDBACK.Printf("Editing %s with %q ...\n", targetPath, editor)
        
                        cmd := exec.Command(editor, contentPath)
                        cmd.Stdin = os.Stdin
       @@ -93,59 +65,10 @@ func NewContent(s *hugolib.Site, kind, name string) (err error) {
                return nil
        }
        
       -// createMetadata generates Metadata for a new page based upon the metadata
       -// found in an archetype.
       -func createMetadata(archetype parser.Page, name string) (map[string]interface{}, error) {
       -        archMetadata, err := archetype.Metadata()
       -        if err != nil {
       -                return nil, err
       -        }
       -
       -        metadata, err := cast.ToStringMapE(archMetadata)
       -        if err != nil {
       -                return nil, err
       -        }
       -
       -        var date time.Time
       -
       -        for k, v := range metadata {
       -                if v == "" {
       -                        continue
       -                }
       -                lk := strings.ToLower(k)
       -                switch lk {
       -                case "date":
       -                        date, err = cast.ToTimeE(v)
       -                        if err != nil {
       -                                return nil, err
       -                        }
       -                case "title":
       -                        // Use the archetype title as is
       -                        metadata[lk] = v
       -                }
       -        }
       -
       -        if metadata == nil {
       -                metadata = make(map[string]interface{})
       -        }
       -
       -        if date.IsZero() {
       -                date = time.Now()
       -        }
       -
       -        if _, ok := metadata["title"]; !ok {
       -                metadata["title"] = helpers.MakeTitle(helpers.Filename(name))
       -        }
       -
       -        metadata["date"] = date.Format(time.RFC3339)
       -
       -        return metadata, nil
       -}
       -
        // FindArchetype takes a given kind/archetype of content and returns an output
        // path for that archetype.  If no archetype is found, an empty string is
        // returned.
       -func FindArchetype(s *hugolib.Site, kind string) (outpath string) {
       +func findArchetype(s *hugolib.Site, kind string) (outpath string) {
                search := []string{s.PathSpec.AbsPathify(s.Cfg.GetString("archetypeDir"))}
        
                if s.Cfg.GetString("theme") != "" {
   DIR diff --git a/create/content_template_handler.go b/create/content_template_handler.go
       @@ -0,0 +1,94 @@
       +// Copyright 2017 The Hugo Authors. All rights reserved.
       +//
       +// Licensed under the Apache License, Version 2.0 (the "License");
       +// you may not use this file except in compliance with the License.
       +// You may obtain a copy of the License at
       +// http://www.apache.org/licenses/LICENSE-2.0
       +//
       +// Unless required by applicable law or agreed to in writing, software
       +// distributed under the License is distributed on an "AS IS" BASIS,
       +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       +// See the License for the specific language governing permissions and
       +// limitations under the License.
       +
       +package create
       +
       +import (
       +        "bytes"
       +        "fmt"
       +        "time"
       +
       +        "github.com/gohugoio/hugo/source"
       +
       +        "github.com/gohugoio/hugo/hugolib"
       +        "github.com/gohugoio/hugo/tpl"
       +        "github.com/spf13/afero"
       +)
       +
       +const (
       +        archetypeTemplateTemplate = `+++
       +title = "{{ replace .BaseFileName "-" " " | title }}"
       +date = {{ .Date }}
       +draft = true
       ++++`
       +)
       +
       +func executeArcheTypeAsTemplate(s *hugolib.Site, kind, targetPath, archetypeFilename string) ([]byte, error) {
       +
       +        var (
       +                archetypeContent  []byte
       +                archetypeTemplate []byte
       +                err               error
       +        )
       +
       +        sp := source.NewSourceSpec(s.Deps.Cfg, s.Deps.Fs)
       +        f := sp.NewFile(targetPath)
       +
       +        data := struct {
       +                Type string
       +                Date string
       +                *source.File
       +        }{
       +                Type: kind,
       +                Date: time.Now().Format(time.RFC3339),
       +                File: f,
       +        }
       +
       +        if archetypeFilename == "" {
       +                // TODO(bep) archetype revive the issue about wrong tpl funcs arg order
       +                archetypeTemplate = []byte(archetypeTemplateTemplate)
       +        } else {
       +                archetypeTemplate, err = afero.ReadFile(s.Fs.Source, archetypeFilename)
       +                if err != nil {
       +                        return nil, fmt.Errorf("Failed to read archetype file %q: %s", archetypeFilename, err)
       +                }
       +
       +        }
       +
       +        // Reuse the Hugo template setup to get the template funcs properly set up.
       +        templateHandler := s.Deps.Tmpl.(tpl.TemplateHandler)
       +        if err := templateHandler.AddTemplate("_text/archetype", string(archetypeTemplate)); err != nil {
       +                return nil, fmt.Errorf("Failed to parse archetype file %q: %s", archetypeFilename, err)
       +        }
       +
       +        templ := templateHandler.Lookup("_text/archetype")
       +
       +        var buff bytes.Buffer
       +        if err := templ.Execute(&buff, data); err != nil {
       +                return nil, fmt.Errorf("Failed to process archetype file %q: %s", archetypeFilename, err)
       +        }
       +
       +        archetypeContent = buff.Bytes()
       +
       +        if !bytes.Contains(archetypeContent, []byte("date")) || !bytes.Contains(archetypeContent, []byte("title")) {
       +                // TODO(bep) remove some time in the future.
       +                s.Log.FEEDBACK.Println(fmt.Sprintf(`WARNING: date and/or title missing from archetype file %q. 
       +From Hugo 0.24 this must be provided in the archetype file itself, if needed. Example:
       +%s
       +`, archetypeFilename, archetypeTemplateTemplate))
       +
       +        }
       +
       +        return archetypeContent, nil
       +
       +}
   DIR diff --git a/create/content_test.go b/create/content_test.go
       @@ -45,9 +45,9 @@ func TestNewContent(t *testing.T) {
                }{
                        {"post", "post/sample-1.md", []string{`title = "Post Arch title"`, `test = "test1"`, "date = \"2015-01-12T19:20:04-07:00\""}},
                        {"emptydate", "post/sample-ed.md", []string{`title = "Empty Date Arch title"`, `test = "test1"`}},
       -                {"stump", "stump/sample-2.md", []string{`title = "sample 2"`}},     // no archetype file
       -                {"", "sample-3.md", []string{`title = "sample 3"`}},                // no archetype
       -                {"product", "product/sample-4.md", []string{`title = "sample 4"`}}, // empty archetype front matter
       +                {"stump", "stump/sample-2.md", []string{`title = "Sample 2"`}},     // no archetype file
       +                {"", "sample-3.md", []string{`title = "Sample 3"`}},                // no archetype
       +                {"product", "product/sample-4.md", []string{`title = "SAMPLE-4"`}}, // empty archetype front matter
                }
        
                for _, c := range cases {
       @@ -108,8 +108,10 @@ func initFs(fs *hugofs.Fs) error {
                                content: "+++\ndate = \"2015-01-12T19:20:04-07:00\"\ntitle = \"Post Arch title\"\ntest = \"test1\"\n+++\n",
                        },
                        {
       -                        path:    filepath.Join("archetypes", "product.md"),
       -                        content: "+++\n+++\n",
       +                        path: filepath.Join("archetypes", "product.md"),
       +                        content: `+++
       +title = "{{ .BaseFileName  | upper }}"
       ++++`,
                        },
                        {
                                path:    filepath.Join("archetypes", "emptydate.md"),
   DIR diff --git a/parser/frontmatter.go b/parser/frontmatter.go
       @@ -13,6 +13,8 @@
        
        package parser
        
       +// TODO(bep) archetype remove unused from this package.
       +
        import (
                "bytes"
                "encoding/json"