From 08588f9907299b1a927e281d5c65b46b7cefa427 Mon Sep 17 00:00:00 2001 From: EuAndreh Date: Tue, 4 Apr 2023 08:33:41 -0300 Subject: Revamp v2/ --- v2/.envrc | 2 + v2/.gitignore | 15 +- v2/Makefile | 16 +- v2/TODOs.md | 1 - v2/aux/ci/git-post-receive.sh | 186 +++++++++++++++ v2/aux/ci/git-pre-receive.sh | 14 ++ v2/aux/ci/report.sh | 250 +++++++++++++++++++++ v2/aux/domain.txt | 1 + v2/aux/lib.sh | 37 +++ v2/aux/po4a-cfg.sh | 109 +++++++++ v2/aux/workflow/TODOs.sh | 1 - v2/aux/workflow/favicon.html | 1 - v2/aux/workflow/preamble.md | 1 - v2/aux/workflow/style.css | 1 - v2/dynamic.mk | 104 +++++---- v2/po/euandre.org.pot | 72 ++++++ v2/po/po4a.cfg | 7 + v2/po/pt.po | 53 +++++ v2/src/bin/absolute | 4 +- v2/src/bin/extract | 133 ----------- v2/src/bin/makemake | 137 +++++++++++ v2/src/bin/url-for | 10 +- v2/src/content/.well-known/security.txt | 4 + v2/src/content/favicon.svg | 1 + .../pastebins/raku-tuple-type-annotation.md | 37 +++ v2/src/content/pastebins/sicp-exercise-3-19.md | 10 +- v2/src/content/public.asc.txt | 86 +++++++ v2/src/content/static/atom.svg | 1 - v2/src/content/static/envelope.svg | 1 - v2/src/content/static/favicon.svg | 1 - v2/src/content/static/link.svg | 1 - v2/src/content/static/lock.svg | 1 - v2/src/content/static/public.asc.txt | 1 - v2/src/content/static/styles.css | 149 ------------ v2/src/content/style.css | 149 ++++++++++++ v2/src/content/tils/lisp-three-way-conditional.md | 63 ++++++ v2/src/development/config.env.in | 6 - v2/src/development/dynmake.sh | 79 ------- v2/src/development/genhtml.sh | 68 +++--- v2/src/development/getconf.sh | 119 ++++++++++ v2/src/development/lib.sh | 33 +++ v2/src/development/security-txt.sh.in | 82 +++++++ v2/src/lib/base-conf.in | 9 + v2/src/lib/base.en.conf | 3 + v2/src/lib/base.pt.conf | 3 + v2/src/lib/postamble.en.html | 7 + v2/src/lib/postamble.pt.html | 5 + v2/src/lib/preamble.en.html | 37 +++ v2/src/lib/preamble.pt.html | 36 +++ 49 files changed, 1672 insertions(+), 475 deletions(-) delete mode 120000 v2/TODOs.md create mode 100755 v2/aux/ci/git-post-receive.sh create mode 100755 v2/aux/ci/git-pre-receive.sh create mode 100755 v2/aux/ci/report.sh create mode 100644 v2/aux/domain.txt create mode 100644 v2/aux/lib.sh create mode 100755 v2/aux/po4a-cfg.sh delete mode 120000 v2/aux/workflow/TODOs.sh delete mode 100644 v2/aux/workflow/favicon.html delete mode 120000 v2/aux/workflow/preamble.md delete mode 120000 v2/aux/workflow/style.css create mode 100644 v2/po/euandre.org.pot create mode 100644 v2/po/po4a.cfg create mode 100644 v2/po/pt.po delete mode 100755 v2/src/bin/extract create mode 100755 v2/src/bin/makemake create mode 100644 v2/src/content/.well-known/security.txt create mode 120000 v2/src/content/favicon.svg create mode 100644 v2/src/content/pastebins/raku-tuple-type-annotation.md create mode 100644 v2/src/content/public.asc.txt delete mode 120000 v2/src/content/static/atom.svg delete mode 120000 v2/src/content/static/envelope.svg delete mode 120000 v2/src/content/static/favicon.svg delete mode 120000 v2/src/content/static/link.svg delete mode 120000 v2/src/content/static/lock.svg delete mode 120000 v2/src/content/static/public.asc.txt delete mode 100644 v2/src/content/static/styles.css create mode 100644 v2/src/content/style.css create mode 100644 v2/src/content/tils/lisp-three-way-conditional.md delete mode 100644 v2/src/development/config.env.in delete mode 100755 v2/src/development/dynmake.sh create mode 100755 v2/src/development/getconf.sh create mode 100644 v2/src/development/lib.sh create mode 100755 v2/src/development/security-txt.sh.in create mode 100644 v2/src/lib/base-conf.in create mode 100644 v2/src/lib/base.en.conf create mode 100644 v2/src/lib/base.pt.conf create mode 100644 v2/src/lib/postamble.en.html create mode 100644 v2/src/lib/postamble.pt.html create mode 100644 v2/src/lib/preamble.en.html create mode 100644 v2/src/lib/preamble.pt.html (limited to 'v2') diff --git a/v2/.envrc b/v2/.envrc index 1bdbb88..aa81005 100644 --- a/v2/.envrc +++ b/v2/.envrc @@ -2,3 +2,5 @@ set -eu export PATH="$PWD/src/bin:$PATH" +export GIT_DIR="$PWD"/../.git +export GIT_WORK_TREE="$PWD"/../ diff --git a/v2/.gitignore b/v2/.gitignore index 4ce7eaa..505c08b 100644 --- a/v2/.gitignore +++ b/v2/.gitignore @@ -1,9 +1,8 @@ -/src/development/config.env /generated.mk -/src/content/TODOs.html -/aux/tld.txt -/src/content/.well-known/security.txt - -/src/content/pastebins/*.html -/src/content/pastebins/*.txt -/src/content/pastebins/*.entry-* +/*.sentinel +/src/lib/base-conf +/src/development/security-txt.sh +/public/ +/src/content/*/*.conf +/src/content/*/*.content +/src/content/*/*.html diff --git a/v2/Makefile b/v2/Makefile index b0acb8f..e7a7279 100644 --- a/v2/Makefile +++ b/v2/Makefile @@ -1,12 +1,18 @@ .POSIX: .DEFAULT: - $(MAKE) generated.mk - $(MAKE) -f dynamic.mk $< + @$(MAKE) deps + @$(MAKE) -f dynamic.mk $< -all: generated.mk - $(MAKE) -f dynamic.mk all +all: deps + @$(MAKE) -f dynamic.mk all + +deps: generated.mk po/po4a.cfg generated.mk: ALWAYS - sh src/development/dynmake.sh > $@ + @sh src/bin/makemake > generated.mk + +po/po4a.cfg: ALWAYS + @sh aux/po4a-cfg.sh | ifnew $@ + po4a $@ ALWAYS: diff --git a/v2/TODOs.md b/v2/TODOs.md deleted file mode 120000 index 090bb76..0000000 --- a/v2/TODOs.md +++ /dev/null @@ -1 +0,0 @@ -../TODOs.md \ No newline at end of file diff --git a/v2/aux/ci/git-post-receive.sh b/v2/aux/ci/git-post-receive.sh new file mode 100755 index 0000000..76adccf --- /dev/null +++ b/v2/aux/ci/git-post-receive.sh @@ -0,0 +1,186 @@ +#!/bin/sh +# shellcheck source=/dev/null disable=2317 +. /etc/rc +set -eu + + +# shellcheck disable=2034 +read -r _oldrev SHA REFNAME + +if [ "$SHA" = '0000000000000000000000000000000000000000' ]; then + exit +fi + + +SKIP_DEPLOY=false +for n in $(seq 0 $((GIT_PUSH_OPTION_COUNT - 1))); do + opt="$(eval "printf '%s' \"\$GIT_PUSH_OPTION_$n\"")" + case "$opt" in + ci.skip) + cat <<-EOF + + "$opt" option detected, not running CI. + + EOF + exit + ;; + deploy.skip) + SKIP_DEPLOY=true + ;; + *) + ;; + esac +done + + +epoch() { + awk 'BEGIN { srand(); print(srand()); }' +} + +now() { + date '+%Y-%m-%dT%H:%M:%S%:z' +} + +NAME="$(basename "$PWD" .git)" +LOGS_DIR=/var/log/ci/"$NAME"/ +HTML_OUTDIR="/srv/www/s/$NAME" +TIMESTAMP="$(now)" +FILENAME="$TIMESTAMP-$SHA.log" +LOGFILE="$LOGS_DIR/$FILENAME" +mkdir -p "$LOGS_DIR" + + +END_MARKER='\033[0m' +LIGHT_BLUE_B='\033[1;36m' +YELLOW='\033[1;33m' + +blue() { + printf "${LIGHT_BLUE_B}%s${END_MARKER}" "$1" +} + +yellow() { + printf "${YELLOW}%s${END_MARKER}" "$1" +} + +info() { + sed "s|^\(.\)|$(blue 'CI'): \1|" +} + + +uuid() { + od -xN20 /dev/urandom | + head -n1 | + awk '{OFS="-"; print $2$3,$4,$5,$6,$7$8$9}' +} + +tmpname() { + printf '%s/uuid-tmpname with spaces.%s' "${TMPDIR:-/tmp}" "$(uuid)" +} + +mkdtemp() { + name="$(tmpname)" + mkdir -- "$name" + printf '%s' "$name" +} + + +{ + cat <<-EOF | info + Starting CI job at: $(now) + EOF + START="$(epoch)" + + duration() { + if [ "$RUN_DURATION" -gt 60 ]; then + cat <<-EOF + $(yellow 'WARNING'): run took more than 1 minute! ($RUN_DURATION seconds) + EOF + else + cat <<-EOF + Run took $RUN_DURATION seconds. + EOF + fi + } + + finish() { + STATUS="$?" + END="$(epoch)" + RUN_DURATION=$((END - START)) + cat <<-EOF | info + Finishing CI job at: $(now) + Exit status was $STATUS + Re-run with: + \$ $CMD + $(duration) + EOF + + NOTE="$( + cat <<-EOF + See CI logs with: + git notes --ref=refs/notes/ci-logs show $SHA + git notes --ref=refs/notes/ci-data show $SHA + + Exit status: $STATUS + Duration: $RUN_DURATION + EOF + )" + git notes --ref=refs/notes/ci-data add -f -m "$( + cat <<-EOF + status $STATUS + sha $SHA + filename $FILENAME + duration $RUN_DURATION + timestamp $TIMESTAMP + to-prod $TO_PROD + refname $REFNAME + EOF + )" "$SHA" + git notes --ref=refs/notes/ci-logs add -f -F "$LOGFILE" "$SHA" + git notes add -f -m "$NOTE" "$SHA" + + { + printf 'Git CI HTML report for %s (%s) started.\n' "$NAME" "$SHA" >&2 + DIR="$(mkdtemp)" + REMOTE="$PWD" + cd "$DIR" + { + git clone "$REMOTE" . + git fetch origin 'refs/notes/*:refs/notes/*' + } 1>/dev/null 2>&1 + sh aux/ci/report.sh -n "$NAME" -o public-ci + sudo -u deployer mkdir -p "$HTML_OUTDIR"/ci/ + sudo -u deployer rsync \ + --chmod=D775,F664 \ + --chown=deployer:deployer \ + --delete \ + -a \ + public-ci/ "$HTML_OUTDIR"/ci/ + rm -rf "$DIR" + printf 'Git CI HTML report for %s (%s) finished.\n' "$NAME" "$SHA" >&2 + } 2>&1 | logger -i -p local0.warn -t git-ci 1>/dev/null 2>&1 & + } + trap finish EXIT + + unset GIT_DIR + + if [ "$REFNAME" = 'refs/heads/main' ] && [ "$SKIP_DEPLOY" = false ]; then + cat <<-EOF | info + In branch "main", running deploy for $SHA. + EOF + TO_PROD=true + CMD="sudo cicd $NAME $SHA" + else + if [ "$SKIP_DEPLOY" = true ]; then + cat <<-EOF | info + "deploy.skip" option detected, skipping deploy for $SHA. + EOF + else + cat <<-EOF | info + Not on branch "main", skipping deploy for $SHA. + EOF + fi + TO_PROD=false + CMD="sudo cicd -n $NAME $SHA" + fi + $CMD +} 2>&1 | ts -s '%.s' | tee "$LOGFILE" diff --git a/v2/aux/ci/git-pre-receive.sh b/v2/aux/ci/git-pre-receive.sh new file mode 100755 index 0000000..199d06e --- /dev/null +++ b/v2/aux/ci/git-pre-receive.sh @@ -0,0 +1,14 @@ +#!/bin/sh +set -eu + +read -r _oldrev SHA _refname +unset GIT_DIR + +if [ "$SHA" = '0000000000000000000000000000000000000000' ]; then + exit +fi + +printf 'Upgrading post-receive hook...' >&2 +git show "$SHA":aux/ci/git-post-receive.sh > hooks/post-receive +chmod +x hooks/post-receive +printf 'done.\n' >&2 diff --git a/v2/aux/ci/report.sh b/v2/aux/ci/report.sh new file mode 100755 index 0000000..0a0a0ae --- /dev/null +++ b/v2/aux/ci/report.sh @@ -0,0 +1,250 @@ +#!/bin/sh +set -eu + +usage() { + cat <<-'EOF' + Usage: + aux/ci/report.sh -o OUTDIR + aux/ci/report.sh -h + EOF +} + +help() { + cat <<-'EOF' + + + Options: + -o OUTDIR the directory where to place the generated files + -h, --help show this message + + + Gather data from Git Notes, and generate an HTML report on CI runs. + + Two refs with notes are expected: + 1. refs/notes/ci-data: contains metadata abount the CI runs, + with timestamps, filenames and exit status; + 2. refs/notes/ci-logs: contains the content of the log. + + When reconstructing the CI run, the $FILENAME present in + the refs/notes/ci-data ref names the file, and its content comes + from refs/notes/ci-logs. + + On a CI run that generated the numbers from 1 to 10, for a file named + 'my-ci-run-2020-01-01-deadbeef.log' that exited successfully, ran for + 15 seconds and was deployed to production, the expected output on the + target directory "public" is: + + $ tree public/ + public/ + index.html + data/ + 2020-01-01T01:00:00-deadbeef.log + ... + logs/ + 2020-01-01T01:00:00-deadbeef.log + ... + + $ cat public/data/2020-01-01T01:00:00-deadbeef.log + status 0 + sha deadbeef + filename deadbeef 2020-01-01T01:00:00-deadbeef.log + duration 15 + timestamp 2020-01-01T01:00:00 + to-prod true + refname refs/heads/main + + $ cat public/logs/2020-01-01T01:00:00-deadbeef.log + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + + The generated 'index.html' is a webpage with the list of all known + CI runs, their status, a link to the commit and a link to the + log and data files. + + To enable fetching these refs by default, do so in the git config: + + $ git config --add remote.origin.fetch '+refs/notes/*:refs/notes/*' + + + Examples: + + Generate the report on the 'www' directory: + + $ sh aux/ci/report.sh -o www + EOF +} + + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +while getopts 'o:h' flag; do + case "$flag" in + o) + OUTDIR="$OPTARG" + ;; + h) + usage + help + exit + ;; + *) + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + +. aux/lib.sh + +eval "$(assert_arg "${OUTDIR:-}" '-o OUTDIR')" + + +esc() { + sed \ + -e 's|&|\&|g' \ + -e 's|<|\<|g' \ + -e 's|>|\>|g' \ + -e 's|"|\"|g' \ + -e "s|'|\'|g" +} + +mkdir -p "$OUTDIR" +cd "$OUTDIR" +mkdir -p logs data + +for c in $(git notes list | cut -d' ' -f2); do + git notes --ref=refs/notes/ci-data show "$c" > data/FILENAME-tmp + FILENAME="$(grep '^filename ' data/FILENAME-tmp | cut -d' ' -f2-)" + mv data/FILENAME-tmp data/"$FILENAME" + git notes --ref=refs/notes/ci-logs show "$c" > logs/"$FILENAME" +done + +{ + cat <<-EOF + + + + + + + $NAME - CI logs + + + +
+

+ CI logs for + $NAME +

+
    + EOF + + + PASS='✅' # ✅ + WARN='🐌' # 🐌 + FAIL='❌' # ❌ + find data/ -type f | LANG=C.UTF-8 sort -r | while read -r f; do + STATUS="$( grep '^status ' "$f" | cut -d' ' -f2- | esc)" + SHA="$( grep '^sha ' "$f" | cut -d' ' -f2- | esc)" + FILENAME="$(grep '^filename ' "$f" | cut -d' ' -f2- | esc)" + DURATION="$(grep '^duration ' "$f" | cut -d' ' -f2- | cut -d'"' -f1 | esc)" + MESSAGE="$({ + git log -1 --format=%B "$SHA" || { + git fetch origin "$SHA" + git log -1 --format=%B "$SHA" + } + } | esc)" + + if [ "$STATUS" = 0 ]; then + if [ "$DURATION" -le 60 ]; then + STATUS_MARKER="$PASS" + else + STATUS_MARKER="$WARN" + fi + else + STATUS_MARKER="$FAIL" + fi + + cat <<-EOF +
  1. +
    #
    + $STATUS_MARKER -
    ${DURATION:-?}s
    +
    (commit)
    +
    $FILENAME
    +
    (data)
    +
    +
    $MESSAGE
    +
  2. + EOF + done + + cat <<-EOF +
+
+ + + EOF +} > index.html diff --git a/v2/aux/domain.txt b/v2/aux/domain.txt new file mode 100644 index 0000000..fd7ea0f --- /dev/null +++ b/v2/aux/domain.txt @@ -0,0 +1 @@ +euandre.org diff --git a/v2/aux/lib.sh b/v2/aux/lib.sh new file mode 100644 index 0000000..93a37eb --- /dev/null +++ b/v2/aux/lib.sh @@ -0,0 +1,37 @@ +#!/bin/sh + +DOMAIN="$(cat aux/domain.txt)" +NAME="$(basename "$PWD")" +export DOMAIN NAME + +assert_arg() { + if [ -z "$1" ]; then + printf 'Missing %s.\n\n' "$2" >&2 + cat <<-'EOF' + usage >&2 + exit 2 + EOF + fi +} + +uuid() { + od -xN20 /dev/urandom | + head -n1 | + awk '{OFS="-"; print $2$3,$4,$5,$6,$7$8$9}' +} + +tmpname() { + printf '%s/uuid-tmpname-without-spaces.%s' "${TMPDIR:-/tmp}" "$(uuid)" +} + +mkstemp() { + name="$(tmpname)" + touch -- "$name" + printf '%s' "$name" +} + +mkdtemp() { + name="$(tmpname)" + mkdir -p -- "$name" + printf '%s' "$name" +} diff --git a/v2/aux/po4a-cfg.sh b/v2/aux/po4a-cfg.sh new file mode 100755 index 0000000..b20e303 --- /dev/null +++ b/v2/aux/po4a-cfg.sh @@ -0,0 +1,109 @@ +#!/bin/sh +set -eu + +usage() { + cat <<-'EOF' + Usage: + aux/po4a-cfg.sh > po/po4a.cfg + aux/po4a-cfg.sh -h + EOF +} + +help() { + cat <<-'EOF' + + + Options: + -h, --help show this message + + + Discover translatable files in the repository (via + git-ls-files(1)) that have '.en.' or '/en/' in their name and + emit the configuration file to be used with po4a(1). + + + Examples: + + Setup i18n on a new repository: + + $ mkdir po + $ touch po/pt.po + $ touch po/"$(basename "$PWD")".pot + $ aux/po4a-cfg.sh > po/po4a.cfg + $ po4a po/po4a.cfg + + + Conditionally update the configuration in a Makefile: + + po/po4a.cfg: ALWAYS + @sh aux/po4a-cfg.sh | ifnew $@ + po4a $@ + EOF +} + + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +while getopts 'h' flag; do + case "$flag" in + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + +. aux/lib.sh + + +guess_type() { + case "$1" in + *.md) + echo text + ;; + *.[1-9]*.in) + echo man + ;; + *.html) + echo xhtml + ;; + *) + echo text + ;; + esac +} + + +cat <<-'EOF' + [options] --keep 0 --master-charset UTF-8 --localized-charset UTF-8 + + [po_directory] po + +EOF + +git ls-files | grep -F '.en.' | while read -r file; do + TYPE="$(guess_type "$file")" + # shellcheck disable=2016 + VAR_FILE="$(printf '%s' "$file" | sed 's|\.en\.|.$lang.|')" + # shellcheck disable=2016 + printf '[type: %s] %s $lang:%s\n' "$TYPE" "$file" "$VAR_FILE" +done diff --git a/v2/aux/workflow/TODOs.sh b/v2/aux/workflow/TODOs.sh deleted file mode 120000 index aaa6c50..0000000 --- a/v2/aux/workflow/TODOs.sh +++ /dev/null @@ -1 +0,0 @@ -../../../aux/workflow/TODOs.sh \ No newline at end of file diff --git a/v2/aux/workflow/favicon.html b/v2/aux/workflow/favicon.html deleted file mode 100644 index 6f1bac8..0000000 --- a/v2/aux/workflow/favicon.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/v2/aux/workflow/preamble.md b/v2/aux/workflow/preamble.md deleted file mode 120000 index 739f3ea..0000000 --- a/v2/aux/workflow/preamble.md +++ /dev/null @@ -1 +0,0 @@ -../../../aux/workflow/preamble.md \ No newline at end of file diff --git a/v2/aux/workflow/style.css b/v2/aux/workflow/style.css deleted file mode 120000 index ffff132..0000000 --- a/v2/aux/workflow/style.css +++ /dev/null @@ -1 +0,0 @@ -../../../aux/workflow/style.css \ No newline at end of file diff --git a/v2/dynamic.mk b/v2/dynamic.mk index 8abb62e..d31be9f 100644 --- a/v2/dynamic.mk +++ b/v2/dynamic.mk @@ -1,7 +1,6 @@ .POSIX: -FQDN = euandre.org -PORT = 4444 -BASE_URL = +DOMAIN = euandre.org +EMAIL = eu@euandre.org default: all @@ -11,73 +10,90 @@ include generated.mk .SUFFIXES: -.SUFFIXES: .md .html .in .entry-content .entry-env - +.SUFFIXES: .in .md .conf .content .html .in: sed \ - -e 's|@FQDN@|$(FQDN)|g' \ - -e 's|@BASE_URL@|$(BASE_URL)|g' \ + -e 's|@DOMAIN@|$(DOMAIN)|g' \ + -e 's|@EMAIL@|$(EMAIL)|g' \ < $< > $@ if [ -x $< ]; then chmod +x $@; fi +.md.conf: + sh src/development/getconf.sh $< > $@ + +.md.content: + awk 'sep >= 2; /^---$$/ {sep++}' < $< > $@ + .md.html: sh src/development/genhtml.sh $< > $@ -.md.entry-content: - extract -t content $? > $@ -.md.entry-env: - extract -t env $? > $@ +favicons = \ + public/favicon.png \ + public/favicon.ico \ +derived-assets = \ + $(all-generated) \ + $(favicons) \ + src/lib/base-conf \ + src/development/security-txt.sh \ -pastebins.html = $(pastebins.md:.md=.html) +$(all-generated.conf) $(all-generated.content): $(non-content) -html = \ - $(pastebins.html) \ +all: public +$(all-generated.conf): src/lib/base-conf -ALL = \ - src/content/TODOs.html \ - $(html) \ - +clean: + rm -rf \ + public/ $(derived-assets) *.sentinel generated.mk -all: $(ALL) +public: $(favicons) public-copy-content.sentinel -$(html) src/bin/absolute src/bin/extract src/bin/url-for: src/development/config.env -$(html): src/development/genhtml.sh +public-mkdir.sentinel: + mkdir -p public + touch $@ +public/favicon.png: public-mkdir.sentinel src/content/favicon.svg + inkscape -o $@ -w 2048 -h 2048 -b white src/content/favicon.svg -collections = pastebins +public/favicon.ico: public-mkdir.sentinel src/content/favicon.svg + convert src/content/favicon.svg $@ -clean: - for c in $(collections); do \ - rm -f \ - src/content/$$c/*.entry-* \ - src/content/$$c/*.txt; \ - done - rm -rf \ - $(ALL) generated.mk src/development/config.env \ +public-copy-content.sentinel: $(all-generated.html) $(static-content) \ + src/content/public.asc.txt src/content/.well-known/security.txt + echo $? | \ + tr ' ' '\n' | \ + sed 's|^src/content/||' | \ + tee $@-tmp | \ + xargs dirname | \ + sort | \ + uniq | \ + xargs -P`nproc` -I% mkdir -p public/% + xargs -P`nproc` -I% cp src/content/% public/% < $@-tmp + rm -f $@-tmp + touch $@ -src/content/TODOs.html: TODOs.md - sh aux/workflow/TODOs.sh -n website -m public-inbox > $@ +src/content/public.asc.txt: + gpg --armour --export '$(EMAIL)' > $@ -public: all +src/content/.well-known/security.txt: src/content/public.asc.txt src/development/security-txt.sh + sh src/development/security-txt.sh > $@ check: -dev-check: check - -fqdn: - printf '$(FQDN)' - - +dev: check run: all - open 'http://localhost:$(PORT)' - serve -d src/content/ -p $(PORT) - -deploy: all - rsync -avzP src/content/ $(FQDN):/home/user-data/www/default/v2/ --delete + serve -d public/ + +upload: public + rsync \ + --rsync-path='sudo -u deployer rsync' \ + -avzP \ + --delete \ + --exclude 's/*' \ + public/ $(DOMAIN):/srv/www/ diff --git a/v2/po/euandre.org.pot b/v2/po/euandre.org.pot new file mode 100644 index 0000000..d3613c2 --- /dev/null +++ b/v2/po/euandre.org.pot @@ -0,0 +1,72 @@ +# SOME DESCRIPTIVE TITLE +# Copyright (C) YEAR Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2023-04-04 06:28-0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Plain text +#: src/lib/base.en.conf:2 +msgid "date_fmt='%B %-d, %Y'" +msgstr "" + +#. type: Plain text +#: src/lib/base.en.conf:3 +msgid "site_name=\"EuAndreh's website\"" +msgstr "" + +#. type: Content of:

+#: src/lib/postamble.en.html:2 +msgid "" +"Comment and see existing discussions | view source" +msgstr "" + +#. type: Attribute 'lang' of: +#: src/lib/preamble.en.html:2 +msgid "$lang" +msgstr "" + +#. type: Content of: +#: src/lib/preamble.en.html:9 +msgid "$(htmlesc \"$title\")" +msgstr "" + +#. type: Content of: <html><body><header><nav><ul> +#: src/lib/preamble.en.html:23 +msgid "" +"<a href=\"$lang_url\">EuAndreh</a> <a href=\"$(url-for " +"'about.html')\">About</a>" +msgstr "" + +#. type: Content of: <html><body><main><article><h1> +#: src/lib/preamble.en.html:32 +msgid "$title_html" +msgstr "" + +#. type: Content of: <html><body><main><article><p> +#: src/lib/preamble.en.html:35 +msgid "Posted on" +msgstr "" + +#. type: Content of: <html><body><main><article><p><time> +#: src/lib/preamble.en.html:35 +msgid "$date_formatted" +msgstr "" + +#. type: Content of: <html><body><main><article> +#: src/lib/preamble.en.html:37 +msgid "EOF" +msgstr "" diff --git a/v2/po/po4a.cfg b/v2/po/po4a.cfg new file mode 100644 index 0000000..877f5a9 --- /dev/null +++ b/v2/po/po4a.cfg @@ -0,0 +1,7 @@ +[options] --keep 0 --master-charset UTF-8 --localized-charset UTF-8 + +[po_directory] po + +[type: text] src/lib/base.en.conf $lang:src/lib/base.$lang.conf +[type: xhtml] src/lib/postamble.en.html $lang:src/lib/postamble.$lang.html +[type: xhtml] src/lib/preamble.en.html $lang:src/lib/preamble.$lang.html diff --git a/v2/po/pt.po b/v2/po/pt.po new file mode 100644 index 0000000..2eb3ca6 --- /dev/null +++ b/v2/po/pt.po @@ -0,0 +1,53 @@ +#. type: Plain text +#: src/lib/base.en.conf:2 +msgid "date_fmt='%B %-d, %Y'" +msgstr "" + +#. type: Plain text +#: src/lib/base.en.conf:3 +msgid "site_name=\"EuAndreh's website\"" +msgstr "" + +#. type: Content of: <p> +#: src/lib/postamble.en.html:2 +msgid "" +"<a href=\"@mailto_uri@\">Comment</a> and see <a href=\"@discussions_url@" +"\">existing discussions</a> | <a href=\"@sourcecode_url@\">view source</a>" +msgstr "" + +#. type: Attribute 'lang' of: <html> +#: src/lib/preamble.en.html:2 +msgid "$lang" +msgstr "" + +#. type: Content of: <html><head><title> +#: src/lib/preamble.en.html:9 +msgid "$(htmlesc \"$title\")" +msgstr "" + +#. type: Content of: <html><body><header><nav><ul> +#: src/lib/preamble.en.html:23 +msgid "" +"<a href=\"$lang_url\">EuAndreh</a> <a href=\"$(url-for 'about." +"html')\">About</a>" +msgstr "" + +#. type: Content of: <html><body><main><article><h1> +#: src/lib/preamble.en.html:32 +msgid "$title_html" +msgstr "" + +#. type: Content of: <html><body><main><article><p> +#: src/lib/preamble.en.html:35 +msgid "Posted on" +msgstr "" + +#. type: Content of: <html><body><main><article><p><time> +#: src/lib/preamble.en.html:35 +msgid "$date_formatted" +msgstr "" + +#. type: Content of: <html><body><main><article> +#: src/lib/preamble.en.html:37 +msgid "EOF" +msgstr "" diff --git a/v2/src/bin/absolute b/v2/src/bin/absolute index ae25b43..6434219 100755 --- a/v2/src/bin/absolute +++ b/v2/src/bin/absolute @@ -62,6 +62,6 @@ done shift $((OPTIND - 1)) -. src/development/config.env +. src/lib/base-conf -printf 'https://%s%s' "$FQDN" "$(cat)" +printf 'https://%s%s' "$domain" "$(cat)" diff --git a/v2/src/bin/extract b/v2/src/bin/extract deleted file mode 100755 index 7bbcba7..0000000 --- a/v2/src/bin/extract +++ /dev/null @@ -1,133 +0,0 @@ -#!/bin/sh -set -eu - - -usage() { - cat <<-'EOF' - Usage: - extract -t TYPE FILENAME - extract -h - EOF -} - -help() { - cat <<-'EOF' - - Options: - -t TYPE the type of extraction to perform ("content" or "env") - -h, --help show this message - - FILENAME the name of the input file, also to be used as - URL. - - - Separate the content from the "frontmatter", and emit the - selected one, given the FILENAME. - - - Examples: - - Get the content: - - $ extract -t content src/file.md > src/file.entry-content - - - Get the "frontmatter": - - $ extract -t env src/f.md > src/f.entry-env - EOF -} - - -for flag in "$@"; do - case "$flag" in - --) - break - ;; - --help) - usage - help - exit - ;; - *) - ;; - esac -done - -TYPE='' -while getopts 't:h' flag; do - case "$flag" in - t) - TYPE="$OPTARG" - ;; - h) - usage - help - exit - ;; - *) - usage >&2 - exit 2 - ;; - esac -done -shift $((OPTIND - 1)) - - -FILENAME="${1:-}" -eval "$(assert-arg "$FILENAME" 'FILENAME')" -eval "$(assert-arg "$TYPE" '-t TYPE')" - - -case "$TYPE" in - content) - . "${FILENAME%.md}.entry-env" - printf '%s\n' "$PREAMBLE" - awk ' - separator >= 2 - /^---$/ { separator++ } - ' "$FILENAME" - ;; - env) - cat src/development/config.env - awk ' - /^---$/ { - if (++separator > 1) { - exit - } else { - next - } - } - - { print } - ' "$FILENAME" - printf "FILENAME='%s'\n" "$FILENAME" - cat <<-'REAL_EOF' - TITLE="${TITLE:-$SITE_NAME}" - - URI_TITLE="$(printf '%s' "$TITLE" | uri)" - - URL="$( - printf '%s' "$FILENAME" | - sed \ - -e 's|^src/content/||' \ - -e 's|md$|html|' - )" - - PREAMBLE="$(cat <<EOF - # $TITLE - - <p class="timestamp"> - Posted on <time datetime="$DATE">$(LANG="$LANGUAGE" date -d "$DATE" "$DATE_FMT")</time> - </p> - EOF - )" - REAL_EOF - ;; - *) - printf 'Bad value for TYPE: "%s".\n\n' \ - "$TYPE" >&2 - usage >&2 - exit 2 - ;; -esac diff --git a/v2/src/bin/makemake b/v2/src/bin/makemake new file mode 100755 index 0000000..f4ab87a --- /dev/null +++ b/v2/src/bin/makemake @@ -0,0 +1,137 @@ +#!/bin/sh +set -eu + + +usage() { + cat <<-'EOF' + Usage: + makemake + makemake -h + EOF +} + +help() { + cat <<-'EOF' + + Options: + -h, --help show this message + + + Generate make(1) code for later evaluation by make(1). What + this scripts does is fill the gap where make(1) can't handle + globs and dynamic dependencies, and uses some ad-hoc scripts + to generate those. + EOF +} + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +while getopts 'h' flag; do + case "$flag" in + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + + + +varlist() { + printf '%s = \\\n' "$1" + sed \ + -e 's/^/ /' \ + -e 's/$/ \\/' + printf '\n' +} + +html_deps() { + "$@" | sed 's/^\(.*\)\.md$/\1.conf \1.content: \1.md/' + "$@" | sed 's/^\(.*\)\.md$/\1.html: \1.conf \1.content/' + printf '\n' +} + + +content_mds() { + find src/content/"$1"/ -type f -name '*.md' +} + +RESOURCES=' +pastebins +tils +' + +EXTENSIONS=' +.md +.conf +.content +.prehtml +.posthtml +.html +' + +for r in $RESOURCES; do + content_mds "$r" | varlist "$r".md + for e in $EXTENSIONS; do + if [ "$e" = '.md' ]; then + continue + fi + printf '%s%s = $(%s.md:.md=%s)\n' "$r" "$e" "$r" "$e" + done + printf '%s =' "$r" + for e in $EXTENSIONS; do + if [ "$e" = '.md' ]; then + continue + fi + printf ' $(%s%s)' "$r" "$e" + done + printf '\n' + html_deps content_mds "$r" + printf '\n' +done + +all_resources() { + echo $RESOURCES | tr ' ' '\n' +} + +all_vars() { + EXT="$1" + all_resources | + sed 's|^|$(|' | + sed "s|$|$EXT)|" | + varlist all-generated"$EXT" +} + +for e in $EXTENSIONS; do + all_vars "$e" +done +all_vars '' + + +git ls-files | + grep -v '^src/content/' | + varlist 'non-content' + +git ls-files src/content/ | + grep -v '\.md$' | + grep -Ev "src/content/($(all_resources | paste -sd'|'))/" | + varlist 'static-content' diff --git a/v2/src/bin/url-for b/v2/src/bin/url-for index 025a546..c31ff84 100755 --- a/v2/src/bin/url-for +++ b/v2/src/bin/url-for @@ -1,7 +1,6 @@ #!/bin/sh set -eu - usage() { cat <<-'EOF' Usage: @@ -69,9 +68,12 @@ while getopts 'h' flag; do done shift $((OPTIND - 1)) +. src/development/lib.sh + + FILE="${1:-}" -eval "$(assert-arg "$FILE" 'FILE')" +eval "$(assert_arg "$FILE" 'FILE')" -. src/development/config.env +. src/lib/base-conf -printf '%s/%s' "$BASE_URL" "$FILE" +printf '%s%s' "${base_url:-/}" "$FILE" diff --git a/v2/src/content/.well-known/security.txt b/v2/src/content/.well-known/security.txt new file mode 100644 index 0000000..dd35c49 --- /dev/null +++ b/v2/src/content/.well-known/security.txt @@ -0,0 +1,4 @@ +Contact: mailto:eu@euandre.org +Encryption: https://euandre.org/public.asc.txt +Expires: 2024-07-15T00:00:00z +Preferred-Languages: en, pt diff --git a/v2/src/content/favicon.svg b/v2/src/content/favicon.svg new file mode 120000 index 0000000..313dcc5 --- /dev/null +++ b/v2/src/content/favicon.svg @@ -0,0 +1 @@ +../../../static/lord-favicon.svg \ No newline at end of file diff --git a/v2/src/content/pastebins/raku-tuple-type-annotation.md b/v2/src/content/pastebins/raku-tuple-type-annotation.md new file mode 100644 index 0000000..3d5ff34 --- /dev/null +++ b/v2/src/content/pastebins/raku-tuple-type-annotation.md @@ -0,0 +1,37 @@ +--- + +title: Raku tuple type annotation + +date: 2019-12-29 + +layout: post + +lang: en + +ref: raku-tuple-type-annotation + +--- + +```perl +# Single Str return value: this works +sub f1(Str $in --> Str) { + $in; +} + +# Tuple of Str as return value: this works +sub f2(Str $in) { + ($in, $in); +} + +# Tuple of Str as return value with type annotation: this doesn't works +sub f2(Str $in --> (Str, Str)) { + ($in, $in); +} +``` + +Error log is: + +```perl +===SORRY!=== Error while compiling /path/to/my/file +Malformed return value +``` diff --git a/v2/src/content/pastebins/sicp-exercise-3-19.md b/v2/src/content/pastebins/sicp-exercise-3-19.md index fd2c52b..8834889 100644 --- a/v2/src/content/pastebins/sicp-exercise-3-19.md +++ b/v2/src/content/pastebins/sicp-exercise-3-19.md @@ -1,14 +1,14 @@ --- -TITLE='SICP exercise 3.19' +title: SICP exercise 3.19 -DATE='2021-09-02' +date: 2021-09-02 -LAYOUT='post' +layout: post -LANGUAGE='en' +lang: en -REF='sicp-exercise-3-19' +id: sicp-exercise-3-19 --- diff --git a/v2/src/content/public.asc.txt b/v2/src/content/public.asc.txt new file mode 100644 index 0000000..533b54c --- /dev/null +++ b/v2/src/content/public.asc.txt @@ -0,0 +1,86 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +LsPdAc9FGcUNEy+/AlLpM1Y= +=2ZCp +-----END PGP PUBLIC KEY BLOCK----- diff --git a/v2/src/content/static/atom.svg b/v2/src/content/static/atom.svg deleted file mode 120000 index 41c6d3f..0000000 --- a/v2/src/content/static/atom.svg +++ /dev/null @@ -1 +0,0 @@ -../../../../static/atom.svg \ No newline at end of file diff --git a/v2/src/content/static/envelope.svg b/v2/src/content/static/envelope.svg deleted file mode 120000 index bd0c577..0000000 --- a/v2/src/content/static/envelope.svg +++ /dev/null @@ -1 +0,0 @@ -../../../../static/envelope.svg \ No newline at end of file diff --git a/v2/src/content/static/favicon.svg b/v2/src/content/static/favicon.svg deleted file mode 120000 index 33566ab..0000000 --- a/v2/src/content/static/favicon.svg +++ /dev/null @@ -1 +0,0 @@ -../../../../static/lord-favicon.svg \ No newline at end of file diff --git a/v2/src/content/static/link.svg b/v2/src/content/static/link.svg deleted file mode 120000 index bf69c40..0000000 --- a/v2/src/content/static/link.svg +++ /dev/null @@ -1 +0,0 @@ -../../../../static/link.svg \ No newline at end of file diff --git a/v2/src/content/static/lock.svg b/v2/src/content/static/lock.svg deleted file mode 120000 index f9a4f33..0000000 --- a/v2/src/content/static/lock.svg +++ /dev/null @@ -1 +0,0 @@ -../../../../static/lock.svg \ No newline at end of file diff --git a/v2/src/content/static/public.asc.txt b/v2/src/content/static/public.asc.txt deleted file mode 120000 index 5175f38..0000000 --- a/v2/src/content/static/public.asc.txt +++ /dev/null @@ -1 +0,0 @@ -../../../../public.asc \ No newline at end of file diff --git a/v2/src/content/static/styles.css b/v2/src/content/static/styles.css deleted file mode 100644 index 0ec67a8..0000000 --- a/v2/src/content/static/styles.css +++ /dev/null @@ -1,149 +0,0 @@ -/* General declarations */ - -body { - margin: 0px auto; - padding: 1%; - max-width: 750px; -} - -.svg-icon { - vertical-align: middle; -} - - -/* Navigation header */ - -nav a { - color: maroon; - font-size: 18px; - margin: 12px; - text-decoration: none; -} - -nav ul, nav li { - display: inline; -} - -nav ul li a { - color: black; - font-size: 14px; - margin: 6px; -} - - -/* Article bodies */ - -.timestamp { - color: #555; - font-size: 14px; - font-style: italic; -} - -blockquote { - font-style: italic; - color: dimgrey; - padding-left: 10px; - border-left: 3px solid #ccc; -} - -ul.no-style { - list-style-type: none; -} - -ul.no-style li { - margin: 20px 0px; -} - - -/* Footer */ - -footer { - font-size: 14px; - margin-top: 30px; - padding: 12px 0px 12px 0px; -} - -footer li { - list-style-type: none; - margin-top: 10px; -} - -footer li a { - margin-left: 5px; - user-select: none; -} - -/* Code blocks */ - -/* The "lineno" class is the default generated by Rouge for table-row in code blocks, see: - https://github.com/rouge-ruby/rouge */ -.line-number, pre.lineno { - margin-right: 3px; - padding-right: 3px; - border-right: 1px solid; - border-color: hsla(0, 0%, 0%, 0.3); - text-align: right; - user-select: none; -} - -.code-line { - padding-left: 8px; -} - -.code-block { - padding: 6px 4px; - display: block; -} - -.code-block, pre.highlight { - border: 1px solid #ccc; - border-radius: 10px; -} - -pre { - overflow: auto; -} - - -/* Code block anchors */ - -.line-number a, a.code-line-anchor { - color: black; - text-decoration: none; -} - -a.code-line-anchor:hover { - text-decoration: underline; -} - - -/* Header anchor */ - -.header-anchor { - color: black; - text-decoration: none; - display: block; - margin-bottom: 15px; -} - -.header-anchor { -} - - -.header-anchor img { - margin-left: 5px; - visibility: hidden; -} - -.header-anchor:hover img { - visibility: visible; -} - - -/* Plaintext code block links */ - -.plaintext-link { - margin: auto auto 0 auto; - text-align: right; - font-family: monospace; -} diff --git a/v2/src/content/style.css b/v2/src/content/style.css new file mode 100644 index 0000000..0ec67a8 --- /dev/null +++ b/v2/src/content/style.css @@ -0,0 +1,149 @@ +/* General declarations */ + +body { + margin: 0px auto; + padding: 1%; + max-width: 750px; +} + +.svg-icon { + vertical-align: middle; +} + + +/* Navigation header */ + +nav a { + color: maroon; + font-size: 18px; + margin: 12px; + text-decoration: none; +} + +nav ul, nav li { + display: inline; +} + +nav ul li a { + color: black; + font-size: 14px; + margin: 6px; +} + + +/* Article bodies */ + +.timestamp { + color: #555; + font-size: 14px; + font-style: italic; +} + +blockquote { + font-style: italic; + color: dimgrey; + padding-left: 10px; + border-left: 3px solid #ccc; +} + +ul.no-style { + list-style-type: none; +} + +ul.no-style li { + margin: 20px 0px; +} + + +/* Footer */ + +footer { + font-size: 14px; + margin-top: 30px; + padding: 12px 0px 12px 0px; +} + +footer li { + list-style-type: none; + margin-top: 10px; +} + +footer li a { + margin-left: 5px; + user-select: none; +} + +/* Code blocks */ + +/* The "lineno" class is the default generated by Rouge for table-row in code blocks, see: + https://github.com/rouge-ruby/rouge */ +.line-number, pre.lineno { + margin-right: 3px; + padding-right: 3px; + border-right: 1px solid; + border-color: hsla(0, 0%, 0%, 0.3); + text-align: right; + user-select: none; +} + +.code-line { + padding-left: 8px; +} + +.code-block { + padding: 6px 4px; + display: block; +} + +.code-block, pre.highlight { + border: 1px solid #ccc; + border-radius: 10px; +} + +pre { + overflow: auto; +} + + +/* Code block anchors */ + +.line-number a, a.code-line-anchor { + color: black; + text-decoration: none; +} + +a.code-line-anchor:hover { + text-decoration: underline; +} + + +/* Header anchor */ + +.header-anchor { + color: black; + text-decoration: none; + display: block; + margin-bottom: 15px; +} + +.header-anchor { +} + + +.header-anchor img { + margin-left: 5px; + visibility: hidden; +} + +.header-anchor:hover img { + visibility: visible; +} + + +/* Plaintext code block links */ + +.plaintext-link { + margin: auto auto 0 auto; + text-align: right; + font-family: monospace; +} diff --git a/v2/src/content/tils/lisp-three-way-conditional.md b/v2/src/content/tils/lisp-three-way-conditional.md new file mode 100644 index 0000000..f53451b --- /dev/null +++ b/v2/src/content/tils/lisp-three-way-conditional.md @@ -0,0 +1,63 @@ +--- + +title: Three-way conditional for number signs on Lisp + +date: 2021-04-24 3 + +updated_at: 2021-08-14 + +layout: post + +lang: en + +ref: three-way-conditional-for-number-signs-on-lisp + +--- + +A useful macro from Paul Graham's [On Lisp][on-lisp] book: + +```lisp +(defmacro nif (expr pos zero neg) + (let ((g (gensym))) + `(let ((,g ,expr)) + (cond ((plusp ,g) ,pos) + ((zerop ,g) ,zero) + (t ,neg))))) +``` + +After I looked at this macro, I started seeing opportunities to using it in many places, and yet I didn't see anyone else using it. + +The latest example I can think of is section 1.3.3 of [Structure and Interpretation of Computer Programs][sicp], which I was reading recently: + +```scheme +(define (search f neg-point pos-point) + (let ((midpoint (average neg-point pos-point))) + (if (close-enough? neg-point post-point) + midpoint + (let ((test-value (f midpoint))) + (cond ((positive? test-value) + (search f neg-point midpoint)) + ((negative? test-value) + (search f midpoint pos-point)) + (else midpoint)))))) +``` + +Not that the book should introduce such macro this early, but I couldn't avoid feeling bothered by not using the `nif` macro, which could even remove the need for the intermediate `test-value` variable: + +```scheme +(define (search f neg-point pos-point) + (let ((midpoint (average neg-point pos-point))) + (if (close-enough? neg-point post-point) + midpoint + (nif (f midpoint) + (search f neg-point midpoint) + (midpoint) + (search f midpoint pos-point))))) +``` + +It also avoids `cond`'s extra clunky parentheses for grouping, which is unnecessary but built-in. + +As a macro, I personally feel it tilts the balance towards expressivenes despite its extra cognitive load toll. + +[on-lisp]: http://www.paulgraham.com/onlisptext.html +[sicp]: https://mitpress.mit.edu/sites/default/files/sicp/index.html diff --git a/v2/src/development/config.env.in b/v2/src/development/config.env.in deleted file mode 100644 index ca2afe7..0000000 --- a/v2/src/development/config.env.in +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -SITE_NAME="EuAndreh's website" -FQDN='@FQDN@' -BASE_URL='@BASE_URL@' -DATE_FMT='+%B %-d, %Y' diff --git a/v2/src/development/dynmake.sh b/v2/src/development/dynmake.sh deleted file mode 100755 index 126c211..0000000 --- a/v2/src/development/dynmake.sh +++ /dev/null @@ -1,79 +0,0 @@ -#!/bin/sh -set -eu - - -usage() { - cat <<-'EOF' - Usage: - dynmake.sh - dynmake.sh -h - EOF -} - -help() { - cat <<-'EOF' - - Options: - -h, --help show this message - - - Generate make(1) code for later evaluation by make(1). What - this scripts does is fill the gap where make(1) can't handle - globs and dynamic dependencies, and uses some ad-hoc scripts - to generate those. - EOF -} - -for flag in "$@"; do - case "$flag" in - --) - break - ;; - --help) - usage - help - exit - ;; - *) - ;; - esac -done - -while getopts 'h' flag; do - case "$flag" in - h) - usage - help - exit - ;; - *) - usage >&2 - exit 2 - ;; - esac -done -shift $((OPTIND - 1)) - - - -varlist() { - sed -e 's/^/ /' \ - -e 's/$/ \\/' -} - - -# -# Pastebins -# - -pastebins() { - find src/content/pastebins/ -name '*.md' -} - -printf 'pastebins.md = \\\n' -pastebins | varlist -printf '\n' - -pastebins | sed 's/^\(.*\)\.md$/\1.html: \1.entry-env/' -pastebins | sed 's/^\(.*\)\.md$/\1.html: \1.entry-content/' -pastebins | sed 's/^\(.*\)\.md$/\1.entry-content: \1.entry-env/' diff --git a/v2/src/development/genhtml.sh b/v2/src/development/genhtml.sh index a1e8afb..cb8fd73 100755 --- a/v2/src/development/genhtml.sh +++ b/v2/src/development/genhtml.sh @@ -1,21 +1,6 @@ #!/bin/sh set -eu -# FIXMEs: -# - feeds -# - link to next and/or previous in <head> -# - translation support -# - validate input variables: regex for date (same as _plugins/linter.rb) -# - `date -d` isn't POSIX -# - parse commonmark and use a custom HTML emitter over <pre><code> regex -# - handle mixture of personal scripts -# - sitemap? How does it even work? -# - dark mode -# - generate security.txt dynamically -# - config.env should depend on dynamic.mk? - - - usage() { cat <<-'EOF' Usage: @@ -81,12 +66,13 @@ while getopts 'h' flag; do done shift $((OPTIND - 1)) +. src/development/lib.sh FILENAME="${1:-}" -eval "$(assert-arg "$FILENAME" 'FILENAME')" +eval "$(assert_arg "$FILENAME" 'FILENAME')" -. "${FILENAME%.md}.entry-env" +. "${FILENAME%.md}.conf" # # Utility functions @@ -216,28 +202,28 @@ emit_body() { cat <<-EOF <!DOCTYPE html> - <html lang="$LANGUAGE"> + <html lang="$lang"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> - <link rel="stylesheet" type="text/css" href="$(url-for 'static/styles.css')" /> - <link rel="icon" type="image/svg+xml" href="$(url-for 'static/favicon.svg')" /> + <link rel="stylesheet" type="text/css" href="$style_url" /> + <link rel="icon" type="image/svg+xml" href="$favicon_url" /> - <title>$TITLE + $$title_html - - - + + + - - + +

@@ -245,8 +231,19 @@ cat <<-EOF
- $(emit_body) + \$(emit_body)
+EOF +exit + + +.md.rehtml: + F="$<"; . "$${F%.md}.conf"; envsubst < src/lib/reamble."$$lang".html > $@ + +.md.osthtml: + F="$<"; . "$${F%.md}.conf"; envsubst < src/lib/ostamble."$$lang".html > $@ + +
  • a envelope icon representing an email address - eu@euandre.org + $email
  • a lock icon representing a GPG public key @@ -275,3 +272,16 @@ cat <<-EOF EOF + +# FIXMEs: +# - feeds +# - link to next and/or previous in +# - translation support +# - validate input variables: regex for date (same as _plugins/linter.rb) +# - `date -d` isn't POSIX +# - parse commonmark and use a custom HTML emitter over
     regex
    +# - handle mixture of personal scripts
    +# - sitemap?  How does it even work?
    +# - dark mode
    +# - generate security.txt dynamically
    +# - config.env should depend on dynamic.mk?
    diff --git a/v2/src/development/getconf.sh b/v2/src/development/getconf.sh
    new file mode 100755
    index 0000000..dd623f7
    --- /dev/null
    +++ b/v2/src/development/getconf.sh
    @@ -0,0 +1,119 @@
    +#!/bin/sh
    +set -eu
    +
    +
    +usage() {
    +	cat <<-'EOF'
    +		Usage:
    +		  src/development/getconf.sh FILENAME
    +		  src/development/getconf.sh -h
    +	EOF
    +}
    +
    +help() {
    +	cat <<-'EOF'
    +
    +		Options:
    +		  -h, --help    show this message
    +
    +		  FILENAME      the name of the input file, also to be used as
    +		                URL.
    +
    +
    +		Separate the content from the "frontmatter", and emit the
    +		selected one, given the FILENAME.
    +
    +
    +		Examples:
    +
    +		  Get the "frontmatter" of src/f.conf:
    +
    +		    $ src/development/getconf.sh src/f.md > src/f.conf
    +	EOF
    +}
    +
    +
    +for flag in "$@"; do
    +	case "$flag" in
    +		--)
    +			break
    +			;;
    +		--help)
    +			usage
    +			help
    +			exit
    +			;;
    +		*)
    +			;;
    +	esac
    +done
    +
    +while getopts 'h' flag; do
    +	case "$flag" in
    +		h)
    +			usage
    +			help
    +			exit
    +			;;
    +		*)
    +			usage >&2
    +			exit 2
    +			;;
    +	esac
    +done
    +shift $((OPTIND - 1))
    +
    +. src/development/lib.sh
    +
    +FILENAME="${1:-}"
    +eval "$(assert_arg "$FILENAME" 'FILENAME')"
    +
    +
    +escape() {
    +	sed 's|\([`"$]\)|\\\1|g'
    +}
    +
    +{
    +	cat src/lib/base-conf | tee "$FILENAME".tmp
    +	DELIMITER=0
    +	while read -r line; do
    +		if [ "$line" = '---' ]; then
    +			DELIMITER=$((DELIMITER + 1))
    +			continue
    +		fi
    +		if [ "$DELIMITER" = 2 ]; then
    +			break
    +		fi
    +		if [ -z "$line" ]; then
    +			continue
    +		fi
    +
    +		KEY="$(  printf '%s' "$line" | cut -d: -f1)"
    +		VALUE="$(printf '%s' "$line" | cut -d: -f2- | sed 's|^ ||' | escape)"
    +		printf '%s="%s"\n' "$KEY" "$VALUE"
    +	done < "$FILENAME" | tee -a "$FILENAME".tmp
    +	. "$FILENAME".tmp
    +
    +	cat src/lib/base."$lang".conf
    +	. src/lib/base."$lang".conf
    +
    +	title="${title:-"$site_name"}"
    +	url_part="$(printf '%s' "${FILENAME%.md}.html" | sed 's|^src/content/||')"
    +
    +	printf 'title="%s"\n' "$(printf '%s' "$title" | escape)"
    +	printf 'title_html="%s"\n' "$(printf '%s' "$title" | htmlesc | escape)"
    +	printf 'filename="%s"\n' "$FILENAME"
    +	printf 'url_part="%s"\n' "$url_part"
    +	printf 'url="%s"\n' "$(url-for "$url_part" | absolute)"
    +	printf 'date_formatted="%s"\n' "$(LANG="$lang" date -d "$date" +"$date_fmt" | escape)"
    +	printf 'mailto_uri="%s%s"\n' "$mailto_uri_prefix" "$(uri "$title")"
    +	printf 'discussions_url="%s%s"\n' "$discussions_url_prefix" "$(uri "$title")"
    +	printf 'sourcecode_url="%s%s"\n' "$sourcecode_url_prefix" "$FILENAME"
    +
    +	printf 'lang_url="%s"\n' "$(url-for "$lang"/)"
    +
    +	printf 'style_url="%s"\n' "$(url-for 'style.css')"
    +	printf 'favicon_url="%s"\n' "$(url-for 'favicon.svg')"
    +
    +	rm -f "$FILENAME".tmp
    +} | grep . | sed 's|^|export |'
    diff --git a/v2/src/development/lib.sh b/v2/src/development/lib.sh
    new file mode 100644
    index 0000000..9d183f9
    --- /dev/null
    +++ b/v2/src/development/lib.sh
    @@ -0,0 +1,33 @@
    +#!/bin/sh
    +
    +assert_arg() {
    +	if [ -z "$1" ]; then
    +		printf 'Missing %s.\n\n' "$2" >&2
    +		cat <<-'EOF'
    +			usage >&2
    +			exit 2
    +		EOF
    +	fi
    +}
    +
    +uuid() {
    +        od -xN20 /dev/urandom |
    +                head -n1 |
    +                awk '{OFS="-"; print $2$3,$4,$5,$6,$7$8$9}'
    +}
    +
    +tmpname() {
    +        echo "${TMPDIR:-/tmp}/uuid-tmpname with spaces.$(uuid)"
    +}
    +
    +mkstemp() {
    +	name="$(tmpname)"
    +	touch "$name"
    +	echo "$name"
    +}
    +
    +mkdtemp() {
    +        name="$(tmpname)"
    +	mkdir "$name"
    +        echo "$name"
    +}
    diff --git a/v2/src/development/security-txt.sh.in b/v2/src/development/security-txt.sh.in
    new file mode 100755
    index 0000000..8f6613f
    --- /dev/null
    +++ b/v2/src/development/security-txt.sh.in
    @@ -0,0 +1,82 @@
    +#!/bin/sh
    +set -eu
    +
    +usage() {
    +	cat <<-'EOF'
    +		Usage:
    +		  src/development/security-txt.sh
    +		  src/development/security-txt.sh -h
    +	EOF
    +}
    +
    +help() {
    +	cat <<-'EOF'
    +
    +
    +		Options:
    +		  -h, --help    show this message
    +
    +
    +		Generate the RFC 9116 "security.txt" file from data in the
    +		repository.
    +
    +
    +		Examples:
    +
    +		  Just run it:
    +
    +		    $ sh src/development/security-txt.sh > .well-known/security.txt
    +	EOF
    +}
    +
    +
    +for flag in "$@"; do
    +	case "$flag" in
    +		--)
    +			break
    +			;;
    +		--help)
    +			usage
    +			help
    +			exit
    +			;;
    +		*)
    +			;;
    +	esac
    +done
    +
    +while getopts 'h' flag; do
    +	case "$flag" in
    +		h)
    +			usage
    +			help
    +			exit
    +			;;
    +		*)
    +			usage >&2
    +			exit 2
    +	esac
    +done
    +shift $((OPTIND - 1))
    +
    +
    +
    +EXPIRES="$(
    +	LANG=C.UTF-8 gpg --list-key eu@euandre.org |
    +		awk '/^pub/ { print substr($(NF), 1, 10) }'
    +)T00:00:00z"
    +
    +LANGS="en$(
    +	echo po/??.po |
    +		sed 's|\.po$||'  |
    +		sed 's|^po/|, |' |
    +		paste -sd,
    +)"
    +
    +
    +cat <<-EOF
    +	Contact: mailto:@EMAIL@
    +	Encryption: https://@DOMAIN@/public.asc.txt
    +	Expires: $EXPIRES
    +	Preferred-Languages: $LANGS
    +EOF
    diff --git a/v2/src/lib/base-conf.in b/v2/src/lib/base-conf.in
    new file mode 100644
    index 0000000..a33755a
    --- /dev/null
    +++ b/v2/src/lib/base-conf.in
    @@ -0,0 +1,9 @@
    +site_name="EuAndreh's website"
    +domain='@DOMAIN@'
    +email='@EMAIL@'
    +base_url=''
    +lang=en
    +list_addr='~euandreh/public-inbox@lists.sr.ht'
    +mailto_uri_prefix="mailto:$list_addr?Subject=Re%3A%20"
    +discussions_url_prefix="https://lists.sr.ht/~euandreh/public-inbox?search="
    +sourcecode_url_prefix="https://$domain/git/$domain/tree/"
    diff --git a/v2/src/lib/base.en.conf b/v2/src/lib/base.en.conf
    new file mode 100644
    index 0000000..89344fb
    --- /dev/null
    +++ b/v2/src/lib/base.en.conf
    @@ -0,0 +1,3 @@
    +date_fmt='%B %-d, %Y'
    +
    +site_name="EuAndreh's website"
    diff --git a/v2/src/lib/base.pt.conf b/v2/src/lib/base.pt.conf
    new file mode 100644
    index 0000000..89344fb
    --- /dev/null
    +++ b/v2/src/lib/base.pt.conf
    @@ -0,0 +1,3 @@
    +date_fmt='%B %-d, %Y'
    +
    +site_name="EuAndreh's website"
    diff --git a/v2/src/lib/postamble.en.html b/v2/src/lib/postamble.en.html
    new file mode 100644
    index 0000000..485d81c
    --- /dev/null
    +++ b/v2/src/lib/postamble.en.html
    @@ -0,0 +1,7 @@
    +

    + Comment + and see + existing discussions + | + view source +

    diff --git a/v2/src/lib/postamble.pt.html b/v2/src/lib/postamble.pt.html new file mode 100644 index 0000000..2e65735 --- /dev/null +++ b/v2/src/lib/postamble.pt.html @@ -0,0 +1,5 @@ +

    + Comment and see existing discussions | view source +

    diff --git a/v2/src/lib/preamble.en.html b/v2/src/lib/preamble.en.html new file mode 100644 index 0000000..9ea6780 --- /dev/null +++ b/v2/src/lib/preamble.en.html @@ -0,0 +1,37 @@ + + + + + + + + + $(htmlesc "$title") + + + + + + + + + + +
    + +
    +
    +
    +
    +

    + $title_html +

    +

    + Posted on +

    +EOF diff --git a/v2/src/lib/preamble.pt.html b/v2/src/lib/preamble.pt.html new file mode 100644 index 0000000..9800470 --- /dev/null +++ b/v2/src/lib/preamble.pt.html @@ -0,0 +1,36 @@ + + + + + + + + + $(htmlesc "$title") + + + + + + + + + + +
    + +
    +
    +
    +
    +

    + $title_html +

    +

    + Posted on +

    +EOF -- cgit v1.2.3