# 
# 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 " --strict                      strict tree-lint (warnings->errors)\\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 "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=

strict=

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

dir=.

while test $# -ne 0 ; do

  case "$1" in 

    --strict)  shift
               strict=--strict
               ;;

    -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
                ;;


    -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"


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

cd "$wdroot" 

larch tagging-method --strict > /dev/null

larch valid-log-file -e import -- "$logfile" "$wdroot"

larch nested larch tree-lint $strict "$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

rm -rf "$tmpdir"
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
# 
# 
  
sort_fqrn_list()
{
  sed -e 's+\(.*\)/\(.*\)--\(.*\)--\([0-9]*\)\.\([0-9]*\)--\(.*\)-\([0-9]*\)+\1,\2,\3,\4,\5,\6,\7+' \
      -e 's+\(.*\)/\(.*\)--\([0-9]*\)\.\([0-9]*\)--\(.*\)-\([0-9]*\)+\1,\2,,\3,\4,\5,\6+' \
  | sort -u -t, -k 1,1 -k2,2 -k3,3 -k4,4n -k5,5n -k6,6 -k7,7n \
  | sed -e 's+^\(.*\),\(.*\),,\(.*\),\(.*\),\(.*\),\(.*\)+\1/\2--\3.\4--\5-\6+' \
        -e 's+^\(.*\),\(.*\),\(.*\),\(.*\),\(.*\),\(.*\),\(.*\)+\1/\2--\3--\4.\5--\6-\7+' 
}


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" ) \
      | sort_fqrn_list \
      | 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

################################################################
# Phase Shift
# 
# This is really vestigial.
# 

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


################################################################
# 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

