home · contact · privacy
Re-write date handling, remove dependency on filesystem lastmod dates.
authorChristian Heller <c.heller@plomlompom.de>
Mon, 2 Jan 2017 21:10:53 +0000 (22:10 +0100)
committerChristian Heller <c.heller@plomlompom.de>
Mon, 2 Jan 2017 21:10:53 +0000 (22:10 +0100)
14 files changed:
README.md
processor/all.do
processor/default.html.do
processor/feed.xml.do
processor/helpers.sh
processor/index.html.do
processor/metadata/automatic_metadata.do [new file with mode: 0644]
processor/metadata/default.automatic_metadata.do [new file with mode: 0644]
processor/metadata/default.feed_snippet.do
processor/metadata/default.index_snippet.do
processor/metadata/default.intermediate.do
processor/metadata/default.uuid.do [deleted file]
processor/metadata/uuid.do [deleted file]
test.sh

index bfb117436f74a0a07058aa7befdf519119ca115a..822c08d594be5e0cc29b3e07acc2a3cdba68a2c4 100644 (file)
--- a/README.md
+++ b/README.md
@@ -29,10 +29,13 @@ You can then enter the directory and run redo there. This will generate article
 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
 ----------------------------------------------
index e448a44fac615a12ae7f94581d6b2965805cc041..3d09097c48be7a4f2b511c404797dc9ccc1c4614 100644 (file)
@@ -15,11 +15,11 @@ for file in "$metadata_dir"/*.intermediate; do
     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
index c9bfbdb9eb160e59d383127c87f5a941b4afe14d..c44d00b40655b9eeaedc24d742baf9ffe9ca6156 100644 (file)
@@ -3,8 +3,8 @@
 # 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
@@ -19,9 +19,9 @@ title_plaintext=`echo "$title_html" | html2text`
 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")
index 513d538e08f416717b1a8b1c83bd94f52896f270..eed86ed353a327063311d59b7eb5aebe01e09910 100644 (file)
@@ -4,23 +4,23 @@
 . ./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
@@ -37,16 +37,16 @@ printf "<id>urn:uuid:%s</id>\n" "$uuid"
 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
index 2869a29a3d414db7066c71e17ff1439b0b7c6c92..64d1123ce89e73ad080cd7a9b614d33266325178 100644 (file)
@@ -6,10 +6,32 @@ escape_html() {
 }
 
 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"
index 5149cace9c3aeb31e00388e726c001c1182d3fb8..031029404ade82260ccb369b63f345d9961cb82f 100644 (file)
@@ -17,13 +17,12 @@ tmp_snippets_dir=.tmp_index_snippets
 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
 
diff --git a/processor/metadata/automatic_metadata.do b/processor/metadata/automatic_metadata.do
new file mode 100644 (file)
index 0000000..44285d2
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+if [ ! -f "$1" ]; then
+  uuidgen
+  date -u "+%s"
+fi
diff --git a/processor/metadata/default.automatic_metadata.do b/processor/metadata/default.automatic_metadata.do
new file mode 100644 (file)
index 0000000..85f0604
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+if [ ! -f "$1" ]; then
+  uuidgen
+  date -u "+%s_%N"
+  echo 00000000000000000000000000000000
+  echo 0
+fi
index 3321ac4071f684123499a6fcc3174fec2a87439f..8dca59b68f3bc67bc816dc5ad858b020af87e9a9 100644 (file)
@@ -3,20 +3,20 @@
 # 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"
index a1ff6f966cb6bc6c155be184058e140909439ab1..9df84fb1226ee81d48dc40384377fd3194d3178a 100644 (file)
@@ -3,8 +3,8 @@
 # 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"
@@ -15,13 +15,13 @@ redo-ifchange "$template_file"
 # 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' '%'
index a09d4b2e5022c884a2fe61832d205940582501fa..bf87309575ba431c31d95327d762bbe831b89671 100644 (file)
@@ -1,11 +1,14 @@
 #!/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"
@@ -13,3 +16,13 @@ elif [ -f "$mdfile" ]; then
   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
diff --git a/processor/metadata/default.uuid.do b/processor/metadata/default.uuid.do
deleted file mode 100644 (file)
index 5efffc8..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-
-if [ ! -f "$1" ]; then
-  uuidgen > "$1"
-fi
diff --git a/processor/metadata/uuid.do b/processor/metadata/uuid.do
deleted file mode 100644 (file)
index ba9e919..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-
-if [ ! -f "$1" ]; then
-  uuidgen
-fi
diff --git a/test.sh b/test.sh
index 025ebc4d5a7a0d7f8922ea7c234181eaaae30f53..60ce2bd1f5cee8178a8bf4b52888009fe7f0d864 100755 (executable)
--- a/test.sh
+++ b/test.sh
@@ -1,10 +1,27 @@
 #!/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 =="
@@ -24,7 +41,7 @@ diff_test()
   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" 
@@ -38,10 +55,35 @@ cp "$working_dir/$expected_files_dir"/bar\ baz.md .
 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"
@@ -53,7 +95,7 @@ for file in "$expected_files_dir"/*.html.ignoring; do
   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" | \