-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdiff-hash-trees.sh
More file actions
executable file
·94 lines (83 loc) · 2.19 KB
/
diff-hash-trees.sh
File metadata and controls
executable file
·94 lines (83 loc) · 2.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#!/bin/bash
set -e
export PATH="/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:$PATH"
# Parse flags
JSON=false
QUIET=false
POSITIONAL=()
while [ $# -gt 0 ]; do
case "$1" in
--json) JSON=true; shift ;;
--quiet) QUIET=true; shift ;;
*) POSITIONAL+=("$1"); shift ;;
esac
done
set -- "${POSITIONAL[@]}"
FILE_A="${1:?Usage: diff-hash-trees.sh [--json] [--quiet] <hash-file-a> <hash-file-b>}"
FILE_B="${2:?Usage: diff-hash-trees.sh [--json] [--quiet] <hash-file-a> <hash-file-b>}"
if [ ! -f "$FILE_A" ]; then
echo "ERROR: '$FILE_A' not found" >&2
exit 1
fi
if [ ! -f "$FILE_B" ]; then
echo "ERROR: '$FILE_B' not found" >&2
exit 1
fi
# Single awk pass: FNR==NR reads FILE_A, then FILE_B
# Outputs tagged lines: A <path>, R <path>, C <path>
RAW=$(awk '
FNR==NR { a[$2] = $1; next }
{ b[$2] = $1 }
END {
for (p in b) {
if (!(p in a)) print "A " p
else if (a[p] != b[p]) print "C " p
}
for (p in a) {
if (!(p in b)) print "R " p
}
}
' "$FILE_A" "$FILE_B")
ADDED=$(echo "$RAW" | awk '/^A /{print substr($0,3)}' | sort)
REMOVED=$(echo "$RAW" | awk '/^R /{print substr($0,3)}' | sort)
CHANGED=$(echo "$RAW" | awk '/^C /{print substr($0,3)}' | sort)
# Trim empty lines
ADDED=$(echo "$ADDED" | sed '/^$/d')
REMOVED=$(echo "$REMOVED" | sed '/^$/d')
CHANGED=$(echo "$CHANGED" | sed '/^$/d')
HAS_CHANGES=false
if [ -n "$ADDED" ] || [ -n "$REMOVED" ] || [ -n "$CHANGED" ]; then
HAS_CHANGES=true
fi
if $QUIET; then
if $HAS_CHANGES; then exit 1; else exit 0; fi
fi
if $JSON; then
python3 -c "
import json
def to_list(s):
return [l for l in s.strip().split('\n') if l] if s.strip() else []
print(json.dumps({
'added': to_list('''$ADDED'''),
'removed': to_list('''$REMOVED'''),
'changed': to_list('''$CHANGED'''),
}))"
if $HAS_CHANGES; then exit 1; else exit 0; fi
fi
# Human-readable output
if ! $HAS_CHANGES; then
echo "NO_CHANGES"
exit 0
fi
if [ -n "$ADDED" ]; then
echo "ADDED:"
echo "$ADDED" | while IFS= read -r LINE; do echo " $LINE"; done
fi
if [ -n "$REMOVED" ]; then
echo "REMOVED:"
echo "$REMOVED" | while IFS= read -r LINE; do echo " $LINE"; done
fi
if [ -n "$CHANGED" ]; then
echo "CHANGED:"
echo "$CHANGED" | while IFS= read -r LINE; do echo " $LINE"; done
fi