Replace shebang with following if Nix is installed to automatically pull in dependencies.
#!/usr/bin/env nix-shell
#! nix-shell -i bash -p git fd ripgrep
#!/usr/bin/env bash | |
# syncthing share. some parent directory | |
targetShare="$PWD" | |
while true; do | |
if [ -d "$targetShare/.stfolder" ]; then break; fi | |
if [ "$targetShare" == "/" ]; then | |
echo "Could not find parent Syncthing share" | |
exit 1; | |
fi | |
targetShare=$(realpath "$targetShare/..") | |
done | |
# search scope | |
fdArgs="--no-ignore" | |
# regex to detect sync conflicts | |
conflictRegex='\.sync-conflict-[0-9]+-[0-9]{6}-[A-Z0-9]{7}(\..+)?$' | |
# regex to detect if file is in progress of being merged | |
mergeRegex='^<<<<<<< .+$\n(.*\n)*^=======$\n(.*\n)*^>>>>>>> .+$\n' | |
sharePath="${PWD#"$targetShare/"}" | |
conflicts="$(fd "$conflictRegex" . --type file $fdArgs)" | |
if [ "$conflicts" == "" ]; then echo "No conflicts, exiting."; exit 0; fi | |
count=$(echo "%s" "$conflicts" | wc -l) | |
countLen=$(printf "%d" "$count" | wc -c) | |
echo "Fixing $count conflict(s) via 3-way merge:"; | |
echo "$conflicts" | while read -r path; do | |
i=$((${i:-0} + 1)) | |
dir=$(dirname "$path") | |
name=$(basename "$path") | |
sanitizedName="$(echo "$name" | sed -r "s/$conflictRegex//")" | |
extension="$(echo "$name" | rev | cut -d. -f1 | rev)" # might be empty | |
# find paths for 3-way merge | |
base="$dir/$sanitizedName" | |
ancestors="$(fd \ | |
"$(echo "$sanitizedName" | sed -r "s/\.$extension\$//")" \ | |
"$targetShare/.stversions/$sharePath/$dir" \ | |
--type file $fdArgs 2>/dev/null)" | |
other="$path" | |
printf "[$(printf "%0${countLen}d" "$i")/$count] Merging '%s': " "$(echo "$base" | sed -r 's/^\.\///')" | |
# pick "latest" ancestor | |
ancestor="$(echo "$ancestors" | sort -hr | head -1)" | |
# if no common ancestor, try empty file | |
ancestor="${ancestor:-/dev/null}" | |
# check if base even exists | |
if [ ! -f "$base" ]; then echo "conflict file references non-existant base, skipping."; continue; fi | |
if rg --quiet --multiline "$mergeRegex" "$base"; then echo "file has pending manual merge, skipping."; continue; fi | |
# perform actual merge | |
git merge-file "$base" "$ancestor" "$other" 2>/dev/null | |
# for documentation on exit codes, see: `man git-merge-file` | |
mergeStatus="$?" | |
if [ "$mergeStatus" -eq 255 ]; then echo "can't merge binary files, skipping."; continue; fi | |
if [ "$mergeStatus" -gt 127 ]; then echo "could not perform merge due to unknown error ($mergeStatus)."; continue; fi | |
if [ "$mergeStatus" -eq 0 ]; then echo "merged cleanly."; rm "$other"; continue; fi | |
if [ "$mergeStatus" -lt 0 ]; then echo "could not perform merge due to error ($mergeStatus)."; continue; fi | |
if [ "$mergeStatus" -gt 0 ]; then echo "needs manual intervention for $mergeStatus merge(s)."; rm "$other"; continue; fi | |
done |