forked from pEp.foundation/pEpEngine
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
575 lines
16 KiB
Bash
575 lines
16 KiB
Bash
#!/bin/bash -e
|
|
# This is a Bash (-*- sh -*- for what concerns Emacs) script.
|
|
|
|
# @file release
|
|
# @brief A helper script for positron to make releases
|
|
# @license GNU General Public License 3.0 - see LICENSE.txt
|
|
|
|
# Portability is not terribly important, as this script is only meant to be
|
|
# executed by the p≡p Engine maintainer; however it should probably run on
|
|
# reasonably POSIX-like systems. If in doubt run on a GNU system.
|
|
|
|
|
|
# Utility
|
|
# #####################################################
|
|
|
|
fatal ()
|
|
{
|
|
echo "$scriptname FATAL ERROR: $@" \
|
|
> /dev/stderr
|
|
exit -1
|
|
}
|
|
|
|
confirm ()
|
|
{
|
|
prompt="$@"
|
|
echo -ne "$prompt\nDo you want to continue? (y/n)\n> "
|
|
|
|
while read reply; do
|
|
reply=$(echo "$reply" | tr '[:upper:]' '[:lower:]')
|
|
if test "$reply" == 'y' || test "$reply" == 'ye' \
|
|
|| test "$reply" == 'yes'; then
|
|
return
|
|
elif test "$reply" == 'n' || test "$reply" == 'no'; then
|
|
fatal 'you backed out'
|
|
else
|
|
echo 'I did not understand.'
|
|
echo -ne "$prompt\nDo you want to continue? (y/n)\n> "
|
|
fi
|
|
done
|
|
}
|
|
|
|
|
|
|
|
# Global initialisation
|
|
# #####################################################
|
|
|
|
scriptname="$0"
|
|
scriptcommandline="$@"
|
|
|
|
# Sanity checks. These are meant to catch distraction, not malice.
|
|
|
|
# Make sure we are in a reasonable directory.
|
|
cd $(dirname "$0")
|
|
if ! test -e src/pEpEngine.h || ! test -e src/echo_api.c; then
|
|
fatal "this is not a recent p≡p Engine source directory"
|
|
fi
|
|
if ! test -e .git/config; then
|
|
fatal "this does not look like a git repository containing the p≡p Engine"
|
|
fi
|
|
|
|
# Make sure this script is not executed by mistake by somebody who is just
|
|
# playing around. This behaviour is trivial to change in case of actual need,
|
|
# but since it modifies the sources and the repository it should not be run
|
|
# blindly.
|
|
if test "$HOSTNAME" != 'moore'; then
|
|
fatal "you are on $HOSTNAME, not on positron's computer. You should not do this."
|
|
fi
|
|
if test "$USER" != 'luca'; then
|
|
fatal "you are $USER, not positron. You should not do this."
|
|
fi
|
|
|
|
|
|
# Version component handling
|
|
# #####################################################
|
|
|
|
# Given a version, fail fatally if it is ill-formed; do nothing in case of
|
|
# success.
|
|
validate_version ()
|
|
{
|
|
version="$1"
|
|
if ! echo "$version" \
|
|
| grep -q '^v\?[0-9]\+\.[0-9]\+\(\.[0-9]\+\(-\?RC[0-9]\+\)\?\)\?$'; then
|
|
fatal "ill-formed version \"$version\""
|
|
elif echo "$version" | grep -q '\.0[0-9]'; then
|
|
fatal "ill-formed version \"$version\" ('0' most significant digit)"
|
|
elif echo "$version" | grep -q -- '-\?RC0$'; then
|
|
fatal "ill-formed version \"$version\" ('-RC0' is not valid)"
|
|
fi
|
|
}
|
|
|
|
# Given version components print a nice complete version, without a "v" prefix.
|
|
# Arguments:
|
|
# * major version number
|
|
# * minor version number
|
|
# * patch version number (optional)
|
|
# * RC version number (optional)
|
|
make_version ()
|
|
(
|
|
major="$1"
|
|
minor="$2"
|
|
patch="$3"
|
|
rc="$4"
|
|
if test "$patch" = ''; then
|
|
patch='0'
|
|
fi
|
|
if test "$rc" = '0'; then
|
|
rc=''
|
|
fi
|
|
if test "$rc" = ''; then
|
|
echo "$major.$minor.$patch"
|
|
else
|
|
echo "$major.$minor.$patch-RC$rc"
|
|
fi
|
|
)
|
|
|
|
# Given a version return its major (respectively: minor, patch, RC) component.
|
|
major_of ()
|
|
(
|
|
validate_version "$1"
|
|
echo "$1" | sed 's/^v\?\([0-9]\+\)\..*$/\1/'
|
|
)
|
|
minor_of ()
|
|
(
|
|
validate_version "$1"
|
|
echo "$1" | sed 's/^v\?[0-9]\+\.\([0-9]\+\)\..*$/\1/'
|
|
)
|
|
patch_of ()
|
|
(
|
|
version="$1"
|
|
validate_version "$version"
|
|
result=$(echo "$version" | sed 's/^v\?[0-9]\+\.[0-9]\+\.\([0-9]\+\).*/\1/')
|
|
if test "$result" = "$version"; then
|
|
echo '0'
|
|
else
|
|
echo "$result"
|
|
fi
|
|
)
|
|
rc_of ()
|
|
(
|
|
validate_version "$1"
|
|
if echo "$1" | grep -q 'RC[0-9]\+'; then
|
|
echo "$1" | sed 's/^.*RC\([0-9]\+\)$/\1/'
|
|
else
|
|
echo '0'
|
|
fi
|
|
)
|
|
|
|
# Given a version, return success iff the version is an RC version.
|
|
is_rc ()
|
|
{
|
|
validate_version "$1"
|
|
rc=$(rc_of "$1")
|
|
test "$rc" != '0'
|
|
}
|
|
|
|
|
|
# RC successor versions
|
|
# #####################################################
|
|
|
|
next_major_rc ()
|
|
(
|
|
version="$1"; validate_version "$version"
|
|
major=$(major_of "$version"); minor=$(minor_of "$version")
|
|
patch=$(patch_of "$version"); rc=$(rc_of "$version")
|
|
|
|
test "$minor" != '0' && fatal "next major RC: non-zero minor in $version"
|
|
test "$patch" != '0' && fatal "next major RC: non-zero patch in $version"
|
|
if is_rc "$version"; then
|
|
make_version "$major" "$minor" "$patch" $(( "$rc" + 1 ))
|
|
else
|
|
make_version $(( "$major" + 1 )) 0 0 1
|
|
fi
|
|
)
|
|
|
|
next_minor_rc ()
|
|
(
|
|
version="$1"; validate_version "$version"
|
|
major=$(major_of "$version"); minor=$(minor_of "$version")
|
|
patch=$(patch_of "$version"); rc=$(rc_of "$version")
|
|
|
|
test "$patch" != '0' && fatal "next minor RC: non-zero patch in $version"
|
|
if is_rc "$version"; then
|
|
make_version "$major" "$minor" "$patch" $(( "$rc" + 1 ))
|
|
else
|
|
make_version "$major" $(( "$minor" + 1 )) 0 1
|
|
fi
|
|
)
|
|
|
|
next_patch_rc ()
|
|
(
|
|
version="$1"; validate_version "$version"
|
|
major=$(major_of "$version"); minor=$(minor_of "$version")
|
|
patch=$(patch_of "$version"); rc=$(rc_of "$version")
|
|
|
|
if is_rc "$version"; then
|
|
make_version "$major" "$minor" "$patch" $(( "$rc" + 1 ))
|
|
else
|
|
make_version "$major" "$minor" $(( "$patch" + 1 )) 1
|
|
fi
|
|
)
|
|
|
|
|
|
# Non-RC successor versions
|
|
# #####################################################
|
|
|
|
next_major ()
|
|
(
|
|
version="$1"; validate_version "$version"
|
|
major=$(major_of "$version"); minor=$(minor_of "$version")
|
|
patch=$(patch_of "$version"); rc=$(rc_of "$version")
|
|
|
|
if is_rc "$version"; then
|
|
test "$minor" != '0' && fatal "next major: non-zero minor in RC version $version"
|
|
test "$patch" != '0' && fatal "next major: non-zero patch in RC version $version"
|
|
make_version "$major" "$minor" "$patch"
|
|
else
|
|
make_version $(( "$major" + 1 )) 0 0
|
|
fi
|
|
)
|
|
|
|
next_minor ()
|
|
(
|
|
version="$1"; validate_version "$version"
|
|
major=$(major_of "$version"); minor=$(minor_of "$version")
|
|
patch=$(patch_of "$version"); rc=$(rc_of "$version")
|
|
|
|
if is_rc "$version"; then
|
|
test "$patch" != '0' && fatal "next minor: non-zero patch in RC version $version"
|
|
make_version "$major" "$minor" "$patch"
|
|
else
|
|
make_version "$major" $(( "$minor" + 1 )) 0
|
|
fi
|
|
)
|
|
|
|
next_patch ()
|
|
(
|
|
version="$1"; validate_version "$version"
|
|
major=$(major_of "$version"); minor=$(minor_of "$version")
|
|
patch=$(patch_of "$version"); rc=$(rc_of "$version")
|
|
|
|
if is_rc "$version"; then
|
|
make_version "$major" "$minor" "$patch"
|
|
else
|
|
make_version "$major" "$minor" $(( "$patch" + 1 ))
|
|
fi
|
|
)
|
|
|
|
|
|
# Code generation
|
|
# #####################################################
|
|
|
|
# Emit the content of src/pEp_engine_version.h to stdout
|
|
# * version
|
|
# * a Boolean value (either 'yes' or 'no') for plus;
|
|
# * a branch suffix, which may be empty
|
|
emit_version_h_content ()
|
|
{
|
|
version="$1"; validate_version "$version"
|
|
plus="$2"
|
|
case "$plus" in
|
|
'yes') true;;
|
|
'no') true;;
|
|
* ) fatal "emit_version_h_content: invalid value \"$plus\" for plus";;
|
|
esac
|
|
branchsuffix="$3"
|
|
|
|
if test "$plus" = 'yes'; then
|
|
plusornothing='+'
|
|
else
|
|
plusornothing=''
|
|
fi
|
|
|
|
major=$(major_of "$version")
|
|
minor=$(minor_of "$version")
|
|
patch=$(patch_of "$version")
|
|
rc=$(rc_of "$version")
|
|
if is_rc "$version"; then
|
|
rc_or_release='Release Candidate'
|
|
else
|
|
rc_or_release='release'
|
|
fi
|
|
|
|
cat <<EOF
|
|
/**
|
|
* @file pEp_engine_version.h
|
|
* @brief machine-generated version information for the pEp Engine
|
|
* @generated by the p≡p Engine $scriptname script with options
|
|
* $scriptcommandline
|
|
* @license GNU General Public License 3.0 - see LICENSE.txt
|
|
*/
|
|
#ifndef _PEP_ENGINE_VERSION_H_
|
|
#define _PEP_ENGINE_VERSION_H_
|
|
|
|
#define PEP_ENGINE_VERSION_MAJOR $major
|
|
#define PEP_ENGINE_VERSION_MINOR $minor
|
|
#define PEP_ENGINE_VERSION_PATCH $patch
|
|
|
|
$(if is_rc "$version"; then
|
|
echo "#define PEP_ENGINE_VERSION_RC $(printf '%-4i' $rc)/* This is a Release Candidate. */"
|
|
else
|
|
echo '/* PEP_ENGINE_VERSION_RC is not defined: not a Release Candidate. */'
|
|
fi)
|
|
|
|
$(if test "$plus" = 'yes'; then
|
|
echo "#define PEP_ENGINE_VERSION_PLUS + /* This is a MODIFIED $rc_or_release */"
|
|
else
|
|
echo "/* PEP_ENGINE_VERSION_PLUS not defined: this is an UNmodified $rc_or_release. */"
|
|
fi)
|
|
|
|
$(if test "$branchsuffix" != ''; then
|
|
echo "#define PEP_ENGINE_VERSION_BRANCH_SUFFIX $branchsuffix /* A non-release branch */"
|
|
else
|
|
echo "/* PEP_ENGINE_VERSION_BRANCH_SUFFIX not defined. */"
|
|
fi)
|
|
|
|
/* The main version string for the user. */
|
|
#define PEP_ENGINE_VERSION "$version$plusornothing"
|
|
|
|
#endif /* #ifndef _PEP_ENGINE_VERSION_H_ */
|
|
EOF
|
|
}
|
|
|
|
# Argument
|
|
# * a line to be passed to echo -ne
|
|
prepend_to_NEWS ()
|
|
{
|
|
line_for_echo_ne="$1"
|
|
|
|
(mv NEWS NEWS-bk \
|
|
&& echo -en "$line_for_echo_ne" | cat - NEWS-bk > NEWS \
|
|
&& rm NEWS-bk) \
|
|
|| (mv NEWS-bk NEWS; fatal 'could not update NEWS')
|
|
}
|
|
|
|
|
|
# Releasing function
|
|
# #####################################################
|
|
|
|
release ()
|
|
{
|
|
version="$1"
|
|
|
|
confirm "Releasing version $version on branch $branchname"
|
|
|
|
if ! echo "$branchname" | grep -q '^Release_' \
|
|
&& test "$branchname" != 'master'; then
|
|
fatal "branch \"$branchname\" does not look like a release branch name"
|
|
fi
|
|
if test "$gitrepositoryclean" == 'no'; then
|
|
fatal "git repository not clean"
|
|
fi
|
|
firstlineinNEWS=$(echo $(head --lines=1 NEWS))
|
|
if test "$firstlineinNEWS" == ''; then
|
|
fatal 'The first line in NEWS is empty: it should not be, since we are about to prepend the version number to a list of changes'
|
|
fi
|
|
|
|
versionfile=src/pEpEngine_version.h
|
|
prepend_to_NEWS "v$version $(date '+%Y-%m-%d')\n"
|
|
emit_version_h_content "$version" 'no' > "$versionfile"
|
|
git add "$versionfile"
|
|
git commit -m "set version to $version" \
|
|
"$versionfile" NEWS
|
|
git tag --sign \
|
|
--local-user='positron@pep.foundation' \
|
|
-m "v$version" \
|
|
"v$version"
|
|
emit_version_h_content "$version" 'yes' > "$versionfile"
|
|
prepend_to_NEWS "\n"
|
|
git commit -m "add trailing \"+\" sign to version after $version, prepend an empty line to NEWS" \
|
|
"$versionfile" NEWS
|
|
git push --tags origin HEAD:"$branchname"
|
|
cat <<EOF
|
|
|
|
Now go to
|
|
https://gitea.pep.foundation/pEp.foundation/pEpEngine/releases/new
|
|
and mark an Engine release for v${version} on branch $branchname .
|
|
EOF
|
|
}
|
|
|
|
# Global variable definitions
|
|
# #####################################################
|
|
|
|
# Compute version data from the git repository state.
|
|
latestcommit=$(git log | grep '^commit ' | head --lines=1 | awk '{print $2}')
|
|
latestvtagcommitline=$(git log --decorate=full \
|
|
| grep ' (tag: refs/tags/v' | head --lines=1)
|
|
latestvtagcommit=$(echo "$latestvtagcommitline" | awk '{print $2}')
|
|
latestvtagname=$(echo "$latestvtagcommitline" | awk '{print $4}' \
|
|
| sed 's@.*/\(v[0-9][^)]\+\))$@\1@')
|
|
branchname=$(git branch --show-current)
|
|
if test "$branchname" = ''; then
|
|
branchname='detached-head'
|
|
fi
|
|
if test "$(git status --short --untracked-files=no)" == ''; then
|
|
gitrepositoryclean=yes
|
|
else
|
|
gitrepositoryclean=no
|
|
fi
|
|
|
|
|
|
### # Just for testing, of course #############################
|
|
# branchname='foobar'
|
|
# #latestvtagname='v3.2.9-RC2'
|
|
# latestvtagname='v3.2.9'
|
|
# gitrepositoryclean=yes
|
|
###############################################################
|
|
|
|
# Compute the release number from the most recent git tag name.
|
|
latestversion=$(echo "$latestvtagname" | sed 's/^v//')
|
|
|
|
# Compute the release branch suffix from the branch name; leave it empty
|
|
# if the repository is on a release branch.
|
|
if test "$branchname" == 'master' \
|
|
|| echo "$branchname" | grep -q '^Release_'; then
|
|
branchsuffix=''
|
|
else
|
|
branchsuffix="-$branchname"
|
|
fi
|
|
|
|
# Validate and normalise the current version.
|
|
validate_version "$latestversion"
|
|
latestmajor=$(major_of "$latestversion")
|
|
latestminor=$(minor_of "$latestversion")
|
|
latestpatch=$(patch_of "$latestversion")
|
|
latestrc=$(rc_of "$latestversion")
|
|
latestversion=$(make_version "$latestmajor" "$latestminor" "$latestpatch" "$latestrc")
|
|
|
|
|
|
# echo $latestversion
|
|
# patch_of "$latestversion"
|
|
# rc_of "$latestversion"
|
|
# exit 0
|
|
|
|
# Command line handling
|
|
# #####################################################
|
|
|
|
help ()
|
|
{
|
|
cat <<EOF
|
|
SYNOPSIS
|
|
$scriptname [option] ...
|
|
|
|
Common options
|
|
--help Print this help message
|
|
--version Print version information about this script
|
|
|
|
Version numbers
|
|
--latest, --current Deal with the current version number
|
|
--next-major Deal with the next major release's version number
|
|
--next-minor Deal with the next minor release's version number
|
|
--next-patch Deal with the next patch release's version number
|
|
--next-major-rc Deal with the next major RC's version number
|
|
--next-minor-rc Deal with the next minor RC's version number
|
|
--next-patch-rc Deal with the next patch RC's version number
|
|
|
|
Actions
|
|
--release Make a release
|
|
--print Just show a release number (default)
|
|
|
|
EOF
|
|
exit 0
|
|
}
|
|
|
|
version ()
|
|
{
|
|
cat <<EOF
|
|
$scriptname is not versioned.
|
|
|
|
This comes from p≡p. Written by Luca Saiu.
|
|
EOF
|
|
exit 0
|
|
}
|
|
|
|
# Arguments:
|
|
# * the version
|
|
handle_version_number ()
|
|
{
|
|
version="$1"
|
|
|
|
theversion="$version"
|
|
if test "$anyversionspecified" = 'yes'; then
|
|
fatal "specified two different versions: you had already described $theversion"
|
|
fi
|
|
anyversionspecified='yes'
|
|
}
|
|
|
|
# Arguments:
|
|
# * the action
|
|
handle_action ()
|
|
{
|
|
action="$1"
|
|
|
|
if test "$release" != 'no'; then
|
|
fatal "an action was already specified (release)"
|
|
elif test "$print" != 'no'; then
|
|
fatal "an action was already specified (print)"
|
|
elif test "$action" = 'release'; then
|
|
release='yes'
|
|
elif test "$action" = 'print'; then
|
|
print='yes'
|
|
else
|
|
fatal "unknown action $action"
|
|
fi
|
|
}
|
|
|
|
require_version_number ()
|
|
{
|
|
if test "$anyversionspecified" = 'no'; then
|
|
fatal "no version number specified"
|
|
fi
|
|
|
|
# Check that the version is actually correct. This is needed in case some
|
|
# previous error was ignored: see the comment after the argument loop;
|
|
# however we do not need to print an error message here, since one has been
|
|
# printed already.
|
|
validate_version "$theversion" &> /dev/null
|
|
}
|
|
|
|
if test "$#" = '0'; then
|
|
fatal "not enough arguments: see --help"
|
|
fi
|
|
|
|
release='no'
|
|
print='no'
|
|
anyversionspecified='no'
|
|
theversion=''
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
# Common.
|
|
'--help' )
|
|
help;;
|
|
'--version' )
|
|
version;;
|
|
|
|
# Version numbers.
|
|
'--latest' | '--current' )
|
|
handle_version_number "$latestversion";;
|
|
'--next-major' )
|
|
handle_version_number $(next_major "$latestversion");;
|
|
'--next-minor' )
|
|
handle_version_number $(next_minor "$latestversion");;
|
|
'--next-patch' )
|
|
handle_version_number $(next_patch "$latestversion");;
|
|
'--next-major-rc' )
|
|
handle_version_number $(next_major_rc "$latestversion");;
|
|
'--next-minor-rc' )
|
|
handle_version_number $(next_minor_rc "$latestversion");;
|
|
'--next-patch-rc' )
|
|
handle_version_number $(next_patch_rc "$latestversion");;
|
|
|
|
# Actions
|
|
'--release' )
|
|
handle_action 'release';;
|
|
'--print' )
|
|
handle_action 'print';;
|
|
|
|
# Default.
|
|
* )
|
|
fatal "unknown argument $arg";;
|
|
esac
|
|
done
|
|
|
|
# Make sure a version number was specified. This is also necessary to catch
|
|
# version errors, since we use functions such as next_minor inside $( ... ),
|
|
# which makes errors not fatal.
|
|
require_version_number
|
|
# emit_version_h_content "$theversion" 'yes' "$branchsuffix"
|
|
# fatal "remove this"
|
|
|
|
if test "$release" != 'no'; then
|
|
release "$theversion"
|
|
else # we take print to be the default
|
|
echo "v${theversion}"
|
|
fi
|