#!/bin/sh # -*- Mode: Sh -*- # hook --- # Author : Manoj Srivastava ( srivasta@golden-gryphon.com ) # Created On : Sat May 3 00:53:06 2003 # Created On Node : anzu.internal.golden-gryphon.com # Last Modified By : Manoj Srivastava # Last Modified On : Mon Aug 20 13:51:18 2007 # Last Machine Used: anzu.internal.golden-gryphon.com # Update Count : 56 # Status : Working revision. # HISTORY : # Description : This is the hook script called by arch for every # action taken, and is used to customize the behaviour # of arch. # # arch-tag: 58104430-9dd2-4300-bbcd-af0f5f4545ad # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # ## ## Before the hook script is called, arch arranges to have certain ## envirnment variables set. Not all variables are set for all ## commands; the list below gives the variables and the commands for ## which they are set. The actual command is present in the first ## argument. ## # ARCH_ACTION: alway # gives the current action being taken ARCH_ACTION="$1" # ARCH_ARCHIVE: always # represents the registered name of the archive on which the action # is being performed # # ARCH_LOCATION: make-archive # gives the location of the archive being prepared by tla # # ARCH_REVISION: import, tag, commit, find-pristine, make-pristine # gives the exact revision being (import|tagg|commit)ed. # # ARCH_CATEGORY: make-category # gives the category being prepared (format: category) # # ARCH_BRANCH: make-branch # gives the branch being prepared (format: category--branch) # # ARCH_VERSION: make-version # gives the version being prepared (format: category--branch--version) # # ARCH_TREE_ROOT: commit, import # gives the location of the working tree from which tla is performing # the action # # ARCH_TAGGED_ARCHIVE: tag # gives the archive of the revision from which tla will create the tag # # ARCH_TAGGED_REVISION # gives the revision from which tla will create the tagged version # # ARCH_LOG: commit, tag, import # Contains the name of a file containing the full text for the newly # created log file (the file pointed to by ARCH_LOG may be # temporary). This is in baz 1.5 and greater only. # # Allow selection of tla or baz CMD=tla # Default address to mail notifications to MAILTO=srivasta # How often to cache versions CACHE_EVERY=20; # Logging convenience function hookLog() { echo "hook: $@" } # Create a debug output file safely. if [ -x /bin/tempfile ]; then HOOK_OUT=$(tempfile -p hook -m 0600 ); else set -e mkdir /tmp/hook$$ HOOK_OUT=/tmp/hook$$/out set +e fi # Debug stuff. if [ "$ARCH_HOOK_DEBUG" == "1" ]; then echo "$@" >> $HOOK_OUT env | sort >> $HOOK_OUT echo "" >> $HOOK_OUT fi ## ## Allow for an per-project hook script. On collaborative projects, ## each contributor must have his own copy of the hook script, and ## keep it up to date with some master copy; there is no standard ## mechanism for arranging such synchronisation. It would clearly be ## convenient if the hook scripts for a project could be kept in the ## project tree itself; I don't generally use it.' ## extra_hook="$ARCH_TREE_ROOT/{arch}/=hook" if [ -x "$extra_hook" ] ; then : echo "$extrahook" $@ fi ## ## This is a kludge. This is a list of arch categories for which we ## send mail to ${package}_cvs@packages.qa.debian.org. I wish there ## was something more elegant. ## PACKAGES="angband angband-doc c2man calc checkpolicy cvs-buildpackage debian-policy dist flex flex-old fvwm gnus kernel-package libcgi-perl libgraphics-colordeficiency-perl libgraphics-colornames-perl libgraphics-colorobject-perl liblog-log4perl-perl libmodule-load-perl libselinux libsemanage libsepol mailagent make make-dfsg make-doc-non-dfsg polgen-dfsg polgen-doc-non-dfsg policycoreutils psgml refpolicy selinux-doc sepolgen setools slat tla-tools tome ucf vm wm-icons" ## ## This helpre function is a simple wrapper around sendmail, and is ## used through out this hook to send mail. This is a drop in ## replacement of mailx. ## Takes three arguments: ## The first argument is a literal -s ## The second argument is a subject ## The Third argument is the recipient mail address ## The body is read in from STDIN. ## sendmail_wrapper() { if [ $# -ne 3 ] ; then echo 1>&2 "sendmail usage error: need 3 arguments" exit 1 fi if [ "$1" != "-s" ] ; then echo 1>&2 "sendmail usage error: first argument must be -s" exit 1 fi ( cat <<EOF To: $3 BCC: srivasta@debian.org Subject: $2 X-PTS-Approved: Yes EOF cat ) | /usr/sbin/sendmail -oi -t } ## ## This helper function essentially is a complex awk function that ## reads and arch Log entry, and formats it for a mail message. This ## function takes no arguments, and reads arch log entries from ## STDIN. It is also used to sanitize the input when we look for ## Closes: entr5ies in the commit log while looking forbugs that might ## have been fixed for this commit. ## cl_entry() { awk -v archive="$archive" \ -v version="$version" \ -v category="$category" \ -v branch="$branch" \ -v patch="$patch" \ -v no_files="$no_files" \ 'BEGIN { getline; while (!match ($0, "^$")) { field = tolower ($1); sub (":.*", "", field); headers[field] = $0; sub ("^[^:]*:[ \t]*", "", headers[field]); getline; while (match ($0, "^[ \t]")) { headers[field] = headers[field] $0; getline; } } } { if (body == "") body = " " $0; else body = body "\n " $0; } END { date = headers["standard-date"]; author = headers["creator"]; summary = headers["summary"]; revision = headers["revision"] if (date == "") { # this is almost vestigial: a backwards compatibility # hack just for the author of arch, some of whose log # messages pre-date the "standard-date" header field. # split (headers["date"], ugly_date, "[ \t]+"); date = ugly_date[6] "-" ugly_date[2] "-" ugly_date[3]; } sub("[[:space:]].*GMT.*", " GMT", date); print date "\t" author "\t" patch; print ""; print " Summary:"; print " " summary; print " Revision:"; print " " revision; print ""; print body; print ""; if (no_files == "") { file_list(0, "new-files", "{arch}/" category "/" branch "/" version "/" archive "/patch-log/" patch); file_list(0, "removed-files"); file_list(0, "modified-files"); file_pair_list("renamed-files"); file_list(0, "new-directories"); file_list(0, "removed-directories"); file_list(0, "modified-directories"); file_pair_list("renamed-directories"); file_list(0, "new-patches", archive "/" version "--" patch); print "" } } function file_list (base_only, field_name, exclude) { for (x in items) delete items[x]; n_items = split (headers[field_name], items, "[ \t]+"); if ((n_items == 0) || ((exclude != "") && (n_items == 1))) return; sub("-", " ", field_name); print " " field_name ":" printf(" "); width = 0; items_on_line = 0; for (x = 1; x <= n_items; ++x) { if (exclude == items[x]) continue; if (base_only) sub (".*/", "", items[x]); if ((items_on_line == 0) || ((width + length (items[x]) + 1) < 64)) { width += length (items[x]) + 1; ++items_on_line; printf(" %s", items[x]); } else { printf("\n"); printf(" "); printf(" %s", items[x]); width = length(items[x]) + 1; items_on_line = 1; } } printf "\n" printf "\n" } function file_pair_list (field_name) { for (x in items) delete items[x]; n_items = split (headers[field_name], items, "[ \t]+"); if (n_items == 0) return; sub("-", " ", field_name); print " " field_name ":" for (x = 1; x <= n_items; ++x) { printf(" %s\n", items[x]); printf(" ==> %s\n", items[x + 1]); x = x + 1; } printf "\n" printf "\n" }' } ## ## This is a helper function which uses the same hueristic the Debian ## BTS uses when looking for bugs to close in a package's ## debian/changelog entry. This function uses the cl_entry function ## to sanitize the arch log; parses it for bugs that have been fixed, ## and sends the clensed log entry to the bug report, as well as ## tagging the bug pending. ## ## This is useful when a new pload is worked on over an extended ## period of time, as it helps automate communication of the bug ## status and work done, even though an upload is not currently ## forthcoming. ## update_bug() { changes=$($CMD cat-archive-log "${ARCH_ARCHIVE}/${ARCH_REVISION}" | cl_entry ) echo "$changes" | perl -e ' my %Seen; { local $/; # enable localized slurp mode my $string=<>; while ( $string =~ m/closes:\s*(?:bug)?\#\s*\d+(?:,\s*(?:bug)?\#\s*\d+)*/gsmi ) { my $match="$&"; while ($match =~ /(\d+)/g) { $Seen{$1}++; } } } for (sort keys %Seen) { print "$_\n"; } ' | while read bug; do echo | \ sendmail_wrapper -s "Fix for Bug#$bug commited to version control" \ $bug@bugs.debian.org,control@bugs.debian.org<<EOF tags $bug +pending thanks Hi, The following change has been committed for this bug, and so the fix will be in the next upload. =================================================================== $changes EOF done } ## ## cache a full source tree in the repository. This can speed up ## subsequent calls to get for that and subsequent revisions. ## update_library() { local buf="" buf="$($CMD library-add --sparse "${ARCH_ARCHIVE}/${ARCH_REVISION}" 2>&1)" if [ $? -ne 0 ] ; then ## ## If something goes wrong while caching, send notifications. ## hookLog "Sending failure notice of caching ${ARCH_REVISION} to $MAILTO" echo "$buf" | \ sendmail_wrapper -s "$CMD library-add ${ARCH_ARCHIVE}/${ARCH_REVISION} failed" \ $MAILTO return 1 fi return 0 } ## ## This helper functions helps to update mirror archives whenever a ## change is made to the local archive. If the mirroring failsm it ## sends a failure notice. ## update_mirror() { mirror="${1}" limit=$($CMD parse-package-name --package-version $ARCH_REVISION) local buf="" ## must delete ARCH_ARCHIVE variable since this $CMD instance will ## not override it, thus when it calls this hook again we won't be ## able to tell that we are operating on the mirror, resulting in ## duplicate mails buf="$(env -u ARCH_ARCHIVE $CMD archive-mirror "${ARCH_ARCHIVE}" "$mirror" "$limit" || true)" if [ $? -ne 0 ] ; then ## ## If something goes wrong while mirroring, send ## notifications. ## hookLog "Sending failure notice of mirroring of ${ARCH_REVISION} to $MAILTO" echo "$buf" | \ sendmail_wrapper -s "$CMD archive-mirror ${ARCH_ARCHIVE} $limit failed" \ $MAILTO return 1 fi return 0 } ## ## This helper function generates the body of the optional ## notification sent when a new category is created. This may be ## used to send announcements of new revisions to subscribers of the ## package. ## new_category() { cat<<EOF Hi, A new category (${ARCH_CATEGORY}) has been created in the archive ${ARCH_ARCHIVE}. regards, The Arch Archive Bot EOF } ## ## This helper function generates the body of the optional ## notification sent when a new branch is created. This may be ## used to send announcements of new revisions to subscribers of the ## package. ## new_branch() { cat<<EOF Hi, A new category (${ARCH_BRANCH}) has been created in the archive ${ARCH_ARCHIVE}. regards, The Arch Archive Bot EOF } ## ## This helper function generates the body of the optional ## notification sent when a new branch is created.This may be ## used to send announcements of new revisions to subscribers of the ## package. ## new_revision() { changes=$($CMD cat-archive-log "${ARCH_ARCHIVE}/${ARCH_REVISION}" | cl_entry ) cat<<EOF Hi, A new category (${ARCH_BRANCH}) has been created in the archive ${ARCH_ARCHIVE}. regards, The Arch Archive Bot =================================================================== $changes EOF } ## ## This is the big switch where most of the real work gets done. We ## look at ARCH_ACTION, and act accordingly, ## case "${ARCH_ACTION}" in commit | import) ## ## This is where we do most of the interesting things, since ## the repository is usually changed by commits and imports ## (which is really just the initial commit). ## ARCH_CATEGORY="$($CMD parse-package-name --category $ARCH_REVISION)"; ARCH_BRANCH="$($CMD parse-package-name --branch $ARCH_REVISION)"; ARCH_VERSION="$($CMD parse-package-name --vsn $ARCH_REVISION)"; ARCH_BRANCH="$($CMD parse-package-name --branch $ARCH_REVISION)"; limit=$($CMD parse-package-name --package-version $ARCH_REVISION) patch=${ARCH_PATCH##*-}; ## ## Do things only for some of the repositories ## case "${ARCH_ARCHIVE}" in srivasta@debian.org--lenny|srivasta@debian.org--etch|srivasta@debian.org--20[0-9][0-9]-selinux|srivasta@debian.org--20[0-9][0-9]-primary) ## ## If any changes are made to my public archives ## (Debian, selinux, and a couple of others), cache ## every $CACHE_EVERY revisions (like once every 20 or ## so); and uncache the previously cached version. ## This helps peopletrying to check out my stuff; at ## most they have to go get $CACHE_EVERY patches from ## the last cached revision. ## library=$($CMD my-revision-library) ## ## Do not create a cache for a package called test ## if [ "${ARCH_CATEGORY}" != "test" ]; then if [ ${patch:-0} -gt 0 ]; then k=$(( $patch % $CACHE_EVERY )); if [ $k -eq 0 ]; then echo $CMD cacherev "${ARCH_ARCHIVE}" $CMD cacherev "${ARCH_ARCHIVE}" ## ## Remove older cached versions, keeping ## two cached versions in place. ## if [ $patch > $(( $CACHE_EVERY + $CACHE_EVERY )) ]; then j=$(( $patch - $CACHE_EVERY - $CACHE_EVERY )); l=$(( $j % $CACHE_EVERY )); if [ $l -eq 0 ]; then echo $CMD uncacherev \ "${ARCH_ARCHIVE}/${ARCH_CATEGORY}--${ARCH_BRANCH}--${ARCH_VERSION}--patch-$j" $CMD uncacherev \ "${ARCH_ARCHIVE}/${ARCH_CATEGORY}--${ARCH_BRANCH}--${ARCH_VERSION}--patch-$j" $CMD uncacherev \ "${ARCH_ARCHIVE}-MIRROR/${ARCH_CATEGORY}--${ARCH_BRANCH}--${ARCH_VERSION}--patch-$j" fi fi fi fi fi ## ## Now, if the category matches one of my packages, ## look to see if any bugs have been closed in this ## commit, and, if so, send the log to the bug, and ## tag it fixed. ## update_bug; ;; srivasta@golden-gryphon.com--imin) ## ## This is an ikiwiki commit. Make sure we update the ## checkout of the wiki on the webserver. ## case "${ARCH_CATEGORY}" in manoj) if [ "${ARCH_BRANCH}" = "publish" ]; then ## Ladon is the server hostig the wiki hookLog "Update wiki pages." (ssh ladon bin/update-wiki > $HOME/var/log/wiki.log 2>&1 )& fi ;; *) esac esac ## ## The rest is stuff we do for all the archives. ## ## If we are committing to an archive for which we have a ## corresponding -MIRROR defined, update the mirror now, and ## tell the human what is going on, since it can take time. ## if [ -f "${HOME}/.arch-params/=locations/${ARCH_ARCHIVE}-MIRROR" ]; then if [ "${ARCH_CATEGORY}--${ARCH_BRANCH}" != "ikiwiki--upstream" ]; then hookLog "Replicating $ARCH_ARCHIVE with limit $limit" update_mirror "${ARCH_ARCHIVE}-MIRROR" else hookLog "Not mirroring ikiwiki--upstream" fi else hookLog "Not mirroring $ARCH_ARCHIVE" fi ## ## Special handling for Debian packages. ## for package in $PACKAGES; do if [ "$ARCH_CATEGORY" = "$package" ]; then ## ## Send full logs via mail to packages.qa.debian.org ## for the commit. People can subscribe to a mailing ## list setup for each package to get commit logs, if ## they so desire. ## hookLog "Sending notice of ${ARCH_REVISION} to ${package}_cvs@packages.qa.debian.org" $CMD cat-log "${ARCH_REVISION}" | \ sendmail_wrapper -s "Changes to archive ${ARCH_REVISION}" \ ${package}_cvs@packages.qa.debian.org; break; fi if [ "$ARCH_CATEGORY" = "debian-dir" ] && [ "$ARCH_BRANCH" = "$package" ]; then ## ## While not committing the package, we are committing ## the ./debian directory associated with the package, ## so again, send in the commit log to the mailing ## list. ## hookLog "Sending notice of ${ARCH_REVISION} to ${package}_cvs@packages.qa.debian.org" $CMD cat-log "${ARCH_REVISION}" | \ sendmail_wrapper -s "Changes to archive ${ARCH_REVISION}" \ ${package}_cvs@packages.qa.debian.org; ## ## Arch has the concept of a grab file, and people can ## get all the components of a software package by ## just feeding arch either the grab file (either ## locally, or via a http URL). With this, we make ## sure we create the config and grab files, and ## upload it to a public location mentioned in ## ./debian/control for all my packages. ## (${HOME}/bin/arch_create_config -p "$package"; ${HOME}/bin/arch_upload_grab $package; ) break; fi done case "$ARCH_ARCHIVE" in "debian-policy@lists.debian.org--lenny"|"debian-policy@lists.debian.org--etch") ## ## For the Debian policy commits, also send mail to the ## policy list with full commit logs. This is a group ## maintained package, so changes to this are ## disseminated slightly more volubly. ## hookLog "Sending notice of ${ARCH_REVISION} to debian-policy@lists.debian.org" $CMD cat-log "${ARCH_REVISION}" | \ sendmail_wrapper -s "Changes to archive ${ARCH_REVISION}" \ debian-policy@lists.debian.org; ;; *) ## ## a no-op. If any other packages need special ## actions, they can go above. ## : echo "" esac ;; find-pristine|make-pristine|make-tmp-pristine) ## ## a no-op. ## : echo "" ;; find-cached-revision) ## ## Whenever we try to find a revision, add it to our local sparse ## cache library. ## update_library; ;; find-archive) ## ## Hmm. Why is this here? ## $CMD-find-archive "$ARCH_ARCHIVE" exit $? ;; make-category) case "$ARCH_ARCHIVE" in "debian-policy@lists.debian.org--lenny"|"debian-policy@lists.debian.org--etch") ## ## Since Debian policy is a group maintained package, ## any new categories should be made very public. ## Send mail to the policy mailing lists. ## hookLog "Sending notice of new category to debian-policy@lists.debian.org" new_category | \ sendmail_wrapper -s "New category $ARCH_CATEGORY in archive $ARCH_ARCHIVE" \ debian-policy@lists.debian.org ;; *) ## ## Or else, send a mail for archival purposes. ## hookLog "Sending notice of ${ARCH_CATEGORY} to $MAILTO" new_category | \ sendmail_wrapper -s "New category $ARCH_CATEGORY in archive $ARCH_ARCHIVE" \ $MAILTO ;; esac ;; make-branch) case "$ARCH_ARCHIVE" in "debian-policy@lists.debian.org--lenny"|"debian-policy@lists.debian.org--etch") ## ## Since Debian policy is a group maintained package, ## any new branches should be made very public. ## Send mail to the policy mailing lists. ## hookLog "Sending notice of ${ARCH_BRANCH} to debian-policy@lists.debian.org" new_branch | \ sendmail_wrapper -s "New branch ${ARCH_BRANCH} in archive ${ARCH_ARCHIVE}"\ debian-policy@lists.debian.org ;; *) ## ## Or else, send a mail for archival purposes. ## hookLog "Sending notice of ${ARCH_BRANCH%%--*} to $MAILTO" new_branch | \ sendmail_wrapper -s "New branch ${ARCH_BRANCH} in archive $ARCH_ARCHIVE" \ $MAILTO ;; esac ;; make-version) case "$ARCH_ARCHIVE" in "debian-policy@lists.debian.org--lenny"|"debian-policy@lists.debian.org--etch") ## ## Since Debian policy is a group maintained package, ## any new versions should be made very public. ## Send mail to the policy mailing lists. ## hookLog "Sending notice of ${ARCH_VERSION} to debian-policy@lists.debian.org" new_version | \ sendmail_wrapper -s "New vesion ${ARCH_VERSION} in archive ${ARCH_ARCHIVE}" \ debian-policy@lists.debian.org ;; *) ## ## a no-op. I don't want an email for every version. ## : echo "" esac ;; *) ## ## a no-op. I don't want an email for every version. ## : echo "" esac exit 0; # update_rsync() # { # local TMPD="$(mktemp -q -d $HOME/arch/ARCH/,rsync-tmp.XXXXXX)" || return 1 # $CMD get --silent --no-pristine yaboot--devel--1.3 "${TMPD}/yaboot" && \ # (cd "${TMPD}/yaboot" && setftime --restore-all 0arch-timestamps0) # if [ $? -ne 0 ] ; then # rm -rf "$TMPD" # return 2 # fi # $CMD get --silent --no-pristine yaboot--devel--1.99 "${TMPD}/yaboot-devel" && \ # (cd "${TMPD}/yaboot-devel" && $CMD buildcfg --no-pristines libs > /dev/null) && \ # ln -sf ../../COPYING "${TMPD}/yaboot-devel/lib/libc/COPYING" && \ # (cd "${TMPD}/yaboot-devel" && setftime --restore-all 0arch-timestamps0) && \ # (cd "${TMPD}/yaboot-devel/lib/libc" && setftime --restore-all 0arch-timestamps0) # if [ $? -ne 0 ] ; then # rm -rf "$TMPD" # return 3 # fi # (cd "$TMPD/yaboot" && \ # rsync -aqz --delete --exclude=.arch-ids --exclude={arch} --exclude=0arch-timestamps0 \ # --password-file="${HOME}/secure/rsync" . ash::yaboot-eb-rw) # if [ $? -ne 0 ] ; then # rm -rf "$TMPD" # return 4 # fi # (cd "$TMPD/yaboot-devel" && \ # rsync -aqz --delete --exclude=.arch-ids --exclude={arch} --exclude=0arch-timestamps0 \ # --password-file="${HOME}/secure/rsync" . ash::yaboot-devel-eb-rw) # if [ $? -ne 0 ] ; then # rm -rf "$TMPD" # return 5 # fi # rm -rf "$TMPD" || return 6 # }