URI: 
       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 }