#!/bin/sh
# 
# commit.sh: archive a pre-patch revision
################################################################
# 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 "archive a revision\\n"
                printf "usage: commit [options] [[archive/]version]\\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 " -L --log-file file            specify the log-file\\n"
                printf " --not-default                 do not make this the default branch\\n"
                printf " --no-lint                     do not tree-lint the project tree\\n"
                printf "\\n"
		printf " -d --dir DIR                  cd to DIR first\\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 " --seal                        commit the version revision\\n"
		printf " --fix                         commit a versionfix- patch level\\n"
		printf " --continuation [archive/]prev-revision  commit a continuation revision\\n"
		printf " --out-of-date-ok              permit commit even if project tree is\\n"
                printf "                                 not up to date\\n"
		printf " --unchanged-ok                commit even if project tree is\\n"
                printf "                                 unmodified\\n"
                printf "\\n"
                printf " --dry-run                     don't actually commit -- just\\n"
                printf "                               prepare the patch set\\n"
                printf "\\n"
		printf " --explicit                    force the explicit tagging method\\n"
		printf " --implicit                    force the implicit tagging method\\n"
		printf " --names                       force the name-based tagging method\\n"
                printf "\\n"
                printf "Archive a revision of the project tree containing DIR (or the\\n"
                printf "current directory)\\n"
                printf "\\n"
                printf "If there are any automated ChangeLog files, update them before\\n"
		printf "computing the patch set.\\n"
                printf "\\n"
                printf "Ordinarily no commit will occur if the only changes to the project\\n"
                printf "tree are the new log entry and changes to ChangeLog file.  To force\\n"
                printf "such a commit to occur anyway, use \"--unchanged-ok\".\\n"
                printf "\\n"
                exit 0
                ;;

      *)
                ;;
    esac
  done
fi

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

archroot=
archive=

no_lint=
makedefault=1
logfile=
continuation=0
continuation_revision=
fix=0
seal=0
out_of_date_ok=0
dry_run=
unchanged_ok=
__restart=

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

method=

dir=.

while test $# -ne 0 ; do

  case "$1" in 

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

     --explicit)	shift
			method=--explicit
			;;

     --implicit)	shift
			method=--implicit
			;;

     --names)		shift	
			method=--names
			;;

     ----restart) shift
		 __restart=----restart
		 ;;

     --no-lint)  shift
		 no_lint=--no-lint
		 ;;

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


    -R|--root)          shift
                        if test $# -eq 0 ; then
                          printf "commit: -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 "commit: -A and --archive require an argument\\n" 1>&2
                          printf "try --help\\n" 1>&2
                          exit 1
                        fi
                        archive="$1"
                        shift
                        ;;

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

    --not-default)      shift
                        makedefault=0
                        ;;

    --fix)		shift
    			fix=1
			seal=0
			continuation=0
			;;

    --seal)		shift
    			fix=0
			seal=1
			continuation=0
			unchanged_ok=--unchanged-ok
			;;

    --continuation)	shift
    			fix=0
			seal=0
			continuation=1
			unchanged_ok=--unchanged-ok
                        if test $# -eq 0 ; then
                          printf "commit: --continuation requires an argument\\n" 1>&2
                          printf "try --help\\n" 1>&2
                          exit 1
                        fi
			continuation_revision="$1"
			shift
			;;

    --out-of-date-ok)	shift
    			out_of_date_ok=1
			;;

    --unchanged-ok)	shift
    			unchanged_ok=--unchanged-ok
			;;

    --dry-run)		shift
    			dry_run=--dry-run
			;;

    -*)                 printf "commit: 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: commit [options] [[archive]/version]\\n" 1>&2
  printf "try --help\\n" 1>&2
  exit 1
fi

if test $# -gt 0 ; then
  archive_version="$1"
  shift
else
  archive_version=
fi

################################################################
# Sanity Check and Process Defaults
# 
  
start_dir="`pwd`"

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

wdroot="`larch tree-root --accurate`"
cd "$wdroot"
  
if test "x$archive_version" = x ; then
  archive_version=`larch tree-version`
else
  larch valid-package-name -e commit --vsn -- "$archive_version"
fi

archive=`larch parse-package-name -R "$archroot" -A "$archive" --arch $archive_version`
version=`larch parse-package-name -R "$archroot" -A "$archive" --package-version $archive_version`
category=`larch parse-package-name --basename $version`
branch=`larch parse-package-name $version`
vsn=`larch parse-package-name -v $version`

if test "x$logfile" = x ; then
  logfile=++log.$version--$archive
fi

cd "$start_dir"
logfile_dir="`dirname \"$logfile\"`"
logfile_base="`basename \"$logfile\"`"
cd "$logfile_dir"
logfile="`pwd`/$logfile_base"

# Make sure the wd has a patch log for this version.
# 
larch wd-check-for-patch-log -e commit -R "$archroot" -A "$archive" "$version" "$wdroot"

# Make sure we have a valid log file for this revision.
# 
larch valid-log-file -e commit -- "$logfile"

tmpdir="$wdroot/,,commit-tmp-dir"


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

if test "(" -z "$__restart" -a ! -z "$quiet" ")" -o ! -z "$report" ; then
  larch heading "commit\\n"
  printf "arguments: %s\\n"  "$command_line" | fold -w 60 | larch body-indent
  larch heading --sub "commit start time: %s\\n" "`date`"
  larch heading --sub "project tree: %s\\n" "$wdroot"
  larch heading --sub "archive: %s\\n" "$archive"
  larch heading --sub "version: %s\\n" "$version"
  if test ! -z "$continuation_revision" ; then
    larch heading --sub "this is a continuation revision (--continuation)\\n"
  elif test $fix -ne 0 ; then
    larch heading --sub "this is versionfix revision (--fix)\\n"
  elif test $seal -ne 0 ; then
    larch heading --sub "this is version revision (--seal)\\n"
  fi
  if test ! -z "$dry_run" ; then 
    larch heading --sub "this is a dry run (no modifications to the archive)\\n"
  fi
fi


################################################################
# Ensure that We Have an Archive Connection 
# 

if test "$WITHARCHIVE" != "$archive" ; then

  if test ! -z "$quiet" ; then
    larch heading --sub "restarting with connection to archive\\n"
  fi

  flags=

  if test $makedefault -eq 0 ; then
    flags="-d $flags"
  fi

  if test $fix -ne 0 ; then
    flags="--fix $flags"
  elif test $seal -ne 0 ; then
    flags="--seal $flags"
  elif test $continuation -ne 0 ; then
    flags="--continuation $continuation_revision $flags"
  fi

  if test $out_of_date_ok -ne 0 ; then
    flags="--out-of-date-ok $flags"
  fi

  exec larch with-archive -R "$archroot" -A "$archive" \
      larch commit -R "$archroot" -A "$archive" \
 		  -L "$logfile" \
		  $silent_opt $quiet_opt $report_opt $verbose_opt $debug_opt \
		  $unchanged_ok \
		  $no_lint \
		  $flags \
		  $dry_run \
		  $method \
		  --dir "$dir" \
		  ----restart \
    		  "$archive/$version"
fi



################################################################
# Create a Temp Dir in Which to Build the Patch
# 

bail()
{
  cd "$wdroot"
  rm -rf "$tmpdir"
  exit 1
}

trap "printf \"commit: interrupted -- cleaning up\\n\" 1>&2 ; bail" INT

mkdir "$tmpdir"


################################################################
# Process Defaults for the Continuation Revision
# 

first()
{
  if test $# = 0 ; then
    printf "first called on empty list\\n" 1>&2
    bail
  else
    printf "%s\\n" "$1" 
  fi
}

second()
{
  if test $# -lt 2 ; then
    printf "first called on short list\\n" 1>&2
    bail
  else
    printf "%s\\n" "$2" 
  fi
}

if test ! -z "$continuation_revision" ; then


  indicated_continuation="`larch indicated-revision -e commit -R \"$archroot\" -A \"$archive\" \"$continuation_revision\"`"

  continuation_archive=${indicated_continuation%%/*}
  continuation_revision=${indicated_continuation#*/}

  continuation_category=`larch parse-package-name --basename $continuation_revision`
  continuation_branch=`larch parse-package-name $continuation_revision`
  continuation_vsn=`larch parse-package-name --vsn $continuation_revision`
  continuation_lvl=`larch parse-package-name --patch-level $continuation_revision`

fi



################################################################
# What Revision Comes Next?
# 


preclude_fix()
{
  if test $fix -ne 0 ; then
    printf "commit: too early for versionfix patches\\n" 1>&2
    printf "\\n" 1>&2
    printf "  version-0 patch level doesn't exist yet.\\n" 1>&2
    printf "\\n" 1>&2
    printf "Try \"--seal\" (see \"larch commit --help\").\\n" 1>&2
    printf "\\n" 1>&2
    bail
  fi
}

all_levels="`larch revisions -R \"$archroot\" -A \"$archive\" --reverse \"$version\"`"

if test "x$all_levels" = x ; then

  if test $continuation -ne 0 ; then
    lvl=base-0
  else
    printf "commit: version has no revisions yet\\n" 1>&2
    printf "\\n" 1>&2
    printf "  version: %s\\n" $version 1>&2
    printf "\\n" 1>&2
    printf "Try \"larch import --help\" or \"commit --continuation\" instead.\\n" 1>&2
    printf "\\n" 1>&2
    bail
  fi

else

  latest_lvl=`first $all_levels`

  case "$latest_lvl" in
    base-0)		preclude_fix
			if test $seal -eq 0 ; then
    			  lvl=patch-1
			else
			  lvl=version-0
			fi
    			;;

    patch-*)		preclude_fix
		        if test $seal -eq 0 ; then
			  lvl="patch-$((${latest_lvl#patch-} + 1))"
			else
			  lvl=version-0
			fi
			;;

    version-0|versionfix-*)

    			lvl="versionfix-$((${latest_lvl##*-} + 1))"
			if test $fix -eq 0 ; then
			  printf "commit: too late for ordinary patches\\n" 1>&2
			  printf "\\n" 1>&2
			  printf "  version-0 already exists.\\n" 1>&2
			  printf "\\n" 1>&2
			  printf "Try \"--fix\" (see \"larch commit --help\").\\n" 1>&2
			  printf "\\n" 1>&2
			  bail
			fi
			;;

    
  esac

fi


# Conditions
#
#   lvl set to the patch level name for the revision 
#     we should create
# 
#   latest_lvl set to the patch level name of the previous revision 
# 
################################################################
# Is the Working Dir Sufficiently Up to Date
# 
# 
#

if test $out_of_date_ok -eq 0 ; then

  cd "$wdroot"

  missing=

  for rev in $all_levels ; do
    if test ! -e "{arch}/$category/$branch/$version/$archive/patch-log/$rev" ; then
      missing="$rev $missing"
    fi
  done

  if test "x$missing" != x ; then
    printf "commit: project tree out of date\\n" 1>&2
    printf "\\n" 1>&2
    printf "  Working directory is missing these patches:\n" 1>&2
    printf "\\n" 1>&2
    for m in $missing ; do
      printf "\t%s\\n" $m 1>&2
    done
    printf "\\n" 1>&2
    printf "  Unable to complete \"commit\".\\n" 1>&2
    printf "\\n" 1>&2
    printf "Try \"larch update --help\" or \"larch commit --out-of-date-ok\"\\n" 1>&2
    printf "\\n" 1>&2
    bail 
  fi

fi


################################################################
# Lint the Source Tree
# 

if test -z "$no_lint" ; then
  cd "$wdroot"

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



################################################################
# Get a Pristine Copy of the Previous Revision to Compare With
# 

cd "$tmpdir"

if test ! -z "$report" ; then
  larch heading --sub "finding (or making) previous revision for comparison\\n"
  if test ! -z "$verbose" ; then
    larch heading --sub --sub "start time: %s\\n" "`date`"
  fi
fi

if test $continuation -eq 0 ; then

  prev_archive="$archive"
  prev_category="$category"
  prev_branch="$branch"
  prev_vsn="$vsn"
  prev_lvl="$latest_lvl"

else

  prev_archive="$continuation_archive"
  prev_category="$continuation_category"
  prev_branch="$continuation_branch"
  prev_vsn="$continuation_vsn"
  prev_lvl="$continuation_lvl"

fi

if test -e "$wdroot/{arch}/++pristine-trees/locked/$prev_category/$prev_branch/$prev_branch--$prev_vsn/$prev_archive/$prev_branch--$prev_vsn--$prev_lvl" ; then

  prev_tree="$wdroot/{arch}/++pristine-trees/locked/$prev_category/$prev_branch/$prev_branch--$prev_vsn/$prev_archive/$prev_branch--$prev_vsn--$prev_lvl"

elif test -e "$wdroot/{arch}/++pristine-trees/unlocked/$prev_category/$prev_branch/$prev_branch--$prev_vsn/$prev_archive/$prev_branch--$prev_vsn--$prev_lvl" ; then

  prev_tree="$wdroot/{arch}/++pristine-trees/unlocked/$prev_category/$prev_branch/$prev_branch--$prev_vsn/$prev_archive/$prev_branch--$prev_vsn--$prev_lvl"

elif larch library-find --silent -A "$prev_archive" "$prev_branch--$prev_vsn--$prev_lvl" > /dev/null ; then

  prev_tree="`larch library-find -A \"$prev_archive\" \"$prev_branch--$prev_vsn--$prev_lvl\"`"

else

  mkdir "$tmpdir/,,prev_tree"
  cd  "$tmpdir/,,prev_tree"

  if ! larch nested \
	   larch build-revision -R "$archroot" -A "$prev_archive" \
  			       --silent $quiet_opt $report_opt $verbose_opt $debug_opt \
			       --cache "$wdroot/.." "$prev_branch--$prev_vsn--$prev_lvl" ; then
    bail
  fi

  cd "$tmpdir"
  larch wd-mv-pristine "$prev_archive" "$prev_branch--$prev_vsn--$prev_lvl" ,,prev_tree "$wdroot"
  prev_tree="$wdroot/{arch}/++pristine-trees/unlocked/$prev_category/$prev_branch/$prev_branch--$prev_vsn/$prev_archive/$prev_branch--$prev_vsn--$prev_lvl"

fi

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

# Conditions
#
#   prev_tree points to a pristine tree for the previous revision
# 
################################################################
# Smudge the ChangeLogs
# 
# Sleaze, pure and simple -- to force the ChangeLogs to show up in 
# the new or modified files lists of the patch set.
# 

if test ! -z "$report" ; then
  larch heading --sub "finding automated ChangeLogs\\n"
fi

cd "$wdroot"

larch inventory $method --source --all --files --tags | sort -k 2 > "$tmpdir/,,mod-tree-files-index"

touch "$tmpdir/,,automated-changelogs"

for cl in `cut -s -f 1 "$tmpdir/,,mod-tree-files-index" | grep -E -e "^.*(/ChangeLog|/ChangeLog\\..*)$" | cat` ; do
  #
  # Is the tree file an automated ChangeLog for which the
  # tree has a patch log?
  # 
  magic="`head -1 "$cl" | grep \"automatically generated by arch changelog\" | cat`"

  if test ! -z "$magic" ; then

    cl_version="`head -5 \"$cl\" | grep \"^# tag: automatic-ChangeLog--\" | head -1 | sed -e \"s/^# tag: automatic-ChangeLog--//\"`"

    if ! test ! -z "$cl_version" && larch wd-check-for-patch-log "$cl_version" "$tree" 2> /dev/null ; then
      magic=
    fi

  fi

  if test ! -z "$magic" ; then

    if test ! -z "$report" ; then
      printf "$cl\\n" | larch body-indent --nonl --sub
    fi

    perms="`file-metadata --symlink --permissions \"$cl\"`"
    chmod u+w "$cl"
    printf "\\n" >> "$cl"
    set-file-metadata $perms "$cl"

    printf "%s\\n" "$cl" >> "$tmpdir/,,automated-changelogs"

  fi

done

if test ! -z "$report" ; then
  if test ! -z "`head -n 1 \"$tmpdir/,,automated-changelogs\"`" ; then 
    printf "\\n" | larch body-indent --sub
  else
    printf "none\\n" | larch body-indent --sub
  fi
fi


################################################################
# Make a Patch Set Between The two Trees
# 

if test ! -z "$report" ; then
  larch heading --sub "making patch set\\n" 
fi

cd "$tmpdir"

larch nested \
  larch mkpatch $method $silent_opt $quiet_opt $report_opt $verbose_opt $debug_opt "$prev_tree" "$wdroot" ,,patch-set

################################################################
# Modify the Patch Set to Include the Wrong Log File
# 

larch patch-add-log ,,patch-set "$archive/$version--$lvl" "$logfile"


################################################################
# Compute the Changed File Sets
# 
# 

cd "$wdroot"
touch "$tmpdir/,,log-ls"
for v in `larch logs` ; do
  for p in `larch log-ls $v` ; do
    printf "%s--%s\\n" $v $p >> "$tmpdir/,,log-ls"
  done
done
printf "%s/%s\\n" "$archive" "$version--$lvl" >> "$tmpdir/,,log-ls"

cd "$prev_tree"
touch "$tmpdir/,,prev-patches"
for v in `larch logs` ; do
  for p in `larch log-ls $v` ; do
    printf "%s--%s\\n" $v $p  >> "$tmpdir/,,prev-patches"
  done
done

cd "$tmpdir"

rm -f ,,tmp
mv ,,log-ls ,,tmp
sort ,,tmp > ,,log-ls

rm -f ,,tmp
mv ,,prev-patches ,,tmp
sort ,,tmp > ,,prev-patches
rm -f ,,tmp

comm -2 -3 ,,prev-patches ,,log-ls > ,,prev-only-patches
comm -1 -3 ,,prev-patches ,,log-ls > ,,wd-only-patches

cd "$tmpdir/,,patch-set/patches"
find . -type f \
| grep -E -e '\.(link-mod|modified|patch|meta-mod)$' \
| sed -e "s/\.[^.]*$//" \
| sort -u \
> "$tmpdir/,,modified-files"

cd "$tmpdir/,,patch-set/patches"
find . -type f -name "=dir-meta-mod" \
| xargs -n 1 need-args dirname \
| sort \
> "$tmpdir/,,modified-dirs"


################################################################
# Has Anything Really Changed?
# 
# 

cd "$tmpdir"

( printf "%s\\n" "./{arch}" ; \
  printf "%s\\n" "./{arch}/$category" ; \
  printf "%s\\n" "./{arch}/$category/$branch" ; \
  printf "%s\\n" "./{arch}/$category/$branch/$version" ; \
  printf "%s\\n" "./{arch}/$category/$branch/$version/$archive" ; \
  printf "%s\\n" "./{arch}/$category/$branch/$version/$archive/patch-log" ) \
| sed -e '{
	    s,[/$*[\\],\\&,g
	    s,^,/^,
	    s,$,$/d,
	  }' \
> ,,ignored-dirs-sed-script

if test  -z "$unchanged_ok" \
         -a -z "`cat ,,prev-only-patches ,,modified-dirs | head -1`" \
         -a  -z "`cat ,,modified-files | sed -e '/^.\/ChangeLog\(\..*\)\{0,1\}$/d' | head -1`" \
	 -a "`cat ,,wd-only-patches`" = "$archive/$version--$lvl" \
    	 -a "`join -v 2 -o 2.1 -1 2 -2 2 ,,patch-set/orig-files-index ,,patch-set/mod-files-index`" = "./{arch}/$category/$branch/$version/$archive/patch-log/$lvl" \
	 -a  -z "`join -v 1 -o 1.1 -1 2 -2 2 ,,patch-set/orig-files-index ,,patch-set/mod-files-index | head -1`" \
	 -a  -z "`join -v 2 -o 2.1 -1 2 -2 2 ,,patch-set/orig-dirs-index ,,patch-set/mod-dirs-index | sed -f ,,ignored-dirs-sed-script | head -1`" \
	 -a  -z "`join -v 1 -o 1.1 -1 2 -2 2 ,,patch-set/orig-dirs-index ,,patch-set/mod-dirs-index | head -1`" \
; then

  # nothing changed -- without the --unchanged-ok option
  # 
  if test ! -z "$quiet" ; then
    larch heading --sub "project tree unchanged except for log entries\\n"
    printf "no commit will take place (use --unchanged-ok to override)\\n" | larch body-indent --sub
    larch heading --sub "commit finish time: %s\\n" "`date`"
    larch heading --sub "commit exit status: 0\\n"
  fi

  cd "$wdroot"
  rm -rf "$tmpdir"
  exit 0
fi

################################################################
# Fix Up the Log File
# 

if test ! -z "$report" ; then
  larch heading --sub "mangling the log file\\n"
fi

cd "$wdroot"
cp "$logfile" "$tmpdir/,,raw-log"

cd "$tmpdir"

(   printf "Revision: %s\\n" $version--$lvl \
 && printf "Archive: %s\\n" $archive \
 && printf "Creator: %s\\n" "`larch my-id`" \
 && printf "Date: %s\\n" "`date`" \
 && printf "Standard-date: %s\\n" "`date -u \"+%Y-%m-%d %H:%M:%S GMT\"`" \
 && sed -e "/^\$/,\$d" ,,raw-log \
 && (  join -v 2 -o 2.1 -1 2 -2 2 ,,patch-set/orig-files-index ,,patch-set/mod-files-index \
     | sed -e 's,^\./,,' \
     | unfold -w 60 \
     | sed -e "1s/^/New-files: /" -e "1!s/^/  /" ) \
 && (  join -v 2 -o 2.1 -1 2 -2 2 ,,patch-set/orig-dirs-index ,,patch-set/mod-dirs-index \
     | sed -e 's,^\./,,' \
     | unfold -w 60 \
     | sed -e "1s/^/New-directories: /" -e "1!s/^/  /" ) \
 && (   join -v 1 -o 1.1 -1 2 -2 2 ,,patch-set/orig-files-index ,,patch-set/mod-files-index \
      | sed -e 's,^\./,,' \
      | unfold -w 60 \
      | sed -e "1s/^/Removed-files: /" -e "1!s/^/  /" ) \
 && (  join -v 1 -o 1.1 -1 2 -2 2 ,,patch-set/orig-dirs-index ,,patch-set/mod-dirs-index \
     | sed -e 's,^\./,,' \
     | unfold -w 60 \
     | sed -e "1s/^/Removed-directories: /" -e "1!s/^/  /" ) \
 && (  awk -f "$ARCH_SUBCMD_ROOT/patch-sets/compute-renamed.awk" \
       	   ",,patch-set/orig-dirs-index" ",,patch-set/mod-dirs-index" \
           ",,patch-set/orig-files-index" ",,patch-set/mod-files-index" \
     | cut -s -d ' ' -f 1,2 \
     | sed -e 's,^\./,,' -e 's, ./, ,' \
     | unfold -w 60 \
     | sed -e "1s/^/Renamed-files: /" -e "1!s/^/  /" ) \
 && (  awk -f "$ARCH_SUBCMD_ROOT/patch-sets/compute-renamed.awk" \
       	   ",,patch-set/orig-dirs-index" ",,patch-set/mod-dirs-index" \
           ",,patch-set/orig-dirs-index" ",,patch-set/mod-dirs-index" \
     | cut -s -d ' ' -f 1,2 \
     | sed -e 's,^\./,,' -e 's, ./, ,' \
     | unfold -w 60 \
     | sed -e "1s/^/Renamed-directories: /" -e "1!s/^/  /" ) \
 && ( cat ,,modified-files | sed -e 's,^\./,,' | unfold -w 60 | sed -e "1s/^/Modified-files: /" -e "1!s/^/  /" ) \
 && ( cat ,,modified-dirs | sed -e 's,^\./,,' | unfold -w 60 | sed -e "1s/^/Modified-directories: /" -e "1!s/^/  /" ) \
 && ( cat ,,wd-only-patches | sed -e 's,^\./,,' | unfold -w 60 | sed -e "1s/^/New-patches: /" -e "1!s/^/  /" ) \
 && ( cat ,,prev-only-patches | sed -e 's,^\./,,' | unfold -w 60 | sed -e "1s/^/Removed-patches: /" -e "1!s/^/  /" ) )\
> ,,cooked-log

if test $continuation -ne 0 ; then
  printf "Continuation-of: %s\\n" "$continuation_archive/$continuation_branch--$continuation_vsn--$continuation_lvl" >> ,,cooked-log
fi

(   printf "\\n" \
 && sed -e "1,/^\$/d" ,,raw-log )\
>> ,,cooked-log

if test ! -z "$quiet" ; then
  sed -e "/^\$/,\$d" ,,cooked-log | larch body-indent --sub
fi

################################################################
# Put the Right Log File in the Patch Set
# 

cd "$tmpdir"
new_file_in_patch=",,patch-set/new-files-archive/{arch}/$category/$branch/$version/$archive/patch-log/$lvl"
rm -f "$new_file_in_patch"
cp ,,cooked-log "$new_file_in_patch"


################################################################
# Fix Up the ChangeLogs as they Appears in the Patch Set
# 

if test ! -z "$report" ; then
  larch heading --sub "updating automated ChangeLogs\\n"
fi

cd "$wdroot"

sort -k 1 "$tmpdir/,,patch-set/mod-files-index" > "$tmpdir/,,mod-files-index-by-name"

for cl in `cat "$tmpdir/,,automated-changelogs"` ; do

  if test ! -z "$report" ; then
    printf "$cl" | larch body-indent --sub
  fi

  cl_version="`head -5 \"$cl\" \
               | grep -E \"^(# line of development: |# (non-)?tag: automatic-ChangeLog--)\" \
	       | head -1 \
	       | sed -e \"s/^# tag: automatic-ChangeLog--//\" \
	       	     -e \"s/^# non-tag: automatic-ChangeLog--//\" \
	       	     -e \"s/^# line of development: //\"`"


  if head -5 "$cl" | grep -q "^(# line of development: |# non-tag: automatic-ChangeLog--)" ; then
    untagged=--untagged
  else
    untagged=
  fi

  if test "$archive/$version" = "$cl_version" ; then
    larch changelog $untagged --new-entry "$lvl,$tmpdir/,,cooked-log" "$archive/$version" > "$cl"
  else
    larch changelog $untagged "$cl_version" > "$cl"
  fi

  # where is the changelog in the prev tree?
  # 
  prev_changelog_file="`printf \"%s\\n\" \"$cl\" \
		        | join -o 2.2 -1 1 -2 1 - \"$tmpdir/,,mod-files-index-by-name\" \
			| join -o 2.1 -1 1 -2 2 - \"$tmpdir/,,patch-set/orig-files-index\"`"

  if test -e "$tmpdir/,,patch-set/patches/$cl.patch" ; then
    set +e
    diff -u "$prev_tree/$prev_changelog_file" "$cl" >  "$tmpdir/,,patch-set/patches/$cl.patch"
    diff_stat=$?
    set -e
    if test $diff_stat -ne 0 -a $diff_stat -ne 1 ; then
      printf "commit: internal error updating %s\\n" "$cl.patch" 1>&2
      printf "  original file: %s\\n" "$prev_tree/$prev_changelog_file" 1>&2
      printf "  modified file: %s\\n" "$cl" 1>&2
      printf "  diff exit status: %d\\n" $diff_stat 1>&2
      printf "\\n"
      exit 1
    fi
  elif test -e "$tmpdir/,,patch-set/new-files-archive/$cl" ; then
    rm -f  "$tmpdir/,,patch-set/new-files-archive/$cl"
    cp -p "$cl"  "$tmpdir/,,patch-set/new-files-archive/$cl"
  else
    printf "commit: internal error\\n" 1>&2
    printf "  can't figure out how to modify patch set for %s\\n" "$cl"
    printf "\\n"
  fi
done

if test ! -z "$report" ; then
  if test ! -z "`head -n 1 \"$tmpdir/,,automated-changelogs\"`" ; then 
    printf "\\n" | larch body-indent --sub
  else
    printf "none\\n" | larch body-indent --sub
  fi
fi

# Conditions
#
#   $tmpdir/,,patch-set		-- patch set for new revision
#   $tmpdir/,,cooked-log	-- log file for new revision
#   $tmpdir/$version--$lvl	-- pristine tree of new revision
#
################################################################
# Construct the larch Template Dir
# 
#

if test ! -z "$report" ; then
  larch heading --sub "assembling the archive directory\\n"
  if test ! -z "$verbose" ; then
    larch heading --sub --sub "start time: %s\\n" "`date`"
  fi
fi

tmparch="$tmpdir/,,arch"
tmparch2="$tmpdir/arch"

mkdir "$tmparch"

mv "$tmpdir/,,patch-set" "$tmparch/$version--$lvl.patches"
cd "$tmparch"
tar -zcf "$version--$lvl.patches.tar.gz" "$version--$lvl.patches"
mv "$version--$lvl.patches" ../,,patch-set

cp "$tmpdir/,,cooked-log" "$tmparch/log"

cd "$tmparch"

larch make-lock revision-lock

if test $continuation -ne 0 ; then
  printf "%s\\n" "$continuation_archive/$continuation_branch--$continuation_vsn--$continuation_lvl" > CONTINUATION
fi

mv "$tmparch" "$tmparch2"

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

# Conditions
# 
#   $tmparch2			-- template of revision directory
#   $prev_tree			-- points to previous revision
# 
# $tmpdir has these files:
#    
#    ,,wd-dirs		Various specialized file lists
#    ,,wd-files
#    ,,log-ls
#    
#    ,,prev-dirs
#    ,,prev-files
#    ,,prev-patches
#    
#    ,,wd-only-dirs	Various file list diffs and intersections
#    ,,prev-only-dirs
#    
#    ,,wd-only-files
#    ,,prev-only-files
#    ,,files-in-both
#    
#    ,,wd-only-patches
#    ,,wd-only-patches
#    
#    ,,modified-files	List of modified files
#    
#    ,,raw-log		Log as written by user
#    
#    ,,cooked-log	Log with headers added
#    
#    ,,patch-set	The pach-set tree
#    
#    arch		A template of the archive directory
# 
#    $version--$lvl	A copy of the project tree
# 
# 
# 
# 
################################################################
# Install the Arch Template Dir or Clean Up the Output Dir
# 
# 

status=0

if test -z "$dry_run" ; then

  if test ! -z "$quiet" ; then
    larch heading --sub "installing the archive directory in the archive\\n"
    if test ! -z "$verbose" ; then
      larch heading --sub --sub "start time: %s\\n" "`date`"
    fi
  fi

  # where does this get stored in the archive?
  # 
  destdir="$category/$branch/$version/$lvl"

  wftp-home

  if ! larch putlast -e commit -R "$archroot" -A "$archive" \
                    lock-revision "$version--$lvl" \
                    "$tmparch2" "$destdir" \
                    wd-txn "$wdroot" "$archive" "$version--$lvl" "$tmparch2/log" \
  ; then

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

    status=1

  else

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

    if larch my-notifier > /dev/null 2>&1 ; then
      notifier="`larch my-notifier`"
      ( cd "$notifier" ; \
        larch without-archive as-daemon $ARCH_LOG_OPTION --null-output larch notify "$notifier" "$archive/$version" )
    fi

    if test ! -z "$report" ; then
      larch heading --sub "updating local cache to include new revision\\n"
    fi

    cd "$tmpdir"
    mkdir ,,new-pristine
    cd ,,new-pristine


    cached_for_this_wd=`larch pristines --unlocked --dir "$wdroot" "$prev_archive/$prev_branch--$prev_vsn--$prev_lvl"`

    if test -z "$cached_for_this_wd" ; then

      if test ! -z "$report" ; then
        larch heading --sub --sub "building revision from scratch\\n"
      fi

      larch nested --sub \
	larch build-revision -A "$archive" \
  	 	            --silent $quiet_opt $report_opt $verbose_opt $debug_opt \
			    --cache "$wdroot/.." \
	    		    "$prev_branch--$prev_vsn--$prev_lvl"

    else
      
      if test ! -z "$report" ; then
        larch heading --sub --sub "recycling cached pristine revision\\n"
      fi

      larch take-from-cache "$prev_archive/$prev_branch--$prev_vsn--$prev_lvl"

    fi

    larch dopatch $method --delete-removed --quiet $report_opt $verbose_opt $debug_opt "$tmpdir/,,patch-set" .

    cd "$tmpdir"
    larch wd-mv-pristine $archive $version--$lvl "$tmpdir/,,new-pristine" "$wdroot"

    cd "$wdroot"
    rm -rf "$tmpdir"
    rm -f "$logfile~"
    mv "$logfile" "$logfile~"

  fi

else

  cd "$tmpdir"

  mv ,,patch-set patch-set

  ln -s "$prev_tree" $prev_branch--$prev_vsn--$prev_lvl

  if test -z "$quiet" ; then
    larch heading --sub "output in %s\\n" "$tmpdir"
  fi

fi

if test ! -z "$quiet" ; then
  larch heading --sub "commit finish time: %s\\n" "`date`"
  larch heading --sub "commit exit status: %d\\n" "$status"
fi

exit $status

# tag: Tom Lord Thu Dec 13 16:04:36 2001 (archive-transactions/fast-commit.sh)
#
