This commit is contained in:
parent
50139c6f51
commit
23fd5fe1d4
@ -1,3 +1,8 @@
|
|||||||
NEUERUNGEN:
|
NEUERUNGEN:
|
||||||
|
|
||||||
- `t=ZIEL_VERZEICHNIS` Parameter im `image_process` Filter
|
- Cached Collection Webrequests
|
||||||
|
- recursive Collections
|
||||||
|
- markdown-Filter `s=SYNTAX_HIGHLIGHT_SHEMA` Parameter
|
||||||
|
- image_process nutzt alle CPU-Kerne
|
||||||
|
- GZIP Vor-Komprimierung der Inhalte und Assets
|
||||||
|
- Code neu organisiert
|
@ -1 +1 @@
|
|||||||
1.1.1
|
1.2.0-pre
|
@ -27,6 +27,10 @@ func ProcessAssets() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
helper.Log.Panicf("could not copy assets from '%s' to '%s': %s", from, to, err)
|
helper.Log.Panicf("could not copy assets from '%s' to '%s': %s", from, to, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if Config.Assets.Compress {
|
||||||
|
compressFilesInDir(to)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
160
pkg/mark2web/collection.go
Normal file
160
pkg/mark2web/collection.go
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
package mark2web
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"gitbase.de/apairon/mark2web/pkg/helper"
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
"github.com/flosch/pongo2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type colCacheEntry struct {
|
||||||
|
data interface{}
|
||||||
|
hit int
|
||||||
|
navnames []string
|
||||||
|
}
|
||||||
|
|
||||||
|
var colCache = make(map[string]*colCacheEntry)
|
||||||
|
|
||||||
|
func (node *TreeNode) handleCollections() {
|
||||||
|
collections := append(node.Config.Collections, node.Config.This.Collections...)
|
||||||
|
for _, colConfig := range collections {
|
||||||
|
if colConfig != nil {
|
||||||
|
if colConfig.Name == nil || *colConfig.Name == "" {
|
||||||
|
helper.Log.Panicf("missing Name in collection config in '%s'", node.InputPath)
|
||||||
|
}
|
||||||
|
if colConfig.URL == nil || *colConfig.URL == "" {
|
||||||
|
helper.Log.Panicf("missing EntriesJSON in collection config in '%s'", node.InputPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if node.ColMap == nil {
|
||||||
|
node.ColMap = make(helper.MapString)
|
||||||
|
}
|
||||||
|
ctx := NewContext()
|
||||||
|
ctx["This"] = node.Config.This
|
||||||
|
ctx["Data"] = node.Config.Data
|
||||||
|
|
||||||
|
url, err := pongo2.RenderTemplateString(*colConfig.URL, ctx)
|
||||||
|
if err != nil {
|
||||||
|
helper.Log.Panicf("invalid template string for Collection Element.URL in '%s': %s", node.InputPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var colData interface{}
|
||||||
|
if cacheEntry, ok := colCache[url]; ok {
|
||||||
|
colData = cacheEntry.data
|
||||||
|
cacheEntry.hit++
|
||||||
|
} else {
|
||||||
|
colData = helper.JSONWebRequest(url)
|
||||||
|
colCache[url] = &colCacheEntry{
|
||||||
|
data: colData,
|
||||||
|
navnames: make([]string, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node.ColMap[*colConfig.Name] = colData
|
||||||
|
|
||||||
|
if navT := colConfig.NavTemplate; navT != nil {
|
||||||
|
var entries []interface{}
|
||||||
|
var ok bool
|
||||||
|
if navT.EntriesAttribute != "" {
|
||||||
|
var colDataMap map[string]interface{}
|
||||||
|
if colDataMap, ok = colData.(map[string]interface{}); ok {
|
||||||
|
entries, ok = colDataMap[navT.EntriesAttribute].([]interface{})
|
||||||
|
if !ok {
|
||||||
|
helper.Log.Debug(spew.Sdump(colDataMap))
|
||||||
|
helper.Log.Panicf("invalid json data in [%s] from url '%s' for entries", navT.EntriesAttribute, url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
entries, ok = colData.([]interface{})
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
helper.Log.Debug(spew.Sdump(colData))
|
||||||
|
helper.Log.Panicf("invalid json data from url '%s', need array of objects for entries or object with configured NavTemplate.EntriesAttribute", url)
|
||||||
|
}
|
||||||
|
|
||||||
|
// build navigation with detail sites
|
||||||
|
for idx, colEl := range entries {
|
||||||
|
ctxE := make(pongo2.Context)
|
||||||
|
err := helper.Merge(&ctxE, ctx)
|
||||||
|
if err != nil {
|
||||||
|
helper.Log.Panicf("could not merge context in '%s': %s", node.InputPath, err)
|
||||||
|
}
|
||||||
|
var jsonCtx map[string]interface{}
|
||||||
|
if jsonCtx, ok = colEl.(map[string]interface{}); !ok {
|
||||||
|
helper.Log.Debug(spew.Sdump(colEl))
|
||||||
|
helper.Log.Panicf("no json object for entry index %d from url '%s'", idx, url)
|
||||||
|
}
|
||||||
|
err = helper.Merge(&ctxE, pongo2.Context(jsonCtx))
|
||||||
|
if err != nil {
|
||||||
|
helper.Log.Panicf("could not merge context in '%s': %s", node.InputPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tpl := ""
|
||||||
|
if navT.Template != "" {
|
||||||
|
tpl, err = pongo2.RenderTemplateString(navT.Template, ctxE)
|
||||||
|
if err != nil {
|
||||||
|
helper.Log.Panicf("invalid template string for NavTemplate.Template in '%s': %s", node.InputPath, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if tpl == "" {
|
||||||
|
tpl = *node.Config.Template
|
||||||
|
}
|
||||||
|
|
||||||
|
dataKey := ""
|
||||||
|
if navT.DataKey != "" {
|
||||||
|
dataKey, err = pongo2.RenderTemplateString(navT.DataKey, ctxE)
|
||||||
|
if err != nil {
|
||||||
|
helper.Log.Panicf("invalid template string for NavTemplate.DataKey in '%s': %s", node.InputPath, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
goTo, err := pongo2.RenderTemplateString(navT.GoTo, ctxE)
|
||||||
|
if err != nil {
|
||||||
|
helper.Log.Panicf("invalid template string for NavTemplate.GoTo in '%s': %s", node.InputPath, err)
|
||||||
|
}
|
||||||
|
goTo = strings.Trim(goTo, "/")
|
||||||
|
goTo = path.Clean(goTo)
|
||||||
|
|
||||||
|
if strings.Contains(goTo, "..") {
|
||||||
|
helper.Log.Panicf("going back via .. in NavTemplate.GoTo forbidden in collection config in '%s': %s", node.InputPath, goTo)
|
||||||
|
}
|
||||||
|
if goTo == "." {
|
||||||
|
helper.Log.Panicf("invalid config '.' for NavTemplate.GoTo in collection config in '%s'", node.InputPath)
|
||||||
|
}
|
||||||
|
if goTo == "" {
|
||||||
|
helper.Log.Panicf("missing NavTemplate.GoTo in collection config in '%s'", node.InputPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
navname := ""
|
||||||
|
if navT.Navname != "" {
|
||||||
|
navname, err = pongo2.RenderTemplateString(navT.Navname, ctxE)
|
||||||
|
if err != nil {
|
||||||
|
helper.Log.Panicf("invalid template string for NavTemplate.Navname in '%s': %s", node.InputPath, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
body := ""
|
||||||
|
if navT.Body != "" {
|
||||||
|
body, err = pongo2.RenderTemplateString(navT.Body, ctxE)
|
||||||
|
if err != nil {
|
||||||
|
helper.Log.Panicf("invalid template string for NavTemplate.Body in '%s': %s", node.InputPath, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if l := len(colCache[url].navnames); colCache[url].hit > 1 &&
|
||||||
|
l > 0 &&
|
||||||
|
navname == colCache[url].navnames[l-1] {
|
||||||
|
// navname before used same url, so recursion loop
|
||||||
|
helper.Log.Panicf("collection request loop detected for in '%s' for url: %s", node.InputPath, url)
|
||||||
|
}
|
||||||
|
|
||||||
|
colCache[url].navnames = append(colCache[url].navnames, navname)
|
||||||
|
|
||||||
|
node.addSubNode(tpl, goTo, navname, colEl, dataKey, body, navT.Hidden)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
89
pkg/mark2web/compress.go
Normal file
89
pkg/mark2web/compress.go
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
package mark2web
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"compress/gzip"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
"gitbase.de/apairon/mark2web/pkg/helper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func handleCompression(filename string, content []byte) {
|
||||||
|
ThreadStart(func() {
|
||||||
|
if _, ok := Config.Compress.Extensions[path.Ext(filename)]; ok {
|
||||||
|
|
||||||
|
if Config.Compress.GZIP {
|
||||||
|
gzFilename := filename + ".gz"
|
||||||
|
|
||||||
|
helper.Log.Infof("writing to compressed output file: %s", gzFilename)
|
||||||
|
var buf bytes.Buffer
|
||||||
|
|
||||||
|
zw, err := gzip.NewWriterLevel(&buf, gzip.BestCompression)
|
||||||
|
if err != nil {
|
||||||
|
helper.Log.Panicf("could not initialize gzip writer for '%s': %s", filename, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if content != nil {
|
||||||
|
// content given
|
||||||
|
_, err = zw.Write(content)
|
||||||
|
if err != nil {
|
||||||
|
helper.Log.Panicf("could not write gziped content for '%s': %s", filename, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// read file
|
||||||
|
f, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
helper.Log.Panicf("could not open file '%s': %s", filename, err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
_, err = io.Copy(zw, f)
|
||||||
|
if err != nil {
|
||||||
|
helper.Log.Panicf("could not gzip file '%s': %s", filename, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = zw.Close()
|
||||||
|
if err != nil {
|
||||||
|
helper.Log.Panicf("could not close gziped content for '%s': %s", filename, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Create(gzFilename)
|
||||||
|
if err != nil {
|
||||||
|
helper.Log.Panicf("could not create file '%s': %s", gzFilename, err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
_, err = buf.WriteTo(f)
|
||||||
|
if err != nil {
|
||||||
|
helper.Log.Panicf("could not write to file '%s': %s", gzFilename, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func compressFilesInDir(dir string) {
|
||||||
|
helper.Log.Noticef("compressing configured files in: %s", dir)
|
||||||
|
|
||||||
|
var _processDir func(string)
|
||||||
|
_processDir = func(d string) {
|
||||||
|
entries, err := ioutil.ReadDir(d)
|
||||||
|
if err != nil {
|
||||||
|
helper.Log.Panicf("could not read dir '%s': %s", d, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entry := range entries {
|
||||||
|
if entry.IsDir() {
|
||||||
|
_processDir(d + "/" + entry.Name())
|
||||||
|
} else {
|
||||||
|
handleCompression(d+"/"+entry.Name(), nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_processDir(dir)
|
||||||
|
|
||||||
|
}
|
@ -13,6 +13,7 @@ type GlobalConfig struct {
|
|||||||
} `yaml:"Webserver"`
|
} `yaml:"Webserver"`
|
||||||
|
|
||||||
Assets struct {
|
Assets struct {
|
||||||
|
Compress bool `yaml:"Compress"`
|
||||||
FromPath string `yaml:"FromPath"`
|
FromPath string `yaml:"FromPath"`
|
||||||
ToPath string `yaml:"ToPath"`
|
ToPath string `yaml:"ToPath"`
|
||||||
Action string `yaml:"Action"`
|
Action string `yaml:"Action"`
|
||||||
@ -26,6 +27,11 @@ type GlobalConfig struct {
|
|||||||
Action string `yaml:"Action"`
|
Action string `yaml:"Action"`
|
||||||
} `yaml:"OtherFiles"`
|
} `yaml:"OtherFiles"`
|
||||||
|
|
||||||
|
Compress struct {
|
||||||
|
GZIP bool `yaml:"GZIP"`
|
||||||
|
Extensions map[string]string `yaml:"Extensions"`
|
||||||
|
} `yaml:"Compress"`
|
||||||
|
|
||||||
Directories struct {
|
Directories struct {
|
||||||
Input string
|
Input string
|
||||||
Output string
|
Output string
|
||||||
|
@ -84,4 +84,7 @@ type PathConfig struct {
|
|||||||
Imaging *ImagingConfig `yaml:"Imaging"`
|
Imaging *ImagingConfig `yaml:"Imaging"`
|
||||||
|
|
||||||
Data helper.MapString `yaml:"Data"`
|
Data helper.MapString `yaml:"Data"`
|
||||||
|
|
||||||
|
// Collections here are recursive if saved as nav, so request should be filtered
|
||||||
|
Collections []*CollectionConfig `yaml:"Collections"`
|
||||||
}
|
}
|
||||||
|
@ -84,18 +84,7 @@ func (node *TreeNode) ProcessContent() {
|
|||||||
}
|
}
|
||||||
goToFixed = path.Clean(goToFixed)
|
goToFixed = path.Clean(goToFixed)
|
||||||
|
|
||||||
switch Config.Webserver.Type {
|
htaccessRedirect(node.OutputPath, goToFixed)
|
||||||
case "apache":
|
|
||||||
htaccessFile := node.OutputPath + "/.htaccess"
|
|
||||||
helper.Log.Noticef("writing '%s' with redirect to: %s", htaccessFile, goToFixed)
|
|
||||||
err := ioutil.WriteFile(htaccessFile, []byte(`RewriteEngine on
|
|
||||||
RewriteRule ^$ %{REQUEST_URI}`+goToFixed+`/ [R,L]
|
|
||||||
`), 0644)
|
|
||||||
if err != nil {
|
|
||||||
helper.Log.Panicf("could not write '%s': %s", htaccessFile, err)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, file := range node.InputFiles {
|
for _, file := range node.InputFiles {
|
||||||
@ -274,6 +263,8 @@ RewriteRule ^$ %{REQUEST_URI}`+goToFixed+`/ [R,L]
|
|||||||
helper.Log.Panicf("could not write to output file '%s': %s", outFile, err)
|
helper.Log.Panicf("could not write to output file '%s': %s", outFile, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleCompression(outFile, []byte(result))
|
||||||
|
|
||||||
//fmt.Println(string(html))
|
//fmt.Println(string(html))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -289,6 +280,8 @@ RewriteRule ^$ %{REQUEST_URI}`+goToFixed+`/ [R,L]
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
helper.Log.Panicf("could not copy file from '%s' to '%s': %s", from, to, err)
|
helper.Log.Panicf("could not copy file from '%s' to '%s': %s", from, to, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleCompression(to, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,127 +35,6 @@ func NewContext() pongo2.Context {
|
|||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *TreeNode) handleCollections() {
|
|
||||||
for _, colConfig := range node.Config.This.Collections {
|
|
||||||
if colConfig != nil {
|
|
||||||
if colConfig.Name == nil || *colConfig.Name == "" {
|
|
||||||
helper.Log.Panicf("missing Name in collection config in '%s'", node.InputPath)
|
|
||||||
}
|
|
||||||
if colConfig.URL == nil || *colConfig.URL == "" {
|
|
||||||
helper.Log.Panicf("missing EntriesJSON in collection config in '%s'", node.InputPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if node.ColMap == nil {
|
|
||||||
node.ColMap = make(helper.MapString)
|
|
||||||
}
|
|
||||||
ctx := NewContext()
|
|
||||||
ctx["This"] = node.Config.This
|
|
||||||
ctx["Data"] = node.Config.Data
|
|
||||||
|
|
||||||
url, err := pongo2.RenderTemplateString(*colConfig.URL, ctx)
|
|
||||||
if err != nil {
|
|
||||||
helper.Log.Panicf("invalid template string for Collection Element.URL in '%s': %s", node.InputPath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
colData := helper.JSONWebRequest(url)
|
|
||||||
node.ColMap[*colConfig.Name] = colData
|
|
||||||
|
|
||||||
if navT := colConfig.NavTemplate; navT != nil {
|
|
||||||
var entries []interface{}
|
|
||||||
var ok bool
|
|
||||||
if navT.EntriesAttribute != "" {
|
|
||||||
var colDataMap map[string]interface{}
|
|
||||||
if colDataMap, ok = colData.(map[string]interface{}); ok {
|
|
||||||
entries, ok = colDataMap[navT.EntriesAttribute].([]interface{})
|
|
||||||
if !ok {
|
|
||||||
helper.Log.Debug(spew.Sdump(colDataMap))
|
|
||||||
helper.Log.Panicf("invalid json data in [%s] from url '%s' for entries", navT.EntriesAttribute, url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
entries, ok = colData.([]interface{})
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
helper.Log.Debug(spew.Sdump(colData))
|
|
||||||
helper.Log.Panicf("invalid json data from url '%s', need array of objects for entries or object with configured NavTemplate.EntriesAttribute", url)
|
|
||||||
}
|
|
||||||
|
|
||||||
// build navigation with detail sites
|
|
||||||
for idx, colEl := range entries {
|
|
||||||
ctxE := make(pongo2.Context)
|
|
||||||
err := helper.Merge(&ctxE, ctx)
|
|
||||||
if err != nil {
|
|
||||||
helper.Log.Panicf("could not merge context in '%s': %s", node.InputPath, err)
|
|
||||||
}
|
|
||||||
var jsonCtx map[string]interface{}
|
|
||||||
if jsonCtx, ok = colEl.(map[string]interface{}); !ok {
|
|
||||||
helper.Log.Debug(spew.Sdump(colEl))
|
|
||||||
helper.Log.Panicf("no json object for entry index %d from url '%s'", idx, url)
|
|
||||||
}
|
|
||||||
err = helper.Merge(&ctxE, pongo2.Context(jsonCtx))
|
|
||||||
if err != nil {
|
|
||||||
helper.Log.Panicf("could not merge context in '%s': %s", node.InputPath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tpl := ""
|
|
||||||
if navT.Template != "" {
|
|
||||||
tpl, err = pongo2.RenderTemplateString(navT.Template, ctxE)
|
|
||||||
if err != nil {
|
|
||||||
helper.Log.Panicf("invalid template string for NavTemplate.Template in '%s': %s", node.InputPath, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if tpl == "" {
|
|
||||||
tpl = *node.Config.Template
|
|
||||||
}
|
|
||||||
|
|
||||||
dataKey := ""
|
|
||||||
if navT.DataKey != "" {
|
|
||||||
dataKey, err = pongo2.RenderTemplateString(navT.DataKey, ctxE)
|
|
||||||
if err != nil {
|
|
||||||
helper.Log.Panicf("invalid template string for NavTemplate.DataKey in '%s': %s", node.InputPath, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
goTo, err := pongo2.RenderTemplateString(navT.GoTo, ctxE)
|
|
||||||
if err != nil {
|
|
||||||
helper.Log.Panicf("invalid template string for NavTemplate.GoTo in '%s': %s", node.InputPath, err)
|
|
||||||
}
|
|
||||||
goTo = strings.Trim(goTo, "/")
|
|
||||||
goTo = path.Clean(goTo)
|
|
||||||
|
|
||||||
if strings.Contains(goTo, "..") {
|
|
||||||
helper.Log.Panicf("going back via .. in NavTemplate.GoTo forbidden in collection config in '%s': %s", node.InputPath, goTo)
|
|
||||||
}
|
|
||||||
if goTo == "." {
|
|
||||||
helper.Log.Panicf("invalid config '.' for NavTemplate.GoTo in collection config in '%s'", node.InputPath)
|
|
||||||
}
|
|
||||||
if goTo == "" {
|
|
||||||
helper.Log.Panicf("missing NavTemplate.GoTo in collection config in '%s'", node.InputPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
navname := ""
|
|
||||||
if navT.Navname != "" {
|
|
||||||
navname, err = pongo2.RenderTemplateString(navT.Navname, ctxE)
|
|
||||||
if err != nil {
|
|
||||||
helper.Log.Panicf("invalid template string for NavTemplate.Navname in '%s': %s", node.InputPath, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
body := ""
|
|
||||||
if navT.Body != "" {
|
|
||||||
body, err = pongo2.RenderTemplateString(navT.Body, ctxE)
|
|
||||||
if err != nil {
|
|
||||||
helper.Log.Panicf("invalid template string for NavTemplate.Body in '%s': %s", node.InputPath, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
node.addSubNode(tpl, goTo, navname, colEl, dataKey, body, navT.Hidden)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (node *TreeNode) fillConfig(inBase, outBase, subDir string, conf *PathConfig) {
|
func (node *TreeNode) fillConfig(inBase, outBase, subDir string, conf *PathConfig) {
|
||||||
inPath := inBase
|
inPath := inBase
|
||||||
if subDir != "" {
|
if subDir != "" {
|
||||||
@ -229,28 +108,47 @@ func (node *TreeNode) fillConfig(inBase, outBase, subDir string, conf *PathConfi
|
|||||||
func (node *TreeNode) addSubNode(tplFilename, subDir string, navname string, ctx interface{}, dataMapKey string, body string, hideInNav bool) {
|
func (node *TreeNode) addSubNode(tplFilename, subDir string, navname string, ctx interface{}, dataMapKey string, body string, hideInNav bool) {
|
||||||
newNode := new(TreeNode)
|
newNode := new(TreeNode)
|
||||||
newNode.root = node.root
|
newNode.root = node.root
|
||||||
newNode.fillConfig(
|
|
||||||
node.InputPath,
|
newPathConfig := new(PathConfig)
|
||||||
node.OutputPath,
|
|
||||||
subDir,
|
|
||||||
node.Config,
|
|
||||||
)
|
|
||||||
if navname != "" {
|
if navname != "" {
|
||||||
newNode.Config.This = ThisPathConfig{
|
newPathConfig.This = ThisPathConfig{
|
||||||
Navname: &navname,
|
Navname: &navname,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if dataMapKey != "" {
|
if dataMapKey != "" {
|
||||||
if newNode.Config.Data == nil {
|
if newPathConfig.Data == nil {
|
||||||
newNode.Config.Data = make(helper.MapString)
|
newPathConfig.Data = make(helper.MapString)
|
||||||
}
|
}
|
||||||
// as submap in Data
|
// as submap in Data
|
||||||
newNode.Config.Data[dataMapKey] = ctx
|
newPathConfig.Data[dataMapKey] = ctx
|
||||||
} else if m, ok := ctx.(map[string]interface{}); ok {
|
} else if m, ok := ctx.(map[string]interface{}); ok {
|
||||||
// direct set data
|
// direct set data
|
||||||
newNode.Config.Data = m
|
newPathConfig.Data = m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mergedConfig := new(PathConfig)
|
||||||
|
err := helper.Merge(mergedConfig, node.Config)
|
||||||
|
if err != nil {
|
||||||
|
helper.Log.Panicf("merge of path config failed: %s", err)
|
||||||
|
}
|
||||||
|
// dont merge Data[DataKey]
|
||||||
|
if dataMapKey != "" {
|
||||||
|
mergedConfig.Data[dataMapKey] = nil
|
||||||
|
} else {
|
||||||
|
mergedConfig.Data = make(helper.MapString)
|
||||||
|
}
|
||||||
|
err = helper.Merge(mergedConfig, newPathConfig)
|
||||||
|
if err != nil {
|
||||||
|
helper.Log.Panicf("merge of path config failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
newNode.fillConfig(
|
||||||
|
node.InputPath,
|
||||||
|
node.OutputPath,
|
||||||
|
subDir,
|
||||||
|
mergedConfig,
|
||||||
|
)
|
||||||
|
|
||||||
// fake via normal file behavior
|
// fake via normal file behavior
|
||||||
newNode.Config.Template = &tplFilename
|
newNode.Config.Template = &tplFilename
|
||||||
newNode.InputFiles = []string{""} // empty file is special for use InputString
|
newNode.InputFiles = []string{""} // empty file is special for use InputString
|
||||||
|
67
pkg/mark2web/htaccess.go
Normal file
67
pkg/mark2web/htaccess.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package mark2web
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"gitbase.de/apairon/mark2web/pkg/helper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func htaccessRedirect(outDir, goTo string) {
|
||||||
|
switch Config.Webserver.Type {
|
||||||
|
case "apache":
|
||||||
|
htaccessFile := outDir + "/.htaccess"
|
||||||
|
helper.Log.Noticef("writing '%s' with redirect to: %s", htaccessFile, goTo)
|
||||||
|
err := ioutil.WriteFile(htaccessFile, []byte(`RewriteEngine on
|
||||||
|
RewriteRule ^$ %{REQUEST_URI}`+goTo+`/ [R,L]
|
||||||
|
`), 0644)
|
||||||
|
if err != nil {
|
||||||
|
helper.Log.Panicf("could not write '%s': %s", htaccessFile, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteWebserverConfig build the config for pre compression and more
|
||||||
|
func WriteWebserverConfig() {
|
||||||
|
switch Config.Webserver.Type {
|
||||||
|
case "apache":
|
||||||
|
configStr := `
|
||||||
|
AddCharset UTF-8 .html
|
||||||
|
AddCharset UTF-8 .json
|
||||||
|
AddCharset UTF-8 .js
|
||||||
|
AddCharset UTF-8 .css
|
||||||
|
|
||||||
|
RewriteEngine on
|
||||||
|
`
|
||||||
|
|
||||||
|
if Config.Compress.GZIP {
|
||||||
|
for ext, contentType := range Config.Compress.Extensions {
|
||||||
|
rExt := regexp.QuoteMeta(ext)
|
||||||
|
|
||||||
|
configStr += `
|
||||||
|
RewriteCond "%{HTTP:Accept-encoding}" "gzip"
|
||||||
|
RewriteCond "%{REQUEST_FILENAME}\.gz" -s
|
||||||
|
RewriteRule "^(.*)` + rExt + `" "$1` + rExt + `\.gz" [QSA]
|
||||||
|
|
||||||
|
RewriteRule "` + rExt + `\.gz$" "-" [E=no-gzip:1]
|
||||||
|
|
||||||
|
<FilesMatch "` + rExt + `\.gz$">
|
||||||
|
ForceType '` + contentType + `; charset=UTF-8'
|
||||||
|
Header append Content-Encoding gzip
|
||||||
|
Header append Vary Accept-Encoding
|
||||||
|
</FilesMatch>
|
||||||
|
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if configStr != "" {
|
||||||
|
htaccessFile := Config.Directories.Output + "/.htaccess"
|
||||||
|
helper.Log.Noticef("writing webserver config to: %s", htaccessFile)
|
||||||
|
err := ioutil.WriteFile(htaccessFile, []byte(configStr), 0644)
|
||||||
|
if err != nil {
|
||||||
|
helper.Log.Panicf("could not write '%s': %s", htaccessFile, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,5 +10,7 @@ func Run(inDir, outDir string, defaultPathConfig *PathConfig) {
|
|||||||
|
|
||||||
ProcessAssets()
|
ProcessAssets()
|
||||||
|
|
||||||
|
WriteWebserverConfig()
|
||||||
|
|
||||||
Wait()
|
Wait()
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ GET https://mark2web.basiscms.de/api/collections/get/mark2webBlog
|
|||||||
?sort[date]=-1
|
?sort[date]=-1
|
||||||
&limit=101
|
&limit=101
|
||||||
&token=985cee34099f4d3b08f18fc22f6296
|
&token=985cee34099f4d3b08f18fc22f6296
|
||||||
|
&filter[link][$exists]=0
|
||||||
|
|
||||||
###
|
###
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ Webserver:
|
|||||||
Type: "apache" # generates .htaccess
|
Type: "apache" # generates .htaccess
|
||||||
|
|
||||||
Assets:
|
Assets:
|
||||||
|
Compress: True
|
||||||
FromPath: "project-files"
|
FromPath: "project-files"
|
||||||
ToPath: "project-files"
|
ToPath: "project-files"
|
||||||
Action: "copy" # symlink, copy or move
|
Action: "copy" # symlink, copy or move
|
||||||
@ -12,3 +13,9 @@ Assets:
|
|||||||
OtherFiles:
|
OtherFiles:
|
||||||
Action: "copy"
|
Action: "copy"
|
||||||
|
|
||||||
|
Compress:
|
||||||
|
GZIP: True
|
||||||
|
Extensions:
|
||||||
|
.html: text/html
|
||||||
|
.css: text/css
|
||||||
|
.js: text/javascript
|
@ -1,7 +1,7 @@
|
|||||||
This:
|
#This:
|
||||||
Collections:
|
Collections:
|
||||||
- Name: blog1st
|
- Name: blog1st
|
||||||
URL: 'https://mark2web.basiscms.de/api/collections/get/mark2webBlog?token={{ Data.token }}&filter[published]=true&sort[date]=-1&skip=0&limit=1'
|
URL: 'https://mark2web.basiscms.de/api/collections/get/mark2webBlog?token={{ Data.token }}&filter[published]=true&sort[date]=-1&skip=0&limit=1{% if Data.details._id %}&filter[link._id]={{ Data.details._id }}{% else %}&filter[link][$exists]=0{% endif %}'
|
||||||
NavTemplate:
|
NavTemplate:
|
||||||
EntriesAttribute: entries
|
EntriesAttribute: entries
|
||||||
GoTo: '{{ date }}-{{ title }}'
|
GoTo: '{{ date }}-{{ title }}'
|
||||||
@ -12,7 +12,7 @@ This:
|
|||||||
Hidden: true # hide from nav, but use this feature for rendering detail sites
|
Hidden: true # hide from nav, but use this feature for rendering detail sites
|
||||||
|
|
||||||
- Name: blog1skip
|
- Name: blog1skip
|
||||||
URL: 'https://mark2web.basiscms.de/api/collections/get/mark2webBlog?token={{ Data.token }}&filter[published]=true&sort[date]=-1&skip=1&limit=100'
|
URL: 'https://mark2web.basiscms.de/api/collections/get/mark2webBlog?token={{ Data.token }}&filter[published]=true&sort[date]=-1&skip=1&limit=100{% if Data.details._id %}&filter[link._id]={{ Data.details._id }}{% else %}&filter[link][$exists]=0{% endif %}'
|
||||||
NavTemplate:
|
NavTemplate:
|
||||||
EntriesAttribute: entries
|
EntriesAttribute: entries
|
||||||
GoTo: '{{ date }}-{{ title }}'
|
GoTo: '{{ date }}-{{ title }}'
|
||||||
|
@ -169,8 +169,8 @@ label {font-weight:600;}
|
|||||||
#header {
|
#header {
|
||||||
position:absolute;
|
position:absolute;
|
||||||
top:50px;
|
top:50px;
|
||||||
left:150px;
|
left:0px;
|
||||||
right:150px;
|
right:0px;
|
||||||
height:auto;
|
height:auto;
|
||||||
z-index:300;
|
z-index:300;
|
||||||
background:none;
|
background:none;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
$('#preloader').fadeIn('fast');
|
$('#preloader').fadeIn('fast');
|
||||||
$(window).on('load', function() {
|
$(window).on('load', function() {
|
||||||
$('.spinner').fadeOut();
|
$('.spinner').fadeOut();
|
||||||
$('#preloader').delay(350).fadeOut('slow');
|
$('#preloader').delay(100).fadeOut('slow');
|
||||||
$('body').delay(350).css({'overflow':'visible'});
|
$('body').delay(100).css({'overflow':'visible'});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user