Initial statyk script
This commit is contained in:
commit
cf35312e6d
361
statyk
Executable file
361
statyk
Executable 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)/*
|
Loading…
Reference in a new issue