From b2e0d78a2c748132e41c06720bc226d0b07f788e Mon Sep 17 00:00:00 2001 From: Sebastian Frank Date: Mon, 18 Mar 2019 13:34:52 +0100 Subject: [PATCH] reorganized code --- {example => _example}/assets/css/main.css | 0 {example => _example}/assets/img/de.png | Bin {example => _example}/assets/img/en.png | Bin {example => _example}/assets/img/logo.png | Bin {example => _example}/config.yml | 0 {example => _example}/content/README.md | 0 {example => _example}/content/config.yml | 0 {example => _example}/content/de/config.yml | 0 .../content/de/main/01_home/README.md | 0 .../content/de/main/01_home/config.yml | 0 .../02_Leistungen und Referenzen/README.md | 0 .../02_Leistungen und Referenzen/bild.jpg | Bin .../de/main/03_kontakt/01_adresse/README.md | 0 .../de/main/03_kontakt/01_adresse/bild.jpg | Bin .../de/main/03_kontakt/01_adresse/config.yml | 0 .../de/main/03_kontakt/02_anfahrt/README.md | 0 .../content/de/main/03_kontakt/config.yml | 0 .../content/de/main/04_impressum/config.yml | 0 .../content/de/main/_zeug/links.md | 0 .../de/service/01_datenschutz/README.md | 0 .../content/de/service/02_agb/README.md | 0 .../content/de/service/03_impressum/README.md | 0 {example => _example}/content/en/config.yml | 0 .../content/en/main/01_home/README.md | 0 .../content/en/main/02_services/README.md | 0 .../content/en/main/03_contact/README.md | 0 .../content/en/main/04_imprint/config.yml | 0 .../content/en/service/01_terms/README.md | 0 .../content/en/service/02_imprint/README.md | 0 {example => _example}/templates/base.html | 0 .../templates/base_intro.html | 0 .../templates/base_multipart.html | 0 {website => _website}/config.yml | 0 {website => _website}/content/config.yml | 0 .../de/01_Navigation/01_mark2web/README.md | 0 .../01_Navigation/02_Installation/README.md | 0 .../de/01_Navigation/02_Installation/bild.jpg | Bin .../03_Benutzung/01_Ordnerstruktur/README.md | 0 .../03_Benutzung/01_Ordnerstruktur/config.yml | 0 .../03_Benutzung/02_Konfiguration/README.md | 0 .../03_Benutzung/02_Konfiguration/config.yml | 0 .../03_Benutzung/03_Inhalte/README.md | 0 .../03_Benutzung/03_Inhalte/config.yml | 0 .../03_Benutzung/04_Templates/README.md | 0 .../03_Benutzung/04_Templates/config.yml | 0 .../de/01_Navigation/03_Benutzung/config.yml | 0 .../de/01_Navigation/04_Blog/README.md | 0 .../de/01_Navigation/04_Blog/config.yml | 0 .../de/02_Rechtliches/01_Impressum/README.md | 0 .../02_Datenschutzerklärung/README.md | 0 {website => _website}/img/blog.jpg | Bin {website => _website}/img/coffee.jpg | Bin {website => _website}/img/design.jpg | Bin {website => _website}/img/desk.jpg | Bin {website => _website}/img/folder.jpg | Bin {website => _website}/img/gears.jpg | Bin {website => _website}/img/html.jpg | Bin {website => _website}/img/keyboard.jpg | Bin {website => _website}/img/laptop.jpg | Bin {website => _website}/img/laptop2.jpg | Bin {website => _website}/img/wire.jpg | Bin {website => _website}/img/write.jpg | Bin .../project-files/css/grid.css | 0 .../project-files/css/main.css | 0 .../project-files/css/menu.css | 0 .../project-files/css/preloader.css | 0 .../project-files/css/slider.css | 0 .../fonts/font-awesome/FontAwesome.otf | Bin .../fonts/font-awesome/font-awesome.css | 0 .../font-awesome/fontawesome-webfont.eot | Bin .../font-awesome/fontawesome-webfont.svg | 0 .../font-awesome/fontawesome-webfont.ttf | Bin .../font-awesome/fontawesome-webfont.woff | Bin .../font-awesome/fontawesome-webfont.woff2 | Bin .../project-files/img/favicon.ico | Bin .../project-files/img/logo.png | Bin .../project-files/img/logo_small.png | Bin .../project-files/img/logo_text.png | Bin .../project-files/js/functions.js | 0 .../project-files/js/preloader.js | 0 .../project-files/js/slick/ajax-loader.gif | Bin .../project-files/js/slick/fonts/slick.eot | Bin .../project-files/js/slick/fonts/slick.svg | 0 .../project-files/js/slick/fonts/slick.ttf | Bin .../project-files/js/slick/fonts/slick.woff | Bin .../project-files/js/slick/slick-custom.js | 0 .../project-files/js/slick/slick-theme.css | 0 .../project-files/js/slick/slick.css | 0 .../project-files/js/slick/slick.min.js | 0 {website => _website}/templates/base.html | 0 .../templates/base_blog.html | 0 .../templates/base_blog_details.html | 0 .../templates/filters/datum.js | 0 .../templates/filters/lib/strings.js | 0 .../templates/partials/matomo.html | 0 helper/assets.go => assets.go | 7 +- build.sh | 3 +- config/tree.go | 24 - content.go | 296 ++++++++++ context/context.go | 266 +++++++++ context/fn_render.go | 24 + context/fn_request.go | 12 + context/path.go | 39 ++ filter/custom.go | 73 +++ filter/dump.go | 12 + .../image_process.go | 161 +----- filter/init.go | 26 + filter/json.go | 35 ++ filter/markdown.go | 29 + filter/relative_path.go | 15 + helper/content.go | 514 ------------------ helper/dir.go | 16 +- helper/markdown.go | 29 + helper/merge.go | 28 + helper/render.go | 103 ---- helper/template_functions.go | 125 ----- helper/webrequest.go | 52 ++ main.go | 143 ----- helper/navigation.go => navigation.go | 9 +- render.go | 60 ++ 120 files changed, 1034 insertions(+), 1067 deletions(-) rename {example => _example}/assets/css/main.css (100%) rename {example => _example}/assets/img/de.png (100%) rename {example => _example}/assets/img/en.png (100%) rename {example => _example}/assets/img/logo.png (100%) rename {example => _example}/config.yml (100%) rename {example => _example}/content/README.md (100%) rename {example => _example}/content/config.yml (100%) rename {example => _example}/content/de/config.yml (100%) rename {example => _example}/content/de/main/01_home/README.md (100%) rename {example => _example}/content/de/main/01_home/config.yml (100%) rename {example => _example}/content/de/main/02_Leistungen und Referenzen/README.md (100%) rename {example => _example}/content/de/main/02_Leistungen und Referenzen/bild.jpg (100%) rename {example => _example}/content/de/main/03_kontakt/01_adresse/README.md (100%) rename {example => _example}/content/de/main/03_kontakt/01_adresse/bild.jpg (100%) rename {example => _example}/content/de/main/03_kontakt/01_adresse/config.yml (100%) rename {example => _example}/content/de/main/03_kontakt/02_anfahrt/README.md (100%) rename {example => _example}/content/de/main/03_kontakt/config.yml (100%) rename {example => _example}/content/de/main/04_impressum/config.yml (100%) rename {example => _example}/content/de/main/_zeug/links.md (100%) rename {example => _example}/content/de/service/01_datenschutz/README.md (100%) rename {example => _example}/content/de/service/02_agb/README.md (100%) rename {example => _example}/content/de/service/03_impressum/README.md (100%) rename {example => _example}/content/en/config.yml (100%) rename {example => _example}/content/en/main/01_home/README.md (100%) rename {example => _example}/content/en/main/02_services/README.md (100%) rename {example => _example}/content/en/main/03_contact/README.md (100%) rename {example => _example}/content/en/main/04_imprint/config.yml (100%) rename {example => _example}/content/en/service/01_terms/README.md (100%) rename {example => _example}/content/en/service/02_imprint/README.md (100%) rename {example => _example}/templates/base.html (100%) rename {example => _example}/templates/base_intro.html (100%) rename {example => _example}/templates/base_multipart.html (100%) rename {website => _website}/config.yml (100%) rename {website => _website}/content/config.yml (100%) rename {website => _website}/content/de/01_Navigation/01_mark2web/README.md (100%) rename {website => _website}/content/de/01_Navigation/02_Installation/README.md (100%) rename {website => _website}/content/de/01_Navigation/02_Installation/bild.jpg (100%) rename {website => _website}/content/de/01_Navigation/03_Benutzung/01_Ordnerstruktur/README.md (100%) rename {website => _website}/content/de/01_Navigation/03_Benutzung/01_Ordnerstruktur/config.yml (100%) rename {website => _website}/content/de/01_Navigation/03_Benutzung/02_Konfiguration/README.md (100%) rename {website => _website}/content/de/01_Navigation/03_Benutzung/02_Konfiguration/config.yml (100%) rename {website => _website}/content/de/01_Navigation/03_Benutzung/03_Inhalte/README.md (100%) rename {website => _website}/content/de/01_Navigation/03_Benutzung/03_Inhalte/config.yml (100%) rename {website => _website}/content/de/01_Navigation/03_Benutzung/04_Templates/README.md (100%) rename {website => _website}/content/de/01_Navigation/03_Benutzung/04_Templates/config.yml (100%) rename {website => _website}/content/de/01_Navigation/03_Benutzung/config.yml (100%) rename {website => _website}/content/de/01_Navigation/04_Blog/README.md (100%) rename {website => _website}/content/de/01_Navigation/04_Blog/config.yml (100%) rename {website => _website}/content/de/02_Rechtliches/01_Impressum/README.md (100%) rename {website => _website}/content/de/02_Rechtliches/02_Datenschutzerklärung/README.md (100%) rename {website => _website}/img/blog.jpg (100%) rename {website => _website}/img/coffee.jpg (100%) rename {website => _website}/img/design.jpg (100%) rename {website => _website}/img/desk.jpg (100%) rename {website => _website}/img/folder.jpg (100%) rename {website => _website}/img/gears.jpg (100%) rename {website => _website}/img/html.jpg (100%) rename {website => _website}/img/keyboard.jpg (100%) rename {website => _website}/img/laptop.jpg (100%) rename {website => _website}/img/laptop2.jpg (100%) rename {website => _website}/img/wire.jpg (100%) rename {website => _website}/img/write.jpg (100%) rename {website => _website}/project-files/css/grid.css (100%) rename {website => _website}/project-files/css/main.css (100%) rename {website => _website}/project-files/css/menu.css (100%) rename {website => _website}/project-files/css/preloader.css (100%) rename {website => _website}/project-files/css/slider.css (100%) rename {website => _website}/project-files/fonts/font-awesome/FontAwesome.otf (100%) rename {website => _website}/project-files/fonts/font-awesome/font-awesome.css (100%) rename {website => _website}/project-files/fonts/font-awesome/fontawesome-webfont.eot (100%) rename {website => _website}/project-files/fonts/font-awesome/fontawesome-webfont.svg (100%) rename {website => _website}/project-files/fonts/font-awesome/fontawesome-webfont.ttf (100%) rename {website => _website}/project-files/fonts/font-awesome/fontawesome-webfont.woff (100%) rename {website => _website}/project-files/fonts/font-awesome/fontawesome-webfont.woff2 (100%) rename {website => _website}/project-files/img/favicon.ico (100%) rename {website => _website}/project-files/img/logo.png (100%) rename {website => _website}/project-files/img/logo_small.png (100%) rename {website => _website}/project-files/img/logo_text.png (100%) rename {website => _website}/project-files/js/functions.js (100%) rename {website => _website}/project-files/js/preloader.js (100%) rename {website => _website}/project-files/js/slick/ajax-loader.gif (100%) rename {website => _website}/project-files/js/slick/fonts/slick.eot (100%) rename {website => _website}/project-files/js/slick/fonts/slick.svg (100%) rename {website => _website}/project-files/js/slick/fonts/slick.ttf (100%) rename {website => _website}/project-files/js/slick/fonts/slick.woff (100%) rename {website => _website}/project-files/js/slick/slick-custom.js (100%) rename {website => _website}/project-files/js/slick/slick-theme.css (100%) rename {website => _website}/project-files/js/slick/slick.css (100%) rename {website => _website}/project-files/js/slick/slick.min.js (100%) rename {website => _website}/templates/base.html (100%) rename {website => _website}/templates/base_blog.html (100%) rename {website => _website}/templates/base_blog_details.html (100%) rename {website => _website}/templates/filters/datum.js (100%) rename {website => _website}/templates/filters/lib/strings.js (100%) rename {website => _website}/templates/partials/matomo.html (100%) rename helper/assets.go => assets.go (72%) create mode 100644 content.go create mode 100644 context/context.go create mode 100644 context/fn_render.go create mode 100644 context/fn_request.go create mode 100644 context/path.go create mode 100644 filter/custom.go create mode 100644 filter/dump.go rename helper/template_filters.go => filter/image_process.go (56%) create mode 100644 filter/init.go create mode 100644 filter/json.go create mode 100644 filter/markdown.go create mode 100644 filter/relative_path.go delete mode 100644 helper/content.go create mode 100644 helper/markdown.go create mode 100644 helper/merge.go delete mode 100644 helper/render.go delete mode 100644 helper/template_functions.go create mode 100644 helper/webrequest.go delete mode 100644 main.go rename helper/navigation.go => navigation.go (88%) create mode 100644 render.go diff --git a/example/assets/css/main.css b/_example/assets/css/main.css similarity index 100% rename from example/assets/css/main.css rename to _example/assets/css/main.css diff --git a/example/assets/img/de.png b/_example/assets/img/de.png similarity index 100% rename from example/assets/img/de.png rename to _example/assets/img/de.png diff --git a/example/assets/img/en.png b/_example/assets/img/en.png similarity index 100% rename from example/assets/img/en.png rename to _example/assets/img/en.png diff --git a/example/assets/img/logo.png b/_example/assets/img/logo.png similarity index 100% rename from example/assets/img/logo.png rename to _example/assets/img/logo.png diff --git a/example/config.yml b/_example/config.yml similarity index 100% rename from example/config.yml rename to _example/config.yml diff --git a/example/content/README.md b/_example/content/README.md similarity index 100% rename from example/content/README.md rename to _example/content/README.md diff --git a/example/content/config.yml b/_example/content/config.yml similarity index 100% rename from example/content/config.yml rename to _example/content/config.yml diff --git a/example/content/de/config.yml b/_example/content/de/config.yml similarity index 100% rename from example/content/de/config.yml rename to _example/content/de/config.yml diff --git a/example/content/de/main/01_home/README.md b/_example/content/de/main/01_home/README.md similarity index 100% rename from example/content/de/main/01_home/README.md rename to _example/content/de/main/01_home/README.md diff --git a/example/content/de/main/01_home/config.yml b/_example/content/de/main/01_home/config.yml similarity index 100% rename from example/content/de/main/01_home/config.yml rename to _example/content/de/main/01_home/config.yml diff --git a/example/content/de/main/02_Leistungen und Referenzen/README.md b/_example/content/de/main/02_Leistungen und Referenzen/README.md similarity index 100% rename from example/content/de/main/02_Leistungen und Referenzen/README.md rename to _example/content/de/main/02_Leistungen und Referenzen/README.md diff --git a/example/content/de/main/02_Leistungen und Referenzen/bild.jpg b/_example/content/de/main/02_Leistungen und Referenzen/bild.jpg similarity index 100% rename from example/content/de/main/02_Leistungen und Referenzen/bild.jpg rename to _example/content/de/main/02_Leistungen und Referenzen/bild.jpg diff --git a/example/content/de/main/03_kontakt/01_adresse/README.md b/_example/content/de/main/03_kontakt/01_adresse/README.md similarity index 100% rename from example/content/de/main/03_kontakt/01_adresse/README.md rename to _example/content/de/main/03_kontakt/01_adresse/README.md diff --git a/example/content/de/main/03_kontakt/01_adresse/bild.jpg b/_example/content/de/main/03_kontakt/01_adresse/bild.jpg similarity index 100% rename from example/content/de/main/03_kontakt/01_adresse/bild.jpg rename to _example/content/de/main/03_kontakt/01_adresse/bild.jpg diff --git a/example/content/de/main/03_kontakt/01_adresse/config.yml b/_example/content/de/main/03_kontakt/01_adresse/config.yml similarity index 100% rename from example/content/de/main/03_kontakt/01_adresse/config.yml rename to _example/content/de/main/03_kontakt/01_adresse/config.yml diff --git a/example/content/de/main/03_kontakt/02_anfahrt/README.md b/_example/content/de/main/03_kontakt/02_anfahrt/README.md similarity index 100% rename from example/content/de/main/03_kontakt/02_anfahrt/README.md rename to _example/content/de/main/03_kontakt/02_anfahrt/README.md diff --git a/example/content/de/main/03_kontakt/config.yml b/_example/content/de/main/03_kontakt/config.yml similarity index 100% rename from example/content/de/main/03_kontakt/config.yml rename to _example/content/de/main/03_kontakt/config.yml diff --git a/example/content/de/main/04_impressum/config.yml b/_example/content/de/main/04_impressum/config.yml similarity index 100% rename from example/content/de/main/04_impressum/config.yml rename to _example/content/de/main/04_impressum/config.yml diff --git a/example/content/de/main/_zeug/links.md b/_example/content/de/main/_zeug/links.md similarity index 100% rename from example/content/de/main/_zeug/links.md rename to _example/content/de/main/_zeug/links.md diff --git a/example/content/de/service/01_datenschutz/README.md b/_example/content/de/service/01_datenschutz/README.md similarity index 100% rename from example/content/de/service/01_datenschutz/README.md rename to _example/content/de/service/01_datenschutz/README.md diff --git a/example/content/de/service/02_agb/README.md b/_example/content/de/service/02_agb/README.md similarity index 100% rename from example/content/de/service/02_agb/README.md rename to _example/content/de/service/02_agb/README.md diff --git a/example/content/de/service/03_impressum/README.md b/_example/content/de/service/03_impressum/README.md similarity index 100% rename from example/content/de/service/03_impressum/README.md rename to _example/content/de/service/03_impressum/README.md diff --git a/example/content/en/config.yml b/_example/content/en/config.yml similarity index 100% rename from example/content/en/config.yml rename to _example/content/en/config.yml diff --git a/example/content/en/main/01_home/README.md b/_example/content/en/main/01_home/README.md similarity index 100% rename from example/content/en/main/01_home/README.md rename to _example/content/en/main/01_home/README.md diff --git a/example/content/en/main/02_services/README.md b/_example/content/en/main/02_services/README.md similarity index 100% rename from example/content/en/main/02_services/README.md rename to _example/content/en/main/02_services/README.md diff --git a/example/content/en/main/03_contact/README.md b/_example/content/en/main/03_contact/README.md similarity index 100% rename from example/content/en/main/03_contact/README.md rename to _example/content/en/main/03_contact/README.md diff --git a/example/content/en/main/04_imprint/config.yml b/_example/content/en/main/04_imprint/config.yml similarity index 100% rename from example/content/en/main/04_imprint/config.yml rename to _example/content/en/main/04_imprint/config.yml diff --git a/example/content/en/service/01_terms/README.md b/_example/content/en/service/01_terms/README.md similarity index 100% rename from example/content/en/service/01_terms/README.md rename to _example/content/en/service/01_terms/README.md diff --git a/example/content/en/service/02_imprint/README.md b/_example/content/en/service/02_imprint/README.md similarity index 100% rename from example/content/en/service/02_imprint/README.md rename to _example/content/en/service/02_imprint/README.md diff --git a/example/templates/base.html b/_example/templates/base.html similarity index 100% rename from example/templates/base.html rename to _example/templates/base.html diff --git a/example/templates/base_intro.html b/_example/templates/base_intro.html similarity index 100% rename from example/templates/base_intro.html rename to _example/templates/base_intro.html diff --git a/example/templates/base_multipart.html b/_example/templates/base_multipart.html similarity index 100% rename from example/templates/base_multipart.html rename to _example/templates/base_multipart.html diff --git a/website/config.yml b/_website/config.yml similarity index 100% rename from website/config.yml rename to _website/config.yml diff --git a/website/content/config.yml b/_website/content/config.yml similarity index 100% rename from website/content/config.yml rename to _website/content/config.yml diff --git a/website/content/de/01_Navigation/01_mark2web/README.md b/_website/content/de/01_Navigation/01_mark2web/README.md similarity index 100% rename from website/content/de/01_Navigation/01_mark2web/README.md rename to _website/content/de/01_Navigation/01_mark2web/README.md diff --git a/website/content/de/01_Navigation/02_Installation/README.md b/_website/content/de/01_Navigation/02_Installation/README.md similarity index 100% rename from website/content/de/01_Navigation/02_Installation/README.md rename to _website/content/de/01_Navigation/02_Installation/README.md diff --git a/website/content/de/01_Navigation/02_Installation/bild.jpg b/_website/content/de/01_Navigation/02_Installation/bild.jpg similarity index 100% rename from website/content/de/01_Navigation/02_Installation/bild.jpg rename to _website/content/de/01_Navigation/02_Installation/bild.jpg diff --git a/website/content/de/01_Navigation/03_Benutzung/01_Ordnerstruktur/README.md b/_website/content/de/01_Navigation/03_Benutzung/01_Ordnerstruktur/README.md similarity index 100% rename from website/content/de/01_Navigation/03_Benutzung/01_Ordnerstruktur/README.md rename to _website/content/de/01_Navigation/03_Benutzung/01_Ordnerstruktur/README.md diff --git a/website/content/de/01_Navigation/03_Benutzung/01_Ordnerstruktur/config.yml b/_website/content/de/01_Navigation/03_Benutzung/01_Ordnerstruktur/config.yml similarity index 100% rename from website/content/de/01_Navigation/03_Benutzung/01_Ordnerstruktur/config.yml rename to _website/content/de/01_Navigation/03_Benutzung/01_Ordnerstruktur/config.yml diff --git a/website/content/de/01_Navigation/03_Benutzung/02_Konfiguration/README.md b/_website/content/de/01_Navigation/03_Benutzung/02_Konfiguration/README.md similarity index 100% rename from website/content/de/01_Navigation/03_Benutzung/02_Konfiguration/README.md rename to _website/content/de/01_Navigation/03_Benutzung/02_Konfiguration/README.md diff --git a/website/content/de/01_Navigation/03_Benutzung/02_Konfiguration/config.yml b/_website/content/de/01_Navigation/03_Benutzung/02_Konfiguration/config.yml similarity index 100% rename from website/content/de/01_Navigation/03_Benutzung/02_Konfiguration/config.yml rename to _website/content/de/01_Navigation/03_Benutzung/02_Konfiguration/config.yml diff --git a/website/content/de/01_Navigation/03_Benutzung/03_Inhalte/README.md b/_website/content/de/01_Navigation/03_Benutzung/03_Inhalte/README.md similarity index 100% rename from website/content/de/01_Navigation/03_Benutzung/03_Inhalte/README.md rename to _website/content/de/01_Navigation/03_Benutzung/03_Inhalte/README.md diff --git a/website/content/de/01_Navigation/03_Benutzung/03_Inhalte/config.yml b/_website/content/de/01_Navigation/03_Benutzung/03_Inhalte/config.yml similarity index 100% rename from website/content/de/01_Navigation/03_Benutzung/03_Inhalte/config.yml rename to _website/content/de/01_Navigation/03_Benutzung/03_Inhalte/config.yml diff --git a/website/content/de/01_Navigation/03_Benutzung/04_Templates/README.md b/_website/content/de/01_Navigation/03_Benutzung/04_Templates/README.md similarity index 100% rename from website/content/de/01_Navigation/03_Benutzung/04_Templates/README.md rename to _website/content/de/01_Navigation/03_Benutzung/04_Templates/README.md diff --git a/website/content/de/01_Navigation/03_Benutzung/04_Templates/config.yml b/_website/content/de/01_Navigation/03_Benutzung/04_Templates/config.yml similarity index 100% rename from website/content/de/01_Navigation/03_Benutzung/04_Templates/config.yml rename to _website/content/de/01_Navigation/03_Benutzung/04_Templates/config.yml diff --git a/website/content/de/01_Navigation/03_Benutzung/config.yml b/_website/content/de/01_Navigation/03_Benutzung/config.yml similarity index 100% rename from website/content/de/01_Navigation/03_Benutzung/config.yml rename to _website/content/de/01_Navigation/03_Benutzung/config.yml diff --git a/website/content/de/01_Navigation/04_Blog/README.md b/_website/content/de/01_Navigation/04_Blog/README.md similarity index 100% rename from website/content/de/01_Navigation/04_Blog/README.md rename to _website/content/de/01_Navigation/04_Blog/README.md diff --git a/website/content/de/01_Navigation/04_Blog/config.yml b/_website/content/de/01_Navigation/04_Blog/config.yml similarity index 100% rename from website/content/de/01_Navigation/04_Blog/config.yml rename to _website/content/de/01_Navigation/04_Blog/config.yml diff --git a/website/content/de/02_Rechtliches/01_Impressum/README.md b/_website/content/de/02_Rechtliches/01_Impressum/README.md similarity index 100% rename from website/content/de/02_Rechtliches/01_Impressum/README.md rename to _website/content/de/02_Rechtliches/01_Impressum/README.md diff --git a/website/content/de/02_Rechtliches/02_Datenschutzerklärung/README.md b/_website/content/de/02_Rechtliches/02_Datenschutzerklärung/README.md similarity index 100% rename from website/content/de/02_Rechtliches/02_Datenschutzerklärung/README.md rename to _website/content/de/02_Rechtliches/02_Datenschutzerklärung/README.md diff --git a/website/img/blog.jpg b/_website/img/blog.jpg similarity index 100% rename from website/img/blog.jpg rename to _website/img/blog.jpg diff --git a/website/img/coffee.jpg b/_website/img/coffee.jpg similarity index 100% rename from website/img/coffee.jpg rename to _website/img/coffee.jpg diff --git a/website/img/design.jpg b/_website/img/design.jpg similarity index 100% rename from website/img/design.jpg rename to _website/img/design.jpg diff --git a/website/img/desk.jpg b/_website/img/desk.jpg similarity index 100% rename from website/img/desk.jpg rename to _website/img/desk.jpg diff --git a/website/img/folder.jpg b/_website/img/folder.jpg similarity index 100% rename from website/img/folder.jpg rename to _website/img/folder.jpg diff --git a/website/img/gears.jpg b/_website/img/gears.jpg similarity index 100% rename from website/img/gears.jpg rename to _website/img/gears.jpg diff --git a/website/img/html.jpg b/_website/img/html.jpg similarity index 100% rename from website/img/html.jpg rename to _website/img/html.jpg diff --git a/website/img/keyboard.jpg b/_website/img/keyboard.jpg similarity index 100% rename from website/img/keyboard.jpg rename to _website/img/keyboard.jpg diff --git a/website/img/laptop.jpg b/_website/img/laptop.jpg similarity index 100% rename from website/img/laptop.jpg rename to _website/img/laptop.jpg diff --git a/website/img/laptop2.jpg b/_website/img/laptop2.jpg similarity index 100% rename from website/img/laptop2.jpg rename to _website/img/laptop2.jpg diff --git a/website/img/wire.jpg b/_website/img/wire.jpg similarity index 100% rename from website/img/wire.jpg rename to _website/img/wire.jpg diff --git a/website/img/write.jpg b/_website/img/write.jpg similarity index 100% rename from website/img/write.jpg rename to _website/img/write.jpg diff --git a/website/project-files/css/grid.css b/_website/project-files/css/grid.css similarity index 100% rename from website/project-files/css/grid.css rename to _website/project-files/css/grid.css diff --git a/website/project-files/css/main.css b/_website/project-files/css/main.css similarity index 100% rename from website/project-files/css/main.css rename to _website/project-files/css/main.css diff --git a/website/project-files/css/menu.css b/_website/project-files/css/menu.css similarity index 100% rename from website/project-files/css/menu.css rename to _website/project-files/css/menu.css diff --git a/website/project-files/css/preloader.css b/_website/project-files/css/preloader.css similarity index 100% rename from website/project-files/css/preloader.css rename to _website/project-files/css/preloader.css diff --git a/website/project-files/css/slider.css b/_website/project-files/css/slider.css similarity index 100% rename from website/project-files/css/slider.css rename to _website/project-files/css/slider.css diff --git a/website/project-files/fonts/font-awesome/FontAwesome.otf b/_website/project-files/fonts/font-awesome/FontAwesome.otf similarity index 100% rename from website/project-files/fonts/font-awesome/FontAwesome.otf rename to _website/project-files/fonts/font-awesome/FontAwesome.otf diff --git a/website/project-files/fonts/font-awesome/font-awesome.css b/_website/project-files/fonts/font-awesome/font-awesome.css similarity index 100% rename from website/project-files/fonts/font-awesome/font-awesome.css rename to _website/project-files/fonts/font-awesome/font-awesome.css diff --git a/website/project-files/fonts/font-awesome/fontawesome-webfont.eot b/_website/project-files/fonts/font-awesome/fontawesome-webfont.eot similarity index 100% rename from website/project-files/fonts/font-awesome/fontawesome-webfont.eot rename to _website/project-files/fonts/font-awesome/fontawesome-webfont.eot diff --git a/website/project-files/fonts/font-awesome/fontawesome-webfont.svg b/_website/project-files/fonts/font-awesome/fontawesome-webfont.svg similarity index 100% rename from website/project-files/fonts/font-awesome/fontawesome-webfont.svg rename to _website/project-files/fonts/font-awesome/fontawesome-webfont.svg diff --git a/website/project-files/fonts/font-awesome/fontawesome-webfont.ttf b/_website/project-files/fonts/font-awesome/fontawesome-webfont.ttf similarity index 100% rename from website/project-files/fonts/font-awesome/fontawesome-webfont.ttf rename to _website/project-files/fonts/font-awesome/fontawesome-webfont.ttf diff --git a/website/project-files/fonts/font-awesome/fontawesome-webfont.woff b/_website/project-files/fonts/font-awesome/fontawesome-webfont.woff similarity index 100% rename from website/project-files/fonts/font-awesome/fontawesome-webfont.woff rename to _website/project-files/fonts/font-awesome/fontawesome-webfont.woff diff --git a/website/project-files/fonts/font-awesome/fontawesome-webfont.woff2 b/_website/project-files/fonts/font-awesome/fontawesome-webfont.woff2 similarity index 100% rename from website/project-files/fonts/font-awesome/fontawesome-webfont.woff2 rename to _website/project-files/fonts/font-awesome/fontawesome-webfont.woff2 diff --git a/website/project-files/img/favicon.ico b/_website/project-files/img/favicon.ico similarity index 100% rename from website/project-files/img/favicon.ico rename to _website/project-files/img/favicon.ico diff --git a/website/project-files/img/logo.png b/_website/project-files/img/logo.png similarity index 100% rename from website/project-files/img/logo.png rename to _website/project-files/img/logo.png diff --git a/website/project-files/img/logo_small.png b/_website/project-files/img/logo_small.png similarity index 100% rename from website/project-files/img/logo_small.png rename to _website/project-files/img/logo_small.png diff --git a/website/project-files/img/logo_text.png b/_website/project-files/img/logo_text.png similarity index 100% rename from website/project-files/img/logo_text.png rename to _website/project-files/img/logo_text.png diff --git a/website/project-files/js/functions.js b/_website/project-files/js/functions.js similarity index 100% rename from website/project-files/js/functions.js rename to _website/project-files/js/functions.js diff --git a/website/project-files/js/preloader.js b/_website/project-files/js/preloader.js similarity index 100% rename from website/project-files/js/preloader.js rename to _website/project-files/js/preloader.js diff --git a/website/project-files/js/slick/ajax-loader.gif b/_website/project-files/js/slick/ajax-loader.gif similarity index 100% rename from website/project-files/js/slick/ajax-loader.gif rename to _website/project-files/js/slick/ajax-loader.gif diff --git a/website/project-files/js/slick/fonts/slick.eot b/_website/project-files/js/slick/fonts/slick.eot similarity index 100% rename from website/project-files/js/slick/fonts/slick.eot rename to _website/project-files/js/slick/fonts/slick.eot diff --git a/website/project-files/js/slick/fonts/slick.svg b/_website/project-files/js/slick/fonts/slick.svg similarity index 100% rename from website/project-files/js/slick/fonts/slick.svg rename to _website/project-files/js/slick/fonts/slick.svg diff --git a/website/project-files/js/slick/fonts/slick.ttf b/_website/project-files/js/slick/fonts/slick.ttf similarity index 100% rename from website/project-files/js/slick/fonts/slick.ttf rename to _website/project-files/js/slick/fonts/slick.ttf diff --git a/website/project-files/js/slick/fonts/slick.woff b/_website/project-files/js/slick/fonts/slick.woff similarity index 100% rename from website/project-files/js/slick/fonts/slick.woff rename to _website/project-files/js/slick/fonts/slick.woff diff --git a/website/project-files/js/slick/slick-custom.js b/_website/project-files/js/slick/slick-custom.js similarity index 100% rename from website/project-files/js/slick/slick-custom.js rename to _website/project-files/js/slick/slick-custom.js diff --git a/website/project-files/js/slick/slick-theme.css b/_website/project-files/js/slick/slick-theme.css similarity index 100% rename from website/project-files/js/slick/slick-theme.css rename to _website/project-files/js/slick/slick-theme.css diff --git a/website/project-files/js/slick/slick.css b/_website/project-files/js/slick/slick.css similarity index 100% rename from website/project-files/js/slick/slick.css rename to _website/project-files/js/slick/slick.css diff --git a/website/project-files/js/slick/slick.min.js b/_website/project-files/js/slick/slick.min.js similarity index 100% rename from website/project-files/js/slick/slick.min.js rename to _website/project-files/js/slick/slick.min.js diff --git a/website/templates/base.html b/_website/templates/base.html similarity index 100% rename from website/templates/base.html rename to _website/templates/base.html diff --git a/website/templates/base_blog.html b/_website/templates/base_blog.html similarity index 100% rename from website/templates/base_blog.html rename to _website/templates/base_blog.html diff --git a/website/templates/base_blog_details.html b/_website/templates/base_blog_details.html similarity index 100% rename from website/templates/base_blog_details.html rename to _website/templates/base_blog_details.html diff --git a/website/templates/filters/datum.js b/_website/templates/filters/datum.js similarity index 100% rename from website/templates/filters/datum.js rename to _website/templates/filters/datum.js diff --git a/website/templates/filters/lib/strings.js b/_website/templates/filters/lib/strings.js similarity index 100% rename from website/templates/filters/lib/strings.js rename to _website/templates/filters/lib/strings.js diff --git a/website/templates/partials/matomo.html b/_website/templates/partials/matomo.html similarity index 100% rename from website/templates/partials/matomo.html rename to _website/templates/partials/matomo.html diff --git a/helper/assets.go b/assets.go similarity index 72% rename from helper/assets.go rename to assets.go index 541cebf..64675c3 100644 --- a/helper/assets.go +++ b/assets.go @@ -1,9 +1,10 @@ -package helper +package mark2web import ( "strings" "gitbase.de/apairon/mark2web/config" + "gitbase.de/apairon/mark2web/helper" cpy "github.com/otiai10/copy" ) @@ -19,10 +20,10 @@ func ProcessAssets() { if !strings.HasPrefix(to, "/") { to = config.Config.Directories.Output + "/" + to } - Log.Noticef("copying assets from '%s' to '%s'", from, to) + helper.Log.Noticef("copying assets from '%s' to '%s'", from, to) err := cpy.Copy(from, to) if err != nil { - 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) } } } diff --git a/build.sh b/build.sh index 0b99f38..df18b1e 100755 --- a/build.sh +++ b/build.sh @@ -1,4 +1,5 @@ #!/bin/sh mkdir -p dist -go build -v -ldflags "-X main.Version=`git describe --tags --long` -X main.GitHash=`git rev-parse HEAD` -X main.BuildTime=`date -u '+%Y-%m-%d_%I:%M:%S%p'`" -o dist/mark2web-`cat VERSION`-${GOOS}-${GOARCH}${FILEEXT} +go build -v -ldflags "-X main.Version=`git describe --tags --long` -X main.GitHash=`git rev-parse HEAD` -X main.BuildTime=`date -u '+%Y-%m-%d_%I:%M:%S%p'`" -o dist/mark2web-`cat VERSION`-${GOOS}-${GOARCH}${FILEEXT} mark2web/main.go + diff --git a/config/tree.go b/config/tree.go index 3ccdfe7..02e577b 100644 --- a/config/tree.go +++ b/config/tree.go @@ -2,9 +2,6 @@ package config import ( "fmt" - "reflect" - - "github.com/imdario/mergo" ) // MapString is a map[string]interface{} which always unmarsahls yaml to map[string]interface{} @@ -149,24 +146,3 @@ type PathConfigTree struct { 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/content.go b/content.go new file mode 100644 index 0000000..36d97cf --- /dev/null +++ b/content.go @@ -0,0 +1,296 @@ +package mark2web + +import ( + "bytes" + "io/ioutil" + "path" + "regexp" + "strings" + + "gitbase.de/apairon/mark2web/config" + "gitbase.de/apairon/mark2web/context" + "gitbase.de/apairon/mark2web/helper" + "github.com/davecgh/go-spew/spew" + "github.com/flosch/pongo2" + cpy "github.com/otiai10/copy" + "gopkg.in/yaml.v2" +) + +// ReadContentDir walks through content directory and builds the tree of configurations +func ReadContentDir(inBase string, outBase string, dir string, conf *config.PathConfig, tree *config.PathConfigTree) { + context.FillNodeConfig(tree, inBase, outBase, dir, conf) + + files, err := ioutil.ReadDir(tree.InputPath) + if err != nil { + helper.Log.Panic(err) + } + + // first only files + for _, f := range files { + p := tree.InputPath + "/" + f.Name() + if !f.IsDir() && f.Name() != "config.yml" { + switch path.Ext(f.Name()) { + case ".md": + helper.Log.Debugf(".MD %s", p) + if tree.InputFiles == nil { + tree.InputFiles = make([]string, 0) + } + tree.InputFiles = append(tree.InputFiles, f.Name()) + break + default: + helper.Log.Debugf("FIL %s", p) + if tree.OtherFiles == nil { + tree.OtherFiles = make([]string, 0) + } + tree.OtherFiles = append(tree.OtherFiles, f.Name()) + } + } + } + + // only directorys, needed config before + for _, f := range files { + p := tree.InputPath + "/" + f.Name() + if f.IsDir() { + helper.Log.Debugf("DIR %s", p) + newTree := new(config.PathConfigTree) + if tree.Sub == nil { + tree.Sub = make([]*config.PathConfigTree, 0) + } + tree.Sub = append(tree.Sub, newTree) + ReadContentDir(tree.InputPath, tree.OutputPath, f.Name(), tree.Config, newTree) + } + } +} + +// ProcessContent walks recursivly through the input paths and processes all files for output +func ProcessContent(rootConf, conf *config.PathConfigTree) { + helper.CreateDirectory(conf.OutputPath) + + curNavPath := strings.TrimPrefix(conf.OutputPath, config.Config.Directories.Output) + curNavPath = strings.TrimPrefix(curNavPath, "/") + curNavPath = path.Clean(curNavPath) + if curNavPath == "." { + curNavPath = "" + } + + goTo := conf.Config.This.GoTo + if goTo != nil && *goTo != "" { + goToFixed := *goTo + if strings.HasPrefix(goToFixed, "/") { + goToFixed = helper.BackToRoot(curNavPath) + goToFixed + } + goToFixed = path.Clean(goToFixed) + + switch config.Config.Webserver.Type { + case "apache": + htaccessFile := conf.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 conf.InputFiles { + var input []byte + inFile := "InputString" + + if file != "" { + inFile = conf.InputPath + "/" + file + helper.Log.Debugf("reading file: %s", inFile) + + var err error + input, err = ioutil.ReadFile(inFile) + if err != nil { + helper.Log.Panicf("could not read '%s':%s", inFile, err) + } + helper.Log.Infof("processing input file '%s'", inFile) + } else { + // use input string if available and input filename == "" + var inputString *string + if i := conf.Config.Index; i != nil { + inputString = i.InputString + } + if inputString != nil { + helper.Log.Debugf("using input string instead of file") + input = []byte(*inputString) + } + } + + newConfig := new(config.PathConfig) + + regex := regexp.MustCompile("(?s)^---(.*?)\\r?\\n\\r?---\\r?\\n\\r?") + yamlData := regex.Find(input) + if string(yamlData) != "" { + // replace tabs + yamlData = bytes.Replace(yamlData, []byte("\t"), []byte(" "), -1) + + helper.Log.Debugf("found yaml header in '%s', merging config", inFile) + err := yaml.Unmarshal(yamlData, newConfig) + if err != nil { + helper.Log.Panicf("could not parse YAML header from '%s': %s", inFile, err) + } + + helper.Log.Debug("merging config with upper config") + oldThis := newConfig.This + helper.Merge(newConfig, conf.Config) + newConfig.This = oldThis + + helper.Log.Debug(spew.Sdump(newConfig)) + + input = regex.ReplaceAll(input, []byte("")) + } else { + helper.Merge(newConfig, conf.Config) + } + + // ignore ??? + ignoreFile := false + var ignoreRegex *string + var stripRegex *string + var outputExt *string + if f := newConfig.Filename; f != nil { + ignoreRegex = f.Ignore + stripRegex = f.Strip + outputExt = f.OutputExtension + } + if ignoreRegex != nil && *ignoreRegex != "" { + regex, err := regexp.Compile(*ignoreRegex) + if err != nil { + helper.Log.Panicf("could not compile filename.ignore regexp '%s' for file '%s': %s", *ignoreRegex, inFile, err) + } + ignoreFile = regex.MatchString(file) + } + + if ignoreFile { + helper.Log.Infof("ignoring file '%s', because of filename.ignore", inFile) + } else { + + // build output filename + outputFilename := file + + var indexInputFile *string + var indexOutputFile *string + if i := newConfig.Index; i != nil { + indexInputFile = i.InputFile + indexOutputFile = i.OutputFile + } + + if indexInputFile != nil && + *indexInputFile == file && + indexOutputFile != nil && + *indexOutputFile != "" { + outputFilename = *indexOutputFile + } else { + if stripRegex != nil && *stripRegex != "" { + regex, err := regexp.Compile(*stripRegex) + if err != nil { + helper.Log.Panicf("could not compile filename.strip regexp '%s' for file '%s': %s", *stripRegex, inFile, err) + } + outputFilename = regex.ReplaceAllString(outputFilename, "$1") + } + if outputExt != nil && *outputExt != "" { + outputFilename += "." + *outputExt + } + } + + outFile := conf.OutputPath + "/" + outputFilename + helper.Log.Debugf("using '%s' as output file", outFile) + + // use --- for splitting document in markdown parts + regex := regexp.MustCompile("\\r?\\n\\r?---\\r?\\n\\r?") + inputParts := regex.Split(string(input), -1) + htmlParts := make([]*pongo2.Value, 0) + + chromaRenderer := false + chromaStyle := "monokai" + if m := newConfig.Markdown; m != nil { + if m.ChromaRenderer != nil && *m.ChromaRenderer { + chromaRenderer = true + } + if m.ChromaStyle != nil && *m.ChromaStyle != "" { + chromaStyle = *m.ChromaStyle + } + } + for _, iPart := range inputParts { + htmlParts = append(htmlParts, + pongo2.AsSafeValue( + string(helper.RenderMarkdown([]byte(iPart), chromaRenderer, chromaStyle)))) + } + + // build navigation + navMap := make(map[string]*NavElement) + navSlice := make([]*NavElement, 0) + navActive := make([]*NavElement, 0) + BuildNavigation(rootConf, &navMap, &navSlice, &navActive, curNavPath) + + // read yaml header as data for template + ctx := context.NewContext() + ctx["This"] = newConfig.This + ctx["Meta"] = newConfig.Meta + ctx["Data"] = newConfig.Data + ctx["ColMap"] = rootConf.ColMap // root as NavMap and NavSlice, for sub go to NavElement.ColMap + ctx["NavMap"] = navMap + ctx["NavSlice"] = navSlice + ctx["NavActive"] = navActive + ctx["Body"] = pongo2.AsSafeValue(string(helper.RenderMarkdown(input, chromaRenderer, chromaStyle))) + ctx["BodyParts"] = htmlParts + ctx["CurrentPath"] = curNavPath + // set active nav element + if len(navActive) > 0 { + ctx["NavElement"] = navActive[len(navActive)-1] + } else { + // if no active path to content, we are in root dir + ctx["NavElement"] = &NavElement{ + GoTo: helper.BackToRoot(curNavPath), + Active: true, + ColMap: rootConf.ColMap, + Data: rootConf.Config.Data, + This: rootConf.Config.This, + SubMap: &navMap, + SubSlice: &navSlice, + } + } + + helper.Log.Debugf("rendering template '%s' for '%s'", *newConfig.Template, outFile) + templateFilename := *newConfig.Template + result, err := RenderTemplate(*newConfig.Template, conf, newConfig, &ctx) + if err != nil { + helper.Log.Panicf("could not execute template '%s' for input file '%s': %s", templateFilename, inFile, err) + } + + result = FixAssetsPath(result, curNavPath) + + helper.Log.Noticef("writing to output file: %s", outFile) + err = ioutil.WriteFile(outFile, []byte(result), 0644) + if err != nil { + helper.Log.Panicf("could not write to output file '%s': %s", outFile, err) + } + + //fmt.Println(string(html)) + } + } + + // process other files, copy... + for _, file := range conf.OtherFiles { + switch config.Config.OtherFiles.Action { + case "copy": + from := conf.InputPath + "/" + file + to := conf.OutputPath + "/" + file + helper.Log.Noticef("copying file from '%s' to '%s'", from, to) + err := cpy.Copy(from, to) + if err != nil { + helper.Log.Panicf("could not copy file from '%s' to '%s': %s", from, to, err) + } + } + } + + i := 0 + for i < len(conf.Sub) { + ProcessContent(rootConf, conf.Sub[i]) + i++ + } +} diff --git a/context/context.go b/context/context.go new file mode 100644 index 0000000..d07d43e --- /dev/null +++ b/context/context.go @@ -0,0 +1,266 @@ +package context + +import ( + "io/ioutil" + "os" + "path" + "regexp" + "strings" + "time" + + "gitbase.de/apairon/mark2web/config" + "gitbase.de/apairon/mark2web/helper" + "github.com/davecgh/go-spew/spew" + "github.com/extemporalgenome/slug" + "github.com/flosch/pongo2" + "gopkg.in/yaml.v2" +) + +var CurrentContext *pongo2.Context +var CurrentTreeNodeConfig *config.PathConfigTree +var CurrentPathConfig *config.PathConfig + +func NewContext() pongo2.Context { + ctx := pongo2.Context{ + "fnRequest": RequestFn, + "fnRender": RenderFn, + + "AssetsPath": config.Config.Assets.ToPath, + "Timestamp": time.Now().Unix, + } + CurrentContext = &ctx + + return ctx +} + +func FillNodeConfig(node *config.PathConfigTree, inBase, outBase, dir string, conf *config.PathConfig) { + inPath := inBase + if dir != "" { + inPath += "/" + dir + } + + helper.Log.Infof("reading input directory: %s", inPath) + + node.InputPath = inPath + + // read config + newConfig := new(config.PathConfig) + helper.Log.Debug("looking for config.yml ...") + configFile := inPath + "/config.yml" + if _, err := os.Stat(configFile); os.IsNotExist(err) { + helper.Log.Debug("no config.yml found in this directory, using upper configs") + helper.Merge(newConfig, conf) + // remove this + newConfig.This = config.ThisPathConfig{} + } else { + helper.Log.Debug("reading config...") + data, err := ioutil.ReadFile(configFile) + if err != nil { + helper.Log.Panicf("could not read file '%s': %s", configFile, err) + } + err = yaml.Unmarshal(data, newConfig) + if err != nil { + helper.Log.Panicf("could not parse YAML file '%s': %s", configFile, err) + } + + helper.Log.Debug("merging config with upper config") + oldThis := newConfig.This + helper.Merge(newConfig, conf) + newConfig.This = oldThis + + helper.Log.Debug(spew.Sdump(newConfig)) + } + + node.Config = newConfig + + // calc outDir + stripedDir := dir + var regexStr *string + if newConfig.Path != nil { + regexStr = newConfig.Path.Strip + } + if regexStr != nil && *regexStr != "" { + if regex, err := regexp.Compile(*regexStr); err != nil { + helper.Log.Panicf("error compiling path.strip regex '%s' from '%s': %s", *regexStr, inBase+"/"+dir, err) + } else { + stripedDir = regex.ReplaceAllString(stripedDir, "$1") + } + } + + if node.Config.This.Navname == nil { + navname := strings.Replace(stripedDir, "_", " ", -1) + node.Config.This.Navname = &navname + } + + stripedDir = slug.Slug(stripedDir) + outPath := outBase + "/" + stripedDir + outPath = path.Clean(outPath) + + helper.Log.Infof("calculated output directory: %s", outPath) + node.OutputPath = outPath + + // handle collections + for _, colConfig := range newConfig.This.Collections { + if colConfig != nil { + if colConfig.Name == nil || *colConfig.Name == "" { + helper.Log.Panicf("missing Name in collection config in '%s'", inPath) + } + if colConfig.URL == nil || *colConfig.URL == "" { + helper.Log.Panicf("missing EntriesJSON in collection config in '%s'", inPath) + } + } + + if node.ColMap == nil { + node.ColMap = make(config.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", inPath, 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", inPath, 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", inPath, 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", inPath, err) + } + } + if tpl == "" { + tpl = *newConfig.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", inPath, err) + } + } + + goTo, err := pongo2.RenderTemplateString(navT.GoTo, ctxE) + if err != nil { + helper.Log.Panicf("invalid template string for NavTemplate.GoTo in '%s': %s", inPath, 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", inPath, goTo) + } + if goTo == "." { + helper.Log.Panicf("invalid config '.' for NavTemplate.GoTo in collection config in '%s'", inPath) + } + if goTo == "" { + helper.Log.Panicf("missing NavTemplate.GoTo in collection config in '%s'", inPath) + } + + 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", inPath, 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", inPath, err) + } + } + + Add2Nav(node, node.Config, tpl, goTo, navname, colEl, dataKey, body, navT.Hidden) + } + } + + } +} + +func Add2Nav(currentNode *config.PathConfigTree, pathConfig *config.PathConfig, tplFilename, outDir string, navname string, ctx interface{}, dataMapKey string, body string, hidden bool) { + newNodeConfig := new(config.PathConfigTree) + FillNodeConfig( + newNodeConfig, + currentNode.InputPath, + currentNode.OutputPath, + outDir, + pathConfig, + ) + if navname != "" { + newNodeConfig.Config.This = config.ThisPathConfig{ + Navname: &navname, + } + } + if dataMapKey != "" { + if newNodeConfig.Config.Data == nil { + newNodeConfig.Config.Data = make(config.MapString) + } + // as submap in Data + newNodeConfig.Config.Data[dataMapKey] = ctx + } else if m, ok := ctx.(map[string]interface{}); ok { + // direct set data + newNodeConfig.Config.Data = m + } + + // fake via normal file behavior + newNodeConfig.Config.Template = &tplFilename + newNodeConfig.InputFiles = []string{""} // empty file is special for use InputString + indexInFile := "" + indexOutFile := "index.html" + if idx := newNodeConfig.Config.Index; idx != nil { + if idx.OutputFile != nil && *idx.OutputFile != "" { + indexOutFile = *idx.OutputFile + } + } + newNodeConfig.Config.Index = &config.IndexConfig{ + InputFile: &indexInFile, + OutputFile: &indexOutFile, + InputString: &body, + } + newNodeConfig.Hidden = hidden + + currentNode.Sub = append(currentNode.Sub, newNodeConfig) +} diff --git a/context/fn_render.go b/context/fn_render.go new file mode 100644 index 0000000..2994b82 --- /dev/null +++ b/context/fn_render.go @@ -0,0 +1,24 @@ +package context + +import ( + "github.com/flosch/pongo2" +) + +// RenderFn renders a pongo2 template with additional context +func RenderFn(templateFilename, outDir, ctx *pongo2.Value, param ...*pongo2.Value) *pongo2.Value { + dataMapKey := "" + body := "" + + for i, p := range param { + switch i { + case 0: + dataMapKey = p.String() + case 1: + body = p.String() + } + } + + Add2Nav(CurrentTreeNodeConfig, CurrentPathConfig, templateFilename.String(), outDir.String(), "", ctx.Interface(), dataMapKey, body, true) + + return pongo2.AsValue(nil) +} diff --git a/context/fn_request.go b/context/fn_request.go new file mode 100644 index 0000000..a7d017a --- /dev/null +++ b/context/fn_request.go @@ -0,0 +1,12 @@ +package context + +import ( + "gitbase.de/apairon/mark2web/helper" + "github.com/flosch/pongo2" +) + +// RequestFn will make a web request and returns map[string]interface form pongo2 +func RequestFn(url *pongo2.Value, args ...*pongo2.Value) *pongo2.Value { + u := url.String() + return pongo2.AsValue(helper.JSONWebRequest(u)) +} diff --git a/context/path.go b/context/path.go new file mode 100644 index 0000000..eb19c84 --- /dev/null +++ b/context/path.go @@ -0,0 +1,39 @@ +package context + +import ( + "path" + "strings" + + "gitbase.de/apairon/mark2web/config" + "gitbase.de/apairon/mark2web/helper" +) + +// ResolveNavPath fixes nav target relative to current navigation path +func ResolveNavPath(target string) string { + curNavPath := (*CurrentContext)["CurrentPath"].(string) + if strings.HasPrefix(target, "/") { + target = helper.BackToRoot(curNavPath) + target + } + target = path.Clean(target) + return target +} + +// ResolveOutputPath fixes output directory relative to current navigation path +func ResolveOutputPath(target string) string { + if strings.HasPrefix(target, "/") { + target = config.Config.Directories.Output + "/" + target + } else { + target = CurrentTreeNodeConfig.OutputPath + "/" + target + } + return path.Clean(target) +} + +// ResolveInputPath fixes input directory relative to current navigation path +func ResolveInputPath(target string) string { + if strings.HasPrefix(target, "/") { + target = config.Config.Directories.Input + "/" + target + } else { + target = CurrentTreeNodeConfig.InputPath + "/" + target + } + return path.Clean(target) +} diff --git a/filter/custom.go b/filter/custom.go new file mode 100644 index 0000000..3b69992 --- /dev/null +++ b/filter/custom.go @@ -0,0 +1,73 @@ +package filter + +import ( + "io/ioutil" + "path" + "strings" + + "gitbase.de/apairon/mark2web/context" + "gitbase.de/apairon/mark2web/helper" + "github.com/ddliu/motto" + "github.com/flosch/pongo2" + _ "github.com/robertkrimen/otto/underscore" +) + +// RegisterFilters reads a directory and register filters from files within it +func RegisterFilters(dir string) { + files, err := ioutil.ReadDir(dir) + if err != nil { + helper.Log.Panicf("could not read from template filters dir '%s': %s", dir, err) + } + for _, f := range files { + if !f.IsDir() { + switch path.Ext(f.Name()) { + case ".js": + fileBase := strings.TrimSuffix(f.Name(), ".js") + jsFile := dir + "/" + f.Name() + helper.Log.Debugf("trying to register filter from: %s", jsFile) + /* + jsStr, err := ioutil.ReadFile(jsFile) + if err != nil { + Log.Panicf("could not read '%s': %s", jsFile, err) + } + */ + vm := motto.New() + fn, err := vm.Run(jsFile) + if err != nil { + helper.Log.Panicf("error in javascript vm for '%s': %s", jsFile, err) + } + if !fn.IsFunction() { + helper.Log.Panicf("%s does not contain a function code", jsFile) + } + + err = pongo2.RegisterFilter( + fileBase, + func(in, param *pongo2.Value) (out *pongo2.Value, erro *pongo2.Error) { + thisObj, _ := vm.Object("({})") + if context.CurrentContext != nil { + thisObj.Set("context", *context.CurrentContext) + } + + if err != nil { + helper.Log.Panicf("could not set context as in '%s': %s", jsFile, err) + } + ret, err := fn.Call(thisObj.Value(), in.Interface(), param.Interface()) + if err != nil { + helper.Log.Panicf("error in javascript file '%s' while calling returned function: %s", jsFile, err) + } + retGo, err := ret.Export() + if err != nil { + helper.Log.Panicf("export error for '%s': %s", jsFile, err) + } + return pongo2.AsValue(retGo), nil + }, + ) + if err != nil { + helper.Log.Panicf("could not register filter from '%s': %s", jsFile, err) + } + + } + } + } + +} diff --git a/filter/dump.go b/filter/dump.go new file mode 100644 index 0000000..9c7c04c --- /dev/null +++ b/filter/dump.go @@ -0,0 +1,12 @@ +package filter + +import ( + "github.com/davecgh/go-spew/spew" + "github.com/flosch/pongo2" +) + +// DumpFilter is a pongo2 filter, which returns a spew.Dump of the input +func DumpFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) { + dumpString := spew.Sdump(in.Interface()) + return pongo2.AsValue(string(dumpString)), nil +} diff --git a/helper/template_filters.go b/filter/image_process.go similarity index 56% rename from helper/template_filters.go rename to filter/image_process.go index c5c5401..e06aecd 100644 --- a/helper/template_filters.go +++ b/filter/image_process.go @@ -1,12 +1,10 @@ -package helper +package filter import ( "crypto/md5" - "encoding/json" "errors" "fmt" "image" - "io/ioutil" "net/http" "net/url" "os" @@ -15,82 +13,16 @@ import ( "strings" "gitbase.de/apairon/mark2web/config" - "github.com/davecgh/go-spew/spew" - "github.com/ddliu/motto" + "gitbase.de/apairon/mark2web/context" + "gitbase.de/apairon/mark2web/helper" "github.com/disintegration/imaging" "github.com/flosch/pongo2" - _ "github.com/flosch/pongo2-addons" - _ "github.com/robertkrimen/otto/underscore" ) -func init() { - err := pongo2.ReplaceFilter("markdown", MarkdownFilter) - if err != nil { - panic(err) - } - - newFilters := map[string]pongo2.FilterFunction{ - "image_process": ImageProcessFilter, - "relative_path": RelativePathFilter, - "json": JSONFilter, - "dump": DumpFilter, - } - for name, fn := range newFilters { - err := pongo2.RegisterFilter(name, fn) - if err != nil { - panic(err) - } - } -} - -// DumpFilter is a pongo2 filter, which returns a spew.Dump of the input -func DumpFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) { - dumpString := spew.Sdump(in.Interface()) - return pongo2.AsValue(string(dumpString)), nil -} - -// JSONFilter is a pongo2 filter, which returns a json string of the input -func JSONFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) { - pretty := false - for _, s := range strings.Split(param.String(), ",") { - switch s { - case "pretty": - pretty = true - } - } - var err error - var jsonBytes []byte - if pretty { - jsonBytes, err = json.MarshalIndent(in.Interface(), "", " ") - - } else { - jsonBytes, err = json.Marshal(in.Interface()) - } - if err != nil { - return nil, &pongo2.Error{ - Sender: "filter:json", - OrigError: err, - } - } - - return pongo2.AsSafeValue(string(jsonBytes)), nil -} - -// MarkdownFilter is a pongo2 filter, which converts markdown to html -func MarkdownFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) { - return pongo2.AsSafeValue( - string( - renderMarkdown( - []byte(in.String()), - currentPathConfig.Markdown, - ))), - nil -} - func parseImageParams(str string) (*config.ImagingConfig, error) { p := config.ImagingConfig{} if str == "" { - config.Merge(&p, currentPathConfig.Imaging) + helper.Merge(&p, context.CurrentPathConfig.Imaging) // Filename and Format are only valid for current image p.Filename = "" p.Format = "" @@ -199,7 +131,7 @@ func ImageProcessFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, * } } else { // local file - imgSource = ResolveInputPath(imgSource) + imgSource = context.ResolveInputPath(imgSource) if p.Filename == "" { p.Filename = fmt.Sprintf( "%s_%s", @@ -211,14 +143,14 @@ func ImageProcessFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, * var imgTarget string if p.TargetDir != "" { - imgTarget = ResolveOutputPath( + imgTarget = context.ResolveOutputPath( path.Clean(p.TargetDir) + "/" + p.Filename, ) pt := path.Dir(imgTarget) if _, err := os.Stat(pt); os.IsNotExist(err) { - Log.Infof("create image target dir: %s", pt) + helper.Log.Infof("create image target dir: %s", pt) if err := os.MkdirAll(pt, 0755); err != nil { return nil, &pongo2.Error{ Sender: "filter:image_resize", @@ -227,16 +159,16 @@ func ImageProcessFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, * } } - p.Filename = ResolveNavPath(p.TargetDir + "/" + p.Filename) + p.Filename = context.ResolveNavPath(p.TargetDir + "/" + p.Filename) } else { - imgTarget = ResolveOutputPath(p.Filename) + imgTarget = context.ResolveOutputPath(p.Filename) } if f, err := os.Stat(imgTarget); err == nil && !f.IsDir() { - Log.Noticef("skipped processing image from %s to %s, file already exists", imgSource, imgTarget) + helper.Log.Noticef("skipped processing image from %s to %s, file already exists", imgSource, imgTarget) } else { - Log.Noticef("processing image from %s to %s", imgSource, imgTarget) + helper.Log.Noticef("processing image from %s to %s", imgSource, imgTarget) if strings.HasPrefix(imgSource, "http://") || strings.HasPrefix(imgSource, "https://") { // webrequest before finding target filename, because of file format in filename } else { @@ -304,74 +236,5 @@ func ImageProcessFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, * } } } - return pongo2.AsValue(ResolveNavPath(p.Filename)), nil -} - -// RelativePathFilter returns the relative path to navpoint based on current nav -func RelativePathFilter(in, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) { - return pongo2.AsValue( - ResolveNavPath( - in.String(), - ), - ), nil -} - -// RegisterFilters reads a directory and register filters from files within it -func RegisterFilters(dir string) { - files, err := ioutil.ReadDir(dir) - if err != nil { - Log.Panicf("could not read from template filters dir '%s': %s", dir, err) - } - for _, f := range files { - if !f.IsDir() { - switch path.Ext(f.Name()) { - case ".js": - fileBase := strings.TrimSuffix(f.Name(), ".js") - jsFile := dir + "/" + f.Name() - Log.Debugf("trying to register filter from: %s", jsFile) - /* - jsStr, err := ioutil.ReadFile(jsFile) - if err != nil { - Log.Panicf("could not read '%s': %s", jsFile, err) - } - */ - vm := motto.New() - fn, err := vm.Run(jsFile) - if err != nil { - Log.Panicf("error in javascript vm for '%s': %s", jsFile, err) - } - if !fn.IsFunction() { - Log.Panicf("%s does not contain a function code", jsFile) - } - - err = pongo2.RegisterFilter( - fileBase, - func(in, param *pongo2.Value) (out *pongo2.Value, erro *pongo2.Error) { - thisObj, _ := vm.Object("({})") - if currentContext != nil { - thisObj.Set("context", *currentContext) - } - - if err != nil { - Log.Panicf("could not set context as in '%s': %s", jsFile, err) - } - ret, err := fn.Call(thisObj.Value(), in.Interface(), param.Interface()) - if err != nil { - Log.Panicf("error in javascript file '%s' while calling returned function: %s", jsFile, err) - } - retGo, err := ret.Export() - if err != nil { - Log.Panicf("export error for '%s': %s", jsFile, err) - } - return pongo2.AsValue(retGo), nil - }, - ) - if err != nil { - Log.Panicf("could not register filter from '%s': %s", jsFile, err) - } - - } - } - } - + return pongo2.AsValue(context.ResolveNavPath(p.Filename)), nil } diff --git a/filter/init.go b/filter/init.go new file mode 100644 index 0000000..0875300 --- /dev/null +++ b/filter/init.go @@ -0,0 +1,26 @@ +package filter + +import ( + "github.com/flosch/pongo2" + _ "github.com/flosch/pongo2-addons" +) + +func init() { + err := pongo2.ReplaceFilter("markdown", MarkdownFilter) + if err != nil { + panic(err) + } + + newFilters := map[string]pongo2.FilterFunction{ + "image_process": ImageProcessFilter, + "relative_path": RelativePathFilter, + "json": JSONFilter, + "dump": DumpFilter, + } + for name, fn := range newFilters { + err := pongo2.RegisterFilter(name, fn) + if err != nil { + panic(err) + } + } +} diff --git a/filter/json.go b/filter/json.go new file mode 100644 index 0000000..d231115 --- /dev/null +++ b/filter/json.go @@ -0,0 +1,35 @@ +package filter + +import ( + "encoding/json" + "strings" + + "github.com/flosch/pongo2" +) + +// JSONFilter is a pongo2 filter, which returns a json string of the input +func JSONFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) { + pretty := false + for _, s := range strings.Split(param.String(), ",") { + switch s { + case "pretty": + pretty = true + } + } + var err error + var jsonBytes []byte + if pretty { + jsonBytes, err = json.MarshalIndent(in.Interface(), "", " ") + + } else { + jsonBytes, err = json.Marshal(in.Interface()) + } + if err != nil { + return nil, &pongo2.Error{ + Sender: "filter:json", + OrigError: err, + } + } + + return pongo2.AsSafeValue(string(jsonBytes)), nil +} diff --git a/filter/markdown.go b/filter/markdown.go new file mode 100644 index 0000000..5a5fe13 --- /dev/null +++ b/filter/markdown.go @@ -0,0 +1,29 @@ +package filter + +import ( + "gitbase.de/apairon/mark2web/context" + "gitbase.de/apairon/mark2web/helper" + "github.com/flosch/pongo2" +) + +// MarkdownFilter is a pongo2 filter, which converts markdown to html +func MarkdownFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) { + chromaRenderer := false + chromaStyle := "monokai" + if m := context.CurrentPathConfig.Markdown; m != nil { + if m.ChromaRenderer != nil && *m.ChromaRenderer { + chromaRenderer = true + } + if m.ChromaStyle != nil && *m.ChromaStyle != "" { + chromaStyle = *m.ChromaStyle + } + } + return pongo2.AsSafeValue( + string( + helper.RenderMarkdown( + []byte(in.String()), + chromaRenderer, + chromaStyle, + ))), + nil +} diff --git a/filter/relative_path.go b/filter/relative_path.go new file mode 100644 index 0000000..132048e --- /dev/null +++ b/filter/relative_path.go @@ -0,0 +1,15 @@ +package filter + +import ( + "gitbase.de/apairon/mark2web/context" + "github.com/flosch/pongo2" +) + +// RelativePathFilter returns the relative path to navpoint based on current nav +func RelativePathFilter(in, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) { + return pongo2.AsValue( + context.ResolveNavPath( + in.String(), + ), + ), nil +} diff --git a/helper/content.go b/helper/content.go deleted file mode 100644 index e243033..0000000 --- a/helper/content.go +++ /dev/null @@ -1,514 +0,0 @@ -package helper - -import ( - "bytes" - "io/ioutil" - "os" - "path" - "regexp" - "strings" - "time" - - "gitbase.de/apairon/mark2web/config" - "github.com/Depado/bfchroma" - "github.com/davecgh/go-spew/spew" - "github.com/extemporalgenome/slug" - "github.com/flosch/pongo2" - cpy "github.com/otiai10/copy" - "gopkg.in/russross/blackfriday.v2" - "gopkg.in/yaml.v2" -) - -func newContext() pongo2.Context { - return pongo2.Context{ - "fnRequest": RequestFn, - "fnRender": RenderFn, - - "AssetsPath": config.Config.Assets.ToPath, - - "Timestamp": time.Now().Unix, - } -} - -func fillNodeConfig(node *config.PathConfigTree, inBase, outBase, dir string, conf *config.PathConfig) { - inPath := inBase - if dir != "" { - inPath += "/" + dir - } - - Log.Infof("reading input directory: %s", inPath) - - node.InputPath = inPath - - // read config - 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") - config.Merge(newConfig, conf) - // remove this - newConfig.This = config.ThisPathConfig{} - } else { - Log.Debug("reading config...") - data, err := ioutil.ReadFile(configFile) - if err != nil { - Log.Panicf("could not read file '%s': %s", configFile, err) - } - err = yaml.Unmarshal(data, newConfig) - if err != nil { - Log.Panicf("could not parse YAML file '%s': %s", configFile, err) - } - - Log.Debug("merging config with upper config") - oldThis := newConfig.This - config.Merge(newConfig, conf) - newConfig.This = oldThis - - Log.Debug(spew.Sdump(newConfig)) - } - - node.Config = newConfig - - // calc outDir - stripedDir := dir - var regexStr *string - if newConfig.Path != nil { - regexStr = newConfig.Path.Strip - } - if regexStr != nil && *regexStr != "" { - if regex, err := regexp.Compile(*regexStr); err != nil { - Log.Panicf("error compiling path.strip regex '%s' from '%s': %s", *regexStr, inBase+"/"+dir, err) - } else { - stripedDir = regex.ReplaceAllString(stripedDir, "$1") - } - } - - if node.Config.This.Navname == nil { - navname := strings.Replace(stripedDir, "_", " ", -1) - node.Config.This.Navname = &navname - } - - stripedDir = slug.Slug(stripedDir) - outPath := outBase + "/" + stripedDir - outPath = path.Clean(outPath) - - Log.Infof("calculated output directory: %s", outPath) - node.OutputPath = outPath - - // handle collections - for _, colConfig := range newConfig.This.Collections { - if colConfig != nil { - if colConfig.Name == nil || *colConfig.Name == "" { - Log.Panicf("missing Name in collection config in '%s'", inPath) - } - if colConfig.URL == nil || *colConfig.URL == "" { - Log.Panicf("missing EntriesJSON in collection config in '%s'", inPath) - } - } - - if node.ColMap == nil { - node.ColMap = make(config.MapString) - } - ctx := newContext() - ctx["This"] = node.Config.This - ctx["Data"] = node.Config.Data - - url, err := pongo2.RenderTemplateString(*colConfig.URL, ctx) - if err != nil { - Log.Panicf("invalid template string for Collection Element.URL in '%s': %s", inPath, err) - } - - colData := 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 { - Log.Debug(spew.Sdump(colDataMap)) - Log.Panicf("invalid json data in [%s] from url '%s' for entries", navT.EntriesAttribute, url) - } - } - } else { - entries, ok = colData.([]interface{}) - } - if !ok { - Log.Debug(spew.Sdump(colData)) - 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 := config.Merge(&ctxE, ctx) - if err != nil { - Log.Panicf("could not merge context in '%s': %s", inPath, err) - } - var jsonCtx map[string]interface{} - if jsonCtx, ok = colEl.(map[string]interface{}); !ok { - Log.Debug(spew.Sdump(colEl)) - Log.Panicf("no json object for entry index %d from url '%s'", idx, url) - } - err = config.Merge(&ctxE, pongo2.Context(jsonCtx)) - if err != nil { - Log.Panicf("could not merge context in '%s': %s", inPath, err) - } - - tpl := "" - if navT.Template != "" { - tpl, err = pongo2.RenderTemplateString(navT.Template, ctxE) - if err != nil { - Log.Panicf("invalid template string for NavTemplate.Template in '%s': %s", inPath, err) - } - } - if tpl == "" { - tpl = *newConfig.Template - } - - dataKey := "" - if navT.DataKey != "" { - dataKey, err = pongo2.RenderTemplateString(navT.DataKey, ctxE) - if err != nil { - Log.Panicf("invalid template string for NavTemplate.DataKey in '%s': %s", inPath, err) - } - } - - goTo, err := pongo2.RenderTemplateString(navT.GoTo, ctxE) - if err != nil { - Log.Panicf("invalid template string for NavTemplate.GoTo in '%s': %s", inPath, err) - } - goTo = strings.Trim(goTo, "/") - goTo = path.Clean(goTo) - - if strings.Contains(goTo, "..") { - Log.Panicf("going back via .. in NavTemplate.GoTo forbidden in collection config in '%s': %s", inPath, goTo) - } - if goTo == "." { - Log.Panicf("invalid config '.' for NavTemplate.GoTo in collection config in '%s'", inPath) - } - if goTo == "" { - Log.Panicf("missing NavTemplate.GoTo in collection config in '%s'", inPath) - } - - navname := "" - if navT.Navname != "" { - navname, err = pongo2.RenderTemplateString(navT.Navname, ctxE) - if err != nil { - Log.Panicf("invalid template string for NavTemplate.Navname in '%s': %s", inPath, err) - } - } - body := "" - if navT.Body != "" { - body, err = pongo2.RenderTemplateString(navT.Body, ctxE) - if err != nil { - Log.Panicf("invalid template string for NavTemplate.Body in '%s': %s", inPath, err) - } - } - - add2Nav(node, node.Config, tpl, goTo, navname, colEl, dataKey, body, navT.Hidden) - } - } - - } -} - -// ReadContentDir walks through content directory and builds the tree of configurations -func ReadContentDir(inBase string, outBase string, dir string, conf *config.PathConfig, tree *config.PathConfigTree) { - fillNodeConfig(tree, inBase, outBase, dir, conf) - - files, err := ioutil.ReadDir(tree.InputPath) - if err != nil { - Log.Panic(err) - } - - // first only files - for _, f := range files { - p := tree.InputPath + "/" + f.Name() - if !f.IsDir() && f.Name() != "config.yml" { - switch path.Ext(f.Name()) { - case ".md": - Log.Debugf(".MD %s", p) - if tree.InputFiles == nil { - tree.InputFiles = make([]string, 0) - } - tree.InputFiles = append(tree.InputFiles, f.Name()) - break - default: - Log.Debugf("FIL %s", p) - if tree.OtherFiles == nil { - tree.OtherFiles = make([]string, 0) - } - tree.OtherFiles = append(tree.OtherFiles, f.Name()) - } - } - } - - // only directorys, needed config before - for _, f := range files { - p := tree.InputPath + "/" + f.Name() - if f.IsDir() { - Log.Debugf("DIR %s", p) - newTree := new(config.PathConfigTree) - if tree.Sub == nil { - tree.Sub = make([]*config.PathConfigTree, 0) - } - tree.Sub = append(tree.Sub, newTree) - ReadContentDir(tree.InputPath, tree.OutputPath, f.Name(), tree.Config, newTree) - } - } -} - -// ProcessContent walks recursivly through the input paths and processes all files for output -func ProcessContent(rootConf, conf *config.PathConfigTree) { - CreateDirectory(conf.OutputPath) - - curNavPath := strings.TrimPrefix(conf.OutputPath, config.Config.Directories.Output) - curNavPath = strings.TrimPrefix(curNavPath, "/") - curNavPath = path.Clean(curNavPath) - if curNavPath == "." { - curNavPath = "" - } - - goTo := conf.Config.This.GoTo - if goTo != nil && *goTo != "" { - goToFixed := *goTo - if strings.HasPrefix(goToFixed, "/") { - goToFixed = BackToRoot(curNavPath) + goToFixed - } - goToFixed = path.Clean(goToFixed) - - switch config.Config.Webserver.Type { - case "apache": - htaccessFile := conf.OutputPath + "/.htaccess" - 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 { - Log.Panicf("could not write '%s': %s", htaccessFile, err) - } - break - } - } - - for _, file := range conf.InputFiles { - var input []byte - inFile := "InputString" - - if file != "" { - inFile = conf.InputPath + "/" + file - Log.Debugf("reading file: %s", inFile) - - var err error - input, err = ioutil.ReadFile(inFile) - if err != nil { - Log.Panicf("could not read '%s':%s", inFile, err) - } - Log.Infof("processing input file '%s'", inFile) - } else { - // use input string if available and input filename == "" - var inputString *string - if i := conf.Config.Index; i != nil { - inputString = i.InputString - } - if inputString != nil { - Log.Debugf("using input string instead of file") - input = []byte(*inputString) - } - } - - newConfig := new(config.PathConfig) - - regex := regexp.MustCompile("(?s)^---(.*?)\\r?\\n\\r?---\\r?\\n\\r?") - yamlData := regex.Find(input) - if string(yamlData) != "" { - // replace tabs - yamlData = bytes.Replace(yamlData, []byte("\t"), []byte(" "), -1) - - Log.Debugf("found yaml header in '%s', merging config", inFile) - err := yaml.Unmarshal(yamlData, newConfig) - if err != nil { - Log.Panicf("could not parse YAML header from '%s': %s", inFile, err) - } - - Log.Debug("merging config with upper config") - oldThis := newConfig.This - config.Merge(newConfig, conf.Config) - newConfig.This = oldThis - - Log.Debug(spew.Sdump(newConfig)) - - input = regex.ReplaceAll(input, []byte("")) - } else { - config.Merge(newConfig, conf.Config) - } - - // ignore ??? - ignoreFile := false - var ignoreRegex *string - var stripRegex *string - var outputExt *string - if f := newConfig.Filename; f != nil { - ignoreRegex = f.Ignore - stripRegex = f.Strip - outputExt = f.OutputExtension - } - if ignoreRegex != nil && *ignoreRegex != "" { - regex, err := regexp.Compile(*ignoreRegex) - if err != nil { - Log.Panicf("could not compile filename.ignore regexp '%s' for file '%s': %s", *ignoreRegex, inFile, err) - } - ignoreFile = regex.MatchString(file) - } - - if ignoreFile { - Log.Infof("ignoring file '%s', because of filename.ignore", inFile) - } else { - - // build output filename - outputFilename := file - - var indexInputFile *string - var indexOutputFile *string - if i := newConfig.Index; i != nil { - indexInputFile = i.InputFile - indexOutputFile = i.OutputFile - } - - if indexInputFile != nil && - *indexInputFile == file && - indexOutputFile != nil && - *indexOutputFile != "" { - outputFilename = *indexOutputFile - } else { - if stripRegex != nil && *stripRegex != "" { - regex, err := regexp.Compile(*stripRegex) - if err != nil { - Log.Panicf("could not compile filename.strip regexp '%s' for file '%s': %s", *stripRegex, inFile, err) - } - outputFilename = regex.ReplaceAllString(outputFilename, "$1") - } - if outputExt != nil && *outputExt != "" { - outputFilename += "." + *outputExt - } - } - - outFile := conf.OutputPath + "/" + outputFilename - Log.Debugf("using '%s' as output file", outFile) - - // use --- for splitting document in markdown parts - regex := regexp.MustCompile("\\r?\\n\\r?---\\r?\\n\\r?") - inputParts := regex.Split(string(input), -1) - htmlParts := make([]*pongo2.Value, 0) - for _, iPart := range inputParts { - htmlParts = append(htmlParts, - pongo2.AsSafeValue( - string(renderMarkdown([]byte(iPart), newConfig.Markdown)))) - } - - // build navigation - navMap := make(map[string]*NavElement) - navSlice := make([]*NavElement, 0) - navActive := make([]*NavElement, 0) - BuildNavigation(rootConf, &navMap, &navSlice, &navActive, curNavPath) - - // read yaml header as data for template - ctx := newContext() - ctx["This"] = newConfig.This - ctx["Meta"] = newConfig.Meta - ctx["Data"] = newConfig.Data - ctx["ColMap"] = rootConf.ColMap // root as NavMap and NavSlice, for sub go to NavElement.ColMap - ctx["NavMap"] = navMap - ctx["NavSlice"] = navSlice - ctx["NavActive"] = navActive - ctx["Body"] = pongo2.AsSafeValue(string(renderMarkdown(input, newConfig.Markdown))) - ctx["BodyParts"] = htmlParts - ctx["CurrentPath"] = curNavPath - // set active nav element - if len(navActive) > 0 { - ctx["NavElement"] = navActive[len(navActive)-1] - } else { - // if no active path to content, we are in root dir - ctx["NavElement"] = &NavElement{ - GoTo: BackToRoot(curNavPath), - Active: true, - ColMap: rootConf.ColMap, - Data: rootConf.Config.Data, - This: rootConf.Config.This, - SubMap: &navMap, - SubSlice: &navSlice, - } - } - - Log.Debugf("rendering template '%s' for '%s'", *newConfig.Template, outFile) - templateFilename := *newConfig.Template - result, err := RenderTemplate(*newConfig.Template, conf, newConfig, &ctx) - if err != nil { - Log.Panicf("could not execute template '%s' for input file '%s': %s", templateFilename, inFile, err) - } - - result = FixAssetsPath(result, curNavPath) - - 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) - } - - //fmt.Println(string(html)) - } - } - - // process other files, copy... - for _, file := range conf.OtherFiles { - switch config.Config.OtherFiles.Action { - case "copy": - from := conf.InputPath + "/" + file - to := conf.OutputPath + "/" + file - Log.Noticef("copying file from '%s' to '%s'", from, to) - err := cpy.Copy(from, to) - if err != nil { - Log.Panicf("could not copy file from '%s' to '%s': %s", from, to, err) - } - } - } - - i := 0 - for i < len(conf.Sub) { - ProcessContent(rootConf, conf.Sub[i]) - i++ - } -} - -func renderMarkdown(input []byte, markdownConf *config.MarkdownConfig) []byte { - var options []blackfriday.Option - - var chromaRenderer *bool - var chromaStyle *string - if m := markdownConf; m != nil { - chromaRenderer = m.ChromaRenderer - chromaStyle = m.ChromaStyle - } - if chromaStyle == nil { - style := "monokai" - chromaStyle = &style - } - if chromaRenderer != nil && *chromaRenderer { - options = []blackfriday.Option{ - blackfriday.WithRenderer( - bfchroma.NewRenderer( - bfchroma.Style(*chromaStyle), - ), - ), - } - } - - // fix \r from markdown for blackfriday - input = bytes.Replace(input, []byte("\r"), []byte(""), -1) - return blackfriday.Run(input, options...) -} diff --git a/helper/dir.go b/helper/dir.go index 1c8738d..e677d78 100644 --- a/helper/dir.go +++ b/helper/dir.go @@ -1,6 +1,9 @@ package helper -import "os" +import ( + "os" + "strings" +) // CreateDirectory creates direcory with all missing parents and panic if error func CreateDirectory(dir string) { @@ -22,3 +25,14 @@ func CreateDirectory(dir string) { Log.Panicf("unknown error for output directory '%s': %s", dir, err) } } + +// BackToRoot builds ../../ string +func BackToRoot(curNavPath string) string { + tmpPath := "" + if curNavPath != "" { + for i := strings.Count(curNavPath, "/") + 1; i > 0; i-- { + tmpPath += "../" + } + } + return tmpPath +} diff --git a/helper/markdown.go b/helper/markdown.go new file mode 100644 index 0000000..adfdfef --- /dev/null +++ b/helper/markdown.go @@ -0,0 +1,29 @@ +package helper + +import ( + "bytes" + + "github.com/Depado/bfchroma" + "gopkg.in/russross/blackfriday.v2" +) + +func RenderMarkdown(input []byte, chromaRenderer bool, chromaStyle string) []byte { + var options []blackfriday.Option + + if chromaStyle == "" { + chromaStyle = "monokai" + } + if chromaRenderer { + options = []blackfriday.Option{ + blackfriday.WithRenderer( + bfchroma.NewRenderer( + bfchroma.Style(chromaStyle), + ), + ), + } + } + + // fix \r from markdown for blackfriday + input = bytes.Replace(input, []byte("\r"), []byte(""), -1) + return blackfriday.Run(input, options...) +} diff --git a/helper/merge.go b/helper/merge.go new file mode 100644 index 0000000..ebcbf2a --- /dev/null +++ b/helper/merge.go @@ -0,0 +1,28 @@ +package helper + +import ( + "reflect" + + "github.com/imdario/mergo" +) + +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/render.go b/helper/render.go deleted file mode 100644 index 68fcfa4..0000000 --- a/helper/render.go +++ /dev/null @@ -1,103 +0,0 @@ -package helper - -import ( - "log" - "path" - "regexp" - "strings" - - "gitbase.de/apairon/mark2web/config" - "github.com/flosch/pongo2" -) - -var templateCache = make(map[string]*pongo2.Template) -var currentContext *pongo2.Context -var currentTreeNodeConfig *config.PathConfigTree -var currentPathConfig *config.PathConfig -var templateDir string - -// BackToRoot builds ../../ string -func BackToRoot(curNavPath string) string { - tmpPath := "" - if curNavPath != "" { - for i := strings.Count(curNavPath, "/") + 1; i > 0; i-- { - tmpPath += "../" - } - } - return tmpPath -} - -// ResolveNavPath fixes nav target relative to current navigation path -func ResolveNavPath(target string) string { - curNavPath := (*currentContext)["CurrentPath"].(string) - if strings.HasPrefix(target, "/") { - target = BackToRoot(curNavPath) + target - } - target = path.Clean(target) - return target -} - -// ResolveOutputPath fixes output directory relative to current navigation path -func ResolveOutputPath(target string) string { - if strings.HasPrefix(target, "/") { - target = config.Config.Directories.Output + "/" + target - } else { - target = currentTreeNodeConfig.OutputPath + "/" + target - } - return path.Clean(target) -} - -// ResolveInputPath fixes input directory relative to current navigation path -func ResolveInputPath(target string) string { - if strings.HasPrefix(target, "/") { - target = config.Config.Directories.Input + "/" + target - } else { - target = currentTreeNodeConfig.InputPath + "/" + target - } - return path.Clean(target) -} - -// SetTemplateDir sets base directory for searching template files -func SetTemplateDir(dir string) { - templateDir = dir -} - -// RenderTemplate renders a pongo2 template with context -func RenderTemplate(filename string, treeNodeConfig *config.PathConfigTree, pathConfig *config.PathConfig, ctx *pongo2.Context) (string, error) { - currentContext = ctx - currentTreeNodeConfig = treeNodeConfig - currentPathConfig = pathConfig - templateFile := templateDir + "/" + filename - template := templateCache[templateFile] - if template == nil { - var err error - if template, err = pongo2.FromFile(templateFile); err != nil { - log.Panicf("could not parse template '%s': %s", templateFile, err) - } else { - templateCache[templateFile] = template - } - } - - 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) - repl := config.Config.Assets.FixTemplate.Replace - toPath := config.Config.Assets.ToPath - - bToRoot := BackToRoot(curNavPath) - regex, err := regexp.Compile(find) - if err != nil { - log.Panicf("could not compile regexp '%s' for assets path: %s", find, err) - } - repl = bToRoot + toPath + "/" + repl - repl = path.Clean(repl) + "/" - Log.Debugf("new assets paths: %s", repl) - return regex.ReplaceAllString(str, repl) - } - - return str -} diff --git a/helper/template_functions.go b/helper/template_functions.go deleted file mode 100644 index b4fd1d1..0000000 --- a/helper/template_functions.go +++ /dev/null @@ -1,125 +0,0 @@ -package helper - -import ( - "encoding/json" - "io/ioutil" - "net/http" - "strings" - - "gitbase.de/apairon/mark2web/config" - "github.com/flosch/pongo2" -) - -func jsonWebRequest(url string) interface{} { - Log.Noticef("requesting url via GET %s", url) - - resp, err := http.Get(url) - if err != nil { - Log.Panicf("could not get url '%s': %s", url, err) - } - defer resp.Body.Close() - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - Log.Panicf("could not read body from url '%s': %s", url, err) - } - - Log.Debugf("output from url '%s':\n%s", url, string(body)) - - if resp.StatusCode >= 400 { - Log.Panicf("bad status '%d - %s' from url '%s'", resp.StatusCode, resp.Status, url) - } - - contentType := resp.Header.Get("Content-Type") - - if strings.Contains(contentType, "json") { - - } else { - Log.Panicf("is not json '%s' from url '%s'", contentType, url) - } - - jsonMap := make(map[string]interface{}) - err = json.Unmarshal(body, &jsonMap) - if err == nil { - return jsonMap - } - - jsonArrayMap := make([]map[string]interface{}, 0) - err = json.Unmarshal(body, &jsonArrayMap) - if err == nil { - return jsonArrayMap - } - - Log.Panicf("could not read json from '%s': invalid type", url) - return nil -} - -// RequestFn will make a web request and returns map[string]interface form pongo2 -func RequestFn(url *pongo2.Value, args ...*pongo2.Value) *pongo2.Value { - u := url.String() - return pongo2.AsValue(jsonWebRequest(u)) -} - -func add2Nav(currentNode *config.PathConfigTree, pathConfig *config.PathConfig, tplFilename, outDir string, navname string, ctx interface{}, dataMapKey string, body string, hidden bool) { - newNodeConfig := new(config.PathConfigTree) - fillNodeConfig( - newNodeConfig, - currentNode.InputPath, - currentNode.OutputPath, - outDir, - pathConfig, - ) - if navname != "" { - newNodeConfig.Config.This = config.ThisPathConfig{ - Navname: &navname, - } - } - if dataMapKey != "" { - if newNodeConfig.Config.Data == nil { - newNodeConfig.Config.Data = make(config.MapString) - } - // as submap in Data - newNodeConfig.Config.Data[dataMapKey] = ctx - } else if m, ok := ctx.(map[string]interface{}); ok { - // direct set data - newNodeConfig.Config.Data = m - } - - // fake via normal file behavior - newNodeConfig.Config.Template = &tplFilename - newNodeConfig.InputFiles = []string{""} // empty file is special for use InputString - indexInFile := "" - indexOutFile := "index.html" - if idx := newNodeConfig.Config.Index; idx != nil { - if idx.OutputFile != nil && *idx.OutputFile != "" { - indexOutFile = *idx.OutputFile - } - } - newNodeConfig.Config.Index = &config.IndexConfig{ - InputFile: &indexInFile, - OutputFile: &indexOutFile, - InputString: &body, - } - newNodeConfig.Hidden = hidden - - currentNode.Sub = append(currentNode.Sub, newNodeConfig) -} - -// RenderFn renders a pongo2 template with additional context -func RenderFn(templateFilename, outDir, ctx *pongo2.Value, param ...*pongo2.Value) *pongo2.Value { - dataMapKey := "" - body := "" - - for i, p := range param { - switch i { - case 0: - dataMapKey = p.String() - case 1: - body = p.String() - } - } - - add2Nav(currentTreeNodeConfig, currentPathConfig, templateFilename.String(), outDir.String(), "", ctx.Interface(), dataMapKey, body, true) - - return pongo2.AsValue(nil) -} diff --git a/helper/webrequest.go b/helper/webrequest.go new file mode 100644 index 0000000..56657e1 --- /dev/null +++ b/helper/webrequest.go @@ -0,0 +1,52 @@ +package helper + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "strings" +) + +func JSONWebRequest(url string) interface{} { + Log.Noticef("requesting url via GET %s", url) + + resp, err := http.Get(url) + if err != nil { + Log.Panicf("could not get url '%s': %s", url, err) + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + Log.Panicf("could not read body from url '%s': %s", url, err) + } + + Log.Debugf("output from url '%s':\n%s", url, string(body)) + + if resp.StatusCode >= 400 { + Log.Panicf("bad status '%d - %s' from url '%s'", resp.StatusCode, resp.Status, url) + } + + contentType := resp.Header.Get("Content-Type") + + if strings.Contains(contentType, "json") { + + } else { + Log.Panicf("is not json '%s' from url '%s'", contentType, url) + } + + jsonMap := make(map[string]interface{}) + err = json.Unmarshal(body, &jsonMap) + if err == nil { + return jsonMap + } + + jsonArrayMap := make([]map[string]interface{}, 0) + err = json.Unmarshal(body, &jsonArrayMap) + if err == nil { + return jsonArrayMap + } + + Log.Panicf("could not read json from '%s': invalid type", url) + return nil +} diff --git a/main.go b/main.go deleted file mode 100644 index 3a52098..0000000 --- a/main.go +++ /dev/null @@ -1,143 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "os" - "path" - - "gitbase.de/apairon/mark2web/config" - "gitbase.de/apairon/mark2web/helper" -) - -var ( - // Version is the app's version string - Version = "UNKNOWN" - // GitHash is the current git hash for this version - GitHash = "UNKNOWN" - // BuildTime is the time of build of this app - BuildTime = "UNKNOWN" -) - -var log = helper.Log - -var contentConfig = new(config.PathConfigTree) - -func main() { - inDir := flag.String("in", "./", "input directory") - outDir := flag.String("out", "html", "output directory") - createOutDir := flag.Bool("create", false, "create output directory if not existing") - //clearOutDir := flag.Bool("clear", false, "clear output directory before generating website") - logLevel := flag.String("logLevel", "info", "log level: debug, info, warning, error") - version := flag.Bool("version", false, "print version of this executable") - - flag.Parse() - if version != nil && *version { - fmt.Printf(`%11s: %s -%11s: %s -%11s: %s -`, "version", Version, "git hash", GitHash, "build time", BuildTime) - os.Exit(0) - } - - level := "info" - if logLevel != nil { - level = *logLevel - } - helper.ConfigureLogger(level) - - if inDir == nil || *inDir == "" { - log.Panic("input directory not specified") - } - iDir := path.Clean(*inDir) - inDir = &iDir - log.Infof("input directory: %s", *inDir) - - if outDir == nil || *outDir == "" { - log.Panic("output directory not specified") - } - oDir := path.Clean(*outDir) - outDir = &oDir - log.Infof("output directory: %s", *outDir) - - if createOutDir != nil && *createOutDir { - if _, err := os.Stat(*outDir); os.IsNotExist(err) { - log.Debugf("output directory '%s' does not exist", *outDir) - log.Debugf("trying to create output directory: %s", *outDir) - err := os.MkdirAll(*outDir, 0755) - if err != nil { - log.Panic(err) - } - log.Noticef("created output directory: %s", *outDir) - } else { - log.Noticef("output directory '%s' already exists", *outDir) - } - } - - if fD, err := os.Stat(*outDir); os.IsNotExist(err) { - log.Panicf("output directory '%s' does not exist, try -create parameter or create manually", *outDir) - } else { - if fD == nil { - log.Panicf("something went wrong, could not get file handle for output dir %s", *outDir) - } else if !fD.IsDir() { - log.Panicf("output directory '%s' is not a directory", *outDir) - } - } - - log.Debug("reading global config...") - configFilename := *inDir + "/config.yml" - err := config.ReadGlobalConfig(configFilename) - if err != nil { - log.Panicf("could not read file '%s': %s", configFilename, err) - } - config.Config.Directories.Input = *inDir - config.Config.Directories.Output = *outDir - - log.Debugf("reading input directory %s", *inDir) - - defaultTemplate := "base.html" - defaultInputFile := "README.md" - defaultOutputFile := "index.html" - defaultPathStrip := "^[0-9]*_(.*)" - defaultPathIgnoreForNav := "^_" - defaultFilenameStrip := "(.*).md$" - defaultFilenameIgnore := "^_" - defaultFilenameOutputExtension := "html" - - defaultPathConfig := new(config.PathConfig) - defaultPathConfig.Template = &defaultTemplate - defaultPathConfig.Index = &config.IndexConfig{ - InputFile: &defaultInputFile, - OutputFile: &defaultOutputFile, - } - defaultPathConfig.Path = &config.DirnameConfig{ - Strip: &defaultPathStrip, - IgnoreForNav: &defaultPathIgnoreForNav, - } - defaultPathConfig.Filename = &config.FilenameConfig{ - Strip: &defaultFilenameStrip, - Ignore: &defaultFilenameIgnore, - OutputExtension: &defaultFilenameOutputExtension, - } - defaultPathConfig.Imaging = &config.ImagingConfig{ - Width: 1920, - Height: 1920, - Process: "fit", - Quality: 75, - } - - helper.ReadContentDir(*inDir+"/content", *outDir, "", defaultPathConfig, contentConfig) - //spew.Dump(contentConfig) - - //spew.Dump(navMap) - - templatesDir := *inDir + "/templates" - helper.SetTemplateDir(templatesDir) - filtersDir := templatesDir + "/filters" - if _, err := os.Stat(filtersDir); !os.IsNotExist(err) { - helper.RegisterFilters(filtersDir) - } - helper.ProcessContent(contentConfig, contentConfig) - - helper.ProcessAssets() -} diff --git a/helper/navigation.go b/navigation.go similarity index 88% rename from helper/navigation.go rename to navigation.go index 950480b..679b69d 100644 --- a/helper/navigation.go +++ b/navigation.go @@ -1,4 +1,4 @@ -package helper +package mark2web import ( "path" @@ -6,6 +6,7 @@ import ( "strings" "gitbase.de/apairon/mark2web/config" + "gitbase.de/apairon/mark2web/helper" ) // NavElement is one element with ist attributes and subs @@ -38,10 +39,10 @@ func BuildNavigation(conf *config.PathConfigTree, curNavMap *map[string]*NavElem if ignNav != nil && *ignNav != "" { regex, err := regexp.Compile(*ignNav) if err != nil { - Log.Panicf("could not compile IngoreForNav regexp '%s' in '%s': %s", *ignNav, el.InputPath, err) + helper.Log.Panicf("could not compile IngoreForNav regexp '%s' in '%s': %s", *ignNav, el.InputPath, err) } if regex.MatchString(path.Base(el.InputPath)) { - Log.Debugf("ignoring input directory '%s' in navigation", el.InputPath) + helper.Log.Debugf("ignoring input directory '%s' in navigation", el.InputPath) continue } } @@ -88,7 +89,7 @@ func BuildNavigation(conf *config.PathConfigTree, curNavMap *map[string]*NavElem if activeNav != "" && activeNav != "/" { // calculate relative path - bToRoot := BackToRoot(activeNav) + bToRoot := helper.BackToRoot(activeNav) navEl.GoTo = bToRoot + navEl.GoTo navEl.GoTo = path.Clean(navEl.GoTo) } diff --git a/render.go b/render.go new file mode 100644 index 0000000..aa4c900 --- /dev/null +++ b/render.go @@ -0,0 +1,60 @@ +package mark2web + +import ( + "log" + "path" + "regexp" + + "gitbase.de/apairon/mark2web/config" + "gitbase.de/apairon/mark2web/context" + "gitbase.de/apairon/mark2web/helper" + "github.com/flosch/pongo2" +) + +var templateCache = make(map[string]*pongo2.Template) +var templateDir string + +// SetTemplateDir sets base directory for searching template files +func SetTemplateDir(dir string) { + templateDir = dir +} + +// RenderTemplate renders a pongo2 template with context +func RenderTemplate(filename string, treeNodeConfig *config.PathConfigTree, pathConfig *config.PathConfig, ctx *pongo2.Context) (string, error) { + context.CurrentContext = ctx + context.CurrentTreeNodeConfig = treeNodeConfig + context.CurrentPathConfig = pathConfig + templateFile := templateDir + "/" + filename + template := templateCache[templateFile] + if template == nil { + var err error + if template, err = pongo2.FromFile(templateFile); err != nil { + log.Panicf("could not parse template '%s': %s", templateFile, err) + } else { + templateCache[templateFile] = template + } + } + + 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 != "" { + helper.Log.Debugf("fixing assets paths for path '%s'", curNavPath) + repl := config.Config.Assets.FixTemplate.Replace + toPath := config.Config.Assets.ToPath + + bToRoot := helper.BackToRoot(curNavPath) + regex, err := regexp.Compile(find) + if err != nil { + log.Panicf("could not compile regexp '%s' for assets path: %s", find, err) + } + repl = bToRoot + toPath + "/" + repl + repl = path.Clean(repl) + "/" + helper.Log.Debugf("new assets paths: %s", repl) + return regex.ReplaceAllString(str, repl) + } + + return str +}