11#! /usr/bin/env bash
22
3- # Detect changed files in the artifacts directory with a text file containing the last hash code of the contents.
3+ # Detect changed files in the artifacts directory or in a given list of paths
4+ # using a text file containing the last hash code of the contents.
45# The hash value is generated based on all files (their names and properties) within the artifacts directory.
56# A change is detected when the current hash and the stored differ.
67#
78# Command line options:
89# --readonly Detect changes without creating or updating the change detection file (stateless).
910# A second call without this option will be needed for the change detection to work.
1011# This is helpful to decide if an operation should be done based on changes while waiting for its success to finally save the change state.
12+ # --paths Comma-separated list of file- and directory-names that are used for calculating the hash based on their name and size.
1113
1214# Fail on any error ("-e" = exit on first error, "-o pipefail" exist on errors within piped commands)
1315set -o errexit -o pipefail
1416
17+ # Overrideable defaults
18+ ARTIFACTS_DIRECTORY=${ARTIFACTS_DIRECTORY:- " artifacts" }
19+ ARTIFACTS_CHANGE_DETECTION_HASH_FILE=${ARTIFACTS_CHANGE_DETECTION_HASH_FILE:- " artifactsChangeDetectionHash.txt" } # Name of the file that contains the hash code of the file list for change detection
20+ ARTIFACTS_CHANGE_DETECTION_HASH_FILE_PATH=" ./${ARTIFACTS_DIRECTORY} /$ARTIFACTS_CHANGE_DETECTION_HASH_FILE "
21+
1522# Function to display script usage
1623usage () {
17- echo " Usage: $0 [--readonly]"
24+ echo " Usage: $0 [--readonly] [--paths <comma separated list of file and directory names>] "
1825 exit 1
1926}
2027
2128# Default values
2229readonlyMode=false
30+ paths=" ./${ARTIFACTS_DIRECTORY} "
2331
2432# Parse command line arguments
2533while [[ $# -gt 0 ]]; do
2634 key=" $1 "
27- case $key in
35+ value=" ${2} "
36+
37+ case ${key} in
2838 --readonly)
2939 readonlyMode=true
40+ ;;
41+ --paths)
42+ paths=" ${value} "
3043 shift
3144 ;;
3245 * )
@@ -41,42 +54,84 @@ if ${readonlyMode}; then
4154 echo " detectChangedArtifacts: Readonly mode activated. Change detection file won't be created." >&2
4255fi
4356
44- ARTIFACTS_DIRECTORY=${ARTIFACTS_DIRECTORY:- " artifacts" }
45- ARTIFACTS_CHANGE_DETECTION_HASH_FILE=${ARTIFACTS_CHANGE_DETECTION_HASH_FILE:- " artifactsChangeDetectionHash.txt" } # Name of the file that contains the hash code of the file list for change detection
46- ARTIFACTS_CHANGE_DETECTION_HASH_FILE_PATH=" ./${ARTIFACTS_DIRECTORY} /$ARTIFACTS_CHANGE_DETECTION_HASH_FILE "
47-
4857# Check if the artifacts directory exists
49- if [ ! -d " ./ ${ARTIFACTS_DIRECTORY }" ] ; then
50- echo 0 # The artifact directory doesn't exist . There is nothing to compare. Therefore assume that there are no changes.
58+ if [ -z " ${paths }" ] ; then
59+ echo 0 # 0=No change detected. The path list is empty . There is nothing to compare. Therefore assume that there are no changes.
5160 exit 0
5261fi
5362
63+ # Function to get file size
64+ get_file_size () {
65+ if [ -f " $1 " ]; then
66+ wc -c < " $1 " | tr -d ' '
67+ else
68+ echo 0
69+ fi
70+ }
71+
72+ # Function to process a single path
73+ unwind_directories () {
74+ if [ -d " $1 " ]; then
75+ # If it's a directory, list all files inside
76+ # except for "node_modules", "target", "temp" and the change detection file itself
77+ find " $1 " \
78+ -type d -name " node_modules" -prune -o \
79+ -type d -name " target" -prune -o \
80+ -type d -name " temp" -prune -o \
81+ -not -name " ${ARTIFACTS_CHANGE_DETECTION_HASH_FILE} " \
82+ -type f \
83+ | sort
84+ elif [ -f " $1 " ]; then
85+ # If it's a file, just echo the file path
86+ echo " $1 "
87+ fi
88+ }
89+
90+ # Function that takes a comma-separated list of file- and directory-names,
91+ # finds all files in the directories
92+ # and calculates the md5 hash for every of these .
93+ get_md5_checksum_of_all_file_names_and_sizes () {
94+ local paths=${1}
95+ local files_and_sizes=" "
96+
97+ for path in ${paths// ,/ } ; do
98+ files=$( unwind_directories " ${path} " )
99+ for file in ${files} ; do
100+ size=$( get_file_size " ${file} " )
101+ files_and_sizes=" ${files_and_sizes}${file}${size} "
102+ done
103+ done
104+
105+ echo " ${files_and_sizes} " | openssl md5 | awk ' {print $2}'
106+ }
107+
54108# Use find to list all files in the directory with their properties,
55109# sort the output, and pipe it to md5 to create a hash
56110# Use openssl md5 that is at least available on Mac and Linux.
57111# See: https://github.com/TRON-US/go-btfs/issues/90#issuecomment-517409369
58- CURRENT_ARTIFACTS_HASH=" $( find " ./ $ARTIFACTS_DIRECTORY " -type f -not -name " ${ARTIFACTS_CHANGE_DETECTION_HASH_FILE} " -exec openssl md5 -binary {} + | openssl md5 | awk ' {print $2} ' ) "
112+ CURRENT_ARTIFACTS_HASH=$( get_md5_checksum_of_all_file_names_and_sizes " ${paths} " )
59113
60114# Assume that the files where changed if the file containing the hash of the file list does not exist yet.
61115if [ ! -f " ${ARTIFACTS_CHANGE_DETECTION_HASH_FILE_PATH} " ] ; then
62- if ! ${readonlyMode} ; then
116+ if [ " ${readonlyMode} " = false ] ; then
63117 # Create the file containing the hash of the files list to a new file for the next call
118+ mkdir -p " ${ARTIFACTS_DIRECTORY} "
64119 echo " ${CURRENT_ARTIFACTS_HASH} " > " ${ARTIFACTS_CHANGE_DETECTION_HASH_FILE_PATH} "
65120 echo " detectChangedArtifacts: Change detection file created" >&2
66121 fi
67- echo 1
122+ echo 1 # 1=Change detected and change detection file created
68123 exit 0
69124fi
70125
71126# Assume that there is no change if the saved hash is equal to the current one.
72127# Otherwise assume that the files where changed and overwrite the hash with the current one for the next call
73128if [[ $( < " ${ARTIFACTS_CHANGE_DETECTION_HASH_FILE_PATH} " ) == " $CURRENT_ARTIFACTS_HASH " ]] ; then
74- echo 0
129+ echo 0 # 0=No change detected
75130else
76131 if ! ${readonlyMode} ; then
77132 # Write the updated hash into the file containing the hash of the files list for the next call
78133 echo " $CURRENT_ARTIFACTS_HASH " > " ${ARTIFACTS_CHANGE_DETECTION_HASH_FILE_PATH} "
79134 echo " detectChangedArtifacts: Change detection file updated" >&2
80135 fi
81- echo 2
136+ echo 2 # 2=Change detected and change detection file updated
82137fi
0 commit comments