Initial statyk script

This commit is contained in:
Yann Esposito (Yogsototh) 2024-01-15 16:08:32 +01:00
commit cf35312e6d
Signed by untrusted user who does not match committer: yogsototh
GPG Key ID: 7B19A4C650D59646
1 changed files with 361 additions and 0 deletions

361
statyk Executable file
View File

@ -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 [<options>] <command> [<args>]"
"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)/*