summaryrefslogtreecommitdiffstats
path: root/maint/bumplibs.in
diff options
context:
space:
mode:
Diffstat (limited to 'maint/bumplibs.in')
-rw-r--r--maint/bumplibs.in291
1 files changed, 291 insertions, 0 deletions
diff --git a/maint/bumplibs.in b/maint/bumplibs.in
new file mode 100644
index 0000000..a142660
--- /dev/null
+++ b/maint/bumplibs.in
@@ -0,0 +1,291 @@
+#!@BASH_PATH@
+#
+# Copyright 2012-2021 the Pacemaker project contributors
+#
+# The version control history for this file may have further details.
+#
+# This source code is licensed under the GNU General Public License version 2
+# or later (GPLv2+) WITHOUT ANY WARRANTY.
+#
+
+# List regular expressions (not globs) that match all of a library's public API
+# headers. Any files ending in "internal.h" will be excluded from matches.
+declare -A HEADERS
+HEADERS[cib]="include/crm/cib.h include/crm/cib/.*.h"
+HEADERS[crmcommon]="include/crm/crm.h
+ include/crm/msg_xml.h
+ include/crm/common/.*.h"
+HEADERS[crmcluster]="include/crm/cluster.h include/crm/cluster/.*.h"
+HEADERS[crmservice]="include/crm/services.*.h"
+HEADERS[lrmd]="include/crm/lrmd.*.h"
+HEADERS[pacemaker]="include/pacemaker.*.h"
+HEADERS[pe_rules]="include/crm/pengine/ru.*.h"
+HEADERS[pe_status]="include/crm/pengine/[^r].*.h include/crm/pengine/r[^u].*.h"
+HEADERS[stonithd]="include/crm/stonith-ng.h include/crm/fencing/.*.h"
+
+yesno() {
+ local RESPONSE
+
+ read -p "$1 " RESPONSE
+ case $(echo "$RESPONSE" | tr A-Z a-z) in
+ y|yes|ano|ja|si|oui) return 0 ;;
+ *) return 1 ;;
+ esac
+}
+
+prompt_to_continue() {
+ yesno "Continue?" || exit 0
+}
+
+find_last_release() {
+ if [ ! -z "$1" ]; then
+ echo "$1"
+ else
+ git tag -l | grep Pacemaker | grep -v rc | sort -Vr | head -n 1
+ fi
+}
+
+find_libs() {
+ find lib -name "*.am" -exec grep "lib.*_la_LDFLAGS.*version-info" \{\} \; \
+ | sed -e 's/lib\(.*\)_la_LDFLAGS.*/\1/'
+}
+
+find_makefile() {
+ find lib -name Makefile.am -exec grep -l "lib${1}_la.*version-info" \{\} \;
+}
+
+find_sources() {
+ local LIB="$1"
+ local AMFILE="$2"
+ local SOURCES
+
+ # Library makefiles should use "+=" to break up long sources lines rather
+ # than backslashed continuation lines, to allow this script to detect
+ # source files correctly. Warn if that's not the case.
+ if
+ grep "lib${LIB}_la_SOURCES.*\\\\" $AMFILE
+ then
+ echo -e "\033[1;35m -- Sources list for lib$LIB is probably truncated! --\033[0m"
+ echo "Edit to use '+=' rather than backslashed continuation lines"
+ prompt_to_continue
+ fi
+
+ SOURCES=$(grep "^lib${LIB}_la_SOURCES" "$AMFILE" \
+ | sed -e 's/.*=//' -e 's/\\//' -e 's:\.\./gnu/:lib/gnu/:')
+
+ for SOURCE in $SOURCES; do
+ if
+ echo $SOURCE | grep -q "/"
+ then
+ echo "$SOURCE"
+ else
+ echo "$(dirname $AMFILE)/$SOURCE"
+ fi
+ done
+}
+
+find_headers_as_of() {
+ local TAG
+ local LIB
+ local FILE
+ local PATTERN
+
+ TAG="$1"
+ LIB="$2"
+
+ for FILE in $(git ls-tree -r --name-only "$TAG"); do
+ for PATTERN in ${HEADERS[$LIB]}; do
+ if [[ $FILE =~ $PATTERN ]] && [[ ! $FILE =~ internal.h$ ]]; then
+ echo "$FILE"
+ break
+ fi
+ done
+ done
+}
+
+extract_version() {
+ grep "lib${1}_la.*version-info" | sed -e 's/.*version-info\s*\(\S*\)/\1/'
+}
+
+shared_lib_name() {
+ local LIB="$1"
+ local VERSION="$2"
+
+ echo "lib${LIB}.so.$(echo $VERSION | cut -d: -f 1)"
+}
+
+process_lib() {
+ local LIB="$1"
+ local LAST_RELEASE="$2"
+ local AMFILE
+ local SOURCES
+ local HEADERS_LAST
+ local HEADERS_HEAD
+ local HEADERS_DIFF
+ local HEADERS_GONE
+ local HEADERS_ADDED
+ local CHANGE
+ local DEFAULT_CHANGE
+
+ if [ -z "${HEADERS[$LIB]}" ]; then
+ echo "Can't check lib$LIB until this script is updated with its headers"
+ prompt_to_continue
+ fi
+
+ AMFILE="$(find_makefile "$LIB")"
+
+ # Get current shared library version
+ VER_NOW=$(cat $AMFILE | extract_version $LIB)
+
+ # Check whether library existed at last release
+ git cat-file -e $LAST_RELEASE:$AMFILE 2>/dev/null
+ if [ $? -ne 0 ]; then
+ echo "lib$LIB is new, not changing version ($VER_NOW)"
+ prompt_to_continue
+ echo ""
+ return
+ fi
+
+ HEADERS_LAST="$(find_headers_as_of "$LAST_RELEASE" "$LIB")"
+ HEADERS_HEAD="$(find_headers_as_of "HEAD" "$LIB")"
+ HEADERS_DIFF="$(diff <(echo "$HEADERS_LAST") <(echo "$HEADERS_HEAD"))"
+ HEADERS_GONE="$(echo "$HEADERS_DIFF" | sed -n -e 's/^< //p')"
+ HEADERS_ADDED="$(echo "$HEADERS_DIFF" | sed -n -e 's/^> //p')"
+
+ # Check whether there were any changes to headers or sources
+ SOURCES="$(find_sources "$LIB" "$AMFILE")"
+ if [ -n "$HEADERS_GONE" ]; then
+ DEFAULT_CHANGE="i" # Removed public header is incompatible change
+ elif [ -n "$HEADERS_ADDED" ]; then
+ DEFAULT_CHANGE="c" # Additions are likely compatible
+ elif git diff --quiet -w $LAST_RELEASE..HEAD $HEADERS_HEAD $SOURCES ; then
+ echo "No changes to $LIB interface"
+ prompt_to_continue
+ echo ""
+ return
+ else
+ DEFAULT_CHANGE="f" # Sources changed, so it's at least a fix
+ fi
+
+ # Show all header changes since last release
+ echo "- Changes in lib$LIB public headers since $LAST_RELEASE:"
+ if [ -n "$HEADERS_GONE" ]; then
+ for HEADER in $HEADERS_GONE; do
+ echo "-- $HEADER was removed"
+ done
+ fi
+ if [ -n "$HEADERS_ADDED" ]; then
+ for HEADER in $HEADERS_ADDED; do
+ echo "++ $HEADER is new"
+ done
+ fi
+ git --no-pager diff --color -w $LAST_RELEASE..HEAD $HEADERS_HEAD
+
+ echo ""
+ if yesno "Show commits (minus refactor/build/merge) touching lib$LIB since $LAST_RELEASE [y/N]?"
+ then
+ git log --color $LAST_RELEASE..HEAD -z $HEADERS_HEAD $SOURCES $AMFILE \
+ | grep -vzE "Refactor:|Build:|Merge pull request"
+ echo
+ prompt_to_continue
+ fi
+
+ # @TODO this seems broken ...
+ #echo ""
+ #if yesno "Show merged PRs touching lib$LIB since $LAST_RELEASE [y/N]?"
+ #then
+ # git log --merges $LAST_RELEASE..HEAD $HEADERS_HEAD $SOURCES $AMFILE
+ # echo
+ # prompt_to_continue
+ #fi
+
+ # Show summary of source changes since last release
+ echo ""
+ echo "- Headers: $HEADERS_HEAD"
+ echo "- Changed sources since $LAST_RELEASE:"
+ git --no-pager diff --color -w $LAST_RELEASE..HEAD --stat $SOURCES
+ echo ""
+
+ # Ask for human guidance
+ echo "Are the changes to lib$LIB:"
+ read -p "[c]ompatible additions, [i]ncompatible additions/removals or [f]ixes? [$DEFAULT_CHANGE]: " CHANGE
+ [ -z "$CHANGE" ] && CHANGE="$DEFAULT_CHANGE"
+
+ # Get (and show) shared library version at last release
+ VER=$(git show $LAST_RELEASE:$AMFILE | extract_version $LIB)
+ VER_1=$(echo $VER | awk -F: '{print $1}')
+ VER_2=$(echo $VER | awk -F: '{print $2}')
+ VER_3=$(echo $VER | awk -F: '{print $3}')
+ echo "lib$LIB version at $LAST_RELEASE: $VER"
+
+ # Show current shared library version if changed
+ if [ $VER_NOW != $VER ]; then
+ echo "lib$LIB version currently: $VER_NOW"
+ fi
+
+ # Calculate new library version
+ case $CHANGE in
+ i|I)
+ echo "New backwards-incompatible version: x+1:0:0"
+ VER_1=$(expr $VER_1 + 1)
+ VER_2=0
+ VER_3=0
+
+ # Some headers define constants for shared library names,
+ # update them if the name changed
+ for H in $HEADERS_HEAD; do
+ sed -i -e "s/$(shared_lib_name "$LIB" "$VER_NOW")/$(shared_lib_name "$LIB" "$VER_1:0:0")/" $H
+ done
+ ;;
+ c|C)
+ echo "New version with backwards-compatible extensions: x+1:0:z+1"
+ VER_1=$(expr $VER_1 + 1)
+ VER_2=0
+ VER_3=$(expr $VER_3 + 1)
+ ;;
+ F|f)
+ echo "Code changed though interfaces didn't: x:y+1:z"
+ VER_2=$(expr $VER_2 + 1)
+ ;;
+ *)
+ echo "Not updating lib$LIB version"
+ prompt_to_continue
+ CHANGE=""
+ ;;
+ esac
+ VER_NEW=$VER_1:$VER_2:$VER_3
+
+ if [ ! -z $CHANGE ]; then
+ if [ "$VER_NEW" != "$VER_NOW" ]; then
+ echo "Updating lib$LIB version from $VER_NOW to $VER_NEW"
+ prompt_to_continue
+ sed -i "s/version-info\s*$VER_NOW/version-info $VER_NEW/" $AMFILE
+ else
+ echo "No version change needed for lib$LIB"
+ prompt_to_continue
+ fi
+ fi
+ echo ""
+}
+
+echo "Definitions:"
+echo "- Compatible additions: new public API functions, structs, etc."
+echo "- Incompatible additions/removals: new arguments to public API functions,"
+echo " new members added to the middle of public API structs,"
+echo " removal of any public API, etc."
+echo "- Fixes: any other code changes at all"
+echo ""
+echo "When possible, improve backward compatibility first:"
+echo "- move new members to the end of structs"
+echo "- use bitfields instead of booleans"
+echo "- when adding arguments, create a new function that the old one can wrap"
+echo ""
+prompt_to_continue
+
+LAST_RELEASE=$(find_last_release "$1")
+for LIB in $(find_libs); do
+ process_lib "$LIB" "$LAST_RELEASE"
+done
+
+# Show all proposed changes
+git --no-pager diff --color -w