--- /dev/null
+#!/bin/bash
+# prepares a template e-mail and HTML file to announce a new release
+# Copyright (c) 2006-2016 Willy Tarreau <w@1wt.eu>
+#
+# In short :
+# - requires git
+# - wants that last commit is a release/tag
+# - no restriction to master, uses last tag
+# - creates mail-$version.txt
+# - creates web-$version.html
+# - indicates how to edit the mail and how to send it
+
+USAGE="Usage: ${0##*/} [-b branch] [-d date] [-o oldver] [-n newver]"
+OUTPUT=
+BRANCH=
+HTML=
+DATE=
+YEAR=
+OLD=
+NEW=
+DIR=
+
+die() {
+ [ "$#" -eq 0 ] || echo "$*" >&2
+ exit 1
+}
+
+err() {
+ echo "$*" >&2
+}
+
+quit() {
+ [ "$#" -eq 0 ] || echo "$*"
+ exit 0
+}
+
+while [ -n "$1" -a -z "${1##-*}" ]; do
+ case "$1" in
+ -d) DATE="$2" ; shift 2 ;;
+ -b) BRANCH="$2" ; shift 2 ;;
+ -o) OLD="$2" ; shift 2 ;;
+ -n) NEW="$2" ; shift 2 ;;
+ -h|--help) quit "$USAGE" ;;
+ *) die "$USAGE" ;;
+ esac
+done
+
+if [ $# -gt 0 ]; then
+ die "$USAGE"
+fi
+
+if ! git rev-parse --verify -q HEAD >/dev/null; then
+ die "Failed to check git HEAD."
+fi
+
+# we want to go to the git root dir
+DIR="$PWD"
+cd $(git rev-parse --show-toplevel)
+
+if [ "$(git rev-parse --verify -q HEAD)" != "$(git rev-parse --verify -q master)" ]; then
+ die "git HEAD doesn't match master branch."
+fi
+
+if [ "$(git diff HEAD|wc -c)" != 0 ]; then
+ err "You appear to have uncommitted local changes, please commit them first :"
+ git status -s -uno >&2
+ die
+fi
+
+if [ -z "$NEW" ]; then
+ NEW="$(git describe --tags HEAD --abbrev=0)"
+ NEW="${NEW#v}"
+ if [ -z "$NEW" ]; then
+ die "Fatal: cannot determine new version, please specify it."
+ fi
+ if [ "$(git describe --tags HEAD)" != "v$NEW" ]; then
+ die "Current version doesn't seem tagged, it reports $(git describe --tags "v$NEW"). Did you release it ?"
+ fi
+fi
+
+if ! git show-ref --tags "v$NEW" >/dev/null; then
+ die "git tag v$NEW already exist, did you create the release ?"
+fi
+
+if [ -z "$OLD" ]; then
+ OLD="$(git describe --tags v${NEW}^ --abbrev=0)"
+ OLD="${OLD#v}"
+fi
+
+if ! git rev-parse --verify -q "v$OLD" >/dev/null; then
+ die "git tag v$OLD doesn't exist."
+fi
+
+# determine the product branch from the new release
+if [ -z "$BRANCH" ]; then
+ subvers=${NEW#[0-9]*.[0-9]*[-.]*[0-9].}
+ [ "${subvers}" = "${NEW}" ] && subvers=""
+ major=${NEW%.$subvers}
+ branch_ext=${major#*[0-9].*[0-9]}
+ BRANCH=${major%${branch_ext}}
+fi
+
+# determine the release date
+if [ -z "$DATE" ]; then
+ DATE="$(git log -1 --pretty=fuller v${NEW} 2>/dev/null | sed -ne '/^CommitDate:/{s/\(^[^ ]*:\)\|\( [-+].*\)//gp;q}')"
+ DATE="$(date +%Y/%m/%d -d "$DATE")"
+fi
+YEAR="${DATE%%/*}"
+
+OUTPUT="$DIR/mail-haproxy-$NEW.txt"
+if [ -e "$OUTPUT" ]; then
+ die "$OUTPUT already exists, please remove it."
+fi
+
+HTML="$DIR/web-haproxy-$NEW.html"
+if [ -e "$HTML" ]; then
+ die "$HTML already exists, please remove it."
+fi
+
+(echo "Subject: [ANNOUNCE] haproxy-$NEW"
+ echo "To: haproxy@formilux.org"
+ echo
+ echo "Hi,"
+ echo
+ echo -n "HAProxy $NEW was released on $DATE. It added "
+ echo -n $(git log --oneline --reverse --format="%s" "v$OLD".."v$NEW^" | wc -l)
+ echo " new commits"
+ echo "after version $OLD."
+ echo
+ echo "- per tag :"
+ git log --oneline --reverse --format="%s" "v$OLD".."v$NEW^" | cut -f1 -d':' | sort | uniq -c
+ echo
+ echo "major commits :"
+ git log --oneline --reverse --format=" - %s" "v$OLD".."v$NEW^" | grep MAJOR
+ echo
+ echo "- per file :"
+ git show "v$OLD".."v$NEW^" -- src/ | grep ^diff | awk '{ print substr($3,7)}' | sort | uniq -c | sort -nr | head -15
+ echo
+ echo "- per topic :"
+ git log --oneline --reverse --format="%s" "v$OLD".."v$NEW^" | cut -f2 -d':' | awk '{sub("s$","",$1); print $1}' | sort | uniq -c
+ echo
+ echo "- sorted changelog :"
+ git log --oneline --reverse --format="%s" "v$OLD".."v$NEW^" | sort
+ echo
+ echo "#############################################################################################"
+) >> "$OUTPUT"
+
+# report the download paths
+if [ -z "${NEW##*-dev*}" ]; then
+ gitdir="haproxy.git"
+else
+ gitdir="haproxy-$BRANCH.git"
+fi
+
+(echo "Please find the usual URLs below :"
+ echo " Site index : http://www.haproxy.org/"
+ echo " Discourse : http://discourse.haproxy.org/"
+ echo " Sources : http://www.haproxy.org/download/${BRANCH}/src/"
+ echo " Git repository : http://git.haproxy.org/git/${gitdir}/"
+ echo " Git Web browsing : http://git.haproxy.org/?p=${gitdir}"
+ echo " Changelog : http://www.haproxy.org/download/${BRANCH}/src/CHANGELOG"
+ echo " Cyril's HTML doc : http://cbonte.github.io/haproxy-dconv/"
+) >> "$OUTPUT"
+
+# sign
+(echo
+ echo "${GIT_COMMITTER_NAME% *}"
+) >> "$OUTPUT"
+
+(echo "---"
+ echo "Complete changelog :"
+ git log --oneline --reverse --format=" - %s" "v$OLD".."v$NEW^"
+ echo "---"
+) >> "$OUTPUT"
+
+
+# prepare the HTML update
+set -- $(date +%e -d "$DATE")
+case "$1" in
+ 11|12|13) day="${1}th" ;;
+ *1) day="${1}st" ;;
+ *2) day="${2}nd" ;;
+ *3) day="${1}rd" ;;
+ *) day="${1}th" ;;
+esac
+
+humandate=$(date "+%B, $day, %Y" -d "$DATE")
+(echo "$humandate</b> : <i>$NEW</i>"
+ echo " <p>"
+ echo " <ul>"
+ echo "<--------------------------- edit contents below --------------------------->"
+ echo "- per tag :"
+ git log --oneline --reverse --format="%s" "v$OLD".."v$NEW^" | cut -f1 -d':' | sort | uniq -c
+ echo
+ echo "- per topic :"
+ git log --oneline --reverse --format="%s" "v$OLD".."v$NEW^" | cut -f2 -d':' | awk '{sub("s$","",$1); print $1}' | sort | uniq -c
+ echo
+ echo "major commits :"
+ git log --oneline --reverse --format=" - %s" "v$OLD".."v$NEW^" | grep MAJOR
+ echo
+ echo "<--------------------------------------------------------------------------->"
+ echo " Code and changelog are available <a href=\"/download/${BRANCH}/src/\">here</a> as usual."
+ echo " </ul>"
+ echo " <p>"
+ echo " <b>"
+) >> "$HTML"
+
+echo "The announce was emitted into file $OUTPUT."
+echo "You can edit it and send it this way :"
+echo
+echo " mutt -i ${OUTPUT##*/} -s \"[ANNOUNCE] haproxy-$NEW\" haproxy@formilux.org"
+echo
+echo "The HTML block was emitted into $HTML and needs to be finished by hand."
+echo
--- /dev/null
+#!/bin/bash
+# creates a new haproxy release at the current commit
+# Copyright (c) 2006-2016 Willy Tarreau <w@1wt.eu>
+#
+# In short :
+# - requires git
+# - works only from master branch
+# - finds old and new version by itself
+# - builds changelog
+# - updates dates and versions in files
+# - commits + tags + signs
+# - no upload!
+
+USAGE="Usage: ${0##*/} [-i] [-y] [-t] [-b branch] [-d date] [-o oldver] [-n newver]"
+INTERACTIVE=
+TAGONLY=
+SAYYES=
+BRANCH=
+DATE=
+YEAR=
+OLD=
+NEW=
+
+die() {
+ [ "$#" -eq 0 ] || echo "$*" >&2
+ exit 1
+}
+
+err() {
+ echo "$*" >&2
+}
+
+quit() {
+ [ "$#" -eq 0 ] || echo "$*"
+ exit 0
+}
+
+do_commit() {
+ (
+ echo "[RELEASE] Released version $NEW"
+ echo
+ echo "Released version $NEW with the following main changes :"
+ sed -ne '/^[ ]*-/,/^$/{p;b a};d;:a;/^$/q' CHANGELOG
+ ) | git commit -a -F -
+}
+
+do_tag() {
+ git tag -u "$GIT_GPG_KEY" -s -m "HAProxy $NEW" v$NEW && echo "Tagged as v$NEW"
+}
+
+while [ -n "$1" -a -z "${1##-*}" ]; do
+ case "$1" in
+ -y) SAYYES=1 ; shift ;;
+ -i) INTERACTIVE=1 ; shift ;;
+ -t) TAGONLY=1 ; shift ;;
+ -d) DATE="$2" ; shift 2 ;;
+ -b) BRANCH="$2" ; shift 2 ;;
+ -o) OLD="$2" ; shift 2 ;;
+ -n) NEW="$2" ; shift 2 ;;
+ -h|--help) quit "$USAGE" ;;
+ *) die "$USAGE" ;;
+ esac
+done
+
+if [ $# -gt 0 ]; then
+ die "$USAGE"
+fi
+
+if [ -z "$GIT_GPG_KEY" ]; then
+ die "GIT_GPG_KEY is not set, it must contain your GPG key ID."
+fi
+
+if ! git rev-parse --verify -q HEAD >/dev/null; then
+ die "Failed to check git HEAD."
+fi
+
+# we want to go to the git top dir
+cd $(git rev-parse --show-toplevel)
+
+if [ "$(git rev-parse --verify -q HEAD)" != "$(git rev-parse --verify -q master)" ]; then
+ die "git HEAD doesn't match master branch."
+fi
+
+if [ "$(git diff HEAD|wc -c)" != 0 ]; then
+ err "You appear to have uncommitted local changes, please commit them first :"
+ git status -s -uno >&2
+ die
+fi
+
+if [ -z "$OLD" ]; then
+ OLD="$(git describe --tags HEAD --abbrev=0)"
+ OLD="${OLD#v}"
+fi
+
+if ! git rev-parse --verify -q "v$OLD" >/dev/null; then
+ die "git tag v$OLD doesn't exist."
+fi
+
+if [ -z "$NEW" ]; then
+ radix="$OLD"
+ while [ -n "$radix" -a -z "${radix%%*[0-9]}" ]; do
+ radix="${radix%[0-9]}"
+ done
+
+ number=${OLD#$radix}
+ if [ -z "$number" -o "$radix" = "$OLD" ]; then
+ die "Fatal: cannot determine new version, please specify it."
+ fi
+ NEW=${radix}$((number+1))
+fi
+
+if git show-ref --tags "v$NEW" >/dev/null; then
+ die "git tag v$NEW already exists, please remove it first."
+fi
+
+# determine the product branch from the new release
+if [ -z "$BRANCH" ]; then
+ subvers=${NEW#[0-9]*.[0-9]*[-.]*[0-9].}
+ [ "${subvers}" = "${NEW}" ] && subvers=""
+ major=${NEW%.$subvers}
+ branch_ext=${major#*[0-9].*[0-9]}
+ BRANCH=${major%${branch_ext}}
+fi
+
+
+# determine the release date
+if [ -z "$DATE" ]; then
+ # Uncomment the line below to use the date of the last commit,
+ # otherwise fall back to current date
+ DATE="$(git log --pretty=fuller -1 v$NEW 2>/dev/null | sed -ne '/^CommitDate:/{s/\(^[^ ]*:\)\|\( [-+].*\)//gp;q}')"
+ DATE="$(date +%Y/%m/%d -d "$DATE")"
+else
+ if [ "$DATE" != "$(date +%Y/%m/%d -d "$DATE")" ]; then
+ die "Date format must exclusively be YYYY/MM/DD ; date was '$DATE'."
+ fi
+fi
+YEAR="${DATE%%/*}"
+
+if [ -n "$TAGONLY" ]; then
+ do_tag || die "Failed to tag changes"
+ echo "Done. You may have to push changes."
+ exit 0
+fi
+
+echo "About to release version $NEW from $OLD at $DATE (branch $BRANCH)."
+if [ -z "$SAYYES" ]; then
+ echo "Press ENTER to continue or Ctrl-C to abort now!"
+ read
+fi
+
+echo "Updating CHANGELOG ..."
+( echo "ChangeLog :"
+ echo "==========="
+ echo
+ echo "$DATE : $NEW"
+ #git shortlog v$OLD.. | sed -ne 's/^ / - /p'
+ git log --oneline --reverse --format=" - %s" v$OLD..
+ echo
+ tail +4 CHANGELOG
+) >.chglog.tmp && mv .chglog.tmp CHANGELOG
+
+echo "Updating VERSION ..."
+rm -f VERSION VERDATE
+echo "$NEW" > VERSION
+
+echo "Updating VERDATE ..."
+echo '$Format:%ci$' > VERDATE
+echo "$DATE" >> VERDATE
+
+echo "Updating haproxy.spec ..."
+sed -e "s/^Version: .*/Version: $NEW/" < examples/haproxy.spec >examples/haproxy.spec- && mv examples/haproxy.spec- examples/haproxy.spec
+
+(sed -ne '0,/^%changelog/p';
+ date -d "$DATE" "+* %a %b %e %Y $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
+ echo "- updated to $(cat VERSION)"
+ echo
+) < examples/haproxy.spec >examples/haproxy.spec-
+sed -ne '0,/^%changelog/d;p' < examples/haproxy.spec >>examples/haproxy.spec-
+mv examples/haproxy.spec- examples/haproxy.spec
+
+# updating branch and date in README and all modified doc files except the outdated architecture.txt
+for file in README doc/intro.txt doc/configuration.txt doc/management.txt $(git diff --name-only v${OLD}.. -- doc); do
+ if [ ! -e "$file" ]; then continue; fi
+ if [ "$file" = doc/architecture.txt ]; then continue; fi
+ echo "Updating $file ..."
+ sed -e "1,10s:\(\sversion\s\).*:\1$BRANCH:" \
+ -e "1,10s:\(\s\)\(20[0-9]\{2\}/[0-9]\{1,2\}/[0-9]\{1,2\}\):\1$DATE:" \
+ -i "$file"
+done
+
+echo "Updating haproxy.c ..."
+sed -e "s:Copyright 2000-[0-9]*\s*Willy Tarreau.*>:Copyright 2000-$YEAR Willy Tarreau <willy@haproxy.org>:" \
+ -i src/haproxy.c
+
+if [ -n "$INTERACTIVE" ]; then
+ vi CHANGELOG VERSION VERDATE examples/haproxy*.spec \
+ src/haproxy.c README doc/configuration.txt \
+ $(git diff --name-only v${OLD}.. -- doc)
+fi
+
+if [ "$(git diff -- CHANGELOG | wc -c)" = 0 ]; then
+ die "CHANGELOG must be updated."
+fi
+
+if [ -z "$SAYYES" ]; then
+ echo "Press ENTER to review the changes..."
+ read
+fi
+
+git diff
+
+echo
+echo "About to commit and tag version $NEW with the following message:"
+echo
+echo "[RELEASE] Released version $NEW with the following main changes :"
+sed -ne '/^[ ]*-/,/^$/{p;b a};d;:a;/^$/q' CHANGELOG
+
+echo
+echo "LAST chance to cancel! Press ENTER to proceed now or Ctrl-C to abort."
+read
+
+do_commit || die "Failed to commit changes"
+do_tag || die "Failed to tag changes"
+
+echo "Do not forget to push updates, publish and announce this version :"
+echo
+echo "git push origin master v$NEW"
+echo "${0%/*}/publish-release"
+echo "${0%/*}/announce-release"
--- /dev/null
+#!/bin/bash
+#
+# Compares multiple branches against a reference and shows which ones contain
+# each commit, and the level of backports since the origin or its own ancestors.
+#
+# Copyright (c) 2016 Willy Tarreau <w@1wt.eu>
+#
+# The purpose is to make it easy to visualize what backports might be missing
+# in a maintenance branch, and to easily spot the ones that are needed and the
+# ones that are not. It solely relies on the "cherry-picked from" tags in the
+# commit messages to find what commit is available where, and can even find a
+# reference commit's ancestor in another branch's commit ancestors as well to
+# detect that the patch is present. When done with the proper references and
+# a correct ordering of the branches, it can be used to quickly apply a set of
+# fixes to a branch since it dumps suggested commands at the end. When doing
+# so it is a good idea to use "HEAD" as the last branch to avoid doing mistakes.
+#
+# Examples :
+# - find what's in master and not in current branch :
+# show-backports -q -m -r master HEAD
+# - find what's in 1.6/master and in hapee-maint-1.5r2 but not in current branch :
+# show-backports -q -m -r 1.6/master hapee-maint-1.5r2 HEAD | grep ' [a-f0-9]\{8\}[-+][0-9] '
+# - check that no recent fix from master is missing in any maintenance branch :
+# show-backports -r master hapee-maint-1.5r2 aloha-7.5 hapee-maint-1.5r1 aloha-7.0
+# - see what was recently merged into 1.6 and has no equivalent in local master :
+# show-backports -q -m -r 1.6/master -b "1.6/master@{1 week ago}" master
+# - check what extra backports are present in hapee-r2 compared to hapee-r1 :
+# show-backports -q -m -r hapee-r2 hapee-r1
+
+
+USAGE="Usage: ${0##*/} [-q] [-m] [-r reference] [-l logexpr] [-s subject] [-b base] branch [...]"
+BRANCHES=( )
+REF=master
+BASE=
+QUIET=
+LOGEXPR=
+SUBJECT=
+MISSING=
+
+die() {
+ [ "$#" -eq 0 ] || echo "$*" >&2
+ exit 1
+}
+
+err() {
+ echo "$*" >&2
+}
+
+quit() {
+ [ "$#" -eq 0 ] || echo "$*"
+ exit 0
+}
+
+short() {
+ # git rev-parse --short $1
+ echo "${1::8}"
+}
+
+dump_commit_matrix() {
+ title=":$REF:"
+ for branch in "${BRANCHES[@]}"; do
+ #echo -n " $branch"
+ title="$title :${branch}:"
+ done
+ title="$title |"
+
+ count=0
+ # now look up commits
+ while read ref subject; do
+ if [ -n "$MISSING" -a "${subject:0:9}" = "[RELEASE]" ]; then
+ continue
+ fi
+
+ upstream="none"
+ missing=0
+ line="$(short $ref)"
+ for branch in "${BRANCHES[@]}"; do
+ set -- $(grep -m 1 $ref "$WORK/${branch//\//_}")
+ newhash=$1 ; shift
+ # count the number of cherry-picks after this one. Since we shift,
+ # the result is in "$#"
+ while [ -n "$1" -a "$1" != "$ref" ]; do
+ shift
+ done
+ if [ -n "$newhash" ]; then
+ line="${line} $(short $newhash)-$#"
+ else
+ # before giving up we can check if our current commit was
+ # itself cherry-picked and check this again. In order not
+ # to have to do it all the time, we can cache the result
+ # for the current line. If a match is found we report it
+ # with the '+' delimiter instead of '-'.
+ if [ "$upstream" = "none" ]; then
+ upstream=( $(git log -1 --pretty --format=%B "$ref" | \
+ sed -n 's/^commit \([^)]*\) upstream\.$/\1/p;s/^(cherry picked from commit \([^)]*\))/\1/p') )
+ fi
+ newhash=""
+ for h in ${upstream[@]}; do
+ set -- $(grep -m 1 $h "$WORK/${branch//\//_}")
+ newhash=$1 ; shift
+ while [ -n "$1" -a "$1" != "$h" ]; do
+ shift
+ done
+ if [ -n "$newhash" ]; then
+ line="${line} $(short $newhash)+$#"
+ break
+ fi
+ done
+ if [ -z "$newhash" ]; then
+ line="${line} -"
+ missing=1
+ fi
+ fi
+ done
+ line="${line} |"
+ if [ -z "$MISSING" -o $missing -gt 0 ]; then
+ [ $((count++)) -gt 0 ] || echo $title
+ [ "$QUIET" != "" -o $count -lt 20 ] || count=0
+ echo "$line"
+ fi
+ done < "$WORK/${REF//\//_}"
+}
+
+while [ -n "$1" -a -z "${1##-*}" ]; do
+ case "$1" in
+ -b) BASE="$2" ; shift 2 ;;
+ -r) REF="$2" ; shift 2 ;;
+ -l) LOGEXPR="$2" ; shift 2 ;;
+ -s) SUBJECT="$2" ; shift 2 ;;
+ -q) QUIET=1 ; shift ;;
+ -m) MISSING=1 ; shift ;;
+ -h|--help) quit "$USAGE" ;;
+ *) die "$USAGE" ;;
+ esac
+done
+
+BRANCHES=( "$@" )
+if [ ${#BRANCHES[@]} = 0 ]; then
+ die "$USAGE"
+fi
+
+for branch in "$REF" "${BRANCHES[@]}"; do
+ if ! git rev-parse --verify -q "$branch" >/dev/null; then
+ die "Failed to check git branch $branch."
+ fi
+done
+
+if [ -z "$BASE" ]; then
+ err "Warning! No base specified, looking for common ancestor."
+ BASE=$(git merge-base --all "$REF" "${BRANCHES[@]}")
+ if [ -z "$BASE" ]; then
+ die "Couldn't find a common ancestor between these branches"
+ fi
+fi
+
+# we want to go to the git root dir
+DIR="$PWD"
+cd $(git rev-parse --show-toplevel)
+
+mkdir -p .git/.show-backports #|| die "Can't create .git/.show-backports"
+WORK=.git/.show-backports
+
+rm -f "$WORK/${REF//\//_}"
+git log --reverse ${LOGEXPR:+--grep $LOGEXPR} --pretty="%H %s" "$BASE".."$REF" | grep "${SUBJECT}" > "$WORK/${branch//\//_}" > "$WORK/${REF//\//_}"
+
+# for each branch, enumerate all commits and their ancestry
+for branch in "${BRANCHES[@]}"; do
+ rm -f "$WORK/${branch//\//_}"
+ git log --reverse --pretty="%H %s" "$BASE".."$branch" | grep "${SUBJECT}" | while read h subject; do
+ echo "$h" $(git log -1 --pretty --format=%B "$h" | \
+ sed -n 's/^commit \([^)]*\) upstream\.$/\1/p;s/^(cherry picked from commit \([^)]*\))/\1/p')
+ done > "$WORK/${branch//\//_}"
+done
+
+count=0
+dump_commit_matrix | column -t | \
+(
+ left_commits=( )
+ right_commits=( )
+ while read line; do
+ # append the subject at the end of the line
+ set -- $line
+ echo -n "$line "
+ if [ "${line::1}" = ":" ]; then
+ echo "---- Subject ----"
+ else
+ # doing it this way prevents git from abusing the terminal
+ echo $(git log -1 --pretty="%s" "$1")
+ left_commits[${#left_commits[@]}]="$1"
+ comm=""
+ while [ -n "$1" -a "$1" != "-" -a "$1" != "|" ]; do
+ comm="${1%-*}"
+ shift
+ done
+ right_commits[${#right_commits[@]}]="$comm"
+ fi
+ done
+ if [ -n "$MISSING" -a ${#left_commits[@]} -eq 0 ]; then
+ echo "No missing commit to apply."
+ elif [ -n "$MISSING" ]; then
+ echo
+ echo "In order to apply all leftmost commits to current branch :"
+ echo " git cherry-pick -x ${left_commits[@]}"
+ echo
+ echo "In order to apply all rightmost commits to current branch :"
+ echo " git cherry-pick -x ${right_commits[@]}"
+ fi
+)
--- /dev/null
+#!/bin/bash
+# puts the public files online after a release
+# Copyright (c) 2006-2016 Willy Tarreau <w@1wt.eu>
+#
+# In short :
+# - requires git
+# - no restriction to master, uses last tag
+# - copies & compresses files, changelog & docs to the final destination
+# - shows a listing of the final file
+
+USAGE="Usage: ${0##*/} [-y] [-b branch] [-n newver] DIR"
+TARGET_DIR=
+OUTPUT=
+SAYYES=
+BRANCH=
+DEVEL=
+NEW=
+DIR=
+DOC=( )
+
+die() {
+ [ "$#" -eq 0 ] || echo "$*" >&2
+ exit 1
+}
+
+err() {
+ echo "$*" >&2
+}
+
+quit() {
+ [ "$#" -eq 0 ] || echo "$*"
+ exit 0
+}
+
+while [ -n "$1" -a -z "${1##-*}" ]; do
+ case "$1" in
+ -y) SAYYES=1 ; shift ;;
+ -b) BRANCH="$2" ; shift 2 ;;
+ -n) NEW="$2" ; shift 2 ;;
+ -h|--help) quit "$USAGE" ;;
+ *) die "$USAGE" ;;
+ esac
+done
+
+if [ $# -ne 1 ]; then
+ die "$USAGE"
+fi
+
+DIR="$1" ; shift
+if [ -z "$DIR" ]; then
+ die "Missing target directory name."
+fi
+
+if [ -n "${DIR##/*}" ]; then
+ DIR="$PWD/$DIR"
+fi
+
+if [ ! -d "$DIR/." ]; then
+ die "Target directory doesn't exist : $DIR"
+fi
+
+if ! git rev-parse --verify -q HEAD >/dev/null; then
+ die "Failed to check git HEAD."
+fi
+
+# we want to go to the git top dir
+cd $(git rev-parse --show-toplevel)
+
+if [ "$(git rev-parse --verify -q HEAD)" != "$(git rev-parse --verify -q master)" ]; then
+ die "git HEAD doesn't match master branch."
+fi
+
+if [ "$(git diff HEAD|wc -c)" != 0 ]; then
+ err "You appear to have uncommitted local changes, please commit them first :"
+ git status -s -uno >&2
+ die
+fi
+
+if [ -z "$NEW" ]; then
+ NEW="$(git describe --tags HEAD --abbrev=0)"
+ NEW="${NEW#v}"
+ if [ -z "$NEW" ]; then
+ die "Fatal: cannot determine new version, please specify it."
+ fi
+ if [ "$(git describe --tags HEAD)" != "v$NEW" ]; then
+ die "Current version doesn't seem tagged, it reports $(git describe --tags "v$NEW"). Did you release it ?"
+ fi
+fi
+
+if ! git show-ref --tags "v$NEW" >/dev/null; then
+ die "git tag v$NEW doesn't exist, did you create the release ?"
+fi
+
+# determine the product branch from the new release
+if [ -z "$BRANCH" ]; then
+ subvers=${NEW#[0-9]*.[0-9]*[-.]*[0-9].}
+ [ "${subvers}" = "${NEW}" ] && subvers=""
+ major=${NEW%.$subvers}
+ branch_ext=${major#*[0-9].*[0-9]}
+ BRANCH=${major%${branch_ext}}
+fi
+
+TARGET_DIR="$DIR/$BRANCH"
+if [ ! -d "$TARGET_DIR/." ]; then
+ die "Target directory doesn't contain branch $BRANCH. You may have to create it in $DIR."
+fi
+
+if [ -z "${NEW##*-dev*}" ]; then
+ DEVEL="/devel"
+fi
+
+if ! mkdir -p "$TARGET_DIR/src$DEVEL" "$TARGET_DIR/doc"; then
+ die "failed to create target directories."
+fi
+
+case "$BRANCH" in
+ 1.3) DOC=( doc/{haproxy-en,haproxy-fr,configuration,architecture}.txt ) ;;
+ 1.4) DOC=( doc/{haproxy-en,haproxy-fr,configuration}.txt ) ;;
+ 1.5) DOC=( doc/{coding-style,configuration,proxy-protocol}.txt ) ;;
+ 1.6) DOC=( doc/{coding-style,intro,management,configuration,proxy-protocol,lua}.txt ) ;;
+ *) DOC=( doc/{coding-style,intro,management,configuration,proxy-protocol,lua}.txt ) ;;
+esac
+
+echo "Ready to produce the following files in $TARGET_DIR/ :"
+echo " haproxy-$NEW.tar.gz -> src${DEVEL}/"
+echo " CHANGELOG -> src/CHANGELOG"
+echo " ${DOC[@]} -> doc/*{,.gz}"
+echo
+
+git ls-tree -l --abbrev=12 "v$NEW" -- CHANGELOG "${DOC[@]}"
+
+if [ -z "$SAYYES" ]; then
+ echo "Press ENTER to continue or Ctrl-C to abort now!"
+ read
+fi
+
+echo "Archiving sources for version $NEW ..."
+rm -f "${TARGET_DIR}/src${DEVEL}/haproxy-${NEW}.tar.gz"{,.md5}
+if ! git archive --format=tar --prefix="haproxy-${NEW}/" "v$NEW" | \
+ gzip -9 > "${TARGET_DIR}/src${DEVEL}/haproxy-${NEW}.tar.gz"; then
+ die "Failed to produce the tar.gz archive"
+fi
+
+( cd "$TARGET_DIR/src${DEVEL}" ; \
+ md5sum haproxy-$NEW.tar.gz > haproxy-$NEW.tar.gz.md5 )
+
+echo "Extracting doc ..."
+git show "v$NEW:CHANGELOG" > "$TARGET_DIR/src/CHANGELOG"
+
+for i in "${DOC[@]}"; do
+ git show "v$NEW:$i" > "$TARGET_DIR/doc/${i#doc/}"
+ gzip -c9 < "$TARGET_DIR/doc/${i#doc/}" > "$TARGET_DIR/doc/${i#doc/}.gz"
+done
+
+echo "Done : ls -l ${TARGET_DIR}"
+( cd "$TARGET_DIR" ;
+ ls -l src/CHANGELOG "src${DEVEL}/haproxy-${NEW}".tar.gz{,.md5} $(for i in "${DOC[@]}"; do echo "doc/${i#doc/}"{,.gz}; done)
+)
+echo