github.com/fighterlyt/hugo@v0.47.1/create/content_template_handler.go (about) 1 // Copyright 2017 The Hugo Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package create 15 16 import ( 17 "bytes" 18 "fmt" 19 "path/filepath" 20 "strings" 21 "time" 22 23 "github.com/gohugoio/hugo/helpers" 24 "github.com/gohugoio/hugo/source" 25 26 "github.com/gohugoio/hugo/hugolib" 27 "github.com/gohugoio/hugo/tpl" 28 "github.com/spf13/afero" 29 ) 30 31 // ArchetypeFileData represents the data available to an archetype template. 32 type ArchetypeFileData struct { 33 // The archetype content type, either given as --kind option or extracted 34 // from the target path's section, i.e. "blog/mypost.md" will resolve to 35 // "blog". 36 Type string 37 38 // The current date and time as a RFC3339 formatted string, suitable for use in front matter. 39 Date string 40 41 // The Site, fully equipped with all the pages etc. Note: This will only be set if it is actually 42 // used in the archetype template. Also, if this is a multilingual setup, 43 // this site is the site that best matches the target content file, based 44 // on the presence of language code in the filename. 45 Site *hugolib.SiteInfo 46 47 // Name will in most cases be the same as TranslationBaseName, e.g. "my-post". 48 // But if that value is "index" (bundles), the Name is instead the owning folder. 49 // This is the value you in most cases would want to use to construct the title in your 50 // archetype template. 51 Name string 52 53 // The target content file. Note that the .Content will be empty, as that 54 // has not been created yet. 55 source.File 56 } 57 58 const ( 59 // ArchetypeTemplateTemplate is used as initial template when adding an archetype template. 60 ArchetypeTemplateTemplate = `--- 61 title: "{{ replace .Name "-" " " | title }}" 62 date: {{ .Date }} 63 draft: true 64 --- 65 66 ` 67 ) 68 69 var ( 70 archetypeShortcodeReplacementsPre = strings.NewReplacer( 71 "{{<", "{x{<", 72 "{{%", "{x{%", 73 ">}}", ">}x}", 74 "%}}", "%}x}") 75 76 archetypeShortcodeReplacementsPost = strings.NewReplacer( 77 "{x{<", "{{<", 78 "{x{%", "{{%", 79 ">}x}", ">}}", 80 "%}x}", "%}}") 81 ) 82 83 func executeArcheTypeAsTemplate(s *hugolib.Site, kind, targetPath, archetypeFilename string) ([]byte, error) { 84 85 var ( 86 archetypeContent []byte 87 archetypeTemplate []byte 88 err error 89 ) 90 91 ps, err := helpers.NewPathSpec(s.Deps.Fs, s.Deps.Cfg) 92 if err != nil { 93 return nil, err 94 } 95 sp := source.NewSourceSpec(ps, ps.Fs.Source) 96 97 f := sp.NewFileInfo("", targetPath, false, nil) 98 99 name := f.TranslationBaseName() 100 101 if name == "index" || name == "_index" { 102 // Page bundles; the directory name will hopefully have a better name. 103 dir := strings.TrimSuffix(f.Dir(), helpers.FilePathSeparator) 104 _, name = filepath.Split(dir) 105 } 106 107 data := ArchetypeFileData{ 108 Type: kind, 109 Date: time.Now().Format(time.RFC3339), 110 Name: name, 111 File: f, 112 Site: &s.Info, 113 } 114 115 if archetypeFilename == "" { 116 // TODO(bep) archetype revive the issue about wrong tpl funcs arg order 117 archetypeTemplate = []byte(ArchetypeTemplateTemplate) 118 } else { 119 archetypeTemplate, err = afero.ReadFile(s.BaseFs.Archetypes.Fs, archetypeFilename) 120 if err != nil { 121 return nil, fmt.Errorf("failed to read archetype file %s", err) 122 } 123 124 } 125 126 // The archetype template may contain shortcodes, and these does not play well 127 // with the Go templates. Need to set some temporary delimiters. 128 archetypeTemplate = []byte(archetypeShortcodeReplacementsPre.Replace(string(archetypeTemplate))) 129 130 // Reuse the Hugo template setup to get the template funcs properly set up. 131 templateHandler := s.Deps.Tmpl.(tpl.TemplateHandler) 132 templateName := "_text/" + helpers.Filename(archetypeFilename) 133 if err := templateHandler.AddTemplate(templateName, string(archetypeTemplate)); err != nil { 134 return nil, fmt.Errorf("Failed to parse archetype file %q: %s", archetypeFilename, err) 135 } 136 137 templ, _ := templateHandler.Lookup(templateName) 138 139 var buff bytes.Buffer 140 if err := templ.Execute(&buff, data); err != nil { 141 return nil, fmt.Errorf("Failed to process archetype file %q: %s", archetypeFilename, err) 142 } 143 144 archetypeContent = []byte(archetypeShortcodeReplacementsPost.Replace(buff.String())) 145 146 return archetypeContent, nil 147 148 }