|
function diff_dirs -d "Quick directory comparison using rsync" |
|
argparse 'g/group' 'h/help' -- $argv |
|
or return 1 |
|
|
|
if set -q _flag_help; or test (count $argv) -lt 2 |
|
echo "Usage: diff_dirs [-g] <folderA> <folderB>" |
|
echo "" |
|
echo "Quick directory comparison using rsync (compares by file size only)." |
|
echo "" |
|
echo "Options:" |
|
echo " -g, --group Group output by collapsing exclusive directories" |
|
echo "" |
|
echo "Output:" |
|
echo " [ONLY in A] - file exists only in folderA" |
|
echo " [ONLY in B] - file exists only in folderB" |
|
echo " [CHANGED] - file exists in both but differs" |
|
return 1 |
|
end |
|
|
|
set -l a (string trim -r -c "/" $argv[1]) |
|
set -l b (string trim -r -c "/" $argv[2]) |
|
set -l nameA (basename $a) |
|
set -l nameB (basename $b) |
|
|
|
# If basenames are the same, use parent/basename |
|
if test "$nameA" = "$nameB" |
|
set nameA (basename (dirname $a))/$nameA |
|
set nameB (basename (dirname $b))/$nameB |
|
end |
|
|
|
if set -q _flag_group |
|
# Grouped output: collapse exclusive directories |
|
rsync -rin8 --size-only --delete "$a/" "$b/" | awk \ |
|
-v labelA="$nameA" -v labelB="$nameB" ' |
|
{ lines[NR] = $0 } |
|
END { |
|
# Find top-level exclusive directories |
|
for (i = 1; i <= NR; i++) { |
|
line = lines[i] |
|
if (line ~ /^\*deleting +[^\/]+\/$/) { |
|
path = line; sub(/^\*deleting +/, "", path) |
|
excl_b[path] = 1 |
|
} |
|
if (line ~ /^cd\+* +[^\/]+\/$/) { |
|
path = line; sub(/^[^ ]+ +/, "", path) |
|
excl_a[path] = 1 |
|
} |
|
} |
|
# Output with collapsing |
|
for (i = 1; i <= NR; i++) { |
|
line = lines[i] |
|
if (line ~ /^\*deleting/) { |
|
path = line; sub(/^\*deleting +/, "", path) |
|
skip = 0 |
|
for (d in excl_b) { if (path != d && index(path, d) == 1) skip = 1 } |
|
if (!skip) printf "[ONLY %-20s] %s\n", labelB, path |
|
continue |
|
} |
|
if (line ~ /^cd\+/) { |
|
path = line; sub(/^[^ ]+ +/, "", path) |
|
skip = 0 |
|
for (d in excl_a) { if (path != d && index(path, d) == 1) skip = 1 } |
|
if (!skip) printf "[ONLY %-20s] %s\n", labelA, path |
|
continue |
|
} |
|
if (line ~ /^>f\+\+\+\+\+/) { |
|
path = line; sub(/^[^ ]+ +/, "", path) |
|
skip = 0 |
|
for (d in excl_a) { if (index(path, d) == 1) skip = 1 } |
|
if (!skip) printf "[ONLY %-20s] %s\n", labelA, path |
|
continue |
|
} |
|
if (line ~ /^>f.s/) { |
|
path = line; sub(/^[^ ]+ +/, "", path) |
|
printf "[CHANGED%17s] %s\n", "", path |
|
} |
|
} |
|
} |
|
' |
|
else |
|
# Verbose output (default) |
|
rsync -rin8 --size-only --delete "$a/" "$b/" | awk \ |
|
-v labelA="$nameA" -v labelB="$nameB" ' |
|
/^\*deleting/ {sub(/^\*deleting +/, ""); printf "[ONLY %-20s] %s\n", labelB, $0; next} |
|
/^>f\+\+\+\+\+/ {sub(/^[^ ]+ +/, ""); printf "[ONLY %-20s] %s\n", labelA, $0; next} |
|
/^>f.s/ {sub(/^[^ ]+ +/, ""); printf "[CHANGED%17s] %s\n", "", $0} |
|
' |
|
end |
|
end |