From 438014583ba2c244675d0f8d7f7f8bf9d568a7c8 Mon Sep 17 00:00:00 2001 From: EuAndreh Date: Sun, 1 Sep 2024 09:14:28 -0300 Subject: Initial version --- src/conf | 217 ++++++++++++++++++++++++++++++++++++---- src/feed | 60 +++++------ src/feedentry | 53 ++++++++++ src/html | 307 ++++++++++++++++++++++++++++----------------------------- src/htmlbody | 26 ++++- src/indexbody | 24 +++++ src/indexentry | 20 ++++ src/mkwb.in | 4 +- src/snippets | 27 +++++ src/sortdata | 16 +-- src/xmlentry | 48 --------- 11 files changed, 536 insertions(+), 266 deletions(-) create mode 100755 src/feedentry create mode 100755 src/indexbody create mode 100755 src/indexentry create mode 100755 src/snippets delete mode 100755 src/xmlentry (limited to 'src') diff --git a/src/conf b/src/conf index 6aa6761..d132a34 100755 --- a/src/conf +++ b/src/conf @@ -1,30 +1,207 @@ #!/bin/sh -set -eu +set -euo pipefail usage() { - echo 'Usage: conf FILENAME' + echo 'Usage: conf BASECONF [GLOBALCONF FILENAME.adoc]' } -FILENAME="${1:-}" + +needs() { + if [ -z "${1:-}" ]; then + printf '%s\n' "$2" >&2 + exit 1 + fi +} + +DATE_I='+%Y-%m-%d' +DATE_Is="${DATE_I}T%H:%M:%S%:z" +datex() { + # date(1), plus non-POSIX -d option + DATESTR="$1" + shift + date -d "$DATESTR" "$@" +} + +dateiso() { + datex "$1" -u "$DATE_Is" +} + +BASECONF="${1:-}" +GLOBALCONF="${2:-}" +FILENAME="${3:-}" +eval "$(assert-arg -- "$BASECONF" 'BASECONF')" +. "$(realpath -- "$BASECONF")" + + +needs "${url_pre:-}" 'Missing required $url_pre (e.g. https://example.com)' +needs "${site_name:-}" 'Missing required $site_name' +needs "${feed_title:-}" 'Missing required $feed_title' +needs "${feed_url:-}" 'Missing required $feed_url' +needs "${feed_alternate_url:-}" 'Missing required $feed_alternate_url' + +needs "${list_addr:-}" 'Missing required $list_addr' +needs "${discussions_url_prefix:-}" 'Missing required $discussions_url_prefix' + +needs "${email:-}" 'Missing required $email' +needs "${author:-}" 'Missing required $author' +needs "${sourcecode_url:-}" 'Missing required $sourcecode_url' +needs "${sourcecode_url_prefix:-}" 'Missing required $sourcecode_url_prefix' + + +if [ -z "$GLOBALCONF" ]; then + now_iso="$(dateiso "@${SOURCE_DATE_EPOCH:-$(date '+%s')}" | shesc)" + feed_title_html="$(printf '%s\n' "$feed_title" | htmlesc | shesc)" + site_name_html="$( printf '%s\n' "$site_name" | htmlesc | shesc)" + if [ -z "${logo_alt:-}" ]; then + logo_alt='The website logo' + fi + logo_alt="$(printf '%s\n' "$logo_alt" | htmlesc | shesc)" + + cat <<-EOF + export now_iso="$now_iso" + export feed_title_html="$feed_title_html" + export site_name_html="$site_name_html" + export feed_url_absolute="$url_pre/$feed_url" + export feed_alternate_url_absolute="$url_pre/$feed_alternate_url" + export logo_alt="$logo_alt" + EOF + exit +fi + +eval "$(assert-arg -- "$BASECONF" 'BASECONF')" eval "$(assert-arg -- "$FILENAME" 'FILENAME')" +. "$(realpath -- "$GLOBALCONF")" + +trap 'rm -f -- "$FILENAME".embedded-config' EXIT + +{ + if head -n1 -- "$FILENAME" | grep -q '^////$'; then + awk 'sep > 1 {exit}; /^\/{4}$/ { sep++; next } { print }' \ + "$FILENAME" + fi +} > "$FILENAME".embedded-config +. "$(realpath -- "$FILENAME".embedded-config)" + +is_article() { + printf '%s\n' "$FILENAME" | grep -qE \ + "^${root_dir}[-a-zA-Z0-9/]*/[0-9]{4}/[0-9]{2}/[0-9]{2}/[-A-Za-z0-9]+\.adoc$" + #^ src /blog/d/a /1970 /01 /01/ /some-file-N4me.adoc +} + +base_url() { + # src/sub/dirs/file.txt -> ../.. + # src/file.txt -> . + printf '%s/\n' "$(dirname -- "$UNPREFIXED")" | + sed \ + -e 's|[^/]*/|../|g' \ + -e 's|/$||' \ + -e 's|^\.\.$|.|' +} + +last3dirnames() { + dirname -- "$UNPREFIXED" | tr '/' '\n' | tail -n3 | paste -sd- +} + +datefmt() { + LANG=en_GB.UTF-8 datex "$1" -u '+%B %-d, %Y' +} + + +if [ -z "${root_dir:-}" ]; then + root_dir="$(dirname -- "$BASECONF")" +fi +root_dir="${root_dir%/}" +if [ -z "${img_dir:-}" ]; then + img_dir=img +fi +img_dir="${img_dir%/}" -date="$(dirname "${FILENAME#src/}" | tr '/' '-')" -date_iso="$(date -ud "${date:?}" -Is)" # FIXME: non POSIX -printf 'export date_iso="%s"\n' "$date_iso" - -cat <<-'EOF' - export domain="DOMAIN" - export email="EMAIL" - export base_url='' - export list_addr='~euandreh/public-inbox@lists.sr.ht' - export mailto_uri_prefix="mailto:$list_addr?Subject=Re%3A%20" - export discussions_url_prefix="https://lists.sr.ht/~euandreh/public-inbox?search=" - export sourcecode_url_prefix="https://$domain/git/$domain/tree/" - export author='EuAndreh' - export url='url1' - export site_name='site_name1' - export feed_article_title='Articles from papo.im' - export lang=en +UNPREFIXED="${FILENAME#$root_dir/}" + +cat "$BASECONF" "$GLOBALCONF" + +date_iso= +date_formatted= +updatedat_iso= +updatedat_formatted= +if is_article; then + date_iso="$(dateiso "$(last3dirnames)" | shesc)" + date_formatted="$(datefmt "$date_iso" | shesc)" + if [ -n "${updatedat:-}" ]; then + updatedat_iso="$(dateiso "$updatedat" | shesc)" + updatedat_formatted="$(datefmt "$updatedat_iso" | shesc)" + fi +fi + +BASE_URL="$(base_url)" +TITLE_RAW="$(cat -- "$FILENAME" | grep '^= .*' | head -n1 | cut -d' ' -f2-)" +TITLEFULL_RAW="$TITLE_RAW | $site_name" + +if [ -z "${css_url:-}" ]; then + css_url="$BASE_URL/style.css" +fi +if [ -z "${atom_url:-}" ]; then + atom_url="$BASE_URL/atom.xml" +fi +if [ -z "${atomicon_url:-}" ]; then + needs "${img_dir:-}" 'Define either $atomicon_url or $img_dir' + atomicon_url="$BASE_URL/$img_dir/atom.svg" +fi +if [ -z "${favicon_url:-}" ]; then + needs "${img_dir:-}" 'Define either $favicon_url or $img_dir' + favicon_url="$BASE_URL/$img_dir/favicon.svg" +fi +if [ -z "${logo_url_prefix:-}" ]; then + needs "${img_dir:-}" 'Define either $logo_url_prefix or $img_dir' + logo_url_prefix="$BASE_URL/$img_dir/logo" +fi +if [ -z "${envelopeicon_url_prefix:-}" ]; then + needs "${img_dir:-}" 'Define either $envelopeicon_url_prefix or $img_dir' + envelopeicon_url_prefix="$BASE_URL/$img_dir/envelope" +fi + +title_uri="$(printf '%s' "$TITLE_RAW" | uri)" +comment_url="$(printf 'mailto:%s?Subject=Re%%3A%%20%s\n' "$list_addr" "$title_uri" | shesc)" +discussions_url="$(printf '%s%s\n' "$discussions_url_prefix" "$title_uri" | shesc)" + +url="$(printf '%s\n' "${UNPREFIXED%.adoc}.html" | shesc)" + +css_url="$( printf '%s\n' "$css_url" | shesc)" +atom_url="$( printf '%s\n' "$atom_url" | shesc)" +atomicon_url="$( printf '%s\n' "$atomicon_url" | shesc)" +favicon_url="$( printf '%s\n' "$favicon_url" | shesc)" +logo_url_prefix="$( printf '%s\n' "$logo_url_prefix" | shesc)" +envelopeicon_url_prefix="$(printf '%s\n' "$envelopeicon_url_prefix" | shesc)" + +source_path="$(printf '%s\n' "$FILENAME" | shesc)" +base_url_prefix="$(printf '%s\n' "$BASE_URL" | shesc)" +title="$( printf '%s\n' "$TITLE_RAW" | shesc)" +title_html="$( printf '%s\n' "$TITLE_RAW" | htmlesc | shesc)" +titlefull="$( printf '%s\n' "$TITLEFULL_RAW" | shesc)" +titlefull_html="$(printf '%s\n' "$TITLEFULL_RAW" | htmlesc | shesc)" +cat <<-EOF + export css_url="$css_url" + export atom_url="$atom_url" + export atomicon_url="$atomicon_url" + export favicon_url="$favicon_url" + export logo_url_prefix="$logo_url_prefix" + export envelopeicon_url_prefix="$envelopeicon_url_prefix" + export source_path="$source_path" + export url="$url" + export url_absolute="$url_pre/$url" + export base_url_prefix="$base_url_prefix" + export title="$title" + export title_html="$title_html" + export titlefull="$titlefull" + export titlefull_html="$titlefull_html" + export date_iso="$date_iso" + export date_formatted="$date_formatted" + export updatedat_iso="$updatedat_iso" + export updatedat_formatted="$updatedat_formatted" + export comment_url="$comment_url" + export discussions_url="$discussions_url" EOF + +cat "$FILENAME".embedded-config diff --git a/src/feed b/src/feed index f202ba6..aa42899 100755 --- a/src/feed +++ b/src/feed @@ -1,52 +1,52 @@ #!/bin/sh -set -eu +set -euo pipefail + usage() { - echo 'Usage: feed FILENAME' + echo 'Usage: feed BASECONF GLOBALCONF FILENAME.sortdata...' } -FILENAME="${1:-}" -eval "$(assert-arg -- "$FILENAME" 'FILENAME')" - +BASECONF="${1:-}" +GLOBALCONF="${2:-}" +FILES="${3:-}" +eval "$(assert-arg -- "$BASECONF" 'BASECONF')" +eval "$(assert-arg -- "$GLOBALCONF" 'GLOBALCONF')" +eval "$(assert-arg -- "$FILES" 'FILENAME.sortdata...')" +. "$(realpath -- "$BASECONF")" +. "$(realpath -- "$GLOBALCONF")" +shift +shift -absolute() { - printf 'https://domain-here.com/%s' "$(cat -)" -} -feed_article_title='' -site_name=' ' -lang=en -now="$(date -uIs)" -url_absolute="$(printf '%s' "${FILENAME#src/}" | absolute)" -site_name_html="$(htmlesc "${site_name:?}")" -collection=article -collection_url_absolute="$(printf '%s' ${lang:?}/ | absolute)" -feed_title_html="$(eval "echo \"\$feed_${collection}_title\"" | htmlesc)" -export now url_absolute site_name_html collection_url_absolute feed_title_html - -DIR="$(dirname "$FILENAME")" - -author= -email= -cat < - - + xml:lang="en"> + + $site_name_html $feed_title_html - $url_absolute - $now + $feed_url_absolute + $now_iso $author $email EOF +} + +post() { + printf '\n' +} + +pre find "$@" | xargs cat | sort -nr | + xargs cat | + sed 's/\.conf$/.feedentry/' | xargs cat -printf '\n' +post diff --git a/src/feedentry b/src/feedentry new file mode 100755 index 0000000..6299e6f --- /dev/null +++ b/src/feedentry @@ -0,0 +1,53 @@ +#!/bin/sh +set -euo pipefail + + +usage() { + echo 'Usage: feedentry FILENAME.htmlbody' +} + +FILENAME="${1:-}" +eval "$(assert-arg -- "$FILENAME" 'FILENAME.htmlbody')" +. "$(realpath -- "${FILENAME%.*}.conf")" + + +update_xml= +if [ -n "${updated_at:-}" ]; then + update_iso="$(date -ud "$updated_at" -Is)" + update_xml=" + $update_iso + " +fi + +cat < + + $title_html + + + + $date_iso + +$update_xml + + $url_absolute + + + + $author + + + $email + + + + +EOF + +head -n5 < "$FILENAME" | htmlesc +printf ' \n' +printf ' \n' "${url:?}" + +htmlesc < "$FILENAME" +printf ' \n' +printf ' \n' diff --git a/src/html b/src/html index 007fcc2..3e100cb 100755 --- a/src/html +++ b/src/html @@ -1,174 +1,165 @@ #!/bin/sh -set -eu +set -euo pipefail + usage() { - echo 'Usage: html FILENAME' + echo 'Usage: html FILENAME.htmlbody' } FILENAME="${1:-}" -eval "$(assert-arg -- "$FILENAME" 'FILENAME')" - -. "${FILENAME%.*}.conf" - -# -# Utility functions -# - -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 - } - - /^

+          

+ Posted on +

+EOF + + if [ -n "$updatedat_formatted" ]; then + cat < + Updated on " +

+EOF + fi + + cat < +EOF } -extract_plaintext_snippets() ( - SNIPPETS="${FILENAME%.*}.snippets" - printf '' > "$SNIPPETS" - F="$(mkstemp)" - cat > "$F" - IFS='' - BLOCK_NUMBER=0 - IN_BLOCK= - while read -r line; do - if [ "$line" = '
' ]; then - IN_BLOCK= - fi - - if [ -n "$IN_BLOCK" ]; then - printf '%s\n' "$line" | htmlesc -d >> "$OUT" - fi - - if printf '%s' "$line" | grep -q "^$INDENT
\)\(.*\)$|\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" = '
' ]; then - printf '%s\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 "%s\n", $0 - next - } - - match($0, /^( +
)(.*)$/, a) {
-			printf "%s", a[1]
-
-			n = 1
-			block_count++
-			printf "\n", block_count, n, block_count, n, n, a[2]
-			in_block = 1
-			next
-		}
-
-		in_block == 1 {
-			n++
-			printf "\n", block_count, n, block_count, n, n, $0
-			next
-		}
-
-		{ print }
-	'
-}
+h1() {
+	if [ "${custom_body:-}" = true ]; then
+		return
+	fi
 
-add_headings_anchors() (
-	IFS=''
-	while read -r line; do
-		if ! printf '%s' "$line" | grep -q "^$INDENT"; then
-			printf '%s\n' "$line"
-			continue
-		fi
-		LVL="$(printf '%s' "$line" | sed "s|^$INDENT.*|\1|")"
-		HEADING="$(printf '%s' "$line" | sed "s|^$INDENT\(.*\)$|\1|")"
-		SLUG="$(slugify "$HEADING")"
-		printf '%s%s\n' \
-			"$INDENT"  \
-			"$LVL"     \
-			"$SLUG"    \
-			"$HEADING" \
-			"$SLUG"    \
-			"${icon_link_url:?}" \
-			"$LVL"
-	done
-)
-
-
-warn_duplicate_ids() {
-	F="$(mkstemp)"
-	tee "$F"
-	{
-		grep "^$INDENT.*&2 < "$F"
-	rm "$F"
+	cat <
+          $title_html
+        
+EOF
 }
 
-emit_body() {
-	< "${FILENAME%.*}.content" \
-		markdown_to_html           |
-		extract_plaintext_snippets |
-		add_line_numbers           |
-		add_headings_anchors       |
-		warn_duplicate_ids
+comments() {
+	if [ "${custom_body:-}" = true ]; then
+		return
+	fi
+
+	cat <
+          
+
+ +EOF } -if [ -r "$FILENAME".prev ]; then - collection_head_prev_html="$( - printf ' ' \ - "$(url-for < "$FILENAME".prev)" - )" - export collection_head_prev_html -fi -if [ -r "$FILENAME".next ]; then - collection_head_next_html="$( - printf ' ' \ - "$(url-for < "$FILENAME".next)" - )" - export collection_head_next_html +head_meta_author_html= +if [ -n "${author:-}" ]; then + head_meta_author_html=" " fi -envsubst < lib/preamble.html | sed '/^$/d' -emit_body | tee "${FILENAME%.*}.htmlbody" -envsubst < lib/postamble.html | sed '/^$/d' + +headlinks() { + if [ -z "${header_links:-}" ]; then + return + fi + + echo '
    ' + + while read -r line; do + link="$(printf '%s\n' "$line" | cut -d' ' -f1)" + name="$(printf '%s\n' "$line" | cut -d' ' -f2)" + cat < + $name + +EOF + done < "$header_links" + + echo '
' +} + + +collection_head_prev_html= +collection_head_post_html= +cat < + + + + +$head_meta_author_html + + + + +$collection_head_prev_html +$collection_head_post_html + $titlefull_html + + +
+ +
+
+
+
+EOF + +h1 +dates + +cat "$FILENAME" + +comments + +cat < +
+ + + +EOF diff --git a/src/htmlbody b/src/htmlbody index 53a4485..e4e5692 100755 --- a/src/htmlbody +++ b/src/htmlbody @@ -1,4 +1,26 @@ #!/bin/sh -set -eu +set -euo pipefail -cat "${1:--}" | asciidoctor -s - + +usage() { + echo 'Usage: htmlbody FILENAME.adoc' +} + +FILENAME="${1:-}" +eval "$(assert-arg -- "$FILENAME" 'FILENAME.adoc')" + + +plaintext_links() { + awk -v BASE="$(basename "$FILENAME" .adoc)".html l' + { print } + /^----$/ { + in_block = !in_block + if (in_block) { + next + } + file = BASE "." count++ ".txt" + print "link:" file "[plaintext,role=plaintext]" + }' "$1" +} + +plaintext_links "$FILENAME" | asciidoctor -s - diff --git a/src/indexbody b/src/indexbody new file mode 100755 index 0000000..93b4f90 --- /dev/null +++ b/src/indexbody @@ -0,0 +1,24 @@ +#!/bin/sh +set -euo pipefail + + +usage() { + echo 'Usage: index FILENAME.conf FILENAME.sortdata...]' +} + +FILENAME="${1:-}" +FILES="${2:-}" +eval "$(assert-arg -- "$FILENAME" 'FILENAME.conf')" +eval "$(assert-arg -- "$FILES" 'FILENAME.sortdata...')" +. "$(realpath -- "$FILENAME")" +shift + + +printf '
    \n' +find "$@" | + xargs cat | + sort -nr | + xargs cat | + sed 's/\.conf$/.indexentry/' | + xargs cat +printf '
\n' diff --git a/src/indexentry b/src/indexentry new file mode 100755 index 0000000..07ffa4a --- /dev/null +++ b/src/indexentry @@ -0,0 +1,20 @@ +#!/bin/sh +set -euo pipefail + + +usage() { + echo 'Usage: indexentry FILENAME.conf' +} + +FILENAME="${1:-}" +eval "$(assert-arg -- "$FILENAME" 'FILENAME.conf')" +. "$(realpath -- "$FILENAME")" + + +cat < + $date_formatted +
+ $title_html + +EOF diff --git a/src/mkwb.in b/src/mkwb.in index 2c698e1..438f779 100755 --- a/src/mkwb.in +++ b/src/mkwb.in @@ -1,5 +1,6 @@ #!/bin/sh -set -eu +set -euo pipefail + usage() { echo 'Usage: mkwb ACTION [OPTION...]' @@ -9,4 +10,5 @@ ACTION="${1:-}" eval "$(assert-arg -- "$ACTION" 'ACTION')" shift + exec '@LIBEXECDIR@'/"$ACTION" "$@" diff --git a/src/snippets b/src/snippets new file mode 100755 index 0000000..e2d7557 --- /dev/null +++ b/src/snippets @@ -0,0 +1,27 @@ +#!/bin/sh +set -euo pipefail + + +usage() { + echo 'Usage: snippets FILENAME.adoc' +} + +FILENAME="${1:-}" +eval "$(assert-arg -- "$FILENAME" 'FILENAME.adoc')" + + +awk -v BASE="${FILENAME%.adoc}.html" ' +/^----$/ { + if (!in_block) { + file = BASE "." count++ ".txt" + system("rm -f " file) + } + in_block = !in_block + next +} + +in_block { + print >> file + print file +} +' "$FILENAME" diff --git a/src/sortdata b/src/sortdata index 5b0b238..df64e9f 100755 --- a/src/sortdata +++ b/src/sortdata @@ -1,14 +1,16 @@ #!/bin/sh -set -eu +set -euo pipefail + usage() { - echo 'Usage: sortdata ENTRYPATH' + echo 'Usage: sortdata FILENAME.conf' } -ENTRYPATH="${1:-}" -eval "$(assert-arg -- "$ENTRYPATH" 'ENTRYPATH')" -. "${ENTRYPATH%.*}.conf" +FILENAME="${1:-}" +eval "$(assert-arg -- "$FILENAME" 'FILENAME.conf')" +. "$(realpath -- "$FILENAME")" + -f=src/"$date_iso".sortdata -ln -frs "${ENTRYPATH%.*}.xmlentry" "$f" # FIXME: -r is no POSIX +f=src/"$date_iso"-"${sort:-0}".sortdata +printf '%s\n' "$FILENAME" > "$f" printf '%s\n' "$f" diff --git a/src/xmlentry b/src/xmlentry deleted file mode 100755 index c2458d1..0000000 --- a/src/xmlentry +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/sh -set -eu - - -usage() { - echo 'Usage: xmlentry FILENAME' -} - -FILENAME="${1:-}" -eval "$(assert-arg -- "$FILENAME" 'FILENAME')" -. "${FILENAME%.*}.conf" - - -title_html= -url_absolute= -update_xml= -cat < - - $title_html - - - - $date_iso - -$update_xml - - $url_absolute - - - - $author - - - $email - - - - -EOF - -head -n1 < "${FILENAME%.*}.htmlbody" | htmlesc -printf ' \n' -printf ' \n' "${url:?}" - -htmlesc < "${FILENAME%.*}.htmlbody" -printf ' \n' -printf ' \n' -- cgit v1.2.3
%s%s
%s%s