--- /dev/null
+#!/bin/bash
+
+# Send a patch series with a cover letter.
+
+# Example usage (dry-run, no emails are sent):
+# kernel-send-patches.sh -f rtc -s "Add PCF2131 patches infos" -e "dt-bindings: rtc: pcf2127: add PCF2131"
+#
+# Example usage (emails are sent):
+# add "-r" option
+
+set -e
+
+PROG_NAME=$(basename $0)
+
+trap 'catch $?' EXIT
+
+catch()
+{
+ if [ "$1" != "0" ]; then
+ # Error handling goes here
+ echo "Error $1 occurred"
+
+ if [ x"${orig_branch}" != x"" ]; then
+ git checkout ${orig_branch}
+ git rebase --abort
+ fi
+ fi
+
+ # Cleanup for both normal exit and error:
+ rm -f /tmp/all.patch
+ rm -f ${compile_script}
+}
+
+# --non: do not print name for each email address
+TO_CMD="`pwd`/scripts/get_maintainer.pl --nogit --nogit-fallback --norolestats --non --nol"
+CC_CMD="`pwd`/scripts/get_maintainer.pl --nogit --nogit-fallback --norolestats --non --nom"
+
+# Set default values
+commit_start=""
+commit_end=""
+DRY_RUN="--dry-run"
+orig_branch=""
+srcdir=""
+compile_cmd="make"
+compile_script=/tmp/kernel-compile-script.sh
+
+print_usage()
+{
+ echo "${PROG_NAME} -- Envoi de patches linux kernel"
+ echo "Usage: ${PROG_NAME} [OPTIONS...] COMMIT_START COMMIT_END"
+ echo
+ echo "Options:"
+ echo " -e end commit (string)"
+ echo " -f folder containing patch infos"
+ echo " -h display this help and exit"
+ echo " -r really send emails (default = dry-run)"
+ echo " -s start commit (string)"
+ echo
+}
+
+while getopts "e:f:hrs:" flag ;do
+ case ${flag} in
+ e)
+ commit_end="${OPTARG}"
+ ;;
+ f)
+ srcdir="${OPTARG}"
+ ;;
+ h)
+ print_usage
+ exit 0
+ ;;
+ r)
+ DRY_RUN=""
+ ;;
+ s)
+ commit_start="${OPTARG}"
+ ;;
+ ?)
+ echo "${PROG_NAME}: Option invalide: ${OPTARG}."
+ echo "Essayez \`${PROG_NAME} -h' pour plus d'informations."
+ exit 1
+ ;;
+ esac
+done
+shift `expr "${OPTIND}" - 1`
+
+# `$#' now represents the number of arguments after the options.
+# `$1' is the first argument, etc.
+if [ $# -ne 0 ]; then
+ echo "${PROG_NAME}: Too many arguments."
+ echo "Essayez \`${PROG_NAME} -h' pour plus d'informations."
+ exit 1
+fi
+
+if [ x"${srcdir}" = x"" ]; then
+ echo "Missing source directory"
+ exit 1
+fi
+
+if [ ! -d ${srcdir} ]; then
+ echo "Source directory not found"
+ exit 1
+fi
+
+if [ ! -f ${srcdir}/cover-letter.txt ]; then
+ echo "Missing cover letter template"
+ exit 1
+fi
+
+if [ ! -f ${srcdir}/infos.sh ]; then
+ echo "Missing patch infos file \"${srcdir}/infos.sh\""
+ exit 1
+fi
+
+source ${srcdir}/infos.sh
+
+if [ x"${commit_start}" = x"" ]; then
+ echo "Missing start commit message"
+ exit 1
+fi
+
+if [ x"${commit_end}" = x"" ]; then
+ echo "Missing end commit message"
+ exit 1
+fi
+
+
+if [ x"${series}" = x"" ]; then
+ echo "Missing series shell variable"
+ exit 1
+fi
+
+if [ x"${subject}" = x"" ]; then
+ echo "Missing subject shell variable"
+ exit 1
+fi
+
+if [ x"${cc_list}" = x"" ]; then
+ echo "Missing cc_list shell variable"
+ exit 1
+fi
+
+patches_branch="kernel_send_patches_v${series}_$(basename ${srcdir})"
+
+# First arg: commit message
+find_commit_by_log()
+{
+ echo $(git log --oneline HEAD~100..HEAD | grep "${1}" | awk {'print $1'})
+}
+
+# Because the cover letter is a special case and not a real patch, running
+# get_maintainer.pl on it would not return any TO or CC addresses.
+# Therefore, manually run get_maintainer.pl on the concatenation of all the
+# patches to build a list of TO and CC addresses, and use these for sending
+# all emails, including cover letter and actual patches.
+collect_email_addresses()
+{
+ cat ${srcdir}/v${series}-*.patch > /tmp/all.patch
+
+ # These variables will have one email address per line"
+ TO_MAIL="$(${TO_CMD} /tmp/all.patch)"
+ CC_MAIL="$(${CC_CMD} /tmp/all.patch)"
+
+ while IFS= read -r line; do
+ TO_OPTS="${TO_OPTS} --to ${line}"
+ done <<< "${TO_MAIL}"
+
+ while IFS= read -r line; do
+ CC_OPTS="${CC_OPTS} --cc ${line}"
+ done <<< "${CC_MAIL}"
+
+ for address in ${cc_list}; do
+ CC_OPTS="${CC_OPTS} --cc ${address}"
+ done
+}
+
+COMMIT_START_SHA1=$(find_commit_by_log "${commit_start}")
+
+if [ x"${COMMIT_START_SHA1}" = x"" ]; then
+ echo "Cannot find start commit identified by: \"${commit_start}\""
+ exit 1
+fi
+
+COMMIT_END_SHA1=$(find_commit_by_log "${commit_end}")
+
+if [ x"${COMMIT_END_SHA1}" = x"" ]; then
+ echo "Cannot find end commit identified by: \"${commit_end}\""
+ exit 1
+fi
+
+rm -rf ${srcdir}/*.patch
+
+git format-patch -v ${series} --output-directory=${srcdir} --cover-letter ${COMMIT_START_SHA1}..${COMMIT_END_SHA1}
+
+# Replace subject line in cover letter:
+sed -i -e "s/\*\*\* SUB.*/${subject}/" ${srcdir}/v${series}-0000-cover-letter.patch
+
+# Replace blurb line in cover letter:
+sed -i -e "/.*BLURB.*/{r ${srcdir}/cover-letter.txt" -e 'd}' ${srcdir}/v${series}-0000-cover-letter.patch
+
+collect_email_addresses
+
+# Check patches (except special case of cover letter patch):
+for p in ${srcdir}/*.patch; do
+ if [ x"$(basename ${p})" != x"v${series}-0000-cover-letter.patch" ]; then
+ if [ x"${ignore_checkpatch_errors}" != x"" ]; then
+ set +e
+ CHECKPATCH_OPS="--ignore ${ignore_checkpatch_errors}"
+ fi
+
+ scripts/checkpatch.pl ${CHECKPATCH_OPS} ${p}
+
+ if [ x"${ignore_checkpatch_errors}" != x"" ]; then
+ set -e
+ fi
+ fi
+done
+
+orig_branch=$(git branch --show-current)
+
+if [ x"${orig_branch}" = x"" ]; then
+ echo "Error: unable to determine current branch"
+ exit 1
+fi
+
+cat > ${compile_script} << "EOF"
+#!/bin/bash
+# Do not edit, auto-generated script
+echo
+echo "Testing commit: $(git log --oneline | head -n 1)"
+COMPILE_CMD
+EOF
+
+sed -i -e "s@COMPILE_CMD@${compile_cmd}@" ${compile_script}
+chmod u+x ${compile_script}
+
+# Compile each commit. Create branch to avoid "detached HEAD" state, and also to
+# keep a record of what was sent:
+if git branch | grep -q ${patches_branch}; then
+ git branch -D ${patches_branch}
+fi
+git checkout -b ${patches_branch} ${COMMIT_END_SHA1}
+git rebase --exec=${compile_script} ${COMMIT_START_SHA1}
+git checkout ${orig_branch}
+
+# Send email(s)
+git send-email ${DRY_RUN} --annotate --thread --no-chain-reply-to \
+ ${TO_OPTS} ${CC_OPTS} \
+ --8bit-encoding=UTF-8 \
+ ${srcdir}/*.patch