From cf35312e6df099b56310a15204fbfb8b9ffa95d2 Mon Sep 17 00:00:00 2001 From: "Yann Esposito (Yogsototh)" Date: Mon, 15 Jan 2024 16:08:32 +0100 Subject: [PATCH] Initial statyk script --- statyk | 361 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 361 insertions(+) create mode 100755 statyk diff --git a/statyk b/statyk new file mode 100755 index 0000000..6800a2c --- /dev/null +++ b/statyk @@ -0,0 +1,361 @@ +#!/bin/bash # -*- mode: Clojure; -*- +#_( + + export COMMANDNAME="$0" + + #_DEPS is same format as deps.edn. Multiline is okay. + DEPS=' + {:deps { + org.clojure/tools.cli {:mvn/version "1.0.214"} + ring/ring-core {:mvn/version "1.11.0"} + ring/ring-jetty-adapter {:mvn/version "1.11.0"} + babashka/fs {:mvn/version "0.5.20"} + }} + ' + + #_You can put other options here + OPTS=' + -J-Xms4m -J-Xmx256m + ' +#_Install Clojure if not present on the system (java is needed though) +if [[ ! -x .local/bin/clojure ]]; then + [[ ! -d .local ]] && mkdir .local + pushd .local + curl -O https://download.clojure.org/install/posix-install-1.11.1.1273.sh + chmod +x posix-install-1.11.1.1273.sh + ./posix-install-1.11.1.1273.sh -p $PWD + popd +fi + +exec clojure $OPTS -Sdeps "$DEPS" -M "$0" "$@" +) + +(ns statyk + (:require [clojure.tools.cli :refer [parse-opts]] + [clojure.pprint :as pp] + [clojure.string :as string] + [ring.util.mime-type :as mime] + [ring.util.response :as resp] + [babashka.fs :as fs] + [ring.adapter.jetty :refer [run-jetty]])) + +(def config + {:source-directory "_src" + :dest-directory "_site" + :port 13375 + :host "127.0.0.1"}) + +(def cli-options + []) + +(defn pr-err! + "Print on std error" + [s & args] + (binding [*out* *err*] + (println (apply format s args)))) + +(defn err! + [s & args] + (apply pr-err! s args) + (System/exit 1)) + +(defn read-file + [path] + (try + (slurp path) + (catch Exception e + (pr-err! "Could not read %s" path) + nil))) + +(defn is-newer? + "returns true if file-1 is newer than file-2" + [f1 f2] + (let [[t1 t2] (mapv #(fs/file-time->millis (fs/get-attribute % "basic:lastModifiedTime")) + [f1 f2])] + (< t2 t1))) + +(defn serve-dest-dir-handler + [request] + (let [path (str dest-directory (:uri request))] + (if-let [content (read-file path)] + (let [mime-type (mime/ext-mime-type path)] + (cond-> (resp/ok content) + mime-type (resp/content-type mime-type))) + {:status 404 + :header {"Content-Type" "text/plain"} + :body (format "File '%s' not found." path)}))) + +(defn html-src-type? [extension] + (contains? #{"org" "md"} extension)) + +(defn css-src-type? [extension] + (contains? #{"css" "scss" "sass"} extension)) + +(defn img-src-type? [extension] + (contains? #{"jpg" "jpeg" "png" "wepb"} extension)) + +(defn replace-extension + [f new-extension] + (str (fs/strip-ext f) "." new-extention)) + +(defn dst-file-name-and-ext + [src-file] + (let [ext (fs/extension src-file) + tmp-path (string/replace src-file + (:source-directory config) + (:dest-directory config)) + dst-path (cond (html-src-type? ext) (replace-extension tmp-path "html") + (css-src-type? ext) (replace-extension tmp-path "css") + (img-src-type? ext) (replace-extension tmp-path "webp") + :else tmp-path)] + {:ext ext + :dst-path dst-path})) + +(defn build-html + [src-file dst-file] + ;; TODO PANDOC then minify + ) +(defn build-css + [src-file dst-file] + ;; TODO cless or copy then minify + ) + +(defn build-img + ;; TODO jpg => webp + ) + +(defn build + "Table with specific commands per type of file" + [src-file dst-file ext] + (cond + (html-src-type? ext) (build-html src-file dst-file) + (css-src-type? ext) (build-css src-file dst-file) + (img-src-type? ext) (build-img src-file dst-file) + :else (fs/copy src-file dst-file))) + +(defn generate-static-files + [] + (doseq [src-file (file-seq (:source-directory config))] + (let [{:keys [ext dst-file]} (dst-file-name src-file)] + (when (is-newer? src-file dst-file) + (build src-file dst-file ext))))) + +(defn show-help + [] + (println (string/join "\n" + ["Usage: statyk [] []" + "Where commands:" + "- serve serve the directory _site" + "- gen generate the files from the sources" + "- clean delete generated files in _site"])) + (System/exit 0)) + +(defn -main [& args] + (let [{:keys [options arguments summary errors] + :as parsed} + (parse-opts args cli-options)] + (when errors + (doseq [err errors] + (pr-err! err) + (System/exit 1))) + (let [command (first arguments)] + (condp = command + "serve" (do + (println "Serve: http://127.0.0.1:13375") + (run-jetty serve-dest-dir-handler + {:port 13375 + :host "127.0.0.1"})) + "gen" (generate-static-files) + (show-help) + (err! (format "unknown command %s" command)))) + (pp/pprint parsed))) + +(apply -main *command-line-args*) + + + +;; Generate a website out of +;; # any kind of document files +;; # txt, markdown, org-mode, gemini etc... +;; +;; all: site +;; SRC_DIR ?= src +;; DST_DIR ?= _site +;; CACHE_DIR ?= .cache +;; +;; # we don't copy source files +;; NO_SRC_FILE := ! -name '*.org' ! -name '*.css' ! -name '*.md' +;; +;; define adv_rule +;; SRC_$(1) := $$(shell find $$(SRC_DIR) -type f $(2)) +;; DST_$(1) := $$(patsubst $$(SRC_DIR)/%,$$(DST_DIR)/%,$$(SRC_$(1))) +;; $$(DST_DIR)/%$(4): $$(SRC_DIR)/%$(4) +;; @mkdir -p "$$(dir $$@)" +;; $(3) +;; .PHONY: $(1) +;; $(1): $$(DST_$(1)) +;; ALL += $(1) +;; endef +;; +;; define rule +;; SRC_$(1) := $$(shell find $$(SRC_DIR) -type f $(2)) +;; DST_$(1) := $$(patsubst $$(SRC_DIR)/%,$$(DST_DIR)/%,$$(SRC_$(1))) +;; $$(DST_DIR)/%.$(1): $$(SRC_DIR)/%.$(1) +;; @mkdir -p "$$(dir $$@)" +;; $(3) +;; .PHONY: $(1) +;; $(1): $$(DST_$(1)) +;; ALL += $(1) +;; endef +;; +;; # copy assets +;; $(eval $(call adv_rule,assets, $$(NO_SRC_FILE),cp "$$<" "$$@",)) +;; +;; # CSS +;; $(eval $(call rule,css,-name '*.css',minify "$$<" > "$$@")) +;; +;; +;; # ORG, MD -> HTML +;; EXT ?= .org +;; SRC_PANDOC_FILES ?= $(shell find $(SRC_DIR) -type f \( -name "*$(EXT)" -o \) $(NO_DRAFT)) +;; DST_PANDOC_FILES ?= $(patsubst %$(EXT),%.html, \ +;; $(patsubst $(SRC_DIR)/%,$(DST_DIR)/%, \ +;; $(SRC_PANDOC_FILES))) +;; PANDOC_TEMPLATE ?= templates/post.html +;; PANDOC_LUA_FILTER ?= engine/links-to-html.lua +;; PANDOC_LUA_FILTER_IMG ?= engine/img-to-webp.lua +;; PANDOC_LUA_METAS ?= engine/metas.lua +;; MK_HTML := engine/mk-html.sh +;; PANDOC := $(MK_HTML) $(PANDOC_TEMPLATE) $(PANDOC_LUA_FILTER) $(PANDOC_LUA_FILTER_IMG) $(PANDOC_LUA_METAS) +;; $(DST_DIR)/%.html: $(SRC_DIR)/%.org $(PANDOC_TEMPLATE) $(PANDOC_LUA_FILTER) $(PANDOC_LUA_FILTER_IMG) $(PANDOC_LUA_METAS) $(MK_HTML) $(ENV_VARS) +;; @mkdir -p "$(dir $@)" +;; $(PANDOC) "$<" "$@.tmp" +;; minify --mime text/html "$@.tmp" > "$@" +;; @rm "$@.tmp" +;; .PHONY: html +;; html: $(DST_PANDOC_FILES) +;; ALL += html +;; +;; # INDEXES +;; SRC_POSTS_DIR ?= $(SRC_DIR)/posts +;; DST_POSTS_DIR ?= $(DST_DIR)/posts +;; SRC_POSTS_FILES ?= $(shell find $(SRC_POSTS_DIR) -type f -name "*$(EXT)") +;; RSS_CACHE_DIR ?= $(CACHE_DIR)/rss +;; DST_XML_FILES ?= $(patsubst %.org,%.xml, \ +;; $(patsubst $(SRC_POSTS_DIR)/%,$(RSS_CACHE_DIR)/%, \ +;; $(SRC_POSTS_FILES))) +;; $(RSS_CACHE_DIR)/%.xml: $(DST_POSTS_DIR)/%.html $(ENV_VARS) +;; @mkdir -p "$(dir $@)" +;; hxclean "$<" > "$@" +;; .PHONY: indexcache +;; indexcache: $(DST_XML_FILES) +;; ALL += indexcache +;; +;; # HTML INDEX +;; DST_INDEX_FILES ?= $(patsubst %.xml,%.index, $(DST_XML_FILES)) +;; MK_INDEX_ENTRY := ./engine/mk-index-entry.sh +;; INDEX_CACHE_DIR ?= $(CACHE_DIR)/rss +;; $(INDEX_CACHE_DIR)/%.index: $(INDEX_CACHE_DIR)/%.xml $(MK_INDEX_ENTRY) $(ENV_VARS) +;; @mkdir -p $(INDEX_CACHE_DIR) +;; $(MK_INDEX_ENTRY) "$<" "$@" +;; +;; HTML_INDEX := $(DST_DIR)/index.html +;; MKINDEX := engine/mk-index.sh +;; INDEX_TEMPLATE ?= templates/index.html +;; $(HTML_INDEX): $(DST_INDEX_FILES) $(MKINDEX) $(INDEX_TEMPLATE) $(ENV_VARS) +;; @mkdir -p $(DST_DIR) +;; $(MKINDEX) +;; .PHONY: index +;; index: $(HTML_INDEX) +;; ALL += index +;; +;; # RSS +;; DST_RSS_FILES ?= $(patsubst %.xml,%.rss, $(DST_XML_FILES)) $(ENV_VARS) +;; MK_RSS_ENTRY := ./engine/mk-rss-entry.sh +;; $(RSS_CACHE_DIR)/%.rss: $(RSS_CACHE_DIR)/%.xml $(MK_RSS_ENTRY) +;; @mkdir -p $(RSS_CACHE_DIR) +;; $(MK_RSS_ENTRY) "$<" "$@" +;; +;; RSS := $(DST_DIR)/rss.xml +;; MKRSS := engine/mkrss.sh +;; $(RSS): $(DST_RSS_FILES) $(MKRSS) $(ENV_VARS) +;; $(MKRSS) +;; +;; .PHONY: rss +;; rss: $(RSS) +;; ALL += rss +;; +;; +;; # ORG -> GEMINI +;; EXT := .org +;; SRC_GMI_FILES ?= $(shell find $(SRC_DIR) -type f -name "*$(EXT)" $(NO_DRAFT)) +;; DST_GMI_FILES ?= $(subst $(EXT),.gmi, \ +;; $(patsubst $(SRC_DIR)/%,$(DST_DIR)/%, \ +;; $(SRC_GMI_FILES))) +;; GMI := engine/org2gemini.sh +;; $(DST_DIR)/%.gmi: $(SRC_DIR)/%.org $(GMI) engine/org2gemini_step1.sh +;; @mkdir -p $(dir $@) +;; $(GMI) "$<" "$@" +;; ALL += $(DST_GMI_FILES) +;; .PHONY: gmi +;; gmi: $(DST_GMI_FILES) +;; +;; # GEMINI INDEX +;; GMI_INDEX := $(DST_DIR)/index.gmi +;; MK_GMI_INDEX := engine/mk-gemini-index.sh +;; $(GMI_INDEX): $(DST_GMI_FILES) $(MK_GMI_INDEX) $(ENV_VARS) +;; @mkdir -p $(DST_DIR) +;; $(MK_GMI_INDEX) +;; ALL += $(GMI_INDEX) +;; .PHONY: gmi-index +;; gmi-index: $(GMI_INDEX) +;; +;; # RSS +;; GMI_ATOM := $(DST_DIR)/gem-atom.xml +;; MK_GEMINI_ATOM := engine/mk-gemini-atom.sh +;; $(GMI_ATOM): $(DST_GMI_FILES) $(MK_GEMINI_ATOM) +;; $(MK_GEMINI_ATOM) +;; ALL += $(GMI_ATOM) +;; .PHONY: gmi-atom +;; gmi-atom: $(GMI_ATOM) +;; +;; .PHONY: gemini +;; gemini: $(DST_GMI_FILES) $(GMI_INDEX) $(GMI_ATOM) +;; +;; # Images +;; OPTIM_IMG := engine/optim-img.sh +;; +;; define img +;; SRC_IMG_$(1) ?= $$(shell find $$(SRC_DIR) -type f -name "*.$(1)") +;; DST_IMG_$(1) ?= $$(patsubst $$(SRC_DIR)/%,$$(DST_DIR)/%,$$(SRC_IMG_$(1))) +;; $$(DST_DIR)/%.$(1): $$(SRC_DIR)/%.$(1) $$(OPTIM_IMG) +;; @mkdir -p $$(dir $$@) +;; $$(OPTIM_IMG) "$$<" "$$@" +;; .PHONY: $(1) +;; $(1): $$(DST_IMG_$(1)) +;; ALL += $(1) +;; endef +;; +;; $(info $(call img,jpg)) +;; $(eval $(call img,jpg)) +;; $(eval $(call img,jpeg)) +;; $(eval $(call img,gif)) +;; $(eval $(call img,png)) +;; +;; .PHONY: img +;; img: jpg jpeg gif png +;; +;; # DEPLOY +;; .PHONY: site +;; site: $(ALL) +;; +;; .PHONY: deploy +;; deploy: $(ALL) +;; engine/sync.sh # deploy to her.esy.fun +;; engine/ye-com-fastpublish.hs # deploy to yannesposito.com (via github pages) +;; +;; .PHONY: clean +;; clean: +;; -[ -f $(ENV_VARS) ] && rm $(ENV_VARS) +;; -[ ! -z "$(DST_DIR)" ] && rm -rf $(DST_DIR)/* +;; -[ ! -z "$(CACHE_DIR)" ] && rm -rf $(CACHE_DIR)/*