#!/bin/sh
# Says which one old file a patch has to bring up, and nothing where the
# patch has already brought one up.
#
# sh devlog/devscripts/first_old_file.sh <check-script> <file> [<file> ...]
#
# It prints the name of the file that has to be fixed, or nothing where
# none does. Whatever the check itself printed for that file goes to
# standard error, so a caller can show it.
#
# WHY THIS EXISTS. A file written years ago may carry a hundred names or
# docblocks that today's rules would not allow. A patch that touches such
# a file cannot be asked to rewrite all of them and do what it came to do
# as well; that is how a round gets spent on nothing. So a patch brings
# up one old file and the rest wait for later patches.
#
# The part that took a round to get right is what counts as this patch's
# share. Refusing the first file with faults and then, once it is clean,
# refusing the next, asks a patch touching four old files to bring up all
# four. What counts here instead is whether the patch has already turned
# some file from faulty into clean: a file that had faults in gold and
# has none now is this patch's share, and every other file is named and
# left. Where the patch has brought none up, the first with faults is
# the one to fix.
GOLD=${GOLD:-/home/claude/gold}
check="$1"
shift
if [ -z "$check" ] || [ -z "$1" ]; then
exit 0
fi
brought_up=""
first_faulty=""
waiting=""
was=/tmp/first_old_was.$$
now=/tmp/first_old_now.$$
for one in "$@"
do
if [ ! -f "$one" ]; then
continue
fi
# A check may print its faults and still exit zero, so what counts
# is whether it named this file, not what it exited with.
sh "$check" "$one" > "$now" 2>&1
if grep -q "^$one:" "$now"; then
faulty_now=1
else
faulty_now=0
fi
# A file the patch does not change cannot be its share either way.
if git diff confirmed-head..HEAD --name-only -- "$one" | grep -q .
then
git show "confirmed-head:$one" > /tmp/first_old_copy.$$ 2>/dev/null
if [ -s /tmp/first_old_copy.$$ ]; then
here=`dirname "$one"`
mkdir -p "/tmp/first_old_tree.$$/$here"
cp /tmp/first_old_copy.$$ "/tmp/first_old_tree.$$/$one"
# The copy of gold's file is read from a tree of its own,
# so a check named by a path of its own must be made
# absolute before the move.
case "$check" in
/*) whole_check="$check" ;;
*) whole_check="`pwd`/$check" ;;
esac
(cd "/tmp/first_old_tree.$$" && \
sh "$whole_check" "$one") > "$was" 2>&1
if grep -q "^$one:" "$was"; then
faulty_before=1
else
faulty_before=0
fi
rm -rf "/tmp/first_old_tree.$$"
if [ "$faulty_before" != "0" ] && [ "$faulty_now" = "0" ]; then
brought_up="$one"
fi
fi
rm -f /tmp/first_old_copy.$$
fi
if [ "$faulty_now" != "0" ]; then
if [ -z "$first_faulty" ]; then
first_faulty="$one"
cat "$now" >&2
else
waiting="$waiting $one"
fi
fi
done
rm -f "$was" "$now"
if [ -n "$waiting" ] || [ -n "$first_faulty" ]; then
if [ -n "$brought_up" ]; then
echo "left for a later patch:$first_faulty$waiting" >&2
exit 0
fi
echo "left for a later patch:$waiting" >&2
fi
if [ -n "$first_faulty" ]; then
echo "$first_faulty"
fi
exit 0