#!/bin/sh
# 
# import.sh - archive a from scratch base 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 from-scratch base revision\\n"
                printf "usage: import [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 "\\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 " --begin                       prepare a revision for check-in\\n"
		printf "                               but do not modify the archive.\\n"
                printf " --finish\\n"
                printf "\\n"
                printf "Archive a from-scratch base revision of the project tree\\n"
                printf "containing DIR (or the current directory)\\n"
                printf "\\n"
                printf "1) Make the selected version and archive the defaults for this working\\n"
                printf "directory (unless -d (--not-default) is specified).\\n"
                printf "\\n"
                printf "2) In a scratch directory, make a pristine copy of the source tree.\\n"
                printf "Install the log file in the patch log of the pristine source tree.\\n"
                printf "\\n"
                printf "3) In the same scratch directory, create a template for the revision\\n"
		printf "directory.  The revision directory is what will eventually be installed\\n"
		printf "in the archive.\\n"
                printf "\\n"
                printf "4) Lock the revision in the archive.  This step will fail if someone else\\n"
		printf "has already committed the same revision.\\n"
                printf "\\n"
    		printf "5) Copy the template for the revision directory to a temporary directory\\n"
                printf "in the archive.\\n"
                printf "\\n"
                printf "6) Mark the project tree as \"might be in a weird sate.\"  A weird state\\n"
                printf "occurs if the revision is committed in the archive, but the project tree\\n"
                printf "hasn't yet been updated to reflect that fact.\\n"
                printf "\\n"
                printf "7) Commit the change to the archive.  This will fail if someone got there\\n"
                printf "first and broke your lock.\\n"
                printf "\\n"
                printf "8) Mark the project tree as definately weird.\\n"
                printf "\\n"
                printf "9) Modify the project tree to reflect the fact that the commit suceeded.\\n"
                printf "\\n"
                printf "10) Mark the project tree as not weird at all.\\n"
                printf "\\n"
                printf "11) Clean up by removing various temporary files in the project tree.\\n"
                printf "\\n"
                printf "If a project tree winds up in a \"maybe weird\" or \"definately weird\"\\n"
                printf "state, try the command \"larch tree-repair --help\" to learn how to recover.\\n"
                printf "\\n"
                exit 0
                ;;

      *)
                ;;
    esac
  done
fi

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

archroot=
archive=
not_default=
logfile=

begin=1
finish=1

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

dir=.

while test $# -ne 0 ; do

  case "$1" in 

    -d|--dir)  shift
               if test $# -eq 0 ; then
                  printf "import: -d and --dir require an argument\\n" 1>&2
                  printf "try --help\\n" 1>&2
                  exit 1
	       fi
	       dir="$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 "import: debugging output enabled\\n"
    		set -x
		debug_opt=--debug
		;;

    --begin)		shift
    			begin=1
    			finish=0
			;;

    --finish)		shift
			begin=0
			finish=1
			;;

    -R|--root)          shift
                        if test $# -eq 0 ; then
                          printf "import: -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 "import: -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 "import: -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
                        not_default=--not-default
                        ;;

    --)			shift
    			break
			;;

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

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

################################################################
# Sanity Check and Process Defaults
# 
  
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 import --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`
patchlvl=base-0

destdir=$category/$branch/$version/$patchlvl
  
tmpdir="$wdroot/,,commit-tmp-dir"
tmptree="$tmpdir/$version--$patchlvl"
tmparch="$tmpdir/,,$patchlvl"
tmparch2="$tmpdir/$patchlvl"

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


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

if test ! -z "$quiet" ; then
  larch heading "import\\n"
  printf "arguments: %s\\n" "$command_line" | fold -w 60 | larch body-indent
  larch heading --sub "import 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"
  larch heading --sub "patch level: %s\\n" "$patchlvl"
fi

################################################################
# Check Roughly That the Version Can Be Created
# 
# Does the wd have a patch log for this version?
# 

larch wd-check-for-patch-log -e import -R "$archroot" -A "$archive" "$version" "$wdroot"


################################################################
# This Script Comes in Two Parts
# 
# This script has a `begin' half, and a `finish' half.
# It can either run both in succession, or either one
# by itself.
# 
# The idea here is that if you are being very careful, 
# you can run the `begin' half, review the results, then
# run the `finish' half.
# 
# First, here are some computed values needed by both the
# begin and the finish half:
# 


################################################################
# The --begin Half of the Script:
# 

if test $begin = 1 ; then

  ################################################################
  # Did --begin Already Start to Run in this Working Directory?
  # 

  if test -e "$tmpdir" ; then
    if test -e "$tmpdir/,,,import" ; then
      operation=import
    else
      operation=commit
    fi

    printf "\\n" 1>&2
    printf "import: fatal error\\n" 1>&2
    printf "\\n" 1>&2
    printf "A temporary directory for a %s operation already exists:\\n" "$operation" 1>&2
    printf "\\n" 1>&2
    printf "	%s\\n" "$tmpdir" 1>&2
    printf "\\n" 1>&2

    ################################################################
    # Did --begin Run to Completion?
    # 

    if test $operation != import ; then
      printf "It appears that you have already started some other\\n" 1>&2
      printf "form of commit but that it did not run to completion.\\n" 1>&2
      printf "\\n" 1>&2
      printf "If you started that other commit with --begin, consider\\n" 1>&2
      printf "finishing it with --end.  Otherwise, remove the temporary\\n" 1>&2
      printf "directory and try again.\\n" 1>&2
      printf "\\n" 1>&2
    elif test -e "$tmparch2" ; then
      printf "It appears that you have already run \"import --begin\".\\n" 1>&2
      printf "Consider trying \"larch import --finish\" now.\\n" 1>&2
      printf "\\n" 1>&2
      printf "\\n" 1>&2
    else
      printf "It appears that a previous \"import\" or \"import --begin\" did\\n" 1>&2
      printf "run to completion.\\n" 1>&2
      printf "\\n" 1>&2
      printf "The recommeded recovery is to remove the temporary directory and\\n" 1>&2
      printf "try again.\\n" 1>&2
      printf "\\n" 1>&2
    fi

    exit 1
  fi


  ################################################################
  # Sanity Check and Process Defaults
  # 
  
  larch valid-log-file -e import -- "$logfile" "$wdroot"

  larch nested larch tree-lint "$wdroot"
  

  ################################################################
  # Set the Default Version for the Working Dir
  # 

  if test -z "$not_default" ; then

    if test ! -z "$report" ; then
      larch heading --sub "set default tree version\\n"
      larch heading --sub --sub "archive: %s\\n" "$archive"
      larch heading --sub --sub "version: %s\\n" "$version"
    fi

    cd "$wdroot"
    larch set-tree-version "$archive/$version"

  fi

  ################################################################
  # Make Temp Dir for our Work
  # 
  # Note that we create the temp dir at the root of the working 
  # directory.  Note that the temp dir must not already exist.
  # If it does, we fail, because that might indicate a concurrent
  # import attempt for the same wd.  We trust the user to be
  # smart enough to remove the temp dir if she sees an error message
  # from mkdir.
  # 
  # The temp dir MUST have a temporary name, otherwise, it will
  # appear to be source and will be recursively copied into the
  # (now infinite) pristine copy of the source.
  # 
  
  bail()
  {
    cd "$wdroot"
    rm -rf "$tmpdir"
    exit 1
  }

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

  mkdir "$tmpdir"
  touch "$tmpdir/,,,import"

  
  ################################################################
  # Create a Temp Dir for the Branch Revision Template
  # 
  #
  
  mkdir "$tmparch"
  cd "$tmparch"
  larch make-lock revision-lock
  
  ################################################################
  # Build the Pristine Tree
  # 
  
  if test ! -z "$report" ; then
    larch heading --sub "make a pristine copy of source tree\\n"
    larch heading --sub --sub "start time: %s\\n" "`date`"
  fi

  cd "$wdroot"
  mkdir "$tmptree"
  
  # Copy the Source
  # 
  larch inventory --source --all \
  | copy-file-list -- - . "$tmptree"

  if test ! -z "$report" ; then
    larch heading --sub --sub "finish time: %s\\n" "`date`"
  fi
  
  ################################################################
  # Sanity check 2
  # 
  # Double check that the pristine tree has a patch log for this
  # version.
  # 

  cd "$tmptree"
  larch wd-check-for-patch-log -e import -R "$archroot" -A "$archive" "$version" "$wdroot"
  
  ################################################################
  # Install the Log File in the Pristine Tree Patch Log and Revision Template
  # 
  # 
  
  if test ! -z "$report" ; then
    larch heading --sub "mangle log entry\\n"
  fi

  cd "$wdroot"
  cp "$logfile" "$tmparch/,,log"
  cd "$tmparch"

  # 
  # start by installing the wrong log file
  # 
  larch copy-to-patch-log -R "$archroot" -A "$archive" "$tmparch/,,log" $version $patchlvl "$tmptree"


  (   printf "Revision: %s\\n" $version--$patchlvl \
   && 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" ,,log \
   && ( cd "$tmptree" ; larch inventory --source --all | grep -v -F "./{arch}" | sed -e "s/\\n/ /" | unfold -w 60 | sed -e "1s/^/New-files: /" -e "1!s/^/  /" ) \
   && ( cd "$tmptree" ; \
        ( larch logs | xargs -n 1 need-args "larch log-ls --full" ) \
        | unfold -w 60 \
        | sed -e "1s/^/New-patches: /" -e "1!s/^/  /" ) \
   && printf "\\n" \
   && sed -e "1,/^\$/d" ,,log ) \
  > log

  rm ,,log

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

  # 
  # now install the right log file
  # 
  larch copy-to-patch-log -R "$archroot" -A "$archive" "$tmparch/log" $version $patchlvl "$tmptree"

  ################################################################
  # Store the tar.gz File in the Revision Template 
  #
  
  if test ! -z "$report" ; then
    larch heading --sub "creating tar file of source\\n"
    larch heading --sub --sub "start time: %s\\n" "`date`"
  fi

  cd "$tmpdir"
  tar -zcf "$tmparch/$version--$patchlvl.src.tar.gz"  "$version--$patchlvl"
  
  if test ! -z "$report" ; then
    larch heading --sub --sub "tar file details\\n"
    (cd "$tmparch" ; ls -l $version--$patchlvl.src.tar.gz) | larch body-indent --sub --sub
    larch heading --sub --sub "finish time: %s\\n" "`date`"
  fi

  ################################################################
  # Finish --begin
  # 
  # The pristine tree and revision template are now ready.  Record
  # that --begin ran to completion by renaming the archive template:
  # 

  cd "$tmpdir"
  mv "$tmparch" "$tmparch2"

  ################################################################
  # Give Advice
  # 

  if test $finish -eq 0 -a ! -z "$quiet" ; then
    larch heading --sub "import finish time: %s\\n" "`date`"
    larch heading --sub --sub "pristine project tree: %s\\n" "$tmptree"
    larch heading --sub --sub "archive data: %s\\n" "$tmparch2"
    exit 0
  fi
  
fi

################################################################
# The --finish Half of the Script:
# 

if test $finish = 1 ; then

  ################################################################
  # Did --begin Already Start to Run in this Working Directory?
  # 

  if test ! -e "$tmpdir" ; then
    printf "\\n" 1>&2
    printf "import: fatal error\\n" 1>&2
    printf "\\n" 1>&2
    printf "You have not run --begin for this import yet.  This directory\\n" 1>&2
    printf "was not found:\\n" 1>&2
    printf "\\n" 1>&2
    printf "	%s\\n" "$tmpdir" 1>&2
    printf "\\n" 1>&2
    exit 1
   fi


  ################################################################
  # Did --begin Run to Completion?
  # 

  if test ! -e "$tmparch2" ; then
    printf "\\n" 1>&2
    printf "import: fatal error\\n" 1>&2
    printf "\\n" 1>&2
    printf "It appears that you have already run \"import --begin\"\n" 1>&2
    printf "but that it did not run to completion.\\n" 1>&2
    printf "\\n" 1>&2
    printf "The recommeded recovery is to remove the temporary directory and\\n" 1>&2
    printf "try again (from --begin).\\n" 1>&2
    printf "\\n" 1>&2
    printf "The temporary directory is:\\n" 1>&2
    printf "\\n" 1>&2
    printf "	%s\\n" "$tmpdir" 1>&2
    printf "\\n" 1>&2
    exit 1
  fi


  ################################################################
  # Attempt to Commit the Revision
  # 

  status=0

  if test ! -z "$quiet" ; then
    larch heading --sub "storing revision in archive\\n"
    larch heading --sub --sub "transaction start: %s\\n" "`date`"
  fi


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

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

    status=1

  else

    if test ! -z "$quiet" ; then
      larch heading --sub --sub "transaction complete: %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

    larch wd-mv-pristine "$archive" "$version--$patchlvl" "$tmptree" "$wdroot"
    cd "$wdroot"
    rm -rf "$tmpdir"
    rm -f "$logfile~"
    mv "$logfile" "$logfile~"
  fi

  if test ! -z "$quiet" ; then
    if test $status -eq 0 ; then
      larch heading --sub "import complete: %s\\n" "`date`"
    fi
  fi

  exit $status

fi

