aboutsummaryrefslogtreecommitdiff
path: root/v2/src/bin
diff options
context:
space:
mode:
Diffstat (limited to 'v2/src/bin')
-rwxr-xr-xv2/src/bin/absolute2
-rwxr-xr-xv2/src/bin/collections69
-rwxr-xr-xv2/src/bin/conf166
-rwxr-xr-xv2/src/bin/feed91
-rwxr-xr-xv2/src/bin/html219
-rwxr-xr-xv2/src/bin/lang-for73
-rwxr-xr-xv2/src/bin/langs69
-rwxr-xr-xv2/src/bin/makemake142
-rwxr-xr-xv2/src/bin/security-txt82
-rwxr-xr-xv2/src/bin/url-for30
-rwxr-xr-xv2/src/bin/xmlentry81
11 files changed, 946 insertions, 78 deletions
diff --git a/v2/src/bin/absolute b/v2/src/bin/absolute
index 6434219..ecf5a64 100755
--- a/v2/src/bin/absolute
+++ b/v2/src/bin/absolute
@@ -62,6 +62,6 @@ done
shift $((OPTIND - 1))
-. src/lib/base-conf
+. src/lib/base.conf
printf 'https://%s%s' "$domain" "$(cat)"
diff --git a/v2/src/bin/collections b/v2/src/bin/collections
new file mode 100755
index 0000000..1df0c39
--- /dev/null
+++ b/v2/src/bin/collections
@@ -0,0 +1,69 @@
+#!/bin/sh
+set -eu
+
+usage() {
+ cat <<-'EOF'
+ Usage:
+ collections
+ collections -h
+ EOF
+}
+
+help() {
+ cat <<-'EOF'
+
+
+ Options:
+ -h, --help show this message
+
+
+ List the registered collections to STDOUT.
+
+ This is done by emiting the content of the "$COLLECTIONS"
+ environment variable.
+
+
+ Examples:
+
+ Just run it:
+
+ $ collections
+ tils
+ pastebins
+ 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))
+
+
+echo "$COLLECTIONS" |
+ tr ' ' '\n' |
+ grep .
diff --git a/v2/src/bin/conf b/v2/src/bin/conf
new file mode 100755
index 0000000..ac02d98
--- /dev/null
+++ b/v2/src/bin/conf
@@ -0,0 +1,166 @@
+#!/bin/sh
+set -eu
+
+
+usage() {
+ cat <<-'EOF'
+ Usage:
+ conf FILENAME
+ conf -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:
+
+ $ conf 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/lib.sh
+
+FILENAME="${1:-}"
+eval "$(assert_arg "$FILENAME" 'FILENAME')"
+
+
+escape() {
+ sed 's|\([`"$]\)|\\\1|g'
+}
+
+tee "$FILENAME".tmp < src/lib/base.conf
+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 'export %s="%s"\n' "$KEY" "$VALUE"
+done < "$FILENAME" | tee -a "$FILENAME".tmp
+# shellcheck source=/dev/null
+. "$FILENAME".tmp
+rm -f "$FILENAME".tmp
+
+
+lang="$(lang-for "$FILENAME")"
+export lang
+printf 'export lang="%s"\n' "$lang"
+
+cat src/lib/base."${lang:?}".conf
+# shellcheck source=/dev/null
+. src/lib/base."$lang".conf
+if [ -z "${title:-}" ]; then
+ title="${site_name:?}"
+ printf 'export title="%s"\n' "$(printf '%s' "$title" | escape)"
+fi
+
+if [ -n "${date:-}" ]; then
+ date_iso="$(date -ud "${date:?}" -Is)"
+ printf 'export date_iso="%s"\n' "$date_iso"
+
+ formatted_date="$(LANG="$lang" date -ud "${date:?}" +"${date_fmt:?}")"
+ export formatted_date
+ printf 'export date_html="%s"\n' "$(envsubst < src/lib/date."$lang".html | escape)"
+
+ echo "${FILENAME%.md}.xmlentry" > "$(dirname "$FILENAME")/$date_iso.sortdata"
+ touch "${FILENAME%.md}.sortref"
+fi
+
+if [ -n "${update:-}" ]; then
+ update_iso="$(date -ud "${update:?}" -Is)"
+ printf 'export update_iso="%s"\n' "$update_iso"
+
+ formatted_update="$(LANG="$lang" date -ud "${update:?}" +"${date_fmt:?}")"
+ export formatted_update
+ printf 'export update_html="%s"\n' "$(envsubst < src/lib/update."$lang".html | escape)"
+
+ printf 'export update_xml=" <updated>%s</updated>"\n' "$update_iso"
+fi
+
+
+url_part="$(printf '%s' "${FILENAME%.md}.html" | sed "s|^$CONTENT_PREFIX||")"
+title_uri="$(uri "$title")"
+
+printf 'export title_html="%s"\n' "$(printf '%s' "$title" | htmlesc | escape)"
+printf 'export filename="%s"\n' "$FILENAME"
+printf 'export url_part="%s"\n' "$url_part"
+printf 'export url="%s"\n' "$(url-for "$url_part" | absolute)"
+printf 'export mailto_uri="%s%s"\n' "${mailto_uri_prefix:?}" "$title_uri"
+printf 'export discussions_url="%s%s"\n' "${discussions_url_prefix:?}" "$title_uri"
+printf 'export sourcecode_url="%s%s"\n' "${sourcecode_url_prefix:?}" "$FILENAME"
+
+printf 'export style_url="%s"\n' "$(url-for 'style.css')"
+printf 'export favicon_url="%s"\n' "$(url-for 'favicon.svg')"
+printf 'export pubkey_url="%s"\n' "$(url-for 'public.asc.txt')"
+
+for f in "$CONTENT_PREFIX"/img/*.svg; do
+ name="$(basename "$f" .svg | sed 's|-|_|g')"
+ printf 'export icon_%s_url="%s"\n' "$name" "$(url-for "img/$(basename "$f")")"
+done
+
+# FIXME: special treatment of root
+printf 'export homepage_url="%s"\n' "$(url-for '/')"
+
+printf 'export about_url="%s"\n' "$(url-for "${about_url_name:?}")"
+
+
+if [ "${layout:-}" = 'post' ]; then
+ export mailto_uri="$mailto_uri_prefix$title_uri"
+ export discussions_url="$discussions_url_prefix$title_uri"
+ export sourcecode_url="$sourcecode_url_prefix$FILENAME"
+ printf 'export comment_html="%s"\n' "$(envsubst < src/lib/comment."$lang".html | escape)"
+fi
diff --git a/v2/src/bin/feed b/v2/src/bin/feed
new file mode 100755
index 0000000..96c40a6
--- /dev/null
+++ b/v2/src/bin/feed
@@ -0,0 +1,91 @@
+#!/bin/sh
+set -eu
+
+usage() {
+ cat <<-'EOF'
+ Usage:
+ feed FILENAME
+ feed -h
+ EOF
+}
+
+help() {
+ cat <<-'EOF'
+
+
+ Options:
+ -h, --help show this message
+
+ FILENAME the target feed to be generated
+
+
+ Generate FILENAME as an Atom feed. The collection type and
+ language are inferred by the name of FILENAME.
+
+
+ Examples:
+
+ Generate a feed for TILs:
+
+ $ feed src/en/feeds/til.xml
+ 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/lib.sh
+
+FILENAME="${1:-}"
+eval "$(assert_arg "$FILENAME" 'FILENAME')"
+
+
+COLLECTION="$(basename "$FILENAME" '.xml')"
+LANGUAGE="$(lang-for "$FILENAME")"
+DIR="$(dirname "$(dirname "$FILENAME")")/$COLLECTION"
+
+
+. src/lib/base.conf
+# shellcheck source=/dev/null
+. src/lib/base."$LANGUAGE".conf
+
+now="$(date -uIs)"
+url="$(url-for "${FILENAME#"$CONTENT_PREFIX"}" | absolute)"
+site_name_html="$(htmlesc "${site_name:?}")"
+export now url site_name_html
+
+
+mkdir -p "$(dirname "$FILENAME")"
+{
+ envsubst < src/lib/feed.xml
+ find "$DIR"/*.sortdata | sort -nr | xargs cat | xargs cat
+ printf '</feed>\n'
+} > "$FILENAME"
diff --git a/v2/src/bin/html b/v2/src/bin/html
new file mode 100755
index 0000000..7e6809c
--- /dev/null
+++ b/v2/src/bin/html
@@ -0,0 +1,219 @@
+#!/bin/sh
+set -eu
+
+usage() {
+ cat <<-'EOF'
+ Usage:
+ html FILENAME
+ html -h
+ EOF
+}
+
+help() {
+ cat <<-'EOF'
+
+
+ Options:
+ -h, --help show this message
+
+ FILENAME the name of the input file .md file
+
+
+ Process the FILENAME, and generate a full HTML page.
+
+
+ Examples:
+
+ Generate the HTML for a pastebin:
+
+ $ html src/a-paste.md > src/a-paste.html
+ EOF
+}
+
+
+for f in "$@"; do
+ case "$f" 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/lib.sh
+
+FILENAME="${1:-}"
+eval "$(assert_arg "$FILENAME" 'FILENAME')"
+
+
+# shellcheck source=/dev/null
+. "${FILENAME%.md}.conf"
+
+#
+# Utility functions
+#
+
+SEEN_SLUGS="$(mkstemp)"
+slugify_once() {
+ SLUG="$(printf '%s' "$1" | slugify)${2:+-$2}"
+ if grep -q "^$SLUG$" "$SEEN_SLUGS"; then
+ N="${2:-0}"
+ N=$((N + 1))
+ slugify_once "$1" "$N"
+ else
+ printf '%s\n' "$SLUG" >> "$SEEN_SLUGS"
+ printf '%s' "$SLUG"
+ fi
+}
+
+INDENT=' '
+markdown_to_html() {
+ md2html | awk -vINDENT="$INDENT" '
+ BEGIN {
+ in_block = 0
+ }
+
+ {
+ if (in_block == 0) {
+ printf "%s", INDENT
+ }
+ print
+ }
+
+ /^<\/code><\/pre>$/ {
+ in_block = 0
+ }
+
+ /^<pre><code/ {
+ in_block = 1
+ }
+ '
+}
+
+extract_plaintext_snippets() {
+ SNIPPETS="${FILENAME%.md}.snippets"
+ printf '' > "$SNIPPETS"
+ F="$(mkstemp)"
+ cat > "$F"
+ (
+ IFS=''
+ BLOCK_NUMBER=0
+ IN_BLOCK=
+ while read -r line; do
+ if [ "$line" = '</code></pre>' ]; then
+ IN_BLOCK=
+ fi
+
+ if [ -n "$IN_BLOCK" ]; then
+ printf '%s\n' "$line" | htmlesc -d >> "$OUT"
+ fi
+
+ if printf '%s' "$line" | grep -q "^$INDENT<pre><code"; then
+ IN_BLOCK=1
+ OUT="${FILENAME%.md}.html.$BLOCK_NUMBER.txt"
+ BLOCK_NUMBER=$((BLOCK_NUMBER + 1))
+ printf '%s\n' "$line" |
+ sed "s|^\($INDENT<pre><code.*>\)\(.*\)$|\2|" |
+ htmlesc -d > "$OUT"
+ printf '%s\n' "$OUT" >> "$SNIPPETS"
+ fi
+ done < "$F"
+
+ BLOCK_NUMBER=0
+ while read -r line; do
+ printf '%s\n' "$line"
+
+ if [ "$line" = '</code></pre>' ]; then
+ printf '%s<p class="plaintext-link"><a href="%s">plaintext</a></p>\n' \
+ "$INDENT" \
+ "$(basename "${url_part:?}").$BLOCK_NUMBER.txt"
+ BLOCK_NUMBER=$((BLOCK_NUMBER + 1))
+ fi
+ done < "$F"
+ )
+
+}
+
+add_line_numbers() {
+ awk '
+ /^<\/code><\/pre>$/ {
+ in_block = 0
+ printf "</tbody></table>%s\n", $0
+ next
+ }
+
+ match($0, /^( +<pre><code.*>)(.*)$/, a) {
+ printf "%s<table rules=columns class=\"code-block\"><tbody>", a[1]
+
+ n = 1
+ block_count++
+ printf "<tr><td class=\"line-number\"><a id=\"B%s-L%s\" href=\"#B%s-L%s\">%s</a></td><td class=\"code-line\">%s</td></tr>\n", block_count, n, block_count, n, n, a[2]
+ in_block = 1
+ next
+ }
+
+ in_block == 1 {
+ n++
+ printf "<tr><td class=\"line-number\"><a id=\"B%s-L%s\" href=\"#B%s-L%s\">%s</a></td><td class=\"code-line\">%s</td></tr>\n", block_count, n, block_count, n, n, $0
+ next
+ }
+
+ { print }
+ '
+}
+
+add_headings_anchors() {
+ (
+ IFS=''
+ while read -r line; do
+ if ! printf '%s' "$line" | grep -q "^$INDENT<h[2-6]>"; then
+ printf '%s\n' "$line"
+ continue
+ fi
+ LVL="$(printf '%s' "$line" | sed "s|^$INDENT<h\(.\)>.*|\1|")"
+ HEADING="$(printf '%s' "$line" | sed "s|^$INDENT<h.>\(.*\)</h.>$|\1|")"
+ SLUG="$(slugify_once "$HEADING")"
+ printf '%s<h%s class="header-anchor" id="%s">%s<a href="#%s" aria-hidden="true"><img class="svg-icon" src="%s" /></a></h%s>\n' \
+ "$INDENT" \
+ "$LVL" \
+ "$SLUG" \
+ "$HEADING" \
+ "$SLUG" \
+ "${icon_link_url:?}" \
+ "$LVL"
+ done
+ )
+}
+
+emit_body() {
+ < "${FILENAME%.md}.content" \
+ markdown_to_html |
+ extract_plaintext_snippets |
+ add_line_numbers |
+ add_headings_anchors
+}
+
+envsubst < src/lib/preamble.html
+emit_body | tee "${FILENAME%.md}.htmlbody"
+envsubst < src/lib/postamble.html
diff --git a/v2/src/bin/lang-for b/v2/src/bin/lang-for
new file mode 100755
index 0000000..f7c57a9
--- /dev/null
+++ b/v2/src/bin/lang-for
@@ -0,0 +1,73 @@
+#!/bin/sh
+set -eu
+
+usage() {
+ cat <<-'EOF'
+ Usage:
+ lang-for FILE
+ lang-for -h
+ EOF
+}
+
+help() {
+ cat <<-'EOF'
+
+
+ Options:
+ -h, --help show this message
+
+ FILE the path of the file to get the language for
+
+
+ Say the language of the given file, using the path of FILE.
+
+
+ Examples:
+
+ Get "en" for "src/en/some-pt.md":
+
+ $ lang-for src/en/some-pt.md
+ en
+ 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/lib.sh
+
+
+FILE="${1:-}"
+eval "$(assert_arg "$FILE" 'FILE')"
+
+
+echo "${FILE#"$CONTENT_PREFIX"/}" |
+ cut -d/ -f1
diff --git a/v2/src/bin/langs b/v2/src/bin/langs
new file mode 100755
index 0000000..8e8aa63
--- /dev/null
+++ b/v2/src/bin/langs
@@ -0,0 +1,69 @@
+#!/bin/sh
+set -eu
+
+usage() {
+ cat <<-'EOF'
+ Usage:
+ langs
+ langs -h
+ EOF
+}
+
+help() {
+ cat <<-'EOF'
+
+
+ Options:
+ -h, --help show this message
+
+
+ List the supported languages, including english, to STDOUT.
+
+ This is done in the same way that po4a(1) does it: by listing
+ the po/*.po files, and getting the name from it.
+
+
+ Examples:
+
+ Just run it:
+
+ $ langs
+ en
+ pt
+ 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))
+
+
+echo po/en.po po/*.po |
+ tr ' ' '\n' |
+ sed 's|^po/\(.*\)\.po$|\1|'
diff --git a/v2/src/bin/makemake b/v2/src/bin/makemake
index e95a040..fdd0e68 100755
--- a/v2/src/bin/makemake
+++ b/v2/src/bin/makemake
@@ -64,84 +64,110 @@ varlist() {
printf '\n'
}
-html_deps() {
- "$@" | sed 's/^\(.*\)\.md$/\1.conf \1.content: \1.md/'
- "$@" | sed 's/^\(.*\)\.md$/\1.snippets \1.html: \1.conf \1.content/'
- printf '\n'
-}
-
-
-content_mds() {
- {
- if [ "$r" = 'pages' ]; then
- echo src/content/*.md
- else
- echo src/content/"$r"/*.md
- fi
- } | tr ' ' '\n'
-}
-
-RESOURCES='
-pages
-pastebins
-tils
-'
EXTENSIONS='
-.md
.conf
.content
.html
.snippets
+.htmlbody
'
-for r in $RESOURCES; do
- content_mds "$r" | varlist "$r".md
- for e in $EXTENSIONS; do
- if [ "$e" = '.md' ]; then
- continue
+COLL_EXTENSIONS='
+.sortref
+.xmlentry
+'
+
+page_ext_filter="^($(echo "$COLL_EXTENSIONS" |
+ tr ' ' '\n' |
+ grep . |
+ paste -sd'|'
+))\$"
+
+
+extensions() {
+ echo "$EXTENSIONS" "$COLL_EXTENSIONS" "$@" |
+ tr ' ' '\n' |
+ grep .
+}
+
+
+printf '.POSIX:\n\n\n'
+for lang in $(langs); do
+ for c in pages $(collections); do
+ if [ "$c" = 'pages' ]; then
+ filter="$page_ext_filter"
+ dir="$CONTENT_PREFIX/$lang"
+ else
+ filter='^$'
+ dir="$CONTENT_PREFIX/$lang/$c"
fi
- # shellcheck disable=2016
- 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
+
+ mds() {
+ # find "$dir"/*.md # FIXME
+ find "$dir"/*.md 2>/dev/null
+ }
+
+ exts() {
+ extensions | grep -Ev "$filter"
+ }
+
+ mds | varlist "$c.$lang.md"
+ exts | sed "s|^\(.*\)\$|$c.$lang\1 = \$($c.$lang.md:.md=\1)|"
+ exts | sed "s|^\(.*\)\$|\$($c.$lang\1)|" | varlist "$c.$lang"
+
+ mds | sed 's/^\(.*\)\.md$/\1.conf \1.content: \1.md/'
+ mds | sed 's/^\(.*\)\.md$/\1.snippets \1.htmlbody \1.html: \1.conf \1.content/'
+ if [ "$c" = 'pages' ]; then
continue
fi
- # shellcheck disable=2016
- printf ' $(%s%s)' "$r" "$e"
+
+ mds | sed 's/^\(.*\)\.md$/\1.sortref: \1.md/'
+ mds | sed 's/^\(.*\)\.md$/\1.xmlentry: \1.html/'
+
+ echo "$CONTENT_PREFIX/$lang/feeds/$c.xml: \$($c.$lang.xmlentry)"
+
+ printf '\n\n'
done
- printf '\n'
- html_deps content_mds "$r"
- printf '\n'
-done
+ for e in $(extensions); do
+ {
+ if ! printf '%s\n' "$e" | grep -qE "$page_ext_filter"; then
+ echo pages
+ fi
+ collections
+ } |
+ sed "s|^\(.*\)\$|\$(\1.$lang$e)|" |
+ varlist "all-generated.$lang$e"
+ done
-all_resources() {
- echo "$RESOURCES" | tr ' ' '\n' | grep .
-}
+ collections |
+ sed "s|^\(.*\)\$|$CONTENT_PREFIX/$lang/feeds/\1.xml|" |
+ varlist "all-generated.$lang.xml"
-all_vars() {
- EXT="$1"
- # shellcheck disable=2016
- all_resources |
- sed 's|^|$(|' |
- sed "s|$|$EXT)|" |
- varlist all-generated"$EXT"
-}
+ extensions '.xml' |
+ sed "s|^\(.*\)\$|\$(all-generated.$lang\1)|" |
+ varlist "all-generated.$lang"
-for e in $EXTENSIONS; do
- all_vars "$e"
+ printf '\n'
+done
+
+for e in $(extensions .xml); do
+ langs |
+ sed "s|^\(.*\)\$|\$(all-generated.\1$e)|" |
+ varlist "all-generated$e"
done
-all_vars ''
+
+# shellcheck disable=2016
+langs |
+ sed 's|^\(.*\)$|$(all-generated.\1)|' |
+ varlist 'all-generated'
-git ls-files |
- grep -v '^src/content/' |
+git ls-files src/ |
+ grep -v ^"$CONTENT_PREFIX"/ |
varlist 'non-content'
-git ls-files src/content/ |
+git ls-files "$CONTENT_PREFIX"/ |
grep -v '\.md$' |
- grep -Ev "src/content/($(all_resources | paste -sd'|'))/" |
varlist 'static-content'
diff --git a/v2/src/bin/security-txt b/v2/src/bin/security-txt
new file mode 100755
index 0000000..7026969
--- /dev/null
+++ b/v2/src/bin/security-txt
@@ -0,0 +1,82 @@
+#!/bin/sh
+set -eu
+
+usage() {
+ cat <<-'EOF'
+ Usage:
+ security-txt
+ security-txt -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:
+
+ $ security-txt > .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 "$EMAIL" |
+ awk '/^pub/ { print substr($(NF), 1, 10) }'
+)T00:00:00z"
+
+LANGUAGES="$(
+ langs |
+ sed 's|^|, |' |
+ tr -d '\n' |
+ sed 's|^, ||'
+)"
+
+
+cat <<-EOF
+ Contact: mailto:$EMAIL
+ Encryption: $(url-for 'public.asc.txt' | absolute)
+ Expires: $EXPIRES
+ Preferred-Languages: $LANGUAGES
+EOF
diff --git a/v2/src/bin/url-for b/v2/src/bin/url-for
index d4099bc..adaccd7 100755
--- a/v2/src/bin/url-for
+++ b/v2/src/bin/url-for
@@ -4,7 +4,7 @@ set -eu
usage() {
cat <<-'EOF'
Usage:
- url-for [-g] FILE
+ url-for FILE
url-for -h
EOF
}
@@ -13,7 +13,6 @@ help() {
cat <<-'EOF'
Options:
- -g global file, not specific to a single language
-h, --help show this message
FILE the path for the URL to be constructed
@@ -25,7 +24,7 @@ help() {
Examples:
- Get the URL for "about.html", when $base_url is "v2" and $lang is "en":
+ Get the URL for "en/about.html", when $base_url is "v2":
$ url-for 'about.html'
/v2/en/about.html
@@ -33,8 +32,8 @@ help() {
Get the URL for "static/favicon.svg", when $base_url is empty:
- $ url-for -g 'static/favicon.svg'
- /static/favicon.svg
+ $ url-for 'img/link.svg'
+ /img/link.svg
EOF
}
@@ -54,12 +53,8 @@ for flag in "$@"; do
esac
done
-GLOBAL=false
-while getopts 'gh' flag; do
+while getopts 'h' flag; do
case "$flag" in
- g)
- GLOBAL=true
- ;;
h)
usage
help
@@ -73,22 +68,19 @@ while getopts 'gh' flag; do
done
shift $((OPTIND - 1))
-. src/development/lib.sh
-
+. src/lib.sh
FILE="${1:-}"
+eval "$(assert_arg "$FILE" 'FILE')"
+
+
if [ "$FILE" = '/' ]; then
FILE=''
fi
-. src/lib/base-conf
+. src/lib/base.conf
# shellcheck source=/dev/null
. src/lib/base."${lang:?}".conf
-if [ "$GLOBAL" = true ]; then
- L=''
-else
- L="${lang:?}/"
-fi
-printf '%s%s%s' "${base_url:-/}" "$L" "$FILE"
+printf '%s%s' "${base_url:-/}" "$FILE"
diff --git a/v2/src/bin/xmlentry b/v2/src/bin/xmlentry
new file mode 100755
index 0000000..b0760ae
--- /dev/null
+++ b/v2/src/bin/xmlentry
@@ -0,0 +1,81 @@
+#!/bin/sh
+set -eu
+
+usage() {
+ cat <<-'EOF'
+ Usage:
+ xmlentry FILENAME
+ xmlentry -h
+ EOF
+}
+
+help() {
+ cat <<-'EOF'
+
+
+ Options:
+ -h, --help show this message
+
+ FILENAME the name of the input .md file
+
+
+ Process FILE, and generate an Atom feed entry.
+
+
+ Examples:
+
+ Generate the XML entry for a TIL:
+
+ $ xmlentry src/tils/a-til.md > src/tils/a-til.xml
+ 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/lib.sh
+
+FILENAME="${1:-}"
+eval "$(assert_arg "$FILENAME" 'FILENAME')"
+
+
+# shellcheck source=/dev/null
+. "${FILENAME%.md}.conf"
+
+envsubst < src/lib/entry.xml
+
+head -n1 < "${FILENAME%.md}.htmlbody" | htmlesc
+printf ' </summary>\n'
+printf ' <content type="html" xml:base="%s">\n' "${url:?}"
+
+htmlesc < "${FILENAME%.md}.htmlbody"
+printf ' </content>\n'
+printf ' </entry>\n'