# undo.sh - temporarily undo changes in project tree
#
################################################################
# Copyright (C) 2001, 2002, 2003 Tom Lord, Alexander Deruwe
# 
# 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 "undo and save changes in project tree\\n"
          printf "usage: undo [options] [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 "\\n"
          printf " --silent                      no output (except odd errors)\\n"
          printf " --quiet                       brief output\\n"
          printf " --report                      outline output\\n"
          printf " --verbose                     maximal output\\n"
          printf " --debug                       debugging output\\n"
          printf "\\n"
          printf " -d --dir DIR                  cd to DIR first\\n"
          printf "\\n"
          printf " -o --output PATCH             save the patch set in PATCH\\n"
          printf " --no-output                   discard the resulting patch set\\n"
          printf "\\n"
          printf "Compute a patch set describing the changes from REVISION\\n"
          printf "to the project tree containing DIR.  Save the patch in\\n"
          printf "PATCH (which must not already exist) and apply the patch\\n"
          printf "in reverse to the project tree containing DIR.\\n"
          printf "\\n"
          printf "The effect is to remove local changes in the DIR project tree\\n"
          printf "but save them in a convenient form (see \"larch redo --help\"\\n"
          printf "and \"larch dopatch --help\").\\n"
          printf "\\n"
          printf "If REVISION is not specified, the latest ancestor of the\\n"
          printf "default version of project tree is used.\\n"
          printf "\\n"
          printf "If REVISION is specified as a VERSION, the latest ancestor\\n"
          printf "of the project tree in that VERSION is used.\\n"
          printf "\\n"
          printf "If DIR is not specified, \".\" is assumed.\\n"
          printf "\\n"
          printf "If PATCH is not specified, a temporary file-name of the\\n"
          printf "matching \",,undo-*\" is used.\\n"
          printf "\\n"
          printf "If \"--no-output\" is specified, the patch set is not saved.\\n"
          printf "\\n"
          printf "See also \"larch redo --help\" \\n"
          printf "and \"larch what-changed --help\".\\n"
          printf "\\n"
          exit 0
          ;;

      *)
          ;;
    esac
  done
fi

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

archroot=
archive=

dir=.

output=
no_output=

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

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

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


    --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 "undo: debugging output enabled\\n"
                    set -x
                    debug=--debug
                    ;;

    -d|--dir)       shift
                    if test $# -lt 1 ; then
                      printf "undo: -d and --dir require an argument\\n" 1>&2
                      printf "try --help\\n" 1>&2
                      exit 1
                    fi
                    dir="$1"
                    shift
                    ;;

    -o|--output)    shift
                    if test $# -lt 1 ; then
                      printf "undo: -o and --output require an argument\\n" 1>&2
                      printf "try --help\\n" 1>&2
                      exit 1
                    fi
                    output="$1"
                    no_output=
                    shift
                    ;;

    --no-output)    shift
                    no_output=--no-output
                    output=
                    ;;

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

    *)
        break
        ;;
  esac
done



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

if test $# -gt 1 ; then
  printf "usage: undo [options] [REVISION]\\n"
  printf "try --help\\n"
  exit 1
fi

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


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

here="`pwd`"

cd "$dir"
dir="`pwd`"

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

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

larch valid-package-name -e undo -t --vsn "$rvnspec"

if test ! -z "$output" ; then

  cd "$here"
  cd $(dirname "$output")
  output_dir="`pwd`"
  output_basename=$(basename "$output")
  output="$output_dir/$output_basename"

else

  cd "$wdroot"

  undo_prefix=",,undo"

  level=`ls | grep -E -e "^$undo_prefix-[0-9]+$" | sort -t - -k 2,2n -r | head -n 1 | sed -e 's/.*-//'`
  if test -z "$level" ; then
    level=1
  else
    level=$((level + 1))
  fi

  output_dir="$wdroot"
  output_basename="$undo_prefix-$level"
  output="$output_dir/$output_basename"

fi



if test -e "$output" ; then
  printf "undo: output directory already exists\\n" 1>&2
  printf "  dir: %s\\n" "$output" 1>&2
  printf "\\n" 1>&2
  exit 1
fi



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

if test ! -z "$quiet" ; then
  larch heading "undo\\n"
  printf "arguments: %s\\n" "$command_line" | fold -w 60 | larch body-indent
  larch heading --sub "project tree: %s\\n" "$wdroot"
  larch heading --sub "revision spec: %s\\n" "$rvnspec"
  larch heading --sub "output directory: %s\\n" "$output"
fi


################################################################
# Lint the Tree
# 
# Make sure that there is nothing fatally bad in the tree.
# 

cd "$wdroot"

if test ! -z "$silent" ; then
  larch nested larch tree-lint > /dev/null
else
  larch nested larch tree-lint
fi



################################################################
# Compute Diffs
# 


if test ! -z "$report" ; then
  larch heading --sub "computing patch set\\n"
  if test ! -z "$verbose" ; then
    larch heading --sub --sub "start time: %s\\n" "`date`"
  fi
fi

cd "$wdroot"

larch nested larch what-changed --quiet $silent_opt $quiet_opt $report_opt $verbose_opt $debug_opt \
                                --output "$output" \
                                --diffs \
                                "$rvnspec"

if test ! -z "$verbose" ; then
  larch heading --sub --sub "finish time: %s\\n" "`date`"
fi


################################################################
# Reverse changes in Project Tree
#

if test ! -z "$report" ; then
  larch heading --sub "reverting local changes\\n"
  if test ! -z "$verbose" ; then
    larch heading --sub --sub "start time: %s\\n" "`date`"
  fi
fi

larch nested larch dopatch --reverse --quiet $silent_opt $report_opt $verbose_opt $debug_opt "$output" "$wdroot"

if test ! -z "$verbose" ; then
  larch heading --sub --sub "finish time: %s\\n" "`date`"
fi

################################################################
# Delete changes if requested
#

if test ! -z "$no_output" ; then
  if test ! -z "$report" ; then
    larch heading --sub "removing patch set directory\\n" 
    larch heading --sub --sub "dir: %s\\n" "$output"
  fi

  rm -rf "$output"
fi

exit 0

#
# vim: set expandtab shiftwidth=2 softtabstop=2:
