# 
# tag.sh: create a continuation revision quickly
################################################################
# 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 "create a continuation revision (tag or branch)\\n"
                printf "usage: tag [options] [archive/]source [archive/]tag\\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 "\\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 "\\n"
                printf "Create the continuation revision TAG-VERSION (branch point or tag)\\n"
                printf "whichis equivalent to SOURCE-VERSION (plus a log entry).\\n"
                printf "\\n"
                printf "If no log entry is provided, a trivial log entry will be created\\n."
                printf "\\n"
                exit 0
                ;;

      *)
                ;;
    esac
  done
fi

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

archroot=
archive=

__restart=

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

seal=
fix=

while test $# -ne 0 ; do

  case "$1" in 

    --fix)      shift
                fix=--fix
                seal=
                ;;

    --seal)     shift
                seal=--seal
                fix=
                ;;

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

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

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

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

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

    *)                  break
                        ;;
  esac

done



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

if test $# -ne 2 ; then
  printf "usage: tag [options] [archive/]source [archive/]tag\\n" 1>&2
  printf "try --help\\n" 1>&2
  exit 1
fi

source_spec="$1"
shift

tag_spec="$1"
shift


################################################################
# Sanity Check and Process Defaults
# 
  
dir="`pwd`"
cd "$dir"
dir="`pwd`"

larch valid-package-name -e tag --tolerant "$source_spec"
source_archive="`larch parse-package-name -R \"$archroot\" -A \"$archive\" --arch \"$source_spec\"`"
source_non_arch="`larch parse-package-name -R \"$archroot\" -A \"$archive\" --non-arch \"$source_spec\"`"

larch valid-package-name -e tag --tolerant "$tag_spec"
tag_archive="`larch parse-package-name -R \"$archroot\" -A \"$archive\" --arch \"$tag_spec\"`"
tag_non_arch="`larch parse-package-name -R \"$archroot\" -A \"$archive\" --non-arch \"$tag_spec\"`"

if test ! -z "$logfile" ; then
  logfile_dir="`dirname \"$logfile\"`"
  logfile_base="`basename \"$logfile\"`"
  cd "$logfile_dir"
  logfile_dir="`pwd`"
  logfile="$logfile_dir/$logfile_base"
  larch valid-log-file -e tag -- "$logfile"
else
  logfile=
  logfile_dir=
  logfile_base=
fi

myid="`larch my-id`"


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

if test "(" -z "$__restart" -a ! -z "$quiet" ")" -o ! -z "$report" ; then
  larch heading "tag\\n"
  printf "arguments: %s\\n"  "$command_line" | fold -w 60 | larch body-indent
  larch heading --sub "tag start time: %s\\n" "`date`"
  larch heading --sub "source archive: %s\\n" "$source_archive"
  larch heading --sub "source spec: %s\\n" "$source_spec"
  larch heading --sub "tag archive: %s\\n" "$tag_archive"
  larch heading --sub "tag spec: %s\\n" "$tag_spec"
fi


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

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

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

  exec larch with-archive -A "$tag_archive" \
      larch tag -A "$tag_archive" \
                  -L "$logfile" \
                  $silent_opt $quiet_opt $report_opt $verbose_opt $debug_opt \
                  ----restart \
                  $seal $fix \
                  "$source_archive/$source_non_arch" \
                  "$tag_archive/$tag_non_arch"
fi



################################################################
# Finish Identifying the Source and Tag Revisions
# 

source_category="`larch parse-package-name --basename \"$source_spec\"`"
source_branch="`larch parse-package-name \"$source_spec\"`"
source_revision="`larch indicated-revision \"$source_archive/$source_non_arch\"`"
source_version="`larch parse-package-name --package-version \"$source_revision\"`"
source_vsn="`larch parse-package-name -v \"$source_revision\"`"
source_lvl="`larch parse-package-name --lvl \"$source_revision\"`"

if test ! -z "$quiet" ; then
  larch heading --sub "source revision: %s\\n" "$source_revision"
fi

tag_category="`larch parse-package-name --basename \"$tag_spec\"`"
tag_branch="`larch parse-package-name \"$tag_spec\"`"

if larch valid-package-name --vsn "$tag_spec" ; then
  tag_version="`larch parse-package-name --package-version \"$tag_spec\"`"
else
  tag_version="`larch versions --reverse \"$tag_archive/$tag_branch\" | head -n 1 || true`"
  if test -z "$tag_version" ; then
    printf "tag: no versions on branch\\n" 1>&2
    printf "  archive: %s\\n" "$tag_archive" 1>&2
    printf "  branch: %s\\n" "$tag_branch" 1>&2
    printf "\\n" 1>&2
    exit 1
  fi
fi

tag_vsn="`larch parse-package-name --vsn \"$tag_version\"`"

if larch valid-package-name --patch-level "$tag_spec" ; then
  tag_previous="`larch indicated-revision \"$tag_archive/$tag_version\" 2> /dev/null || true`"
  tag_requested_lvl="`larch parse-package-name --lvl \"$tag_non_arch\"`"
  tag_specific_lvl=yes
else
  tag_previous="`larch indicated-revision \"$tag_archive/$tag_non_arch\" 2> /dev/null || true`"
  tag_requested_lvl=
  tag_specific_lvl=
fi


if test -z "$tag_previous" ; then
  tag_revision="$tag_version--base-0"
  tag_lvl=base-0
else
  tag_prev_lvl="`larch parse-package-name --lvl \"$tag_previous\"`"
  tag_prev_version="`larch parse-package-name --package-version \"$tag_previous\"`"

  case $tag_prev_lvl in

  base-0|patch-*)       if test ! -z "$fix" ; then
                          printf "tag: too early for --fix\\n" 1>&2
                          printf "  version-0 revision doesn't exist yet\\n" 1>&2
                          printf "  archive: %s\\n" "$tag_archive" 1>&2
                          printf "  version: %s\\n" "$tag_prev_version" 1>&2
                          printf "\\n" 1>&2
                          exit 1
                        fi

                        if test ! -z "$seal" ; then
                          tag_revision="$tag_version--version-0"
                          tag_lvl=version-0
                        else
                          tag_prev_seq=${tag_prev_lvl##*-}
                          tag_lvl="patch-$(($tag_prev_seq + 1))"
                          tag_revision="$tag_version--$tag_lvl"
                        fi
                        ;;

  version-0)            if test ! -z "$fix" ; then
                          tag_lvl=versionfix-1
                          tag_revision="$tag_version--$tag_lvl"
                        elif test ! -z "$seal" ; then
                          printf "tag: too late for --seal\\n" 1>&2
                          printf "  version-0 revision already exists\\n" 1>&2
                          printf "  archive: %s\\n" "$tag_archive" 1>&2
                          printf "  version: %s\\n" "$tag_prev_version" 1>&2
                          printf "\\n" 1>&2
                          exit 1
                        else
                          printf "tag: too late for ordinary revision (try --fix)\\n" 1>&2
                          printf "  version-0 revision already exists\\n" 1>&2
                          printf "  archive: %s\\n" "$tag_archive" 1>&2
                          printf "  version: %s\\n" "$tag_prev_version" 1>&2
                          printf "\\n" 1>&2
                          exit 1
                        fi
                        ;;

  versionfix-*)         if test ! -z "$fix" ; then
                          tag_prev_seq=${tag_prev_lvl##*-}
                          tag_lvl="versionfix-$(($tag_prev_seq + 1))"
                          tag_revision="$tag_version--$tag_lvl"
                        elif test ! -z "$seal" ; then
                          printf "tag: too late for --seal\\n" 1>&2
                          printf "  version-0 revision already exists\\n" 1>&2
                          printf "  archive: %s\\n" "$tag_archive" 1>&2
                          printf "  version: %s\\n" "$tag_prev_version" 1>&2
                          printf "\\n" 1>&2
                          exit 1
                        else
                          printf "tag: too late for ordinary revision (try --fix)\\n" 1>&2
                          printf "  version-0 revision already exists\\n" 1>&2
                          printf "  archive: %s\\n" "$tag_archive" 1>&2
                          printf "  version: %s\\n" "$tag_prev_version" 1>&2
                          printf "\\n" 1>&2
                          exit 1
                        fi
                        ;;
  esac
fi

if test ! -z "$tag_specific_lvl" -a "$tag_requested_lvl" != "$tag_lvl" ; then
  printf "tag: revision out of sequence\\n" 1>&2
  printf "  archive: %s\\n" "$tag_archive" 1>&2
  printf "  version: %s\\n" "$tag_prev_version" 1>&2
  printf "  latest revision: %s\\n" "$tag_prev_lvl" 1>&2
  printf "  requested revision: %s\\n" "$tag_requested_lvl" 1>&2
  printf "\\n" 1>&2
  exit 1
fi
  
if test ! -z "$quiet" ; then
  larch heading --sub "tag revision: %s\\n" "$tag_revision"
fi

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

cd "$dir"
tmpdir="$dir/,,tag--$tag_version--$tag_archive.$$"

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

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

rm -rf "$tmpdir"
mkdir "$tmpdir"


#
################################################################
# Compute the List of Patches in the Continued Revision
# 

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 "$quiet" ; then
  larch heading --sub "finding patches included in tagged revision\\n"
fi

cd "$tmpdir"

larch merge-points $debug_opt "$source_archive/$source_version--$source_lvl" \
| awk '{ print $2 }' \
> ,,included-patches

printf "%s\\n" "$tag_archive/$tag_version--$tag_lvl" >> ,,included-patches


# Conditions
#
#   tag_lvl set to the patch level name for the revision 
#     we should create
# 
################################################################
# Ensure that a Logfile With Added Headers Exists 
# 

if test ! -z "$quiet" ; then
  larch heading --sub "mangling log message\\n" 
fi

cd "$tmpdir"

if test -z "$logfile" ; then
  printf "Summary: tag of %s/%s\\n" "$source_archive" "$source_version--$source_lvl" > ,,logfile-raw
  printf "Keywords: \\n" >> ,,logfile-raw
  printf "\\n" >> ,,logfile-raw
  printf "(automatically generated log message)\\n" >> ,,logfile-raw
  printf "\\n" >> ,,logfile-raw
else
  cp "$logfile" ,,logfile-raw
fi

printf "Revision: %s\\n" "$tag_version--$tag_lvl" > ,,logfile-cooked
printf "Archive: %s\\n" "$tag_archive" >> ,,logfile-cooked
printf "Creator: %s\\n" "$myid" >> ,,logfile-cooked
printf "Date: %s\\n" "`date`" >> ,,logfile-cooked
printf "Standard-date: %s\\n" "`date -u \"+%Y-%m-%d %H:%M:%S GMT\"`" >> ,,logfile-cooked
printf "New-files: %s\\n" "{arch}/$tag_category/$tag_branch/$tag_version/$tag_archive/patch-log/$tag_lvl" >> ,,logfile-cooked
cat ,,included-patches | sort_fqrn_list | unfold -w 60 | sed -e "1s/^/New-patches: /" -e "1!s/^/  /" >> ,,logfile-cooked
printf "Continuation-of: %s\\n" "$source_archive/$source_version--$source_lvl" >> ,,logfile-cooked
cat ,,logfile-raw >> ,,logfile-cooked

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

################################################################
# Make a Patch Set For the Tag
# 

cd "$tmpdir"

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

larch empty-patch ,,patch-set
larch patch-add-log ,,patch-set "$tag_archive/$tag_revision" ,,logfile-cooked


################################################################
# 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/$tag_version--$tag_lvl.patches"
cd "$tmparch"
tar -zcf "$tag_version--$tag_lvl.patches.tar.gz" "$tag_version--$tag_lvl.patches"
mv "$tag_version--$tag_lvl.patches" ../,,patch-set

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

cd "$tmparch"

larch make-lock revision-lock
printf "%s\\n" "$source_archive/$source_branch--$source_vsn--$source_lvl" > CONTINUATION

mv "$tmparch" "$tmparch2"

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

################################################################
# Install the Arch Template Dir or Clean Up the Output Dir
# 
# 
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="$tag_category/$tag_branch/$tag_version/$tag_lvl"

wftp-home

if ! larch putlast -e tag -A "$tag_archive" \
                  lock-revision "$tag_version--$tag_lvl" \
                  "$tmparch2" "$destdir" \
                  noop \
; then

  if test ! -z "$verbose" ; 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" "$tag_archive/$tag_version" )
  fi

  cd "$dir"
  rm -rf "$tmpdir"
fi

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

exit $status

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