#!/bin/sh
# 
# whats-missing.sh - print patches missing from a project tree
################################################################
# Copyright (C) 2001, 2002 Tom Lord
# 
# See the file "COPYING" for further information about
# the copyright and warranty status of this work.
# 

set -e 

################################################################
# special options
# 
# Some options are special:
# 
#	--version | -V
#	--help | -h
#       --debug
# 
debug=

if test $# -ne 0 ; then

  for opt in "$@" ; do
    case $opt in

      --debug)  set -x
		debug=--debug
		shift
		;;

      --version|-V) exec larch --version
                    ;;


      --help|-h)
		printf "print patches missing from a project tree\\n"
		printf "usage: whats-missing [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 " -d --dir DIR                  specify project tree\\n"
		printf " -r --reverse                  sort from oldest to newest\\n"
		printf " -s --summary                  print a summary of each patch\\n"
		printf " -f --full                     print full names of patch levels\\n"
		printf " --merges                      print the merge list for each patch\\n"
		printf "                                (implies --full)\\n"
		printf "\\n"
		printf "Print a list of patches missing in the project tree containing\\n"
		printf "DIR (or the current directory) for VERSION (or the default version.\\n"
		printf "of the project tree).\\n"
		printf "\\n"
		printf "The flag --merges means, for each patch, to print the list of patches\\n"
		printf "included in the patch in two columns.  For example:\\n"
		printf "\\n"
		printf "            PATCH-A	PATCH-A\\n"
		printf "            PATCH-A	PATCH-B\\n"
		printf "            PATCH-A	PATCH-C\\n"
		printf "\\n"
		printf "means that PATCH-A includes the changes from PATCH-B and PATCH-C.\\n"
		printf "(Every patch includes at least itself.)\\n"
		printf "\\n"
		printf "\\n"
		printf "\\n"
		exit 0
      		;;

      *)
		;;
    esac
  done
fi

################################################################
# Ordinary Options
# 
# 
archroot=
archive=
reverse=
summary=
full=
dir=
merges=

while test $# -ne 0 ; do

  case "$1" in 

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

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


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


    -r|--reverse)	shift
    			reverse=-r
			;;

    -s|--summary)	shift
			summary=--summary
			;;

    -f|--full)		shift
			full=--full
			;;

    --merges)		shift
			merges=--merges
			full=--full
			;;

    --)			shift
			break
			;;

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

    *)			break
    			;;

  esac

done



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

if test $# -lt 0 ; then
  printf "usage: whats-missing [options] [[archive/]version ...]\\n" 1>&2
  printf "try --help\\n" 1>&2
  printf "\\n" 1>&2
  exit 1
fi

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

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

if test -z "$dir" ; then
  dir="`pwd`"
else
  cd "$dir"
  dir="`pwd`"
fi

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

if test -z "$archive_version" ; then
  cd "$wdroot"
  archive_version="`larch tree-version`"
fi

larch valid-package-name -e whats-missing --tolerant -- "$archive_version"

arch="`larch parse-package-name -R \"$archroot\" -A \"$archive\" --arch \"$archive_version\"`"
non_arch="`larch parse-package-name -R \"$archroot\" -A \"$archive\" --non-arch \"$archive_version\"`"
category="`larch parse-package-name --basename \"$archive_version\"`"
branch="`larch parse-package-name --package \"$archive_version\"`"


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

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

  exec larch with-archive -A "$arch"  \
    larch whats-missing $debug --dir "$wdroot" $reverse $summary $merges $full "$arch/$non_arch" "$@"

fi


################################################################
# Print the List
# 

if larch valid-package-name --vsn "$archive_version" ; then
  version="`larch parse-package-name -R \"$archroot\" -A \"$arch\" --package-version \"$archive_version\"`"
else
  version="`larch versions --reverse \"$arch/$branch\" | head -1`"
fi


cd "$wdroot"

rm -f ,,whats-missing.$$.archive
rm -f ,,whats-missing.$$.wd

clean_up()
{
  cd "$wdroot"
  rm -f ,,whats-missing.$$.archive
  rm -f ,,whats-missing.$$.wd
}

finish()
{
  clean_up
  exit "$1"
}

trap "printf \"whats-missing: interrupted -- cleaning up\\n\" 1>&2 ; finish 2" INT

larch revisions "$arch/$version" | sort > ,,whats-missing.$$.archive
larch log-ls "$arch/$version" | sort >  ,,whats-missing.$$.wd

if test ! -z "$full" ; then
  prefix="$arch/$version--"
else
  prefix=
fi

comm -2 -3 ,,whats-missing.$$.archive ,,whats-missing.$$.wd \
| sort -t- -k 1,1${reverse#-} -k 2,2${reverse#-}n \
| awk -v prefix="$prefix" \
      -v version="$arch/$version" \
      -v summary="$summary" \
      -v merges="$merges" \
      '{
	 if (merges != "")
	   {
	     command="larch cat-archive-log --headers " prefix $1 " | larch log-header-field --list new-patches ";

	     while (1)
	       {
		 status = (command | getline included);

		 if (status == 0)
		   {
		     break;
		   }
		 else if (status > 0)
		   {
		     print prefix $1 " " included;
		   }
		 else
		   {
		     printf("\\n") | "cat 1>&2";
		     printf("whats-missing: I/O error reading log file\\n") | "cat 1>&2";
		     printf("  revision: \\n", $1) | "cat 1>&2"
		     printf("\\n") | "cat 1>&2";
		     exit(1);
		   }
	       }
	   }
	 else
	   {
	     print prefix $1;
	   }
         if (summary != "")
	   {
	     if (0 > system("larch cat-archive-log  " version "--" $1 " | larch log-header-field summary | sed -e \"s/^/    /\""))
	       {
	         exit(1);
	       }
	   }
       }' \
|| finish 1

################################################################
# Tail Recurse on Remaining Arguments
# 

if test $# -ne 0 ; then
  clean_up
  exec larch whats-missing $debug -A "$archive" --dir "$wdroot" $reverse $summary $merges $full "$@"
else
  finish 0
fi
