From b64bbf81557962c5076f432250f38d6c9c25819d Mon Sep 17 00:00:00 2001 From: Steven Baltakatei Sandoval <baltakatei@gmail.com> Date: Sat, 30 Apr 2022 02:08:45 +0000 Subject: [PATCH] feat(user/bkots):Add script to run ots recursively --- doc/user/bkots..flowchart.odg | Bin 0 -> 24436 bytes unitproc/bktemp-get_parent_dirnames | 36 ++ unitproc/bktemp-processArgs | 59 ++- user/bkots | 658 ++++++++++++++++++++++++++++ 4 files changed, 732 insertions(+), 21 deletions(-) create mode 100644 doc/user/bkots..flowchart.odg create mode 100644 unitproc/bktemp-get_parent_dirnames create mode 100644 user/bkots diff --git a/doc/user/bkots..flowchart.odg b/doc/user/bkots..flowchart.odg new file mode 100644 index 0000000000000000000000000000000000000000..ea0787db2800ec01800885143626877afb9d1697 GIT binary patch literal 24436 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 X{A#F!hyQIi@{8BEDO%L>+t&X8152L7 literal 0 HcmV?d00001 diff --git a/unitproc/bktemp-get_parent_dirnames b/unitproc/bktemp-get_parent_dirnames new file mode 100644 index 0000000..1a5184f --- /dev/null +++ b/unitproc/bktemp-get_parent_dirnames @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +# Desc: Provides newline-delimited list of each parent dir + +yell() { echo "$0: $*" >&2; } # print script path and all args to stderr +die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status +try() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails +get_parent_dirnames() { + # Desc: Provides newline-delimited list of each parent dir of a file or dir + # Usage: get_parent_dirnames arg1 + # Input: arg1 input path + # Output: stdout newline-delimited list of parent dirs + # Version: 0.0.1 + # Depends: yell(), die(), try() + local path + + # Check input + if [[ $# -ne 1 ]]; then die "FATAL:Incorrect number of arguments:$#"; fi; + if ! { [[ -f $1 ]] || [[ -d $1 ]]; }; then die "FATAL:Not a file or dir:$1"; fi; + + # Process path + path="$1"; + while [[ -f $path ]] || [[ -d $path ]]; do + path="$(dirname "$path")"; + name_base_previous="$name_base"; + name_base="$(basename "$path")"; + ## Check for stop condition (dirname returns same result as previous iteration) + if [[ $name_base == "$name_base_previous" ]]; then break; fi; + echo "$name_base"; + done; +}; # Output parent dirnames to stdout + +# Test code +sleep 1 && get_parent_dirnames /home/baltakatei/Downloads/ & # should work +sleep 2 && get_parent_dirnames /home/baltakatei/Downloads/ foo & # should fail +sleep 3 && get_parent_dirnames bar/baz & # should fail +sleep 4; diff --git a/unitproc/bktemp-processArgs b/unitproc/bktemp-processArgs index ca29c35..27679a2 100644 --- a/unitproc/bktemp-processArgs +++ b/unitproc/bktemp-processArgs @@ -4,6 +4,7 @@ #==BEGIN Define script parameters== #===BEGIN Define variables=== : +declare -ag arrayPosArgs #===END Define variables=== #===BEGIN Declare local script functions=== @@ -17,7 +18,7 @@ vbm() { # Input: arg1: string # vars: opVerbose # Output: stderr - # Depends: bash 5.0.3, GNU-coreutils 8.30 (echo, date) + # Depends: bash 5.1.16, GNU-coreutils 8.30 (echo, date) if [ "$opVerbose" = "true" ]; then functionTime="$(date --iso-8601=ns)"; # Save current time in nano seconds. @@ -30,7 +31,7 @@ vbm() { showUsage() { # Desc: Display script usage information # Usage: showUsage - # Version 0.0.1 + # Version 0.0.2 # Input: none # Output: stdout # Depends: GNU-coreutils 8.30 (cat) @@ -50,18 +51,21 @@ showUsage() { -I, --input-dir Define input directory path. -o, --output-file - Define output file path + Define output file path. -O, --output-dir - Define output directory path + Define output directory path. + -- + Indicate end of options. EXAMPLE: bktemp-processArgs -o foo.txt + bktemp-processArgs -o foo.txt -- some_file.txt EOF } # Display information on how to use this script. showVersion() { # Desc: Displays script version and license information. # Usage: showVersion - # Version: 0.0.1 + # Version: 0.0.2 # Input: scriptVersion var containing version string # Output: stdout # Depends: vbm(), yell, GNU-coreutils 8.30 @@ -70,14 +74,14 @@ showVersion() { vbm "DEBUG:showVersion function called." cat <<'EOF' -bktemp-processArgs 0.0.1 +bktemp-processArgs 1.0.0 Copyright (C) 2021 Steven Baltakatei Sandoval License GPLv3: GNU GPL version 3 This is free software; you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. - GNU Coreutils 8.30 - Copyright (C) 2018 Free Software Foundation, Inc. + GNU Coreutils 8.32 + Copyright (C) 2020 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. @@ -90,7 +94,7 @@ EOF processArgs() { # Desc: Processes arguments provided to script. # Usage: processArgs "$@" - # Version: 0.0.1 + # Version: 1.0.0 # Input: "$@" (list of arguments provided to the function) # Output: Sets following variables used by other functions: # opVerbose Indicates verbose mode enable status. (ex: "true", "false") @@ -98,15 +102,18 @@ processArgs() { # pathFileOut1 Path to output file. # pathDirIn1 Path to input directory. # pathFileIn1 Path to input file. - # opFileOut1_overwrite Indicates whether file pathFileOut1 should be overwritten (ex: "true", "false') + # opFileOut1_overwrite Indicates whether file pathFileOut1 should be overwritten (ex: "true", "false"). + # arrayPosArgs Array of remaining positional argments # Depends: # yell() Displays messages to stderr. # vbm() Displays messsages to stderr if opVerbose set to "true". - # showUsage() Displays usage information about parent script - # showVersion() Displays version about parent script - # External dependencies: bash (5.0.3), echo + # showUsage() Displays usage information about parent script. + # showVersion() Displays version about parent script. + # arrayPosArgs Global array for storing non-option positional arguments (i.e. arguments following the `--` option). + # External dependencies: bash (5.1.16), echo # Ref./Attrib.: # [1]: Marco Aurelio (2014-05-08). "echo that outputs to stderr". https://stackoverflow.com/a/23550347 + # [2]: "Handling positional parameters" (2018-05-12). https://wiki.bash-hackers.org/scripting/posparams # Initialize function vbm "DEBUG:processArgs function called." @@ -169,8 +176,16 @@ processArgs() { yell "ERROR:Specified output directory is not valid:""$2"; yell "Exiting."; exit 1; - fi ;; - *) yell "ERROR: Unrecognized argument."; exit 1;; # Handle unrecognized options. See [1]. + fi ;; + --) # End of all options. See [2]. + shift; + for arg in "$@"; do + vbm "DEBUG:adding to arrayPosArgs:$arg"; + arrayPosArgs+=("$arg"); + done; + break;; + -*) showUsage; yell "ERROR: Unrecognized option."; exit 1;; # Display usage + *) showUsage; yell "ERROR: Unrecognized argument."; exit 1;; # Handle unrecognized options. See [1]. esac shift done @@ -186,12 +201,14 @@ processArgs() { #==BEGIN sample code== processArgs "$@"; yell "DEBUG:Provided arguments..:""$*" -yell "DEBUG:opVerbose...........:$opVerbose"; -yell "DEBUG:pathDirOut1.........:$pathDirOut1"; -yell "DEBUG:pathFileOut1........:$pathFileOut1"; -yell "DEBUG:pathDirIn1..........:$pathDirIn1"; -yell "DEBUG:pathFileIn1.........:$pathFileIn1"; -yell "DEBUG:opFileOut1_overwrite:$opFileOut1_overwrite"; +yell "DEBUG:opVerbose...........:${opVerbose:-<unset>}"; +yell "DEBUG:pathDirOut1.........:${pathDirOut1:-<unset>}"; +yell "DEBUG:pathFileOut1........:${pathFileOut1:-<unset>}"; +yell "DEBUG:pathDirIn1..........:${pathDirIn1:-<unset>}"; +yell "DEBUG:pathFileIn1.........:${pathFileIn1:-<unset>}"; +yell "DEBUG:opFileOut1_overwrite:${opFileOut1_overwrite:-<unset>}"; +yell "DEBUG:arrayPosArgs........:$(if [[ -v arrayPosArgs ]]; then declare -p arrayPosArgs; else printf "<unset>"; fi )"; +#yell "DEBUG:arrayPosArgs........:${arrayPosArgs[*]}"; #==END sample code== # Author: Steven Baltaktei Sandoval diff --git a/user/bkots b/user/bkots new file mode 100644 index 0000000..fa9b7da --- /dev/null +++ b/user/bkots @@ -0,0 +1,658 @@ +#!/usr/bin/env bash + +# Define variables +declare -Ag appRollCall # Associative array for storing app status +declare -Ag fileRollCall # Associative array for storing file status +declare -Ag dirRollCall # Associative array for storing dir status +declare -ag arrayPosArgs # Associative array for processArgs() function + +# Declare functions +yell() { echo "$0: $*" >&2; } # print script path and all args to stderr +die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status +try() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails +checkapp() { + # Desc: If arg is a command, save result in assoc array 'appRollCall' + # Usage: checkapp arg1 arg2 arg3 ... + # Version: 0.1.1 + # Input: global assoc. array 'appRollCall' + # Output: adds/updates key(value) to global assoc array 'appRollCall' + # Depends: bash 5.0.3 + local returnState + + #===Process Args=== + for arg in "$@"; do + if command -v "$arg" 1>/dev/null 2>&1; then # Check if arg is a valid command + appRollCall[$arg]="true"; + if ! [ "$returnState" = "false" ]; then returnState="true"; fi; + else + appRollCall[$arg]="false"; returnState="false"; + fi; + done; + + #===Determine function return code=== + if [ "$returnState" = "true" ]; then + return 0; + else + return 1; + fi; +} # Check that app exists +checkfile() { + # Desc: If arg is a file path, save result in assoc array 'fileRollCall' + # Usage: checkfile arg1 arg2 arg3 ... + # Version: 0.1.1 + # Input: global assoc. array 'fileRollCall' + # Output: adds/updates key(value) to global assoc array 'fileRollCall'; + # Output: returns 0 if app found, 1 otherwise + # Depends: bash 5.0.3 + local returnState + + #===Process Args=== + for arg in "$@"; do + if [ -f "$arg" ]; then + fileRollCall["$arg"]="true"; + if ! [ "$returnState" = "false" ]; then returnState="true"; fi; + else + fileRollCall["$arg"]="false"; returnState="false"; + fi; + done; + + #===Determine function return code=== + if [ "$returnState" = "true" ]; then + return 0; + else + return 1; + fi; +} # Check that file exists +checkdir() { + # Desc: If arg is a dir path, save result in assoc array 'dirRollCall' + # Usage: checkdir arg1 arg2 arg3 ... + # Version 0.1.2 + # Input: global assoc. array 'dirRollCall' + # Output: adds/updates key(value) to global assoc array 'dirRollCall'; + # Output: returns 0 if all args are dirs; 1 otherwise + # Depends: Bash 5.0.3 + local returnState + + #===Process Args=== + for arg in "$@"; do + if [ -z "$arg" ]; then + dirRollCall["(Unspecified Dirname(s))"]="false"; returnState="false"; + elif [ -d "$arg" ]; then + dirRollCall["$arg"]="true"; + if ! [ "$returnState" = "false" ]; then returnState="true"; fi + else + dirRollCall["$arg"]="false"; returnState="false"; + fi + done + + #===Determine function return code=== + if [ "$returnState" = "true" ]; then + return 0; + else + return 1; + fi +} # Check that dir exists +displayMissing() { + # Desc: Displays missing apps, files, and dirs + # Usage: displayMissing + # Version 1.0.0 + # Input: associative arrays: appRollCall, fileRollCall, dirRollCall + # Output: stderr: messages indicating missing apps, file, or dirs + # Output: returns exit code 0 if nothing missing; 1 otherwise + # Depends: bash 5, checkAppFileDir() + local missingApps value appMissing missingFiles fileMissing + local missingDirs dirMissing + + #==BEGIN Display errors== + #===BEGIN Display Missing Apps=== + missingApps="Missing apps :"; + #for key in "${!appRollCall[@]}"; do echo "DEBUG:$key => ${appRollCall[$key]}"; done + for key in "${!appRollCall[@]}"; do + value="${appRollCall[$key]}"; + if [ "$value" = "false" ]; then + #echo "DEBUG:Missing apps: $key => $value"; + missingApps="$missingApps""$key "; + appMissing="true"; + fi; + done; + if [ "$appMissing" = "true" ]; then # Only indicate if an app is missing. + echo "$missingApps" 1>&2; + fi; + unset value; + #===END Display Missing Apps=== + + #===BEGIN Display Missing Files=== + missingFiles="Missing files:"; + #for key in "${!fileRollCall[@]}"; do echo "DEBUG:$key => ${fileRollCall[$key]}"; done + for key in "${!fileRollCall[@]}"; do + value="${fileRollCall[$key]}"; + if [ "$value" = "false" ]; then + #echo "DEBUG:Missing files: $key => $value"; + missingFiles="$missingFiles""$key "; + fileMissing="true"; + fi; + done; + if [ "$fileMissing" = "true" ]; then # Only indicate if an app is missing. + echo "$missingFiles" 1>&2; + fi; + unset value; + #===END Display Missing Files=== + + #===BEGIN Display Missing Directories=== + missingDirs="Missing dirs:"; + #for key in "${!dirRollCall[@]}"; do echo "DEBUG:$key => ${dirRollCall[$key]}"; done + for key in "${!dirRollCall[@]}"; do + value="${dirRollCall[$key]}"; + if [ "$value" = "false" ]; then + #echo "DEBUG:Missing dirs: $key => $value"; + missingDirs="$missingDirs""$key "; + dirMissing="true"; + fi; + done; + if [ "$dirMissing" = "true" ]; then # Only indicate if an dir is missing. + echo "$missingDirs" 1>&2; + fi; + unset value; + #===END Display Missing Directories=== + + #==END Display errors== + #==BEGIN Determine function return code=== + if [ "$appMissing" == "true" ] || [ "$fileMissing" == "true" ] || [ "$dirMissing" == "true" ]; then + return 1; + else + return 0; + fi + #==END Determine function return code=== +} # Display missing apps, files, dirs +vbm() { + # Description: Prints verbose message ("vbm") to stderr if opVerbose is set to "true". + # Usage: vbm "DEBUG :verbose message here" + # Version 0.2.0 + # Input: arg1: string + # vars: opVerbose + # Output: stderr + # Depends: bash 5.0.3, GNU-coreutils 8.30 (echo, date) + + if [ "$opVerbose" = "true" ]; then + functionTime="$(date --iso-8601=ns)"; # Save current time in nano seconds. + echo "[$functionTime]:$0:""$*" 1>&2; # Display argument text. + fi + + # End function + return 0; # Function finished. +} # Displays message if opVerbose true +showVersion() { + # Desc: Displays script version and license information. + # Usage: showVersion + # Version: 0.0.1 + # Input: scriptVersion var containing version string + # Output: stdout + # Depends: vbm(), yell, GNU-coreutils 8.30 + + # Initialize function + vbm "DEBUG:showVersion function called." + + cat <<'EOF' +bkots 0.0.1 +Copyright (C) 2022 Steven Baltakatei Sandoval +License GPLv3: GNU GPL version 3 +This is free software; you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. + + GNU Coreutils 8.32 + Copyright (C) 2020 Free Software Foundation, Inc. + License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>. + This is free software: you are free to change and redistribute it. + There is NO WARRANTY, to the extent permitted by law. +EOF + + # End function + vbm "DEBUG:showVersion function ended." + return 0; # Function finished. +} # Display script version. +showUsage() { + # Desc: Display script usage information + # Usage: showUsage + # Version 0.0.1 + # Input: none + # Output: stdout + # Depends: GNU-coreutils 8.30 (cat) + cat <<'EOF' + USAGE: + bkots [ options ] [PATH...] + + POSITIONAL ARGUMENTS: + PATH Path(s) of file(s) or directory(ies) + + OPTIONS: + --dry-run + Do everything except run 'ots' commands. + -h, --help + Display help information. + --include-dotfiles + Include files and directories starting with '.' (not + included by default). + -r, --recursive + Consider files in dirs recursively. + --version + Display script version. + -v, --verbose + Display debugging info. + -- + Mark end of options. Interpret remaining arguments as + positional arguments. + + DESCRIPTION: + Scans files by file paths or directory paths provided by + positional arguments to see if Open Timestamps '.ots' file + exists. If so, attempt to upgrade and verify the '.ots' + file. If no '.ots' file exists, attempt to create one. + + Files with a dotfile parent directory located anywhere in the + file path are ignored by default. (e.g. 'HEAD' in + '/home/user/diary/.git/logs/HEAD' because of '.git'). Dotfiles + themselves are also ignored by default + (e.g. '/home/user/.gitconfig'). + + EXAMPLES: + bkots -v foo.txt + bkots foo.txt bar.pdf /home/username/Pictures/ +EOF +} # Display information on how to use this script. +processArgs() { + # Desc: Processes arguments provided to script. + # Usage: processArgs "$@" + # Version: 1.0.0 + # Input: "$@" (list of arguments provided to the function) + # Output: Sets following variables used by other functions: + # opVerbose Indicates verbose mode enable status. (ex: "true", "false") + # arrayPosArgs Array of remaining positional argments + # Depends: + # yell() Displays messages to stderr. + # vbm() Displays messsages to stderr if opVerbose set to "true". + # showUsage() Displays usage information about parent script. + # showVersion() Displays version about parent script. + # arrayPosArgs Global array for storing non-option positional arguments (i.e. arguments following the `--` option). + # External dependencies: bash (5.1.16), echo + # Ref./Attrib.: + # [1]: Marco Aurelio (2014-05-08). "echo that outputs to stderr". https://stackoverflow.com/a/23550347 + # [2]: "Handling positional parameters" (2018-05-12). https://wiki.bash-hackers.org/scripting/posparams + + # Initialize function + vbm "DEBUG:processArgs function called." + + # Perform work + while [ ! $# -eq 0 ]; do # While number of arguments ($#) is not (!) equal to (-eq) zero (0). + #yell "DEBUG:Starting processArgs while loop." # Debug stderr message. See [1]. + #yell "DEBUG:Provided arguments are:""$*" # Debug stderr message. See [1]. + case "$1" in + --dry-run) # Do not run ots commands + option_dry_run="true"; + vbm "DEBUG:Option enabled:dry run";; + -h | --help) showUsage; exit 1;; # Display usage. + --include-dotfiles) # Include dotfiles + option_include_dotfiles="true"; + vbm "DEBUG:Option enabled:include dotfiles";; + -r | --recursive) # Specify recursive option + option_recursive="true"; + vbm "DEBUG:option enabled:include files in dirs recursively";; + --version) showVersion; exit 1;; # Show version + -v | --verbose) opVerbose="true"; vbm "DEBUG:Verbose mode enabled.";; # Enable verbose mode. See [1]. + --) # End of all options. See [2]. + shift; + for arg in "$@"; do + vbm "DEBUG:adding to arrayPosArgs:$arg"; + arrayPosArgs+=("$arg"); + done; + break;; + -*) showUsage; yell "ERROR: Unrecognized option."; exit 1;; # Display usage + *) # Assume remaining arguments are positional arguments + for arg in "$@"; do + vbm "DEBUG:adding to arrayPosArgs:$arg"; + arrayPosArgs+=("$arg"); + done; + break;; + #*) showUsage; yell "ERROR: Unrecognized argument."; exit 1;; # Handle unrecognized options. See [1]. + esac + shift + done + + # End function + vbm "DEBUG:processArgs function ended." + return 0; # Function finished. +}; # Evaluate script options from positional arguments (ex: $1, $2, $3, etc.). +get_parent_dirnames() { + # Desc: Provides newline-delimited list of each parent dir of a file or dir + # Usage: get_parent_dirnames arg1 + # Input: arg1 input path + # Output: stdout newline-delimited list of parent dirs + # Version: 0.0.1 + # Depends: yell(), die(), try() + local path + + # Check input + if [[ $# -ne 1 ]]; then die "FATAL:Incorrect number of arguments:$#"; fi; + if ! { [[ -f $1 ]] || [[ -d $1 ]]; }; then die "FATAL:Not a file or dir:$1"; fi; + + # Process path + path="$1"; + while [[ -f $path ]] || [[ -d $path ]]; do + path="$(dirname "$path")"; + name_base_previous="$name_base"; + name_base="$(basename "$path")"; + ## Check for stop condition (dirname returns same result as previous iteration) + if [[ $name_base == "$name_base_previous" ]]; then break; fi; + echo "$name_base"; + done; +}; # Output parent dirnames to stdout +main() { + # Desc: Creates `.ots` file: + # - for each file specified in arrayPosArgs array + # - for each file in each dir specified in arrayPosArgs array + # Output file created alongside each file or in output directory specified by pathDirIn1 + # Usage: main "$@"; + # Input: arrayPosArgs array with positional arguments + # pathDirOut1 path for output `.ots` files (if pathDirOut1 is specified and is a path) + # Output: file(s) creates `.ots` file alongside specified files + # Depends: find (GNU findutils) 4.8.0, GNU Coreutils 8.32 (sort) + # Ref/Attrib: [1] How to create an array of unique elements from a string/array in bash https://unix.stackexchange.com/a/167194 + # [2] How to find files containing newlines in their names https://stackoverflow.com/a/21727028 + local -a file_list file_list_pruned; + local -a files_to_verify files_to_upgrade files_to_stamp + local -a files_to_verify_pruned files_to_upgrade_pruned files_to_stamp_pruned + + # Process args + processArgs "$@"; + + # Check dependencies + if ! checkapp ots find; then + displayMissing; + die "FATAL:Missing dependencies."; + fi; + + # Check arguments + ## Mark if output dir option specified + if [[ -v pathDirOut1 ]]; then + vbm "DEBUG:output directory specified:pathDirOut1:$pathDirOut1"; + if [[ -d $pathDirOut1 ]]; then + vbm "DEBUG:pathDirOut1:$pathDirOut1"; + config_output_dir="true"; + else + die "ERROR:Not a dir:$pathDirOut1"; + fi; + fi; + + # Display ots details + vbm "$(type ots)"; # show how 'ots' is defined + #TODO: add option to define 'ots' as a bash function that + #populates the ots option '--bitcoin-node FILE' with a + #user-specified FILE. + + # Populate file_list + vbm "DEBUG:begin populate file_list array"; + for item in "${arrayPosArgs[@]}"; do + vbm "DEBUG:adding to file list:item:$item"; + + ## Get full canonicalized path (follow symlinks) + item="$(readlink -f "$item")"; + vbm "DEBUG:item full path:item:$item"; + + ## Add to list: files + if [[ -f $item ]]; then + vbm "DEBUG:is a file:item:$item"; + file_list+=("$item"); + vbm "DEBUG:added to file_list:$item"; + ## Add to list: files in dirs + elif [[ -d $item ]]; then + vbm "DEBUG:is a dir:item:$item"; + ### Check for recursive flag + if [[ "$option_recursive" == "true" ]]; then + vbm "DEBUG:option_recursive:$option_recursive"; + while read -r line; do + file_list+=("$line"); + vbm "DEBUG:added to file_list:$line"; + done < <(find "$item" -type f); + else + while read -r line; do + file_list+=("$line"); + vbm "DEBUG:added to file_list:$line"; + done < <(find "$item" -maxdepth 1 -type f); + fi; + else + die "ERROR:Not a file or dir:item:$item"; + fi; + done; + if [[ $opVerbose == "true" ]]; then + vbm "DEBUG:file_list:"; + printf "%s\n" "${file_list[@]}"; + fi; + + # Prune file_list + for item in "${file_list[@]}"; do + if ! [[ $option_include_dotfiles == "true" ]]; then + ## Ignore files located beneath a dotfile directory (e.g. '/home/my_repo/.git/config') + unset flag_contains_dotfile_parent; + while read -r line; do + ### Check line from output of get_parent_dirnames + pattern="^\."; + if [[ $line =~ $pattern ]]; then + #### line starts with '.' + vbm "DEBUG:Dotfile parent detected. Not including in file_list_pruned:$item"; + vbm "DEBUG:Dotfile in path:item:$item"; + vbm "DEBUG:Dotfile parent:line:$line"; + flag_contains_dotfile_parent="true"; + break + fi; + done < <(get_parent_dirnames "$item"); + if [[ $flag_contains_dotfile_parent == "true" ]]; then + unset flag_contains_dotfile_parent; + continue; # skip to next item (i.e. don't add to file_list_pruned) + fi; + + ## Ignore dotfiles themselves + item_basename="$(basename "$item")"; + pattern="^\."; + if [[ $item_basename =~ $pattern ]]; then + vbm "INFO :Skipping dotfile:item:$item"; + continue; # skip to next item + fi; + fi; + + ## Ignore files with newlines present in filename. See [2]. + if [[ $item =~ $'\n' ]]; then + yell "INFO :Skipping file name with newline:$item"; + continue; # skip to next item + fi; + + ## Ignore files that end in '~'. + if [[ $item =~ ~$ ]]; then + yell "INFO :Skipping file ending in tilde:$item"; + continue; # skip to next item + fi; + + ## Add item to file_list_pruned + file_list_pruned+=("$item"); + done; + if [[ $opVerbose == "true" ]]; then + vbm "DEBUG:file_list_pruned:"; + printf "%s\n" "${file_list_pruned[@]}"; + fi; + + # Decide what actions to take for items in file_list_pruned + for item in "${file_list_pruned[@]}"; do + vbm "DEBUG:considering action to take for item:$item"; + unset path_src path_prf dir_parent dir_source; + + ## Check file extension + if [[ $item =~ .ots$ ]]; then + ### item ends in '.ots'. Item is proof file. + vbm "DEBUG:item ends in '.ots'. Item is proof file:item:$item"; + if [[ -f ${item%.ots} ]]; then + #### Proof file (item) is adjacent to source file + vbm "DEBUG:Proof file (item) is adjacent to source file."; + ##### Upgrade and verify proof file against adjacent source file + vbm "DEBUG:Marking proof file to be upgraded and verified."; + path_src="${item%.ots}"; + path_prf="$item"; + files_to_upgrade+=("$(printf "%s" "$path_prf")"); + files_to_verify+=("$(printf "%s\n%s" "$path_src" "$path_prf")"); + else + #### Proof file (item) is not adjacent to source file + vbm "DEBUG:Proof file (item) is not adjacent to source file."; + #### Check if source file in parent dir + dir_parent="$(dirname "$(dirname "$item")" )"; + cand_src_filename="$(basename "$item")"; + cand_src_path="$dir_parent/$cand_src_filename"; + if [[ -f "$cand_src_path" ]]; then + ##### source file in parent dir + vbm "DEBUG:found source file in parent:cand_src_path:$cand_src_path"; + path_src="$cand_src_path"; + path_prf="$item"; + files_to_upgrade+=("$(printf "%s" "$path_prf")"); + files_to_verify+=("$(printf "%s\n%s" "$path_src" "$path_prf")"); + else + #### Throw non-fatal error + vbm "DEBUG:Source file not found for proof file:item:$item"; + yell "ERROR:Item is proof file but source filei not adjacent in parent dir. item:$item"; + #### Attempt upgrade only + vbm "DEBUG:Marking proof file to be upgraded."; + path_prf="$item"; + files_to_upgrade+=("$(printf "%s" "$path_prf")"); + fi; + fi; + else + ### item does not end in '.ots'. Item is source file. + vbm "DEBUG:item does NOT end in '.ots'. Item is source file."; + if [[ -f "$item".ots ]]; then + #### Proof file is adjacent to source file (item). + vbm "DEBUG:Proof file is adjacent to source file (item)."; + ##### Upgrade and verify proof file against adjacent source file. + vbm "DEBUG:Marking proof file to be upgraded and verified."; + path_src="$item"; + path_prf="$item.ots"; + files_to_upgrade+=("$(printf "%s" "$path_prf")"); + files_to_verify+=("$(printf "%s\n%s" "$path_src" "$path_prf")"); + else + #### Proof file is not adjacent to source file (item). + #### Check if proof file is in subdir + vbm "DEBUG:checking if proof file for source file (item) is in subdir:item:$item"; + unset flag_proof_in_subdir; + dir_item="$(dirname "$item")"; + cand_prf_filename="$(basename "$item")".ots; + while read -r line; do + line_basename="$(basename "$line")"; + if [[ $line_basename == "$cand_prf_filename" ]]; then + flag_proof_in_subdir="true"; + path_prf="$line"; + vbm "DEBUG:proof found in subdir at:line:$line"; + break; + fi; + done < <(find "$dir_item" -mindepth 2 -maxdepth 2 -type f) + if [[ $flag_proof_in_subdir == "true" ]]; then + ##### Proof file is in subdir + vbm "DEBUG:Proof file detected in subdir relative to source file (item)"; + #path_prf="$path_prf"; # set in while loop + path_src="$item"; + files_to_upgrade+=("$(printf "%s" "$path_prf")"); + files_to_verify+=("$(printf "%s\n%s" "$path_src" "$path_prf")"); + else + ##### Proof file is not in subdir + vbm "DEBUG:Proof file not detected in subdir relative to source file (item)."; + #### Stamp source file + vbm "DEBUG:Marking source file to be stamped."; + path_src="$item"; + files_to_stamp+=("$(printf "%s" "$path_src")") + fi; + unset flag_proof_in_subdir; + fi; + fi; + done; + unset path_src path_prf dir_item dir_parent cand_prf_filename cand_src_filename line_basename cand_src_path + + # Prune action lists. + ## Sort and prune file action arrays + ### files to upgrade + while read -r -d $'\0' line; do + vbm "DEBUG:adding to files_to_upgrade_pruned:line:$line"; + files_to_upgrade_pruned+=("$line"); + done < <(printf "%s\0" "${files_to_upgrade[@]}" | sort -zu | shuf -z); # See [1] + if [[ $opVerbose == "true" ]]; then + vbm "DEBUG:files_to_upgrade_pruned:"; + printf "%s\n" "${files_to_upgrade_pruned[@]}"; + fi; + + ### files to verify + while read -r -d $'\0' line; do + vbm "DEBUG:adding to files_to_verify_pruned:line:$line"; + files_to_verify_pruned+=("$line"); + done < <(printf "%s\0" "${files_to_verify[@]}" | sort -zu | shuf -z); # See [1] + if [[ $opVerbose == "true" ]]; then + vbm "DEBUG:files_to_verify_pruned:"; + printf "%s\n\n" "${files_to_verify_pruned[@]}"; + fi; + + ### files to stamp + while read -r -d $'\0' line; do + vbm "DEBUG:adding to files_to_stamp_pruned:line:$line"; + files_to_stamp_pruned+=("$line"); + done < <(printf "%s\0" "${files_to_stamp[@]}" | sort -zu | shuf -z); # See [1] + if [[ $opVerbose == "true" ]]; then + vbm "DEBUG:files_to_stamp_pruned:"; + printf "%s\n" "${files_to_stamp_pruned[@]}"; + fi; + + # Act on files + ## Upgrade files + for item in "${files_to_upgrade_pruned[@]}"; do + path_prf="$(cut -d $'\n' -f1 < <(echo "$item"))"; + if [[ -z "$path_prf" ]]; then + yell "ERROR:blank upgrade item encountered. Skipping:item:$item"; + continue; + fi; + vbm "DEBUG:Attempting to upgrade proof file:path_prf:$path_prf"; + if [[ ! $option_dry_run == "true" ]]; then + ots upgrade "$path_prf"; + else + yell "DEBUG:DRY RUN:Not running:\"ots upgrade $path_prf\""; + fi; + + done; + + ## Verify files + for item in "${files_to_verify_pruned[@]}"; do + path_src="$(cut -d $'\n' -f1 < <(echo "$item"))"; + path_prf="$(cut -d $'\n' -f2 < <(echo "$item"))"; + if [[ -z "$path_src" ]] || [[ -z "$path_prf" ]]; then + yell "ERROR:blank verify item encountered. Skipping:item:$item"; + continue; + fi; + vbm "DEBUG:Attempting to verify source file:path_src:$path_src"; + vbm "DEBUG: against proof file: path_prf:$path_prf"; + if [[ ! $option_dry_run == "true" ]]; then + ots verify -f "$path_src" "$path_prf"; + else + yell "DEBUG:DRY RUN:Not running:\"ots verify -f $path_src $path_prf\""; + fi; + + done; + + ## Stamp files + for item in "${files_to_stamp_pruned[@]}"; do + path_src="$(cut -d $'\n' -f1 < <(echo "$item"))"; + if [[ -z "$path_src" ]]; then + yell "ERROR:blank stamp item encountered. Skipping:item:$item"; + continue; + fi; + vbm "DEBUG:Attempting to stamp source file:path_src:$path_src"; + if [[ ! $option_dry_run == "true" ]]; then + ots stamp "$item"; + else + yell "DEBUG:DRY RUN:Not running:\"ots stamp $item\""; + fi; + + done; + +}; # main program + +# Run program +main "$@"; -- 2.39.5