# file-diffs.sh: compare file with pristine tree
# 
################################################################
# Copyright (C) 2001, 2002 Tom Lord
# 
# See the file "COPYING" for further information about
# the copyright and warranty status of this work.
# 

set -e 

command_line="$*"

################################################################
# special options
# 
# Some options are special:
# 
#       --version | -V
#       --help | -h
# 
if test $# -ne 0 ; then

  for opt in "$@" ; do
    case $opt in

      --version|-V) exec larch --version
                    ;;


      --help|-h)
                printf "compare file with cached pristine revision\\n"
                printf "usage: file-diffs [options] file [[archive/]revision]\\n"
                printf "\\n"
                printf " -V --version                  print version info\\n"
                printf " -h --help                     display help\\n"
                printf "\\n"
                printf " -R --root root                specify the local archive root\\n"
                printf " -A --archive archive          specify the archive name\\n"
                printf "  --cache DIR                  cache directory for locally cached\\n"
                printf "\\n"
                printf " --silent                      no output (except odd errors)\\n"
                printf " --quiet                       brief output\\n"
                printf " --report                      default output\\n"
                printf " --verbose                     maximal output\\n"
                printf " --debug                       debugging output\\n"
                printf "\\n"
                printf " --html                        produce HTML format output\\n"
                printf "\\n"
                printf "Print diffs between FILE and the corresponding file in a cached\\n"
                printf "copy of REVISION.\\n"
                printf "\\n"
                printf "The default patch level for a given version is the latest level for\\n"
                printf "which the project tree has a patch.  The default archive and version\\n"
                printf "is as printed by \"larch tree-version\".\\n"
                printf "\\n"
                exit 0
                ;;

      *)
                ;;
    esac
  done
fi

################################################################
# Ordinary Options
# 
# 

archroot=
archive=
cache_dir=
html=

quiet=--quiet
report=--report
verbose=
silent_opt=
quiet_opt=
report_opt=
verbose_opt=
debug_opt=

while test $# -ne 0 ; do

  case "$1" in 

    --html)     shift
                html=--html
                ;;

    --silent)   shift
                quiet=
                report=
                verbose=
                silent_opt=--silent
                quiet_opt=
                report_opt=
                verbose_opt=
                ;;

    --quiet)    shift
                quiet=--quiet
                report=
                verbose=
                silent_opt=
                quiet_opt=--quiet
                report_opt=
                verbose_opt=
                ;;

    --report)   shift
                quiet=--quiet
                report=--report
                verbose=
                silent_opt=
                quiet_opt=
                report_opt=--report
                verbose_opt=
                ;;

    --verbose)  shift
                quiet=--quiet
                report=--report
                verbose=--verbose
                silent_opt=
                quiet_opt=
                report_opt=
                verbose_opt=--verbose
                ;;

    --debug)    shift
                larch heading "file-diffs: debugging output enabled\\n"
                set -x
                debug_opt=--debug
                ;;

    -R|--root)          shift
                        if test $# -eq 0 ; then
                          printf "file-diffs: -R and --root require an argument\\n" 1>&2
                          printf "try --help\\n" 1>&2
                          exit 2
                        fi
                        archroot="$1"
                        shift
                        ;;

    -A|--archive)       shift
                        if test $# -eq 0 ; then
                          printf "file-diffs: -A and --archive require an argument\\n" 1>&2
                          printf "try --help\\n" 1>&2
                          exit 2
                        fi
                        archive="$1"
                        shift
                        ;;

    --cache)            shift
                        if test $# -eq 0 ; then
                          printf "file-diffs: --cache requires an argument\\n" 1>&2
                          printf "try --help\\n" 1>&2
                          exit 2
                        fi
                        cache_dir="$1"
                        shift
                        ;;

    --)                 shift
                        break
                        ;;

    -*)                 printf "file-diffs: unrecognized option (%s)\\n" "$1" 1>&2
                        printf "try --help\\n" 1>&2
                        exit 2
                        ;;

    *)                  break
                        ;;
  esac

done



################################################################
# Ordinary Arguments
# 

if test $# -lt 1 -o  $# -gt 2 ; then
  printf "usage: file-diffs [options] file [[archive/]revision]\\n" 1>&2
  printf "try --help\\n" 1>&2
  exit 2
fi

file="$1"
shift

if test $# -ne 0 ; then
  rvnspec="$1"
  shift
else
  rvnspec=
fi

################################################################
# Sanity Check and Process Defaults
# 


dir="`dirname \"$file\"`"

cd "$dir"
dir="`pwd`"
wdroot="`larch tree-root`"

file_base="`basename \"$file\"`"
rel_path=".${dir#$wdroot}/$file_base"

cd "$wdroot"

if test -z "$rvnspec" ; then
  rvnspec="`larch tree-version`"
fi

larch valid-package-name -e file-diffs -t "$rvnspec"

archive="`larch parse-package-name -R \"$archroot\" -A \"$archive\" --arch \"$rvnspec\"`"
category="`larch parse-package-name -R \"$archroot\" -A \"$archive\" --basename \"$rvnspec\"`"
branch="`larch parse-package-name -R \"$archroot\" -A \"$archive\" --package \"$rvnspec\"`"

if larch valid-package-name --vsn -t "$rvnspec" ; then
  version="`larch parse-package-name --package-version \"$rvnspec\"`"
else
  version="`larch logs -r \"$branch\" | head -n 1`"
  if test -z "$version" ; then
    printf "file-diffs: no logs for that branch\\n" 1>&2
    printf "  branch: %s\\n" "$branch" 1>&2
    printf "\\n"
    exit 2
  fi
  version="`larch parse-package-name --package-version \"$version\"`"
fi

if larch valid-package-name --patch-level -t "$rvnspec" ; then
  revision="`larch parse-package-name --non-arch \"$rvnspec\"`"
else
  lvl="`larch log-ls -r \"$version\" | head -n 1`"
  if test -z "$lvl" ; then
    printf "file-diffs: no patch level for that version\\n" 1>&2
    printf "  branch: %s\\n" "$version" 1>&2
    printf "\\n"
    exit 2
  fi
  revision="$version--$lvl"
fi

if test -z "$cache_dir" ; then
  cd "$wdroot/.."
  cache_dir="`pwd`"
  cd "$wdroot"
fi

if larch library-find --silent -A "$archive" "$revision" > /dev/null ; then

  revision_tree="`larch library-find --silent -A \"$archive\" \"$revision\"`"
  revision_index="$revision_tree/,,index"

else

  set +e
  revision_tree="`larch find-in-cache -A \"$archive\" \"$cache_dir\" \"$revision\"`"
  status=$?
  set -e

  if test $status -ne 0 ; then
    printf "file-diffs: revision not in library or local cache\\n" 1>&2
    printf "  revision: %s\\n" "$revision" 1>&2
    printf "\\n" 1>&2
    printf "See \"larch add-pristine\"\\n" 1>&2
    printf "\\n" 1>&2
    exit 2
  fi

  revision_index="`larch cached-index \"$revision_tree\"`"

fi

################################################################
# Greetings
# 

if test ! -z "$quiet" ; then
  larch heading $html "file-diffs\\n"
  printf "arguments: %s\\n"  "$command_line" | fold -w 60 | larch body-indent $html
fi

################################################################
# Identify the File
# 

tagging_method="`larch tagging-method`"

set +e

cd "$wdroot"

case "$tagging_method" in

  names)        tag="?$rel_path"
                status=0
                ;;

  implicit)     tag="`file-tag --implicit \"$rel_path\"`"
                status=$?
                tag="`printf \"%s\\\\n\" \"$tag\" | cut -s -f 2`"
                ;;

  explicit)     tag="`file-tag --explicit \"$rel_path\"`"
                status=$?
                tag="`printf \"%s\\\\n\" \"$tag\" | cut -s -f 2`"
                ;;

  *)            printf "file-diffs: internal error\\n" 1>&2
                printf "  unrecognized tagging method (%s)\\n" "$tagging_method" 1>&2
                printf "\\n" 1>&2
                exit 2
                ;;
esac

if test "$status" -ne 0 ; then
  printf "file-diffs: unable to compute file tag\\n" 1>&2
  printf "  file: %s\\n" "$wdroot/$rel_path" 1>&2
  printf "\\n" 1>&2
  exit 2
fi

if test ! -z "$verbose" ; then
  larch heading $html --sub "tagging method: %s\\n" "$tagging_method"
  larch heading $html --sub "file tag: %s\\n" "$tag"
fi


################################################################
# Find the Corresponding File
# 

revision_path="`printf \"%s\\n\" \"$tag\" | join -o 2.1 -1 1 -2 2 - \"$revision_index\"`"

if test ! -z "$report" ; then
  larch heading $html --sub "new file from: %s\\n" "$wdroot"
  printf "%s\\n" "$rel_path" | larch file-list $html --sub --root "$wdroot"
  larch heading $html --sub "old file from revision: %s\\n" "$archive/$revision"
  printf "%s\\n" "$revision_path" | larch file-list $html --sub --root "$revision_tree"
  if test ! -z "$verbose" ; then
    larch heading $html --sub --sub "old tree: %s\\n" "$revision_tree"
  fi
fi



################################################################
# Compare Files
# 

if test -h "$wdroot/$rel_path" ; then
  new_type=symlink
elif test -d "$wdroot/$rel_path" ; then
  new_type=directory
elif test -f "$wdroot/$rel_path" ; then
  new_type=file
else
  printf "file-diffs: unrecognized file type\\n" 1>&2
  printf "  file: %s\\n" "$wdroot/$rel_path" 1>&2
  printf "\\n"
  exit 2
fi

if test -h "$revision_tree/$revision_path" ; then
  old_type=symlink
elif test -d "$revision_tree/$revision_path" ; then
  old_type=directory
elif test -f "$revision_tree/$revision_path" ; then
  old_type=file
else
  printf "file-diffs: unrecognized file type\\n" 1>&2
  printf "  file: %s\\n" "$revision_tree/$revision_path" 1>&2
  printf "\\n"
  exit 2
fi

status=0

if test "$rel_path" != "$revision_path" ; then
  status=1
  if test ! -z "$quiet" ; then
    if test $old_type != $new_type ; then
      larch heading $html --sub "%s/%s moved between trees\\n" $old_type $new_type
    else
      larch heading $html --sub "%s moved between trees\\n" $old_type
    fi
    larch heading $html --sub --sub "old path: %s\\n" "$revision_path"
    larch heading $html --sub --sub "new path: %s\\n" "$rel_path"
  fi
fi

if test $old_type != $new_type ; then
  status=1
  if test ! -z "$quiet" ; then
    larch heading $html --sub "file changed type\\n"
    larch heading $html --sub --sub "old type: %s\\n" $old_type
    larch heading $html --sub --sub "new type: %s\\n" $new_type
  fi
fi

case $new_type in 

  symlink)      old_link="`read-link \"$revision_tree/$revision_path\"`"
                new_link="`read-link \"$wdroot/$rel_path\"`"

                if test "$old_link" = "$new_link" ; then
                  if test ! -z "$quiet" ; then
                    larch heading $html --sub "equal symbolic links\\n"
                    larch heading $html --sub --sub "link target: %s\\n" "$old_link"
                  fi
                else
                  if test ! -z "$quiet" ; then
                    larch heading $html --sub "unequal symbolic links\\n"
                    larch heading $html --sub --sub "old link target: %s\\n" "$old_link"
                    larch heading $html --sub --sub "new link target: %s\\n" "$new_link"
                  fi
                  status=1
                fi
                ;;

  directory)    if test ! -z "$quiet" ; then
                  larch heading $html --sub "both are directories\\n"
                fi
                ;;

  file)         set +e
                diff "$revision_tree/$revision_path" "$wdroot/$rel_path" > /dev/null 2>&1
                diff_stat=$?
                set -e
                status="$diff_stat"
                if test $diff_stat -eq 1 ; then
                  if test ! -z "$quiet" ; then
                    larch heading $html --sub "context diff\\n"
                  fi
                  if test ! -z "$quiet" ; then
                    diff -u "$revision_tree/$revision_path" "$wdroot/$rel_path" | larch body-indent --sub $html
                  fi
                  status=1
                elif test $diff_stat -eq 0 ; then
                  if test ! -z "$quiet" ; then
                    larch heading $html --sub "files are identical\\n"
                  fi
                elif cmp "$revision_tree/$revision_path" "$wdroot/$rel_path" ; then
                  if test ! -z "$quiet" ; then
                    larch heading $html --sub "binary files are identical\\n"
                  fi
                else
                  if test ! -z "$quiet" ; then
                    larch heading $html --sub "binary files differ\\n"
                  fi
                  status=1
                fi
                ;;

  *)            printf "file-diffs: internal error\\n" 1>&2
                printf "  unhandled file type %s\\n" "$type" 1>&2
                printf "\\n" 1>&2
                exit 2

esac

exit "$status"


# tag: Tom Lord Thu Dec 13 21:06:42 2001 (local-cache/file-diffs.sh)
#
