[PATCH 12/13] example hook for aiaiai-email-dispatcher-helper

Jacob Keller jacob.e.keller at intel.com
Thu Mar 20 16:37:10 PDT 2014


This commit introduces an example hook which uses git-find-base to
determine what project (and even what commit inside that project!) the
patch is based on. This can be used so that patches automatically go to
the correct project, without having to specify the project in the email
address.

Signed-off-by: Jacob Keller <jacob.e.keller at intel.com>
---
 doc/email/example-aiaiai.cfg          |   7 +-
 email/aiaiai-email-autodetect-project | 222 ++++++++++++++++++++++++++++++++++
 2 files changed, 227 insertions(+), 2 deletions(-)
 create mode 100755 email/aiaiai-email-autodetect-project

diff --git a/doc/email/example-aiaiai.cfg b/doc/email/example-aiaiai.cfg
index f9c7e0fbdc67..368a72e061fd 100644
--- a/doc/email/example-aiaiai.cfg
+++ b/doc/email/example-aiaiai.cfg
@@ -48,8 +48,11 @@
 	# A hook called by aiaiai-email-dispatcher-helper, which should insert
 	# custom headers into the mbox file. Specific documentation on this is
 	# provided in the doc/email section, including expected argument
-	# format, as well as what headers are recognized by other tools.
-	dispatcher =
+	# format, as well as what headers are recognized by other tools. The
+	# provided example hook will attempt to use index information stored by
+	# the mbox file's diff in order to determine which project the patch
+	# applies to.
+	dispatcher = /home/aiaiai/git/aiaiai/email/aiaiai-email-autodetect-project
 
 # These options are probably not useful, but may help debug issues with aiaiai
 [debug]
diff --git a/email/aiaiai-email-autodetect-project b/email/aiaiai-email-autodetect-project
new file mode 100755
index 000000000000..426d01f0e9b4
--- /dev/null
+++ b/email/aiaiai-email-autodetect-project
@@ -0,0 +1,222 @@
+#!/bin/sh -efu
+
+# Copyright 2014 Intel Corporation
+# Author: Jacob Keller
+# License: GPLv2
+
+srcdir="$(readlink -ev -- ${0%/*})"
+PATH="$srcdir:$srcdir/..:$srcdir/../helpers:$srcdir/../helpers/libshell:$PATH"
+
+. shell-error
+. shell-args
+. shell-signal
+. aiaiai-sh-functions
+. aiaiai-email-sh-functions
+
+PROG="${0##*/}"
+export message_time="yes"
+
+# This is a small trick to make sure the script is portable - check if 'dash'
+# is present, and if yes - use it.
+if can_switch_to_dash; then
+	exec dash -euf -- "$srcdir/$PROG" "$@"
+	exit $?
+fi
+
+show_usage()
+{
+	cat <<-EOF
+Usage: $PROG [options] <mbox> <cfgfile.ini>
+
+This is an example hook used by aiaiai to automatically determine the project
+that the commit applies to, by using the index information from the first patch
+in the series, and checking each project for information about where patches
+apply. It depends on git-find-base which is included in the helpers folder.
+
+<cfgfile.ini>          - the configuration file.
+<mbox>                 - the mbox file containing the patch series
+
+Options:
+  -v, --verbose          be verbose;
+  -h, --help             show this text and exit.
+EOF
+}
+
+fail_usage()
+{
+	[ -z "$1" ] || printf "%s\n" "$1"
+	show_usage
+	exit 1
+}
+
+list_project_trees()
+{
+	local prj
+
+	print "%s\n" "- Supported Projects -"
+
+	LC_ALL=C sed -n -e "s/^\[prj_\(.*\)\]$/\1/p" "$cfgfile" | \
+		while read -r prj; do
+			# Get project description
+			local descr path url branch commit email
+			ini_config_get_or_die descr  "$cfgfile" "prj_$prj" "description"
+			ini_config_get_or_die path   "$cfgfile" "prj_$prj" "path"
+			ini_config_get_or_die branch "$cfgfile" "prj_$prj" "branch"
+
+			url="$(ini_config_get "$cfgfile" "prj_$prj" "canonical_url")"
+			[ -n "$url" ] || url=$path
+			commit="$(git --git-dir="$(git_dir "$path")" describe --long "$branch")"
+
+			printf "* %s\n" "$prj ($url : $branch)"
+			printf " > %s\n" "$branch last known as $commit"
+		done
+
+}
+
+send_reply()
+{
+	local file="$1"; shift
+	local reply_to reply_cc reply_id reply_subj to cc prj
+
+	fetch_header_or_die reply_to "From" < "$file"
+	fetch_header_or_die reply_subj "Subject" < "$file"
+	fetch_header_or_die reply_id "Message-Id" < "$file"
+
+	to="$(fetch_header "To" < "$file")"
+	cc="$(fetch_header "Cc" < "$file")"
+
+	reply_cc="$(merge_addresses "$to" "$cc")"
+
+	prj="$(fetch_project_name "$reply_cc" "$cfg_ownmail")"
+	[ -z "$prj" ] || verbose "Expected Project \"$prj\""
+	parse_prj_config "$cfgfile" "$prj"
+
+	if [ -n "$pcfg_name" ] && [ "$pcfg_reply_to_all" = "1" ]; then
+		# Strip own address
+		reply_cc="$(merge_addresses "$reply_cc" "$pcfg_always_cc")"
+		reply_cc="$(strip_address "$reply_cc" "$cfg_ownmail")"
+	else
+		reply_cc=
+	fi
+
+	compose_email "$reply_to" "$reply_cc" "$reply_subj" "$reply_id" \
+		> "$tmpdir/mail"
+
+	[ -z "$verbose" ] || cat -- "$tmpdir/mail" >&2
+
+	if [ "$cfg_disable_notifications" != "1" ]; then
+		mutt -x -H "$tmpdir/mail" </dev/null
+	else
+		verbose "Email notifications have been disabled in the configuration file"
+	fi
+}
+
+verbose=
+tmpdir=
+cleanup_handler()
+{
+	if [ "$cfg_preserve_files" = "1" ]; then
+		verbose "Preserved tmpdir: $tmpdir"
+	else
+		[ -z "$tmpdir" ] || verbose "Removing $tmpdir";
+		rm -rf -- "$tmpdir" >&2
+	fi
+}
+set_cleanup_handler cleanup_handler
+
+TEMP=`getopt -n $PROG -o i:,C:,p,v,h --long input:,verbose,help -- "$@"` ||
+	fail_usage ""
+eval set -- "$TEMP"
+
+while true; do
+	case "$1" in
+	-v|--verbose) verbose=-v
+		;;
+	-h|--help)
+		show_usage
+		exit 0
+		;;
+	--) shift; break
+                ;;
+	*) fail_usage "Unrecognized option: $1"
+		;;
+	esac
+	shift
+done
+
+[ "$#" -eq 2 ] || die "Insufficient or too many arguments"
+
+mbox="$(readlink -fv -- "$1")"; shift
+cfgfile="$(readlink -fv -- "$1")"; shift
+commit=
+
+# Parse the configuration file early
+parse_config "$cfgfile"
+
+# Create a temporary directory for storage of any files we might need
+tmpdir="$(mktemp --tmpdir="$cfg_workdir" -dt "$PROG.XXXX")"
+
+# Get the expected project from the patch email
+to="$(fetch_header "To" < "$mbox")"
+cc="$(fetch_header "Cc" < "$mbox")"
+list="$(merge_addresses "$to" "$cc")"
+expected_prj="$(fetch_project_name "$list" "cfg_ownmail")"
+
+# Loop through every project and check if we can find a base commit. If we're
+# given an expected project in the email address, try it first, so that we
+# don't accidentally land on the wrong one.
+for prj in $expected_prj $(LC_ALL=C sed -n -e "s/^\[prj_\(.*\)\]$/\1/p" "$cfgfile"); do
+	# First to be safe, unset the project config variables that we use
+	unset pcfg_branch pcfg_path pcfg_name branch_base
+
+	# Now, parse the (new) project for pcfg variables
+	parse_prj_config "$cfgfile" "$prj"
+
+	# Skip non-existent projects, but warn about it here
+	if [ -z "$pcfg_name" ]; then
+		verbose "Could not find $prj project"
+		continue
+	fi
+
+	# We set our own project variable called branch_base
+	branch_base="$(ini_config_get "$cfgfile" "prj_$prj" "branch_base")"
+
+	# Use git-find-base with the mbox file as input, and check to see if we
+	# can find a commit in this project. Use the branch_base if it's
+	# supplied, otherwise use the parent(s) of pcfg_branch as the limiter.
+	# This enables only checking a small range instead of having to check
+	# the full history. It assumes that all projects use the same base,
+	# however!
+	commit="$(git --git-dir="$(git_dir "$pcfg_path")" find-base "$pcfg_branch" "${branch_base:-$pcfg_branch}^!" < "$mbox" \
+		|| verbose "No matching base commit in project $prj" )"
+
+	# Break out of loop once we find a base
+	[ -z "$commit" ] || break;
+done
+
+if [ -n "$commit" ]; then
+	if [ -n "$expected_prj" ] && [ "$expected_prj" != "$prj" ]; then
+		insert_header "$mbox" "X-Aiaiai-Expected-Project: $expected_prj"
+		verbose "Expected project $expected_prj but got $prj"
+	fi
+	# We found a commit, so insert proper headers
+	insert_header "$mbox" "X-Aiaiai-Project: $prj"
+	insert_header "$mbox" "X-Aiaiai-Base-Commit: $commit"
+else
+	if [ -z "$expected_prj" ]; then
+		# No project, so cancel. However, if we have an expected
+		# project, attempt to test anwyays.
+		insert_header "$mbox" "X-Aiaiai-Cancel-Email-Test-Patchset: 1"
+	fi
+	send_reply "$mbox" <<EOF
+Aiaiai was unable to correctly determine the project for your patch submission.
+Normally the diff index information provided by git's diff mechanism is enough.
+The most probably cause is that your patch is based against an older reference
+to the project.
+
+$(list_project_trees)
+
+If you continue to see this issue, despite rebasing, please contact the system
+maintainer.
+EOF
+fi
-- 
1.8.3.1




More information about the aiaiai mailing list