These files will be linked to symbolically in a directory ./public/.
Some metadata files will also be generated below ./metadata/: For each article,
-there will be generated a .uuid and a .intermediate file; furthermore, files for
+there will be generated a .automatic_metadata (to contain an article's UUID,
+checksum, and creation/modification dates) and a .intermediate file (to contain
+pandoc-formatted article content like title and body); furthermore, files for
data used in ./feed.xml and ./index.html will, if non-existant, be built there
-and can be edited to customize the blog – namely the files url, author, uuid,
-title, index.tmpl, index_snippet.tmpl, article.tmpl.
+and can be edited to customize the blog – namely the files url, author, title,
+index.tmpl, index_snippet.tmpl, article.tmpl. A blog-specific UUID and creation
+date is stored in ./metadata/automatic_metadata
recipe to remotely manage a redo blog with git
----------------------------------------------
rm "$file"
fi
done
-for file in "$metadata_dir"/*.uuid; do
+for file in "$metadata_dir"/*.automatic_metadata; do
basename=$(basename "$file")
if test -f "$file" &&
- ! test -f "${basename%.uuid}.md" &&
- ! test -f "${basename%.uuid}.rst"; then
+ ! test -f "${basename%.automatic_metadata}.md" &&
+ ! test -f "${basename%.automatic_metadata}.rst"; then
rm "$file"
fi
done
# Pull in global dependencies.
. ./helpers.sh
metadata_dir=metadata
-uuid_file="${metadata_dir}/${1%.html}.uuid"
-redo-ifchange "$uuid_file"
+meta_file="${metadata_dir}/${1%.html}.automatic_metadata"
+redo-ifchange "$meta_file"
intermediate_file="${metadata_dir}/${1%.html}.intermediate"
redo-ifchange "$intermediate_file"
title_file="${metadata_dir}"/title
title_html=$(printf "%s" "$title_html" | prep_sed)
title_plaintext=$(escape_html "$title_plaintext" | prep_sed)
body=$(cat "$intermediate_file" | sed 1d | prep_sed)
-datetime_created_unix=$(stat -c%y "${uuid_file}")
-datetime_created_rfc3339=$(date -u "+%Y-%m-%dT%TZ" -d "${datetime_created_unix}")
-datetime_created_friendly=$(date -u "+%Y-%m-%d %T (UTC)" -d "${datetime_created_unix}")
+datetime_created_unix=$(get_creation_date_from_meta_file_seconds "$meta_file")
+datetime_created_rfc3339=$(date -u "+%Y-%m-%dT%TZ" -d "@${datetime_created_unix}")
+datetime_created_friendly=$(date -u "+%Y-%m-%d %T (UTC)" -d "@${datetime_created_unix}")
# Put data into template.
template=$(cat "$template_file")
. ./helpers.sh
metadata_dir=metadata
author_file="$metadata_dir"/author
-uuid_file="$metadata_dir"/uuid
+meta_file="$metadata_dir"/automatic_metadata
title_file="$metadata_dir"/title
url_file="$metadata_dir"/url
redo-ifchange "$url_file"
redo-ifchange "$author_file"
-redo-ifchange "$uuid_file"
+redo-ifchange "$meta_file"
redo-ifchange "$title_file"
# Build some variables. XML-escape even file contents that should not contain
# dangerous characters, just to avoid any XML trouble.
-srcdir=`pwd`
-basepath=$(get_basepath "${metadata_dir}/")
-title=`read_and_escape_file "$title_file" | head -1`
-author=`read_and_escape_file "$author_file" | head -1`
-uuid=`read_and_escape_file "$uuid_file" | head -1`
+srcdir=$(pwd)
tmp_snippets_dir=.tmp_feed_snippets
-feed_gen_date=$(stat -c%Y "${uuid_file}")
+basepath=$(get_basepath "${metadata_dir}/")
+title=$(read_and_escape_file "$title_file" | head -1)
+author=$(read_and_escape_file "$author_file" | head -1)
+uuid=$(get_uuid_from_meta_file "$meta_file")
+feed_gen_date=$(get_creation_date_from_meta_file_seconds "$meta_file")
# Write majority of feed head.
cat << EOF
mkdir -p "$tmp_snippets_dir"
for file in ./*.rst ./*.md; do
if [ -e "$file" ]; then
- uuid_file="${metadata_dir}/${file%.*}.uuid"
- redo-ifchange "$uuid_file"
- published=$(stat -c%Y "${uuid_file}")
+ meta_file="${metadata_dir}/${file%.*}.automatic_metadata"
+ redo-ifchange "$meta_file"
+ published=$(get_creation_date_from_meta_file_nanoseconds "$meta_file")
snippet_file=./${metadata_dir}/"${file%.*}.feed_snippet"
redo-ifchange "$snippet_file"
ln -s "$srcdir/$snippet_file" "./${tmp_snippets_dir}/${published}"
fi
done
-# Derive feed modification date from snippets. Fallback to uuid file mod date.
+# Derive feed modification date from snippets. Fallback to blog creation date.
n_snippet_files=`ls -1 ./${metadata_dir}/*.feed_snippet 2>/dev/null | wc -l`
if [ $n_snippet_files != 0 ]
then
}
read_and_escape_file() {
- in=`cat "$1"`
+ in=$(cat "$1")
escape_html "$in"
}
+get_uuid_from_meta_file() {
+ probable_uuid=$(cat "$1" | head -1)
+ if printf "$probable_uuid" | grep -Eq "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"; then
+ printf "$probable_uuid"
+ else
+ echo "Malformed UUID in meta file." >&2
+ exit 1
+ fi
+}
+
+get_creation_date_from_meta_file_seconds() {
+ cat "$1" | sed -n '2p' | cut -d'_' -f1
+}
+
+get_creation_date_from_meta_file_nanoseconds() {
+ cat "$1" | sed -n '2p'
+}
+
+get_lastmod_date_from_meta_file() {
+ cat "$1" | sed -n '4p'
+}
+
escape_url() {
out=`python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1]))' "$1"`
printf "%s" "$out"
mkdir -p "$tmp_snippets_dir"
for file in ./*.rst ./*.md; do
if [ -e "$file" ]; then
- uuid_file="${metadata_dir}/${file%.*}.uuid"
- redo-ifchange "$uuid_file"
- published=`stat -c%y "${uuid_file}"`
- published_unix=$(date -u "+%s%N" -d "${published}")
+ meta_file="${metadata_dir}/${file%.*}.automatic_metadata"
+ redo-ifchange "$meta_file"
+ published=$(get_creation_date_from_meta_file_nanoseconds "$meta_file")
snippet_file="${metadata_dir}/${file%.*}.index_snippet"
redo-ifchange "$snippet_file"
- ln -s "$srcdir/$snippet_file" "./${tmp_snippets_dir}/${published_unix}"
+ ln -s "$srcdir/$snippet_file" "./${tmp_snippets_dir}/${published}"
fi
done
--- /dev/null
+#!/bin/sh
+
+if [ ! -f "$1" ]; then
+ uuidgen
+ date -u "+%s"
+fi
--- /dev/null
+#!/bin/sh
+
+if [ ! -f "$1" ]; then
+ uuidgen
+ date -u "+%s_%N"
+ echo 00000000000000000000000000000000
+ echo 0
+fi
# Pull in dependencies.
. ../helpers.sh
src_file=$(get_source_file "$1")
-uuid_file="${1%.feed_snippet}.uuid"
-redo-ifchange "$uuid_file"
+meta_file="${1%.feed_snippet}.automatic_metadata"
+redo-ifchange "$meta_file"
intermediate_file="${1%.feed_snippet}.intermediate"
redo-ifchange "$intermediate_file"
# Get variables, write entry.
html_file=$(escape_url "${1%.feed_snippet}.html")
-lastmod=`stat -c%y "$src_file"`
-lastmod_rfc3339=`date -u "+%Y-%m-%dT%TZ" -d "$lastmod"`
-published=`stat -c%y "$uuid_file"`
-published_rfc3339=`date -u "+%Y-%m-%dT%TZ" -d "${published}"`
-title=`read_and_escape_file "$intermediate_file" | head -1`
-uuid=`read_and_escape_file "$uuid_file" | head -1`
-body=`read_and_escape_file "$intermediate_file" | sed 1d`
+lastmod=$(get_lastmod_date_from_meta_file "$meta_file")
+lastmod_rfc3339=$(date -u "+%Y-%m-%dT%TZ" -d "@$lastmod")
+title=$(read_and_escape_file "$intermediate_file" | head -1)
+uuid=$(get_uuid_from_meta_file "$meta_file")
+published_unix=$(get_creation_date_from_meta_file_seconds "$meta_file")
+published_rfc3339=$(date -u "+%Y-%m-%dT%TZ" -d "@${published_unix}")
+body=$(read_and_escape_file "$intermediate_file" | sed 1d)
printf "<entry>\n"
printf "<title type=\"html\">%s</title>\n" "$title"
printf "<id>urn:uuid:%s</id>\n" "$uuid"
# Pull in dependencies.
. ../helpers.sh
src_file=$(get_source_file "$1")
-uuid_file="${1%.index_snippet}.uuid"
-redo-ifchange "$uuid_file"
+meta_file="${1%.index_snippet}.automatic_metadata"
+redo-ifchange "$meta_file"
intermediate_file="${1%.index_snippet}.intermediate"
redo-ifchange "$intermediate_file"
html_file="${src_file%.*}.html"
# Build entry data.
title=$(cat "$intermediate_file" | head -1 | prep_sed)
link=$(escape_url "${1%.index_snippet}.html" | prep_sed)
-datetime_created_unix=$(stat -c%y "${uuid_file}")
-date_created=$(date -u "+%Y-%m-%d" -d "${datetime_created_unix}")
+datetime_created_unix=$(get_creation_date_from_meta_file_seconds "$meta_file")
+date_created_human=$(date -u "+%Y-%m-%d" -d "@${datetime_created_unix}")
# Put data into template.
template=$(cat "$template_file")
printf "%s\n" "$template" | \
sed 's/%TITLE%/'"$title"'/g' | \
sed 's/%LINK%/'"$link"'/g' | \
-sed 's/%DATE_CREATED%/'"$date_created"'/g' | \
+sed 's/%DATE_CREATED%/'"$date_created_human"'/g' | \
tr '\a' '%'
#!/bin/sh
+# Pull in dependencies.
template=intermediate.pandoc_tmpl
-uuidfile="${1%.intermediate}.uuid"
-redo-ifchange "$uuidfile"
+meta_file="${1%.intermediate}.automatic_metadata"
+redo-ifchange "$meta_file"
redo-ifchange "$template"
mdfile="../${1%.intermediate}.md"
rstfile="../${1%.intermediate}.rst"
+
+# Build intermediate file.
if [ -f "$rstfile" ]; then
redo-ifchange "$rstfile"
pandoc -f rst --template="$template" --mathml -t html5 "$rstfile" --base-header-level=2 > "$3"
redo-ifchange "$mdfile"
pandoc -f markdown --template="$template" --mathml -t html5 "$mdfile" --base-header-level=2 > "$3"
fi
+
+# Update meta file if appropriate.
+md5_new=$(md5sum "$3" | cut -d ' ' -f 1)
+md5_old=$(cat "$meta_file" | sed -n '3p')
+if [ ! "$md5_new" = "$md5_old" ]; then
+ new_date=$(date -u "+%s")
+ sed -i '1,2!d' "$meta_file"
+ echo "$md5_new" >> "$meta_file"
+ echo "$new_date" >> "$meta_file"
+fi
+++ /dev/null
-#!/bin/sh
-
-if [ ! -f "$1" ]; then
- uuidgen > "$1"
-fi
+++ /dev/null
-#!/bin/sh
-
-if [ ! -f "$1" ]; then
- uuidgen
-fi
#!/bin/sh
-uuid_test()
+uuid_pattern='[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'
+
+blog_meta_file_test()
+{
+ meta_file="$1"
+ printf "== %s meta file pattern match test ==\n" "$meta_file"
+ if cat "$meta_file" | sed -n '1p' | grep -Eq '^'"$uuid_pattern"'$' \
+ && cat "$meta_file" | sed -n '2p' | grep -Eq "^[0-9]+$"; then
+ echo "== test SUCCESS =="
+ else
+ echo "== test FAILURE =="
+ fi
+}
+
+article_meta_file_test()
{
- uuid_file="$1"
- printf "== %s UUID pattern match test ==\n" "$uuid_file"
- if cat "$uuid_file" | grep -Eq "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"; then
+ meta_file="$1"
+ printf "== %s meta file pattern match test ==\n" "$meta_file"
+ if cat "$meta_file" | sed -n '1p' | grep -Eq '^'"$uuid_pattern"'$' \
+ && cat "$meta_file" | sed -n '2p' | grep -Eq "^[0-9]+_[0-9]+$" \
+ && cat "$meta_file" | sed -n '3p' | grep -Eq "^[0-9a-f]{32}$" \
+ && cat "$meta_file" | sed -n '2p' | grep -Eq "^[0-9]+_[0-9]+$"; then
echo "== test SUCCESS =="
else
echo "== test FAILURE =="
fi
}
-# Set up test directory.
+# Set up test directory, run file creations.
expected_files_dir="test/test_files"
generated_files_dir="test/test_dir"
rm -rf "$generated_files_dir"
redo
cp "$working_dir/$expected_files_dir"/foo.rst .
redo
-cd "$working_dir"
+
+# Test file modification tracking.
+update_datetime_start=$(cat "metadata/bar baz.feed_snippet" | grep '<updated>')
+sleep 1
+sed -i '2d' bar\ baz.md
+redo
+update_datetime_after_invisible_change=$(cat "metadata/bar baz.feed_snippet" | grep '<updated>')
+printf "== testing \"bar baz\"' update tag remaining unchanged with invisible source file change ==\n"
+if [ "$update_datetime_start" = "$update_datetime_after_invisible_change" ]; then
+ echo "== test SUCCESS =="
+else
+ echo "== test FAILURE =="
+fi
+sleep 1
+sed -i '2d' bar\ baz.md
+redo
+update_datetime_after_visible_change=$(cat "metadata/bar baz.feed_snippet" | grep '<updated>')
+printf "== testing \"bar baz\"' update tag changing with visible source file change ==\n"
+if [ "$update_datetime_start" = "$update_datetime_after_visible_change" ]; then
+ echo "== test FAILURE =="
+else
+ echo "== test SUCCESS =="
+fi
+cp "$working_dir/$expected_files_dir"/bar\ baz.md .
+redo
# Compare metadata files.
-uuid_test "$generated_files_dir""/metadata/uuid"
+cd "$working_dir"
+blog_meta_file_test "$generated_files_dir""/metadata/automatic_metadata"
for file in "$expected_files_dir"/metadata/*; do
basename=$(basename "$file")
cmp_file="$generated_files_dir/metadata/$basename"
basename=$(basename "$file")
cmp_file="$generated_files_dir/${basename%.ignoring}"
if [ ! "$file" = "$expected_files_dir""/index.html.ignoring" ]; then
- uuid_test "${generated_files_dir}/metadata/${basename%.html.ignoring}.uuid"
+ article_meta_file_test "${generated_files_dir}/metadata/${basename%.html.ignoring}.automatic_metadata"
fi
generated_file="$cmp_file".ignoring
cat "$cmp_file" | \