# notify.sh: trigger actions for changes to an archive
# 
################################################################
# Copyright (C) 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 "trigger actions for changes to an archive\\n"
                printf "usage: notify [options] notify-dir [limit]"
                printf "\\n"
                printf " -V --version                  print version info\\n"
                printf " -h --help                     display help\\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 "Trigger actions for each udpate to an archive\\n"
                printf "using the rules in NOTIFY-DIR to decide which\\n"
                printf "changes are interesting, and what action should\\n"
                printf "be taken.\\n"
                printf "\\n"
                printf "LIMIT may be an archive name, or a category, branch,\\n"
                printf "or version name.  If present, it restricts the attention\\n"
                printf "of notify to just that archive, category, branch, and/or\\n"
                printf "version.\\n"
                printf "\\n"
                exit 0
                ;;

      *)
                ;;
    esac
  done
fi

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

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

while test $# -ne 0 ; do

  case "$1" in 

    ----presume-lock)           shift
                                presume_lock=----presume-lock
                                ;;

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

    --)                 shift
                        break
                        ;;

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

    *)                  break
                        ;;
  esac

done



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

if test $# -lt 1 -o $# -gt 2 ; then
  printf "usage: notify [options] notify-dir [limit]" 1>&2
  printf "try --help\\n" 1>&2
  exit 1
fi

notify_dir="$1"
shift

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


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

if test -z "$limit" ; then

  only_archive=
  only_category=
  only_branch=
  only_version=

else

  if larch valid-archive-name "$limit" ; then

    only_archive="$limit"
    only_category=
    only_branch=
    only_version=

  else

    larch valid-package-name -e notify --basename --tolerant "$limit"

    only_archive="`larch parse-package-name --arch \"$limit\"`"
    only_category="$only_archive/`larch parse-package-name --basename \"$limit\"`"

    if larch valid-package-name --tolerant "$limit" ; then
      only_branch="$only_archive/`larch parse-package-name \"$limit\"`"
    else
      only_branch=
    fi

    if larch valid-package-name --vsn --tolerant "$limit" ; then
      only_version="$only_archive/`larch parse-package-name --package-version \"$limit\"`"
    else
      only_version=
    fi

  fi
fi


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

if test ! -z "$quiet" ; then
  larch heading "notify\\n"
  printf "arguments: %s\\n" "$command_line" | fold -w 60 | larch body-indent
  larch heading --sub "notify start time: %s\\n" "`date`"
  larch heading --sub "notify dir: %s\\n" "$notify_dir"
fi


################################################################
# Ensure We Hold a Lock on the Notify-Dir
# 

if test -z "$presume_lock" ; then

  if test ! -z "$quiet" ; then
    larch heading --sub "restarting with file lock\\n"
  fi

  cd "$notify_dir"

  exec with-file-lock =rules.archives \
    larch notify $silent_opt $quiet_opt $report_opt $verbose_opt $debug_opt \
                ----presume-lock \
                "$notify_dir" \
                "$limit"

fi


################################################################
# Report New Categories
# 

report_new_categories()
{
  if test "$#" -lt 2 -o "$#" -gt 5 ; then
    printf "\\n"
    printf "notify: bad format in =rules.archives\\n" 1>&2
    printf "  bad data: %s\\n" "$*" 1>&2
    printf "\\n"
    exit 1
  fi

  archive="$1"
  shift

  if test ! -z "$only_archive" -a "(" "$archive" != "$only_archive" ")" ; then
    return
  fi

  recipient="$1"
  shift

  if test ! -z "$quiet" ; then
    larch heading --sub "checking archive for new categoriess\\n"
    larch heading --sub --sub "archive: %s\\n" "$archive"
    larch heading --sub --sub "recipient: %s\\n" "$recipient"
  fi

  larch valid-archive-name -e "notify (processing =rules.archives)" -- "$archive"


  if test ! -d "$archive" ; then
    mkdir -p "$archive"
  fi

  cd "$archive"

  if test ! -d "=categories" ; then
    mkdir -p "=categories"
  fi

  cd =categories

  if test ! -e "$recipient" ; then
    touch "$recipient"
  fi

  larch categories -A "$archive" | sort > ",,$recipient"

  join -v 2 -o 2.1 -1 1 -2 1 "$recipient" ",,$recipient" > ",,$recipient.new"

  if test "`head -n 1 \",,$recipient.new\"`" = "" ; then

    rm ",,$recipient" ",,$recipient.new"

  else

    command="${recipient%%:*}"
    thunk="${recipient#*:}"

    here="`pwd`"
    cd "$notify_dir"

    larch "$command" "$thunk" "$archive" `cat "$here/,,$recipient.new"`

    if test -e =rules.categories ; then
      cp =rules.categories ,,rules.categories
    else
      touch ,,rules.categories
    fi

    for category in `cat "$archive/=categories/,,$recipient.new"` ; do
      printf "%s\\t%s\\n" "$archive/$category" "$*" >> ,,rules.categories
    done

    sort -u ,,rules.categories > ,,tmp

    dangerous-rename ,,tmp =rules.categories

    rm ,,rules.categories

    cd "$archive/=categories"

    dangerous-rename ",,$recipient" "$recipient"
    rm ",,$recipient.new" 
    
  fi
}


cd "$notify_dir"

if test -e =rules.archives ; then

  OLD_IFS="$IFS"
  IFS="
"
  for archive_rule in `cat =rules.archives | larch file-syntax-filter --sh-comments --blank-lines --trailing-spaces` ; do

    IFS="$OLD_IFS"
    cd "$notify_dir"
    report_new_categories $archive_rule

  done

  IFS="$OLD_IFS"

fi

################################################################
# Report New Branches
#

report_new_branches()
{
  if test "$#" -lt 2 -o "$#" -gt 4 ; then
    printf "\\n"
    printf "notify: bad format in =rules.categories\\n" 1>&2
    printf "  bad data: %s\\n" "$*" 1>&2
    printf "\\n"
    exit 1
  fi

  category="$1"
  shift

  recipient="$1"
  shift

  larch valid-package-name --archive --basename -e "notify (processing =rules.categories)"  "$category"
  archive="`larch parse-package-name --arch \"$category\"`"

  if test ! -z "$only_archive" -a "(" "$archive" != "$only_archive" ")" ; then
    return
  fi

  if test ! -z "$only_category" -a "(" "$category" != "$only_category" ")" ; then
    return
  fi

  if test ! -z "$quiet" ; then
    larch heading --sub "checking category for new branches\\n"
    larch heading --sub --sub "category: %s\\n" "$category"
    larch heading --sub --sub "recipient: %s\\n" "$recipient"
  fi

  if test ! -d "$category" ; then
    mkdir -p "$category"
  fi

  cd "$category"

  if test ! -d "=branches" ; then
    mkdir "=branches"
  fi

  cd =branches

  if test ! -e "$recipient" ; then
    touch "$recipient"
  fi

  larch branches "$category" | sort > ",,$recipient"

  join -v 2 -o 2.1 -1 1 -2 1 "$recipient" ",,$recipient" > ",,$recipient.new"

  if test "`head -n 1 \",,$recipient.new\"`" = "" ; then

    rm ",,$recipient" ",,$recipient.new"

  else

    command="${recipient%%:*}"
    thunk="${recipient#*:}"

    here="`pwd`"
    cd "$notify_dir"

    larch "$command" "$thunk" "$category" `cat "$here/,,$recipient.new"`

    if test -e =rules.branches ; then
      cp =rules.branches ,,rules.branches
    else
      touch ,,rules.branches
    fi

    for branch in `cat "$category/=branches/,,$recipient.new"` ; do
      printf "%s\\t%s\\n" "$archive/$branch" "$*" >> ,,rules.branches
    done

    sort -u ,,rules.branches > ,,tmp

    dangerous-rename ,,tmp =rules.branches

    rm ,,rules.branches

    cd "$category/=branches"

    dangerous-rename ",,$recipient" "$recipient"
    rm ",,$recipient.new"
    
  fi
}


cd "$notify_dir"

if test -e =rules.categories ; then

  OLD_IFS="$IFS"
  IFS="
"
  for category_rule in `cat =rules.categories | larch file-syntax-filter --sh-comments --blank-lines --trailing-spaces` ; do

    cd "$notify_dir"

    IFS="$OLD_IFS"

    report_new_branches $category_rule

  done

  IFS="$OLD_IFS"

fi



################################################################
# Report New Versions
#

report_new_versions()
{
  if test "$#" -lt 2 -o "$#" -gt 3 ; then
    printf "\\n"
    printf "notify: bad format in =rules.branches\\n" 1>&2
    printf "  bad data: %s\\n" "$*" 1>&2
    printf "\\n"
    exit 1
  fi

  branch="$1"
  shift

  recipient="$1"
  shift

  larch valid-package-name --archive -e "notify (processing =rules.branches)"  "$branch"

  archive="`larch parse-package-name --arch \"$branch\"`"
  category="`larch parse-package-name --basename \"$branch\"`"
  branch="`larch parse-package-name \"$branch\"`"

  if test ! -z "$only_archive" -a "(" "$archive" != "$only_archive" ")" ; then
    return
  fi

  if test ! -z "$only_category" -a "(" "$archive/$category" != "$only_category" ")" ; then
    return
  fi

  if test ! -z "$only_branch" -a "(" "$archive/$branch" != "$only_branch" ")" ; then
    return
  fi

  if test ! -z "$quiet" ; then
    larch heading --sub "checking branch for new versions\\n"
    larch heading --sub --sub "branch: %s\\n" "$branch"
    larch heading --sub --sub "recipient: %s\\n" "$recipient"
  fi

  if test ! -d "$archive/$category/$branch" ; then
    mkdir -p "$archive/$category/$branch"
  fi

  cd "$archive/$category/$branch"

  if test ! -d "=versions" ; then
    mkdir "=versions"
  fi

  cd =versions

  if test ! -e "$recipient" ; then
    touch "$recipient"
  fi

  larch versions "$archive/$branch" | sort > ",,$recipient"

  join -v 2 -o 2.1 -1 1 -2 1 "$recipient" ",,$recipient" > ",,$recipient.new"

  if test "`head -n 1 \",,$recipient.new\"`" = "" ; then

    rm ",,$recipient" ",,$recipient.new"

  else

    command="${recipient%%:*}"
    thunk="${recipient#*:}"

    here="`pwd`"
    cd "$notify_dir"

    larch "$command" "$thunk" "$archive/$branch" `cat "$here/,,$recipient.new"`

    if test -e =rules.versions ; then
      cp =rules.versions ,,rules.versions
    else
      touch ,,rules.versions
    fi

    for v in `cat "$archive/$category/$branch/=versions/,,$recipient.new"` ; do
      printf "%s\\t%s\\n" "$archive/$v" "$*" >> ,,rules.versions
    done

    sort -u ,,rules.versions > ,,tmp

    dangerous-rename ,,tmp =rules.versions

    rm ,,rules.versions

    cd "$archive/$category/$branch/=versions"

    dangerous-rename ",,$recipient" "$recipient"
    rm ",,$recipient.new" 
    
  fi
}


cd "$notify_dir"

if test -e =rules.branches ; then

  OLD_IFS="$IFS"
  IFS="
"
  for branch_rule in `cat =rules.branches | larch file-syntax-filter --sh-comments --blank-lines --trailing-spaces` ; do

    IFS="$OLD_IFS"

    cd "$notify_dir"

    report_new_versions $branch_rule

  done

  IFS="$OLD_IFS"

fi


################################################################
# Report New Revisions
#

report_new_revisions()
{
  if test "$#" -ne 2 ; then
    printf "\\n"
    printf "notify: bad format in =rules.versions\\n" 1>&2
    printf "  bad data: %s\\n" "$*" 1>&2
    printf "\\n"
    exit 1
  fi

  version="$1"
  shift

  recipient="$1"
  shift

  larch valid-package-name --archive -e "notify (processing =rules.versions)" --vsn  "$version"

  archive="`larch parse-package-name --arch \"$version\"`"
  category="`larch parse-package-name --basename \"$version\"`"
  branch="`larch parse-package-name \"$version\"`"
  version="`larch parse-package-name --package-version \"$version\"`"

  if test ! -z "$only_archive" -a "(" "$archive" != "$only_archive" ")" ; then
    return
  fi

  if test ! -z "$only_category" -a "(" "$archive/$category" != "$only_category" ")" ; then
    return
  fi

  if test ! -z "$only_branch" -a "(" "$archive/$branch" != "$only_branch" ")" ; then
    return
  fi

  if test ! -z "$only_version" -a "(" "$archive/$version" != "$only_version" ")" ; then
    return
  fi

  if test ! -z "$quiet" ; then
    larch heading --sub "checking version for new revisions\\n"
    larch heading --sub --sub "version: %s\\n" "$version"
    larch heading --sub --sub "recipient: %s\\n" "$recipient"
  fi

  if test ! -d "$archive/$category/$branch/$version" ; then
    mkdir -p "$archive/$category/$branch/$version"
  fi

  cd "$archive/$category/$branch/$version"

  if test ! -e "$recipient" ; then
    touch "$recipient"
  fi

  larch revisions "$archive/$version" | sort > ",,$recipient"

  join -v 2 -o 2.1 -1 1 -2 1 "$recipient" ",,$recipient" > ",,$recipient.new"

  if test "`head -n 1 \",,$recipient.new\"`" = "" ; then

    rm ",,$recipient" ",,$recipient.new"

  else

    command="${recipient%%:*}"
    thunk="${recipient#*:}"

    here="`pwd`"

    cd "$notify_dir"

    larch "$command" "$thunk" "$archive/$version" `cat "$here/,,$recipient.new" | sort -t- -k 1,1 -k 2,2n`

    cd "$here"
    dangerous-rename ",,$recipient" "$recipient"
    rm ",,$recipient.new" 
    
  fi
}


cd "$notify_dir"

if test -e =rules.versions ; then

  OLD_IFS="$IFS"
  IFS="
"
  for version_rule in `cat =rules.versions | larch file-syntax-filter --sh-comments --blank-lines --trailing-spaces` ; do

    IFS="$OLD_IFS"

    cd "$notify_dir"

    report_new_revisions $version_rule

  done

  IFS="$OLD_IFS"

fi



################################################################
# Bye
# 

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



  
# tag: Tom Lord Fri Jan 18 20:24:37 2002 (notify/notify.sh)
#
