content_factory.go - hugo - [fork] hugo port for 9front
HTML git clone https://git.drkhsh.at/hugo.git
DIR Log
DIR Files
DIR Refs
DIR Submodules
DIR README
DIR LICENSE
---
content_factory.go (5021B)
---
1 // Copyright 2021 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 hugolib
15
16 import (
17 "context"
18 "fmt"
19 "io"
20 "path/filepath"
21 "strings"
22 "time"
23
24 "github.com/gohugoio/hugo/common/htime"
25 "github.com/gohugoio/hugo/common/paths"
26 "github.com/gohugoio/hugo/hugofs"
27
28 "github.com/gohugoio/hugo/source"
29
30 "github.com/gohugoio/hugo/resources/page"
31
32 "github.com/spf13/afero"
33 )
34
35 // ContentFactory creates content files from archetype templates.
36 type ContentFactory struct {
37 h *HugoSites
38
39 // We parse the archetype templates as Go templates, so we need
40 // to replace any shortcode with a temporary placeholder.
41 shortcodeReplacerPre *strings.Replacer
42 shortcodeReplacerPost *strings.Replacer
43 }
44
45 // ApplyArchetypeFilename archetypeFilename to w as a template using the given Page p as the foundation for the data context.
46 func (f ContentFactory) ApplyArchetypeFi(w io.Writer, p page.Page, archetypeKind string, fi hugofs.FileMetaInfo) error {
47 if fi.IsDir() {
48 return fmt.Errorf("archetype directory (%q) not supported", fi.Meta().Filename)
49 }
50
51 templateSource, err := fi.Meta().ReadAll()
52 if err != nil {
53 return fmt.Errorf("failed to read archetype file %q: %s: %w", fi.Meta().Filename, err, err)
54 }
55
56 return f.ApplyArchetypeTemplate(w, p, archetypeKind, string(templateSource))
57 }
58
59 // ApplyArchetypeTemplate templateSource to w as a template using the given Page p as the foundation for the data context.
60 func (f ContentFactory) ApplyArchetypeTemplate(w io.Writer, p page.Page, archetypeKind, templateSource string) error {
61 ps := p.(*pageState)
62 if archetypeKind == "" {
63 archetypeKind = p.Type()
64 }
65
66 d := &archetypeFileData{
67 Type: archetypeKind,
68 Date: htime.Now().Format(time.RFC3339),
69 Page: p,
70 File: p.File(),
71 }
72
73 templateSource = f.shortcodeReplacerPre.Replace(templateSource)
74
75 templ, err := ps.s.TemplateStore.TextParse("archetype.md", templateSource)
76 if err != nil {
77 return fmt.Errorf("failed to parse archetype template: %s: %w", err, err)
78 }
79
80 result, err := executeToString(context.Background(), ps.s.GetTemplateStore(), templ, d)
81 if err != nil {
82 return fmt.Errorf("failed to execute archetype template: %s: %w", err, err)
83 }
84
85 _, err = io.WriteString(w, f.shortcodeReplacerPost.Replace(result))
86
87 return err
88 }
89
90 func (f ContentFactory) SectionFromFilename(filename string) (string, error) {
91 filename = filepath.Clean(filename)
92 rel, _, err := f.h.AbsProjectContentDir(filename)
93 if err != nil {
94 return "", err
95 }
96
97 parts := strings.Split(paths.ToSlashTrimLeading(rel), "/")
98 if len(parts) < 2 {
99 return "", nil
100 }
101 return parts[0], nil
102 }
103
104 // CreateContentPlaceHolder creates a content placeholder file inside the
105 // best matching content directory.
106 func (f ContentFactory) CreateContentPlaceHolder(filename string, force bool) (string, error) {
107 filename = filepath.Clean(filename)
108 _, abs, err := f.h.AbsProjectContentDir(filename)
109 if err != nil {
110 return "", err
111 }
112
113 // This will be overwritten later, just write a placeholder to get
114 // the paths correct.
115 placeholder := `---
116 title: "Content Placeholder"
117 build:
118 render: never
119 list: never
120 publishResources: false
121 ---
122
123 `
124
125 if force {
126 return abs, afero.WriteReader(f.h.Fs.Source, abs, strings.NewReader(placeholder))
127 }
128 return abs, afero.SafeWriteReader(f.h.Fs.Source, abs, strings.NewReader(placeholder))
129 }
130
131 // NewContentFactory creates a new ContentFactory for h.
132 func NewContentFactory(h *HugoSites) ContentFactory {
133 return ContentFactory{
134 h: h,
135 shortcodeReplacerPre: strings.NewReplacer(
136 "{{<", "{x{<",
137 "{{%", "{x{%",
138 ">}}", ">}x}",
139 "%}}", "%}x}"),
140 shortcodeReplacerPost: strings.NewReplacer(
141 "{x{<", "{{<",
142 "{x{%", "{{%",
143 ">}x}", ">}}",
144 "%}x}", "%}}"),
145 }
146 }
147
148 // archetypeFileData represents the data available to an archetype template.
149 type archetypeFileData struct {
150 // The archetype content type, either given as --kind option or extracted
151 // from the target path's section, i.e. "blog/mypost.md" will resolve to
152 // "blog".
153 Type string
154
155 // The current date and time as a RFC3339 formatted string, suitable for use in front matter.
156 Date string
157
158 // The temporary page. Note that only the file path information is relevant at this stage.
159 Page page.Page
160
161 // File is the same as Page.File, embedded here for historic reasons.
162 // TODO(bep) make this a method.
163 *source.File
164 }
165
166 func (f *archetypeFileData) Site() page.Site {
167 return f.Page.Site()
168 }
169
170 func (f *archetypeFileData) Name() string {
171 return f.Page.File().ContentBaseName()
172 }