From 39f1932cc37aed66c834b62a15f3b10543b39f87 Mon Sep 17 00:00:00 2001 From: Sebastian Frank Date: Thu, 28 Feb 2019 10:43:30 +0100 Subject: [PATCH] generate details sites from fnRender --- .gitmodules | 9 -- config/tree.go | 92 +++++++++++++++ helper/dir.go | 24 ++++ helper/render.go | 12 +- helper/template_functions.go | 61 +++++++++- main.go | 144 ++++------------------- vendor/github.com/aymerick/raymond | 1 - vendor/github.com/gosimple/slug | 1 - vendor/github.com/rainycape/unidecode | 1 - website/templates/base_blog_details.html | 5 +- 10 files changed, 208 insertions(+), 142 deletions(-) create mode 100644 config/tree.go create mode 100644 helper/dir.go delete mode 160000 vendor/github.com/aymerick/raymond delete mode 160000 vendor/github.com/gosimple/slug delete mode 160000 vendor/github.com/rainycape/unidecode diff --git a/.gitmodules b/.gitmodules index 5ecd9c9..a9d1431 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,9 +25,6 @@ [submodule "vendor/github.com/davecgh/go-spew"] path = vendor/github.com/davecgh/go-spew url = https://github.com/davecgh/go-spew -[submodule "vendor/github.com/aymerick/raymond"] - path = vendor/github.com/aymerick/raymond - url = https://github.com/aymerick/raymond [submodule "vendor/github.com/imdario/mergo"] path = vendor/github.com/imdario/mergo url = https://github.com/imdario/mergo @@ -40,12 +37,6 @@ [submodule "vendor/github.com/juju/errors"] path = vendor/github.com/juju/errors url = https://github.com/juju/errors -[submodule "vendor/github.com/gosimple/slug"] - path = vendor/github.com/gosimple/slug - url = https://github.com/gosimple/slug -[submodule "vendor/github.com/rainycape/unidecode"] - path = vendor/github.com/rainycape/unidecode - url = https://github.com/rainycape/unidecode [submodule "vendor/github.com/flosch/pongo2-addons"] path = vendor/github.com/flosch/pongo2-addons url = https://github.com/flosch/pongo2-addons diff --git a/config/tree.go b/config/tree.go new file mode 100644 index 0000000..dff0376 --- /dev/null +++ b/config/tree.go @@ -0,0 +1,92 @@ +package config + +import ( + "reflect" + + "github.com/imdario/mergo" +) + +// ThisPathConfig is struct for This in paths yaml +type ThisPathConfig struct { + Navname *string `yaml:"Navname"` + GoTo *string `yaml:"GoTo"` + Data interface{} `yaml:"Data"` +} + +// IndexConfig describes index input and output file +type IndexConfig struct { + InputFile *string `yaml:"InputFile"` + OutputFile *string `yaml:"OutputFile"` +} + +// MetaData describes meta data for current site/tree node +type MetaData struct { + Title *string `yaml:"Title"` + Description *string `yaml:"Description"` + Keywords *string `yaml:"Keywords"` +} + +// DirnameConfig describes how to handle directory names +type DirnameConfig struct { + Strip *string `yaml:"Strip"` + IgnoreForNav *string `yaml:"IgnoreForNav"` +} + +// FilenameConfig describes how to handle filenames +type FilenameConfig struct { + Strip *string `yaml:"Strip"` + Ignore *string `yaml:"Ignore"` + OutputExtension *string `yaml:"OutputExtension"` +} + +// MarkdownConfig describes markdown handling +type MarkdownConfig struct { + ChromaRenderer *bool `yaml:"ChromaRenderer"` + ChromaStyle *string `yaml:"ChromaStyle"` +} + +// PathConfig of subdir +type PathConfig struct { + This ThisPathConfig `yaml:"This"` + Template *string `yaml:"Template"` + Index *IndexConfig `yaml:"Index"` + Meta *MetaData `yaml:"Meta"` + Path *DirnameConfig `yaml:"Path"` + Filename *FilenameConfig `yaml:"Filename"` + Markdown *MarkdownConfig `yaml:"Markdown"` + + Data interface{} `yaml:"Data"` +} + +// PathConfigTree is complete config tree of content dir +type PathConfigTree struct { + InputPath string + OutputPath string + + InputFiles []string + OtherFiles []string + + Config *PathConfig + Sub []*PathConfigTree +} + +type ptrTransformer struct{} + +func (t ptrTransformer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error { + if typ.Kind() == reflect.Ptr { + return func(dst, src reflect.Value) error { + if dst.CanSet() { + if dst.IsNil() { + dst.Set(src) + } + } + return nil + } + } + return nil +} + +// Merge merges 2 objects or maps +func Merge(dst, src interface{}) error { + return mergo.Merge(dst, src, mergo.WithTransformers(ptrTransformer{})) +} diff --git a/helper/dir.go b/helper/dir.go new file mode 100644 index 0000000..1c8738d --- /dev/null +++ b/helper/dir.go @@ -0,0 +1,24 @@ +package helper + +import "os" + +// CreateDirectory creates direcory with all missing parents and panic if error +func CreateDirectory(dir string) { + Log.Debugf("trying to create output directory: %s", dir) + + if dirH, err := os.Stat(dir); os.IsNotExist(err) { + err := os.MkdirAll(dir, 0755) + if err != nil { + Log.Panicf("could not create output directory '%s': %s", dir, err) + } + Log.Noticef("created output directory: %s", dir) + } else if dirH != nil { + if dirH.IsDir() { + Log.Noticef("output directory '%s' already exists", dir) + } else { + Log.Panicf("output directory '%s' is no directory", dir) + } + } else { + Log.Panicf("unknown error for output directory '%s': %s", dir, err) + } +} diff --git a/helper/render.go b/helper/render.go index 726ed67..c8b243f 100644 --- a/helper/render.go +++ b/helper/render.go @@ -11,9 +11,12 @@ import ( ) var templateCache = make(map[string]*pongo2.Template) -var currentContext map[string]interface{} +var currentContext *map[string]interface{} +var currentTreeNodeConfig *config.PathConfigTree +var currentPathConfig *config.PathConfig var templateDir string +// BackToRoot builds ../../ string func BackToRoot(curNavPath string) string { tmpPath := "" if curNavPath != "" { @@ -30,8 +33,10 @@ func SetTemplateDir(dir string) { } // RenderTemplate renders a pongo2 template with context -func RenderTemplate(filename string, ctx map[string]interface{}) (string, error) { +func RenderTemplate(filename string, treeNodeConfig *config.PathConfigTree, pathConfig *config.PathConfig, ctx *map[string]interface{}) (string, error) { currentContext = ctx + currentTreeNodeConfig = treeNodeConfig + currentPathConfig = pathConfig templateFile := templateDir + "/" + filename template := templateCache[templateFile] if template == nil { @@ -43,9 +48,10 @@ func RenderTemplate(filename string, ctx map[string]interface{}) (string, error) } } - return template.Execute(ctx) + return template.Execute(*ctx) } +// FixAssetsPath replaces assets path based on current path func FixAssetsPath(str, curNavPath string) string { if find := config.Config.Assets.FixTemplate.Find; find != "" { Log.Debugf("fixing assets paths for path '%s'", curNavPath) diff --git a/helper/template_functions.go b/helper/template_functions.go index b181b19..ebd6236 100644 --- a/helper/template_functions.go +++ b/helper/template_functions.go @@ -4,10 +4,14 @@ import ( "encoding/json" "fmt" "io/ioutil" + "log" "net/http" + "path" "strings" + "gitbase.de/apairon/mark2web/config" "github.com/davecgh/go-spew/spew" + "github.com/extemporalgenome/slug" "github.com/flosch/pongo2" ) @@ -52,16 +56,65 @@ func RequestFn(url *pongo2.Value, args ...*pongo2.Value) *pongo2.Value { // RenderFn renders a pongo2 template with additional context func RenderFn(templateFilename, outDir, subCtxName, ctx *pongo2.Value) *pongo2.Value { - currentContext[subCtxName.String()] = ctx - result, err := RenderTemplate(templateFilename.String(), currentContext) + oDirSlug := slug.Slug(outDir.String()) + navPath := path.Clean((*currentContext)["CurrentPath"].(string) + "/" + oDirSlug) + outputPath := path.Clean(currentTreeNodeConfig.OutputPath + "/" + oDirSlug) + CreateDirectory(outputPath) + + newContext := make(map[string]interface{}) + if err := config.Merge(&newContext, *currentContext); err != nil { + Log.Panicf("unable to merge context") + } + newContext[subCtxName.String()] = ctx + newContext["CurrentPath"] = navPath + + newNodeConfig := new(config.PathConfigTree) + if err := config.Merge(newNodeConfig, currentTreeNodeConfig); err != nil { + Log.Panicf("unable to merge tree node config") + } + newNodeConfig.OutputPath = outputPath + + // remember old to set after recursion + oldContext := currentContext + oldNodeConfig := currentTreeNodeConfig + result, err := RenderTemplate( + templateFilename.String(), + newNodeConfig, + currentPathConfig, + &newContext, + ) if err != nil { panic(err) } + currentContext = oldContext + currentTreeNodeConfig = oldNodeConfig result = FixAssetsPath( result, - currentContext["CurrentPath"].(string), + navPath, ) - spew.Dump(result) + //spew.Dump(result) + + // build output filename + outputFilename := "index.html" + + var indexOutputFile *string + if i := currentPathConfig.Index; i != nil { + indexOutputFile = i.OutputFile + } + + if indexOutputFile != nil && *indexOutputFile != "" { + outputFilename = *indexOutputFile + } + + outFile := outputPath + "/" + outputFilename + Log.Debugf("using '%s' as output file", outFile) + + Log.Noticef("writing to output file: %s", outFile) + err = ioutil.WriteFile(outFile, []byte(result), 0644) + if err != nil { + log.Panicf("could not write to output file '%s': %s", outFile, err) + } + return pongo2.AsValue(nil) } diff --git a/main.go b/main.go index d6040b8..86ade26 100644 --- a/main.go +++ b/main.go @@ -7,18 +7,15 @@ import ( "io/ioutil" "os" "path" - "reflect" "regexp" "strings" - "github.com/imdario/mergo" - "gitbase.de/apairon/mark2web/config" "gitbase.de/apairon/mark2web/helper" "github.com/Depado/bfchroma" "github.com/davecgh/go-spew/spew" + "github.com/extemporalgenome/slug" "github.com/flosch/pongo2" - "github.com/gosimple/slug" cpy "github.com/otiai10/copy" "gopkg.in/russross/blackfriday.v2" "gopkg.in/yaml.v2" @@ -38,88 +35,9 @@ var log = helper.Log var inDir *string var outDir *string -// ThisPathConfig is struct for This in paths yaml -type ThisPathConfig struct { - Navname *string `yaml:"Navname"` - GoTo *string `yaml:"GoTo"` - Data interface{} `yaml:"Data"` -} +var contentConfig = new(config.PathConfigTree) -type indexStruct struct { - InputFile *string `yaml:"InputFile"` - OutputFile *string `yaml:"OutputFile"` -} - -type metaStruct struct { - Title *string `yaml:"Title"` - Description *string `yaml:"Description"` - Keywords *string `yaml:"Keywords"` -} - -type pathStruct struct { - Strip *string `yaml:"Strip"` - IgnoreForNav *string `yaml:"IgnoreForNav"` -} - -type filenameStruct struct { - Strip *string `yaml:"Strip"` - Ignore *string `yaml:"Ignore"` - OutputExtension *string `yaml:"OutputExtension"` -} - -type markdownStruct struct { - ChromaRenderer *bool `yaml:"ChromaRenderer"` - ChromaStyle *string `yaml:"ChromaStyle"` -} - -// PathConfig of subdir -type PathConfig struct { - This ThisPathConfig `yaml:"This"` - Template *string `yaml:"Template"` - Index *indexStruct `yaml:"Index"` - Meta *metaStruct `yaml:"Meta"` - Path *pathStruct `yaml:"Path"` - Filename *filenameStruct `yaml:"Filename"` - Markdown *markdownStruct `yaml:"Markdown"` - - Data interface{} `yaml:"Data"` -} - -// PathConfigTree is complete config tree of content dir -type PathConfigTree struct { - InputPath string - OutputPath string - - InputFiles []string - OtherFiles []string - - Config *PathConfig - Sub []*PathConfigTree -} - -var contentConfig = new(PathConfigTree) - -type ptrTransformer struct{} - -func (t ptrTransformer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error { - if typ.Kind() == reflect.Ptr { - return func(dst, src reflect.Value) error { - if dst.CanSet() { - if dst.IsNil() { - dst.Set(src) - } - } - return nil - } - } - return nil -} - -func merge(dst, src interface{}) error { - return mergo.Merge(dst, src, mergo.WithTransformers(ptrTransformer{})) -} - -func readContentDir(inBase string, outBase string, dir string, conf *PathConfig, tree *PathConfigTree) { +func readContentDir(inBase string, outBase string, dir string, conf *config.PathConfig, tree *config.PathConfigTree) { inPath := inBase if dir != "" { inPath += "/" + dir @@ -135,14 +53,14 @@ func readContentDir(inBase string, outBase string, dir string, conf *PathConfig, tree.InputPath = inPath // read config - newConfig := new(PathConfig) + newConfig := new(config.PathConfig) log.Debug("looking for config.yml ...") configFile := inPath + "/config.yml" if _, err = os.Stat(configFile); os.IsNotExist(err) { log.Debug("no config.yml found in this directory, using upper configs") - merge(newConfig, conf) + config.Merge(newConfig, conf) // remove this - newConfig.This = ThisPathConfig{} + newConfig.This = config.ThisPathConfig{} } else { log.Debug("reading config...") data, err := ioutil.ReadFile(configFile) @@ -156,7 +74,7 @@ func readContentDir(inBase string, outBase string, dir string, conf *PathConfig, log.Debug("merging config with upper config") oldThis := newConfig.This - merge(newConfig, conf) + config.Merge(newConfig, conf) newConfig.This = oldThis log.Debug(spew.Sdump(newConfig)) @@ -183,7 +101,7 @@ func readContentDir(inBase string, outBase string, dir string, conf *PathConfig, tree.Config.This.Navname = &navname } - stripedDir = slug.Make(stripedDir) + stripedDir = slug.Slug(stripedDir) outPath := outBase + "/" + stripedDir outPath = path.Clean(outPath) @@ -217,9 +135,9 @@ func readContentDir(inBase string, outBase string, dir string, conf *PathConfig, p := inPath + "/" + f.Name() if f.IsDir() { log.Debugf("DIR %s", p) - newTree := new(PathConfigTree) + newTree := new(config.PathConfigTree) if tree.Sub == nil { - tree.Sub = make([]*PathConfigTree, 0) + tree.Sub = make([]*config.PathConfigTree, 0) } tree.Sub = append(tree.Sub, newTree) readContentDir(inPath, outPath, f.Name(), newConfig, newTree) @@ -234,13 +152,13 @@ type navElement struct { Data interface{} - This ThisPathConfig + This config.ThisPathConfig SubMap *map[string]*navElement SubSlice *[]*navElement } -func buildNavigation(conf *PathConfigTree, curNavMap *map[string]*navElement, curNavSlice *[]*navElement, navActive *[]*navElement, activeNav string) { +func buildNavigation(conf *config.PathConfigTree, curNavMap *map[string]*navElement, curNavSlice *[]*navElement, navActive *[]*navElement, activeNav string) { for _, el := range conf.Sub { var ignNav *string if p := el.Config.Path; p != nil { @@ -312,24 +230,8 @@ func buildNavigation(conf *PathConfigTree, curNavMap *map[string]*navElement, cu } } -func processContent(conf *PathConfigTree) { - log.Debugf("trying to create output directory: %s", conf.OutputPath) - - if dirH, err := os.Stat(conf.OutputPath); os.IsNotExist(err) { - err := os.MkdirAll(conf.OutputPath, 0755) - if err != nil { - log.Panicf("could not create output directory '%s': %s", conf.OutputPath, err) - } - log.Noticef("created output directory: %s", conf.OutputPath) - } else if dirH != nil { - if dirH.IsDir() { - log.Noticef("output directory '%s' already exists", conf.OutputPath) - } else { - log.Panicf("output directory '%s' is no directory", conf.OutputPath) - } - } else { - log.Panicf("unknown error for output directory '%s': %s", conf.OutputPath, err) - } +func processContent(conf *config.PathConfigTree) { + helper.CreateDirectory(conf.OutputPath) curNavPath := strings.TrimPrefix(conf.OutputPath, *outDir) curNavPath = strings.TrimPrefix(curNavPath, "/") @@ -370,7 +272,7 @@ RewriteRule ^$ %{REQUEST_URI}`+goToFixed+`/ [R,L] } log.Infof("processing input file '%s'", inFile) - newConfig := new(PathConfig) + newConfig := new(config.PathConfig) regex := regexp.MustCompile("(?s)^---(.*?)\\r?\\n\\r?---\\r?\\n\\r?") yamlData := regex.Find(input) @@ -383,14 +285,14 @@ RewriteRule ^$ %{REQUEST_URI}`+goToFixed+`/ [R,L] log.Debug("merging config with upper config") oldThis := newConfig.This - merge(newConfig, conf.Config) + config.Merge(newConfig, conf.Config) newConfig.This = oldThis log.Debug(spew.Sdump(newConfig)) input = regex.ReplaceAll(input, []byte("")) } else { - merge(newConfig, conf.Config) + config.Merge(newConfig, conf.Config) } // ignore ??? @@ -484,7 +386,7 @@ RewriteRule ^$ %{REQUEST_URI}`+goToFixed+`/ [R,L] buildNavigation(contentConfig, &navMap, &navSlice, &navActive, curNavPath) // read yaml header as data for template - ctx := make(pongo2.Context) + ctx := make(map[string]interface{}) ctx["This"] = newConfig.This ctx["Meta"] = newConfig.Meta ctx["Data"] = newConfig.Data @@ -502,7 +404,7 @@ RewriteRule ^$ %{REQUEST_URI}`+goToFixed+`/ [R,L] log.Debugf("rendering template '%s' for '%s'", *newConfig.Template, outFile) templateFilename := *newConfig.Template - result, err := helper.RenderTemplate(*newConfig.Template, ctx) + result, err := helper.RenderTemplate(*newConfig.Template, conf, newConfig, &ctx) if err != nil { log.Panicf("could not execute template '%s' for input file '%s': %s", templateFilename, inFile, err) } @@ -632,17 +534,17 @@ func main() { defaultFilenameIgnore := "^_" defaultFilenameOutputExtension := "html" - defaultPathConfig := new(PathConfig) + defaultPathConfig := new(config.PathConfig) defaultPathConfig.Template = &defaultTemplate - defaultPathConfig.Index = &indexStruct{ + defaultPathConfig.Index = &config.IndexConfig{ InputFile: &defaultInputFile, OutputFile: &defaultOutputFile, } - defaultPathConfig.Path = &pathStruct{ + defaultPathConfig.Path = &config.DirnameConfig{ Strip: &defaultPathStrip, IgnoreForNav: &defaultPathIgnoreForNav, } - defaultPathConfig.Filename = &filenameStruct{ + defaultPathConfig.Filename = &config.FilenameConfig{ Strip: &defaultFilenameStrip, Ignore: &defaultFilenameIgnore, OutputExtension: &defaultFilenameOutputExtension, diff --git a/vendor/github.com/aymerick/raymond b/vendor/github.com/aymerick/raymond deleted file mode 160000 index b565731..0000000 --- a/vendor/github.com/aymerick/raymond +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b565731e1464263de0bda75f2e45d97b54b60110 diff --git a/vendor/github.com/gosimple/slug b/vendor/github.com/gosimple/slug deleted file mode 160000 index 42ac18c..0000000 --- a/vendor/github.com/gosimple/slug +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 42ac18c34c2c6f4843fa48167317dcaa9416d1e2 diff --git a/vendor/github.com/rainycape/unidecode b/vendor/github.com/rainycape/unidecode deleted file mode 160000 index cb7f23e..0000000 --- a/vendor/github.com/rainycape/unidecode +++ /dev/null @@ -1 +0,0 @@ -Subproject commit cb7f23ec59bec0d61b19c56cd88cee3d0cc1870c diff --git a/website/templates/base_blog_details.html b/website/templates/base_blog_details.html index 0a3589b..ee0c782 100644 --- a/website/templates/base_blog_details.html +++ b/website/templates/base_blog_details.html @@ -1,9 +1,10 @@ {% extends 'base.html' %} {% block part0 %} -

{{ details.title }}

+

{{ details.title }}

+ {{ details.teaser|markdown }} {% endblock part0 %} {% block part1 %} - + {{ details.body|markdown }} {% endblock part1 %} \ No newline at end of file