From 1dcff64bdb49d81d55320da1e84deabb2923c31d Mon Sep 17 00:00:00 2001 From: Landon Curt Noll Date: Mon, 18 Mar 2024 03:08:56 -0700 Subject: [PATCH] improved how bin/gen-status.sh determines modification dates In `bin/gen-status.sh`, the method to determine the modification date, is now consistent with how `bin/gen-sitemap.sh` does it: look for various forms of `stat(1)` or `ls(1)`. Changed `bin/gen-status.sh` VERSION from "1.1 2024-03-10" to "1.1.1 2024-03-18". --- bin/gen-status.sh | 282 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 199 insertions(+), 83 deletions(-) diff --git a/bin/gen-status.sh b/bin/gen-status.sh index c84860751..49092178e 100755 --- a/bin/gen-status.sh +++ b/bin/gen-status.sh @@ -81,7 +81,7 @@ shopt -s globstar # enable ** to match all files and zero or more directories an # set variables referenced in the usage message # -export VERSION="1.1 2024-03-10" +export VERSION="1.1.1 2024-03-18" NAME=$(basename "$0") export NAME export V_FLAG=0 @@ -118,101 +118,81 @@ export EXIT_CODE="0" # unset TOOL_OPTION declare -ag TOOL_OPTION +export MODTIME_METHOD="" -# usage +# output_modtime - file modification time in W3C Datetime format: # -export USAGE="usage: $0 [-h] [-v level] [-V] [-d topdir] [-n] [-N] - [-t tagline] [-T md2html.sh] [-u repo_url] - [p | pending | o | open | j | judging | c | closed] - - -h print help message and exit - -v level set verbosity level (def level: 0) - -V print version string and exit - - -d topdir set topdir (def: $TOPDIR) - NOTE: The '-d topdir' is passed as leading options on tool command lines. - -D docroot/ set the document root path followed by slash (def: $DOCROOT_SLASH) - NOTE: The '-D docroot/' is passed as leading options on tool command lines. - NOTE: 'docroot' must end in a slash - - -n go thru the actions, but do not update any files (def: do the action) - NOTE: -n is passed to tool - -N do not process anything, just parse arguments (def: process something) - - -t tagline string to write about the tool that formed the markdown content (def: $TAGLINE) - NOTE: 'tagline' may be enclosed within, but may NOT contain an internal single-quote, or double-quote. - -T md2html.sh run 'markdown to html tool' to convert markdown into HTML (def: $MD2HTML_SH) - - -u repo_url Base level URL of target git repo (def: $REPO_URL) - NOTE: The '-u repo_url' is passed as leading options on tool command lines. - -w site_url Base URL of the web site (def: $SITE_URL) - NOTE: The '-w site_url' is passed as leading options on tool command lines. - - [p | pending] Set the contest_status to pending - [o | open] Set the contest_status to open - [j | judging] Set the contest_status to judging - [c | closed] Set the contest_status to closed - (def: do not change contest_status) - -NOTE: The '-v level' is passed as initial command line options to the 'markdown to html tool' (md2html.sh). - The 'tagline' is passed as '-t tagline' to the 'markdown to html tool' (md2html.sh), after the '-v level'. - Any '-T md2html.sh', '-p tool', '-P pandoc_opts', '-u repo_url', '-U top_url' - are passed to the 'markdown to html tool' (md2html.sh), and will be before any command line arguments. - -Exit codes: - 0 all OK - 1 some file is not found, not a readable file or is malformed - 2 -h and help string printed or -V and version string printed - 3 command line error - 4 bash version is too old - 5 some internal tool is not found or not an executable file - 6 problems found with or in the topdir or topdir/YYYY directory - >= 10 internal error - -$NAME version: $VERSION" - -# output_mod_date +# https://www.w3.org/TR/NOTE-datetime # -# output file modification date in UTC timezone in %FT%T+00:00 format +# for use in XML format for sitemaps: # -function output_mod_date +# https://www.sitemaps.org/protocol.html +# +# usage: +# output_modtime filename +# +function output_modtime { - local FILENAME; # filename to obtain mod date - local LS_OUTPUT; # output of the ls(1) command + local FILENAME; # filename argument # parse args # if [[ $# -ne 1 ]]; then - echo "$0: ERROR: in output_mod_date expected 1 arg, found $#" 1>&2 - return 1 + echo "$0: ERROR: in output_modtime: expected 1 arg, found $#" 1>&2 + return 1 fi FILENAME="$1" - if [[ ! -e $FILENAME ]]; then - echo "$0: ERROR: in output_mod_date: filename arg does not exist: $FILENAME" 1>&2 - return 3 - fi - if [[ ! -r $FILENAME ]]; then - echo "$0: ERROR: in output_mod_date: filename arg is not a readable: $FILENAME" 1>&2 - return 5 - fi - # obtain ls output + # produce output given the MODTIME_METHOD # - LS_OUTPUT=$(TZ=UTC ls -D '%FT%T+00:00' -ld "$FILENAME" 2>/dev/null) - status="$?" - if [[ $status -ne 0 ]]; then - echo "$0: ERROR: in output_mod_date: TZ=UTC ls -D '%FT%T+00:00' -ld $FILENAME failed, error: $status" 1>&2 - return 6 - fi - if [[ -z $LS_OUTPUT ]]; then - echo "$0: ERROR: in output_mod_date: TZ=UTC ls -D '%FT%T+00:00' -ld $FILENAME output is empty" 1>&2 - return 7 - fi + case "$MODTIME_METHOD" in - # extract the date string and write it to standard output + # macOS stat # - awk '{print $6;}' <<< "$LS_OUTPUT" - return 0; + macos_stat) + TZ=UTC stat -f '%Sm' -t '%FT%T+00:00' "$FILENAME" + status="$?" + if [[ $status -ne 0 ]]; then + echo "$0: ERROR: in output_modtime:" \ + "TZ=UTC stat -f '%Sm' -t '%FT%T+00:00' $FILENAME failed, error code: $status" 1>&2 + exit 1 + fi + ;; + + # RHEL Linux stat + # + RHEL_stat) + TZ=UTC stat -c '%y' "$FILENAME" | sed -e 's/ /T/' -e 's/\.[0-9]* //' -e 's/\([0-9][0-9]\)$/:&/' + status0="${PIPESTATUS[0]}" + status1="${PIPESTATUS[1]}" + if [[ $status0 -ne 0 || $status1 -ne 0 ]]; then + echo "$0: ERROR: in output_modtime:" \ + "TZ=UTC stat -c '%y' $FILENAME | sed .. failed, error codes: $status0 and $status1" 1>&2 + exit 1 + fi + ;; + + ls_D) + # We want to look at the format of ls -D, not find + # + # SC2012 (info): Use find instead of ls to better handle non-alphanumeric filenames. + # https://www.shellcheck.net/wiki/SC2012 + # shellcheck disable=SC2012 + TZ=UTZ ls -D '%FT%T+00:00' -ld "$FILENAME" | awk '{print $6;}' + status0="${PIPESTATUS[0]}" + status1="${PIPESTATUS[1]}" + if [[ $status0 -ne 0 || $status1 -ne 0 ]]; then + echo "$0: ERROR: in output_modtime:" \ + "TZ=UTZ ls -D '%FT%T+00:00' -ld $FILENAME | awk .. failed, error codes: $status0 and $status1" 1>&2 + exit 1 + fi + ;; + + *) echo "0: in output_modtime: unknown MODTIME_METHOD value: $MODTIME_METHOD" 1>&2 + exit 9 + ;; + esac + return 0 } # output_status_json @@ -274,7 +254,7 @@ function output_status_json # obtain news.html file modification date # - NEWS_MOD_DATE=$(output_mod_date "$NEWS_PATH") + NEWS_MOD_DATE=$(output_modtime "$NEWS_PATH") status="$?" if [[ $status -ne 0 ]]; then echo "$0: ERROR: in output_status_json: modification date of $NEWS_PATH failed, error: $status" 1>&2 @@ -287,7 +267,7 @@ function output_status_json # obtain status.json file modification date # - STATUS_MOD_DATE=$(output_mod_date "$STATUS_PATH") + STATUS_MOD_DATE=$(output_modtime "$STATUS_PATH") status="$?" if [[ $status -ne 0 ]]; then echo "$0: ERROR: in output_status_json: modification date of $STATUS_PATH failed, error: $status" 1>&2 @@ -310,6 +290,58 @@ function output_status_json return 0 } +# usage +# +export USAGE="usage: $0 [-h] [-v level] [-V] [-d topdir] [-n] [-N] + [-t tagline] [-T md2html.sh] [-u repo_url] + [p | pending | o | open | j | judging | c | closed] + + -h print help message and exit + -v level set verbosity level (def level: 0) + -V print version string and exit + + -d topdir set topdir (def: $TOPDIR) + NOTE: The '-d topdir' is passed as leading options on tool command lines. + -D docroot/ set the document root path followed by slash (def: $DOCROOT_SLASH) + NOTE: The '-D docroot/' is passed as leading options on tool command lines. + NOTE: 'docroot' must end in a slash + + -n go thru the actions, but do not update any files (def: do the action) + NOTE: -n is passed to tool + -N do not process anything, just parse arguments (def: process something) + + -t tagline string to write about the tool that formed the markdown content (def: $TAGLINE) + NOTE: 'tagline' may be enclosed within, but may NOT contain an internal single-quote, or double-quote. + -T md2html.sh run 'markdown to html tool' to convert markdown into HTML (def: $MD2HTML_SH) + + -u repo_url Base level URL of target git repo (def: $REPO_URL) + NOTE: The '-u repo_url' is passed as leading options on tool command lines. + -w site_url Base URL of the web site (def: $SITE_URL) + NOTE: The '-w site_url' is passed as leading options on tool command lines. + + [p | pending] Set the contest_status to pending + [o | open] Set the contest_status to open + [j | judging] Set the contest_status to judging + [c | closed] Set the contest_status to closed + (def: do not change contest_status) + +NOTE: The '-v level' is passed as initial command line options to the 'markdown to html tool' (md2html.sh). + The 'tagline' is passed as '-t tagline' to the 'markdown to html tool' (md2html.sh), after the '-v level'. + Any '-T md2html.sh', '-p tool', '-P pandoc_opts', '-u repo_url', '-U top_url' + are passed to the 'markdown to html tool' (md2html.sh), and will be before any command line arguments. + +Exit codes: + 0 all OK + 1 some file is not found, not a readable file or is malformed + 2 -h and help string printed or -V and version string printed + 3 command line error + 4 bash version is too old + 5 some internal tool is not found or not an executable file + 6 problems found with or in the topdir or topdir/YYYY directory + >= 10 internal error + +$NAME version: $VERSION" + # parse command line # while getopts :hv:Vd:D:nNt:T:u:w: flag; do @@ -570,6 +602,89 @@ fi # export STATUS_HTML="status.html" +# verify we have a non-empty readable .top file +# +export TOP_FILE=".top" +if [[ ! -e $TOP_FILE ]]; then + echo "$0: ERROR: .top does not exist: $TOP_FILE" 1>&2 + exit 6 +fi +if [[ ! -f $TOP_FILE ]]; then + echo "$0: ERROR: .top is not a regular file: $TOP_FILE" 1>&2 + exit 6 +fi +if [[ ! -r $TOP_FILE ]]; then + echo "$0: ERROR: .top is not an readable file: $TOP_FILE" 1>&2 + exit 6 +fi +if [[ ! -s $TOP_FILE ]]; then + echo "$0: ERROR: .top is not a non-empty readable file: $TOP_FILE" 1>&2 + exit 6 +fi + +# determine how we can determine the file modification time in W3C Datetime format: +# +# https://www.w3.org/TR/NOTE-datetime +# +# for use in XML format for sitemaps: +# +# https://www.sitemaps.org/protocol.html +# +# Unfortunately there is NO single widely available, but simple command produce a modification +# time in W3C Datetime format. At best we can try one of several methods in the hopes that +# we can find a method for the system in question. +# +# We will attempt to find the modification time in W3C Datetime of the .top file. +# +# Try macOS stat: +# +# TZ=UTC stat -f '%Sm' -t '%FT%T+00:00' filename +# +TZ=UTC stat -f '%Sm' -t '%FT%T+00:00' "$TOP_FILE" > /dev/null 2>&1 +status="$?" +if [[ $status -eq 0 ]]; then + MODTIME_METHOD="macos_stat" + if [[ $V_FLAG -ge 5 ]]; then + echo "$0: debug[5]: TZ=UTC stat -f '%Sm' -t '%FT%T+00:00' works, MODTIME_METHOD: $MODTIME_METHOD" 1>&2 + fi + +else + + # Try RHEL Linux stat: + # + # TZ=UTC stat -c '%y' faq.md | sed -e 's/ /T/' -e 's/\.[0-9]* //' -e 's/\([0-9][0-9]\)$/:&/' + # + # NOTE: We only need to test the stat command. + # + TZ=UTC stat -c '%y' "$TOP_FILE" > /dev/null 2>&1 + status="$?" + if [[ $status -eq 0 ]]; then + MODTIME_METHOD="RHEL_stat" + if [[ $V_FLAG -ge 5 ]]; then + echo "$0: debug[5]: TZ=UTC stat -c '%y' works, MODTIME_METHOD: $MODTIME_METHOD" 1>&2 + fi + + else + + # Try ls -D: + # + # TZ=UTZ ls -D '%FT%T+00:00' -ld + # + TZ=UTZ ls -D '%FT%T+00:00' -ld "$TOP_FILE" > /dev/null 2>&1 + status="$?" + if [[ $status -eq 0 ]]; then + MODTIME_METHOD="ls_D" + if [[ $V_FLAG -ge 5 ]]; then + echo "$0: debug[5]: TZ=UTZ ls -D '%FT%T+00:00' -ld works, MODTIME_METHOD: $MODTIME_METHOD" 1>&2 + fi + + else + echo "$0: ERROR: we cannot determine how to form a file modification time in W3C Datetime formt" 1>&2 + exit 9 + fi + fi +fi + # print running info if verbose # # If -v 3 or higher, print exported variables in order that they were exported. @@ -590,6 +705,7 @@ if [[ $V_FLAG -ge 3 ]]; then echo "$0: debug[3]: NOOP=$NOOP" 1>&2 echo "$0: debug[3]: DOCROOT_SLASH=$DOCROOT_SLASH" 1>&2 echo "$0: debug[3]: EXIT_CODE=$EXIT_CODE" 1>&2 + echo "$0: debug[3]: MODTIME_METHOD=$MODTIME_METHOD" 1>&2 echo "$0: debug[3]: REPO_NAME=$REPO_NAME" 1>&2 for index in "${!TOOL_OPTION[@]}"; do echo "$0: debug[3]: TOOL_OPTION[$index]=${TOOL_OPTION[$index]}" 1>&2