7600aea1707a6dc58e80f29b753a576120254a91
[BK-2020-03.git] / user / bkots
1 #!/usr/bin/env bash
2
3 # Define variables
4 declare -Ag appRollCall # Associative array for storing app status
5 declare -Ag fileRollCall # Associative array for storing file status
6 declare -Ag dirRollCall # Associative array for storing dir status
7 declare -ag arrayPosArgs # Associative array for processArgs() function
8 declare -g ots_delay; ots_delay=1 # minimum time in seconds between ots operations
9 declare -ag calendars;
10 calendars+=("https://finney.calendar.eternitywall.com");
11 calendars+=("https://btc.calendar.catallaxy.com");
12 calendars+=("https://alice.btc.calendar.opentimestamps.org");
13 calendars+=("https://bob.btc.calendar.opentimestamps.org");
14
15 # Declare functions
16 yell() { echo "$0: $*" >&2; } # print script path and all args to stderr
17 die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status
18 try() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails
19 checkapp() {
20 # Desc: If arg is a command, save result in assoc array 'appRollCall'
21 # Usage: checkapp arg1 arg2 arg3 ...
22 # Version: 0.1.1
23 # Input: global assoc. array 'appRollCall'
24 # Output: adds/updates key(value) to global assoc array 'appRollCall'
25 # Depends: bash 5.0.3
26 local returnState
27
28 #===Process Args===
29 for arg in "$@"; do
30 if command -v "$arg" 1>/dev/null 2>&1; then # Check if arg is a valid command
31 appRollCall[$arg]="true";
32 if ! [ "$returnState" = "false" ]; then returnState="true"; fi;
33 else
34 appRollCall[$arg]="false"; returnState="false";
35 fi;
36 done;
37
38 #===Determine function return code===
39 if [ "$returnState" = "true" ]; then
40 return 0;
41 else
42 return 1;
43 fi;
44 } # Check that app exists
45 checkfile() {
46 # Desc: If arg is a file path, save result in assoc array 'fileRollCall'
47 # Usage: checkfile arg1 arg2 arg3 ...
48 # Version: 0.1.1
49 # Input: global assoc. array 'fileRollCall'
50 # Output: adds/updates key(value) to global assoc array 'fileRollCall';
51 # Output: returns 0 if app found, 1 otherwise
52 # Depends: bash 5.0.3
53 local returnState
54
55 #===Process Args===
56 for arg in "$@"; do
57 if [ -f "$arg" ]; then
58 fileRollCall["$arg"]="true";
59 if ! [ "$returnState" = "false" ]; then returnState="true"; fi;
60 else
61 fileRollCall["$arg"]="false"; returnState="false";
62 fi;
63 done;
64
65 #===Determine function return code===
66 if [ "$returnState" = "true" ]; then
67 return 0;
68 else
69 return 1;
70 fi;
71 } # Check that file exists
72 checkdir() {
73 # Desc: If arg is a dir path, save result in assoc array 'dirRollCall'
74 # Usage: checkdir arg1 arg2 arg3 ...
75 # Version 0.1.2
76 # Input: global assoc. array 'dirRollCall'
77 # Output: adds/updates key(value) to global assoc array 'dirRollCall';
78 # Output: returns 0 if all args are dirs; 1 otherwise
79 # Depends: Bash 5.0.3
80 local returnState
81
82 #===Process Args===
83 for arg in "$@"; do
84 if [ -z "$arg" ]; then
85 dirRollCall["(Unspecified Dirname(s))"]="false"; returnState="false";
86 elif [ -d "$arg" ]; then
87 dirRollCall["$arg"]="true";
88 if ! [ "$returnState" = "false" ]; then returnState="true"; fi
89 else
90 dirRollCall["$arg"]="false"; returnState="false";
91 fi
92 done
93
94 #===Determine function return code===
95 if [ "$returnState" = "true" ]; then
96 return 0;
97 else
98 return 1;
99 fi
100 } # Check that dir exists
101 displayMissing() {
102 # Desc: Displays missing apps, files, and dirs
103 # Usage: displayMissing
104 # Version 1.0.0
105 # Input: associative arrays: appRollCall, fileRollCall, dirRollCall
106 # Output: stderr: messages indicating missing apps, file, or dirs
107 # Output: returns exit code 0 if nothing missing; 1 otherwise
108 # Depends: bash 5, checkAppFileDir()
109 local missingApps value appMissing missingFiles fileMissing
110 local missingDirs dirMissing
111
112 #==BEGIN Display errors==
113 #===BEGIN Display Missing Apps===
114 missingApps="Missing apps :";
115 #for key in "${!appRollCall[@]}"; do echo "DEBUG:$key => ${appRollCall[$key]}"; done
116 for key in "${!appRollCall[@]}"; do
117 value="${appRollCall[$key]}";
118 if [ "$value" = "false" ]; then
119 #echo "DEBUG:Missing apps: $key => $value";
120 missingApps="$missingApps""$key ";
121 appMissing="true";
122 fi;
123 done;
124 if [ "$appMissing" = "true" ]; then # Only indicate if an app is missing.
125 echo "$missingApps" 1>&2;
126 fi;
127 unset value;
128 #===END Display Missing Apps===
129
130 #===BEGIN Display Missing Files===
131 missingFiles="Missing files:";
132 #for key in "${!fileRollCall[@]}"; do echo "DEBUG:$key => ${fileRollCall[$key]}"; done
133 for key in "${!fileRollCall[@]}"; do
134 value="${fileRollCall[$key]}";
135 if [ "$value" = "false" ]; then
136 #echo "DEBUG:Missing files: $key => $value";
137 missingFiles="$missingFiles""$key ";
138 fileMissing="true";
139 fi;
140 done;
141 if [ "$fileMissing" = "true" ]; then # Only indicate if an app is missing.
142 echo "$missingFiles" 1>&2;
143 fi;
144 unset value;
145 #===END Display Missing Files===
146
147 #===BEGIN Display Missing Directories===
148 missingDirs="Missing dirs:";
149 #for key in "${!dirRollCall[@]}"; do echo "DEBUG:$key => ${dirRollCall[$key]}"; done
150 for key in "${!dirRollCall[@]}"; do
151 value="${dirRollCall[$key]}";
152 if [ "$value" = "false" ]; then
153 #echo "DEBUG:Missing dirs: $key => $value";
154 missingDirs="$missingDirs""$key ";
155 dirMissing="true";
156 fi;
157 done;
158 if [ "$dirMissing" = "true" ]; then # Only indicate if an dir is missing.
159 echo "$missingDirs" 1>&2;
160 fi;
161 unset value;
162 #===END Display Missing Directories===
163
164 #==END Display errors==
165 #==BEGIN Determine function return code===
166 if [ "$appMissing" == "true" ] || [ "$fileMissing" == "true" ] || [ "$dirMissing" == "true" ]; then
167 return 1;
168 else
169 return 0;
170 fi
171 #==END Determine function return code===
172 } # Display missing apps, files, dirs
173 vbm() {
174 # Description: Prints verbose message ("vbm") to stderr if opVerbose is set to "true".
175 # Usage: vbm "DEBUG :verbose message here"
176 # Version 0.2.0
177 # Input: arg1: string
178 # vars: opVerbose
179 # Output: stderr
180 # Depends: bash 5.0.3, GNU-coreutils 8.30 (echo, date)
181
182 if [ "$opVerbose" = "true" ]; then
183 functionTime="$(date --iso-8601=ns)"; # Save current time in nano seconds.
184 echo "[$functionTime]:$0:""$*" 1>&2; # Display argument text.
185 fi
186
187 # End function
188 return 0; # Function finished.
189 } # Displays message if opVerbose true
190 showVersion() {
191 # Desc: Displays script version and license information.
192 # Usage: showVersion
193 # Version: 0.0.1
194 # Input: scriptVersion var containing version string
195 # Output: stdout
196 # Depends: vbm(), yell, GNU-coreutils 8.30
197
198 # Initialize function
199 vbm "DEBUG:showVersion function called."
200
201 cat <<'EOF'
202 bkots 0.0.4
203 Copyright (C) 2022 Steven Baltakatei Sandoval
204 License GPLv3: GNU GPL version 3
205 This is free software; you are free to change and redistribute it.
206 There is NO WARRANTY, to the extent permitted by law.
207
208 GNU Coreutils 8.32
209 Copyright (C) 2020 Free Software Foundation, Inc.
210 License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
211 This is free software: you are free to change and redistribute it.
212 There is NO WARRANTY, to the extent permitted by law.
213 EOF
214
215 # End function
216 vbm "DEBUG:showVersion function ended."
217 return 0; # Function finished.
218 } # Display script version.
219 showUsage() {
220 # Desc: Display script usage information
221 # Usage: showUsage
222 # Version 0.0.1
223 # Input: none
224 # Output: stdout
225 # Depends: GNU-coreutils 8.30 (cat)
226 cat <<'EOF'
227 USAGE:
228 bkots [ options ] [PATH...]
229
230 POSITIONAL ARGUMENTS:
231 PATH Path(s) of file(s) or directory(ies)
232
233 OPTIONS:
234 --dry-run
235 Do everything except run 'ots' commands.
236 -h, --help
237 Display help information.
238 --include-dotfiles
239 Include files and directories starting with '.' (not
240 included by default).
241 -r, --recursive
242 Consider files in dirs recursively.
243 --version
244 Display script version.
245 -v, --verbose
246 Display debugging info.
247 --
248 Mark end of options. Interpret remaining arguments as
249 positional arguments.
250
251 DESCRIPTION:
252 Scans files by file paths or directory paths provided by
253 positional arguments to see if Open Timestamps '.ots' file
254 exists. If so, attempt to upgrade and verify the '.ots'
255 file. If no '.ots' file exists, attempt to create one.
256
257 Files with a dotfile parent directory located anywhere in the
258 file path are ignored by default. (e.g. 'HEAD' in
259 '/home/user/diary/.git/logs/HEAD' because of '.git'). Dotfiles
260 themselves are also ignored by default
261 (e.g. '/home/user/.gitconfig').
262
263 EXAMPLES:
264 bkots -v foo.txt
265 bkots foo.txt bar.pdf /home/username/Pictures/
266 EOF
267 } # Display information on how to use this script.
268 processArgs() {
269 # Desc: Processes arguments provided to script.
270 # Usage: processArgs "$@"
271 # Version: 1.0.0
272 # Input: "$@" (list of arguments provided to the function)
273 # Output: Sets following variables used by other functions:
274 # opVerbose Indicates verbose mode enable status. (ex: "true", "false")
275 # arrayPosArgs Array of remaining positional argments
276 # Depends:
277 # yell() Displays messages to stderr.
278 # vbm() Displays messsages to stderr if opVerbose set to "true".
279 # showUsage() Displays usage information about parent script.
280 # showVersion() Displays version about parent script.
281 # arrayPosArgs Global array for storing non-option positional arguments (i.e. arguments following the `--` option).
282 # External dependencies: bash (5.1.16), echo
283 # Ref./Attrib.:
284 # [1]: Marco Aurelio (2014-05-08). "echo that outputs to stderr". https://stackoverflow.com/a/23550347
285 # [2]: "Handling positional parameters" (2018-05-12). https://wiki.bash-hackers.org/scripting/posparams
286
287 # Initialize function
288 vbm "DEBUG:processArgs function called."
289
290 # Perform work
291 while [ ! $# -eq 0 ]; do # While number of arguments ($#) is not (!) equal to (-eq) zero (0).
292 #yell "DEBUG:Starting processArgs while loop." # Debug stderr message. See [1].
293 #yell "DEBUG:Provided arguments are:""$*" # Debug stderr message. See [1].
294 case "$1" in
295 --dry-run) # Do not run ots commands
296 option_dry_run="true";
297 vbm "DEBUG:Option enabled:dry run";;
298 -h | --help) showUsage; exit 1;; # Display usage.
299 --include-dotfiles) # Include dotfiles
300 option_include_dotfiles="true";
301 vbm "DEBUG:Option enabled:include dotfiles";;
302 -r | --recursive) # Specify recursive option
303 option_recursive="true";
304 vbm "DEBUG:option enabled:include files in dirs recursively";;
305 --version) showVersion; exit 1;; # Show version
306 -v | --verbose) opVerbose="true"; vbm "DEBUG:Verbose mode enabled.";; # Enable verbose mode. See [1].
307 --) # End of all options. See [2].
308 shift;
309 for arg in "$@"; do
310 vbm "DEBUG:adding to arrayPosArgs:$arg";
311 arrayPosArgs+=("$arg");
312 done;
313 break;;
314 -*) showUsage; yell "ERROR: Unrecognized option."; exit 1;; # Display usage
315 *) # Assume remaining arguments are positional arguments
316 for arg in "$@"; do
317 vbm "DEBUG:adding to arrayPosArgs:$arg";
318 arrayPosArgs+=("$arg");
319 done;
320 break;;
321 #*) showUsage; yell "ERROR: Unrecognized argument."; exit 1;; # Handle unrecognized options. See [1].
322 esac
323 shift
324 done
325
326 # End function
327 vbm "DEBUG:processArgs function ended."
328 return 0; # Function finished.
329 }; # Evaluate script options from positional arguments (ex: $1, $2, $3, etc.).
330 get_parent_dirnames() {
331 # Desc: Provides newline-delimited list of each parent dir of a file or dir
332 # Usage: get_parent_dirnames arg1
333 # Input: arg1 input path
334 # Output: stdout newline-delimited list of parent dirs
335 # Version: 0.0.1
336 # Depends: yell(), die(), try()
337 local path
338
339 # Check input
340 if [[ $# -ne 1 ]]; then die "FATAL:Incorrect number of arguments:$#"; fi;
341 if ! { [[ -f $1 ]] || [[ -d $1 ]]; }; then die "FATAL:Not a file or dir:$1"; fi;
342
343 # Process path
344 path="$1";
345 while [[ -f $path ]] || [[ -d $path ]]; do
346 path="$(dirname "$path")";
347 name_base_previous="$name_base";
348 name_base="$(basename "$path")";
349 ## Check for stop condition (dirname returns same result as previous iteration)
350 if [[ $name_base == "$name_base_previous" ]]; then break; fi;
351 echo "$name_base";
352 done;
353 }; # Output parent dirnames to stdout
354 main() {
355 # Desc: Creates `.ots` file:
356 # - for each file specified in arrayPosArgs array
357 # - for each file in each dir specified in arrayPosArgs array
358 # Output file created alongside each file or in output directory specified by pathDirIn1
359 # Usage: main "$@";
360 # Input: arrayPosArgs array with positional arguments
361 # pathDirOut1 path for output `.ots` files (if pathDirOut1 is specified and is a path)
362 # Output: file(s) creates `.ots` file alongside specified files
363 # Depends: find (GNU findutils) 4.8.0, GNU Coreutils 8.32 (sort)
364 # Ref/Attrib: [1] How to create an array of unique elements from a string/array in bash https://unix.stackexchange.com/a/167194
365 # [2] How to find files containing newlines in their names https://stackoverflow.com/a/21727028
366 local -a file_list file_list_pruned;
367 local -a files_to_verify files_to_upgrade files_to_stamp
368 local -a files_to_verify_pruned files_to_upgrade_pruned files_to_stamp_pruned
369
370 # Process args
371 processArgs "$@";
372
373 # Check dependencies
374 if ! checkapp ots find; then
375 displayMissing;
376 die "FATAL:Missing dependencies.";
377 fi;
378
379 # Check arguments
380 ## Mark if output dir option specified
381 if [[ -v pathDirOut1 ]]; then
382 vbm "DEBUG:output directory specified:pathDirOut1:$pathDirOut1";
383 if [[ -d $pathDirOut1 ]]; then
384 vbm "DEBUG:pathDirOut1:$pathDirOut1";
385 config_output_dir="true";
386 else
387 die "ERROR:Not a dir:$pathDirOut1";
388 fi;
389 fi;
390
391 # Display ots details
392 vbm "$(type ots)"; # show how 'ots' is defined
393 #TODO: add option to define 'ots' as a bash function that
394 #populates the ots option '--bitcoin-node FILE' with a
395 #user-specified FILE.
396
397 # Populate file_list
398 vbm "DEBUG:begin populate file_list array";
399 for item in "${arrayPosArgs[@]}"; do
400 vbm "DEBUG:adding to file list:item:$item";
401
402 ## Get full canonicalized path (follow symlinks)
403 item="$(readlink -f "$item")";
404 vbm "DEBUG:item full path:item:$item";
405
406 ## Add to list: files
407 if [[ -f $item ]]; then
408 vbm "DEBUG:is a file:item:$item";
409 file_list+=("$item");
410 vbm "DEBUG:added to file_list:$item";
411 ## Add to list: files in dirs
412 elif [[ -d $item ]]; then
413 vbm "DEBUG:is a dir:item:$item";
414 ### Check for recursive flag
415 if [[ "$option_recursive" == "true" ]]; then
416 vbm "DEBUG:option_recursive:$option_recursive";
417 while read -r line; do
418 file_list+=("$line");
419 vbm "DEBUG:added to file_list:$line";
420 done < <(find "$item" -type f);
421 else
422 while read -r line; do
423 file_list+=("$line");
424 vbm "DEBUG:added to file_list:$line";
425 done < <(find "$item" -maxdepth 1 -type f);
426 fi;
427 else
428 die "ERROR:Not a file or dir:item:$item";
429 fi;
430 done;
431 if [[ $opVerbose == "true" ]]; then
432 vbm "DEBUG:file_list:";
433 printf "%s\n" "${file_list[@]}";
434 fi;
435
436 # Prune file_list
437 for item in "${file_list[@]}"; do
438 if ! [[ $option_include_dotfiles == "true" ]]; then
439 ## Ignore files located beneath a dotfile directory (e.g. '/home/my_repo/.git/config')
440 unset flag_contains_dotfile_parent;
441 while read -r line; do
442 ### Check line from output of get_parent_dirnames
443 pattern="^\.";
444 if [[ $line =~ $pattern ]]; then
445 #### line starts with '.'
446 vbm "DEBUG:Dotfile parent detected. Not including in file_list_pruned:$item";
447 vbm "DEBUG:Dotfile in path:item:$item";
448 vbm "DEBUG:Dotfile parent:line:$line";
449 flag_contains_dotfile_parent="true";
450 break
451 fi;
452 done < <(get_parent_dirnames "$item");
453 if [[ $flag_contains_dotfile_parent == "true" ]]; then
454 unset flag_contains_dotfile_parent;
455 continue; # skip to next item (i.e. don't add to file_list_pruned)
456 fi;
457
458 ## Ignore dotfiles themselves
459 item_basename="$(basename "$item")";
460 pattern="^\.";
461 if [[ $item_basename =~ $pattern ]]; then
462 vbm "INFO :Skipping dotfile:item:$item";
463 continue; # skip to next item
464 fi;
465 fi;
466
467 ## Ignore files with newlines present in filename. See [2].
468 if [[ $item =~ $'\n' ]]; then
469 yell "INFO :Skipping file name with newline:$item";
470 continue; # skip to next item
471 fi;
472
473 ## Ignore files that end in '~'.
474 if [[ $item =~ ~$ ]]; then
475 yell "INFO :Skipping file ending in tilde:$item";
476 continue; # skip to next item
477 fi;
478
479 ## Add item to file_list_pruned
480 file_list_pruned+=("$item");
481 done;
482 if [[ $opVerbose == "true" ]]; then
483 vbm "DEBUG:file_list_pruned:";
484 printf "%s\n" "${file_list_pruned[@]}";
485 fi;
486
487 # Decide what actions to take for items in file_list_pruned
488 for item in "${file_list_pruned[@]}"; do
489 vbm "DEBUG:considering action to take for item:$item";
490 unset path_src path_prf dir_parent dir_source;
491
492 ## Check file extension
493 if [[ $item =~ .ots$ ]]; then
494 ### item ends in '.ots'. Item is proof file.
495 vbm "DEBUG:item ends in '.ots'. Item is proof file:item:$item";
496 if [[ -f ${item%.ots} ]]; then
497 #### Proof file (item) is adjacent to source file
498 vbm "DEBUG:Proof file (item) is adjacent to source file.";
499 ##### Upgrade and verify proof file against adjacent source file
500 vbm "DEBUG:Marking proof file to be upgraded and verified.";
501 path_src="${item%.ots}";
502 path_prf="$item";
503 files_to_upgrade+=("$(printf "%s" "$path_prf")");
504 files_to_verify+=("$(printf "%s\n%s" "$path_src" "$path_prf")");
505 else
506 #### Proof file (item) is not adjacent to source file
507 vbm "DEBUG:Proof file (item) is not adjacent to source file.";
508 #### Check if source file in parent dir
509 dir_parent="$(dirname "$(dirname "$item")" )";
510 cand_src_filename="$(basename "$item")";
511 cand_src_path="$dir_parent/$cand_src_filename";
512 if [[ -f "$cand_src_path" ]]; then
513 ##### source file in parent dir
514 vbm "DEBUG:found source file in parent:cand_src_path:$cand_src_path";
515 path_src="$cand_src_path";
516 path_prf="$item";
517 files_to_upgrade+=("$(printf "%s" "$path_prf")");
518 files_to_verify+=("$(printf "%s\n%s" "$path_src" "$path_prf")");
519 else
520 #### Throw non-fatal error
521 vbm "DEBUG:Source file not found for proof file:item:$item";
522 yell "ERROR:Item is proof file but source filei not adjacent in parent dir. item:$item";
523 #### Attempt upgrade only
524 vbm "DEBUG:Marking proof file to be upgraded.";
525 path_prf="$item";
526 files_to_upgrade+=("$(printf "%s" "$path_prf")");
527 fi;
528 fi;
529 else
530 ### item does not end in '.ots'. Item is source file.
531 vbm "DEBUG:item does NOT end in '.ots'. Item is source file.";
532 if [[ -f "$item".ots ]]; then
533 #### Proof file is adjacent to source file (item).
534 vbm "DEBUG:Proof file is adjacent to source file (item).";
535 ##### Upgrade and verify proof file against adjacent source file.
536 vbm "DEBUG:Marking proof file to be upgraded and verified.";
537 path_src="$item";
538 path_prf="$item.ots";
539 files_to_upgrade+=("$(printf "%s" "$path_prf")");
540 files_to_verify+=("$(printf "%s\n%s" "$path_src" "$path_prf")");
541 else
542 #### Proof file is not adjacent to source file (item).
543 #### Check if proof file is in subdir
544 vbm "DEBUG:checking if proof file for source file (item) is in subdir:item:$item";
545 unset flag_proof_in_subdir;
546 dir_item="$(dirname "$item")";
547 cand_prf_filename="$(basename "$item")".ots;
548 while read -r line; do
549 line_basename="$(basename "$line")";
550 if [[ $line_basename == "$cand_prf_filename" ]]; then
551 flag_proof_in_subdir="true";
552 path_prf="$line";
553 vbm "DEBUG:proof found in subdir at:line:$line";
554 break;
555 fi;
556 done < <(find "$dir_item" -mindepth 2 -maxdepth 2 -type f)
557 if [[ $flag_proof_in_subdir == "true" ]]; then
558 ##### Proof file is in subdir
559 vbm "DEBUG:Proof file detected in subdir relative to source file (item)";
560 #path_prf="$path_prf"; # set in while loop
561 path_src="$item";
562 files_to_upgrade+=("$(printf "%s" "$path_prf")");
563 files_to_verify+=("$(printf "%s\n%s" "$path_src" "$path_prf")");
564 else
565 ##### Proof file is not in subdir
566 vbm "DEBUG:Proof file not detected in subdir relative to source file (item).";
567 #### Stamp source file
568 vbm "DEBUG:Marking source file to be stamped.";
569 path_src="$item";
570 files_to_stamp+=("$(printf "%s" "$path_src")")
571 fi;
572 unset flag_proof_in_subdir;
573 fi;
574 fi;
575 done;
576 unset path_src path_prf dir_item dir_parent cand_prf_filename cand_src_filename line_basename cand_src_path
577
578 # Prune action lists.
579 ## Sort and prune file action arrays
580 ### files to upgrade
581 while read -r -d $'\0' line; do
582 vbm "DEBUG:adding to files_to_upgrade_pruned:line:$line";
583 files_to_upgrade_pruned+=("$line");
584 done < <(printf "%s\0" "${files_to_upgrade[@]}" | sort -zu | shuf -z); # See [1]
585 if [[ $opVerbose == "true" ]]; then
586 vbm "DEBUG:files_to_upgrade_pruned:";
587 printf "%s\n" "${files_to_upgrade_pruned[@]}";
588 fi;
589
590 ### files to verify
591 while read -r -d $'\0' line; do
592 vbm "DEBUG:adding to files_to_verify_pruned:line:$line";
593 files_to_verify_pruned+=("$line");
594 done < <(printf "%s\0" "${files_to_verify[@]}" | sort -zu | shuf -z); # See [1]
595 if [[ $opVerbose == "true" ]]; then
596 vbm "DEBUG:files_to_verify_pruned:";
597 printf "%s\n\n" "${files_to_verify_pruned[@]}";
598 fi;
599
600 ### files to stamp
601 while read -r -d $'\0' line; do
602 vbm "DEBUG:adding to files_to_stamp_pruned:line:$line";
603 files_to_stamp_pruned+=("$line");
604 done < <(printf "%s\0" "${files_to_stamp[@]}" | sort -zu | shuf -z); # See [1]
605 if [[ $opVerbose == "true" ]]; then
606 vbm "DEBUG:files_to_stamp_pruned:";
607 printf "%s\n" "${files_to_stamp_pruned[@]}";
608 fi;
609
610 # Act on files
611 ## Upgrade files
612 for item in "${files_to_upgrade_pruned[@]}"; do
613 path_prf="$(cut -d $'\n' -f1 < <(echo "$item"))";
614 if [[ -z "$path_prf" ]]; then
615 yell "ERROR:blank upgrade item encountered. Skipping:item:$item";
616 continue;
617 fi;
618 vbm "DEBUG:Attempting to upgrade proof file:path_prf:$path_prf";
619 if [[ ! $option_dry_run == "true" ]]; then
620 #ots upgrade "$path_prf";
621 for url in "${calendars[@]}"; do
622 ots -l "$url" --no-default-whitelist upgrade "$path_prf";
623 done;
624 else
625 yell "DEBUG:DRY RUN:Not running:\"ots upgrade $path_prf\"";
626 fi;
627 sleep "$ots_delay";
628 done;
629
630 ## Verify files
631 for item in "${files_to_verify_pruned[@]}"; do
632 path_src="$(cut -d $'\n' -f1 < <(echo "$item"))";
633 path_prf="$(cut -d $'\n' -f2 < <(echo "$item"))";
634 if [[ -z "$path_src" ]] || [[ -z "$path_prf" ]]; then
635 yell "ERROR:blank verify item encountered. Skipping:item:$item";
636 continue;
637 fi;
638 vbm "DEBUG:Attempting to verify source file:path_src:$path_src";
639 vbm "DEBUG: against proof file: path_prf:$path_prf";
640 if [[ ! $option_dry_run == "true" ]]; then
641 #ots verify -f "$path_src" "$path_prf";
642 for url in "${calendars[@]}"; do
643 ots -l "$url" --no-default-whitelist verify -f "$path_src" "$path_prf";
644 done;
645 else
646 yell "DEBUG:DRY RUN:Not running:\"ots verify -f $path_src $path_prf\"";
647 fi;
648 sleep "$ots_delay";
649 done;
650
651 ## Stamp files
652 for item in "${files_to_stamp_pruned[@]}"; do
653 path_src="$(cut -d $'\n' -f1 < <(echo "$item"))";
654 if [[ -z "$path_src" ]]; then
655 yell "ERROR:blank stamp item encountered. Skipping:item:$item";
656 continue;
657 fi;
658 vbm "DEBUG:Attempting to stamp source file:path_src:$path_src";
659 if [[ ! $option_dry_run == "true" ]]; then
660 #ots stamp "$item";
661 for url in "${calendars[@]}"; do
662 ots -l "$url" --no-default-whitelist stamp "$item";
663 done;
664 else
665 yell "DEBUG:DRY RUN:Not running:\"ots stamp $item\"";
666 fi;
667 sleep "$ots_delay";
668 done;
669
670 }; # main program
671
672 # Run program
673 main "$@";