diff options
-rwxr-xr-x | bin/build/setver.sh | 180 |
1 files changed, 157 insertions, 23 deletions
diff --git a/bin/build/setver.sh b/bin/build/setver.sh index 470e529..ae8b048 100755 --- a/bin/build/setver.sh +++ b/bin/build/setver.sh @@ -2,7 +2,8 @@ # # Sets roverlay's version. # -# Usage: setver [-S,--src <dir>] [--pretend] [--suffix <str>] +# Usage: setver [-S,--src <dir>] [--pretend] [--suffix <str>] [--reset] +# [--git-add] [--git-commit] [--force-commit] [--git-tag] # [+,pbump|++,mbump|Mbump|[setver] <ver>] # # Actions: @@ -15,40 +16,140 @@ # -S, --src <dir> -- set roverlay source directory (default: $PWD) # --pretend -- just show what would be done # --suffix <str> -- replace old version suffix with <str> +# -l, --list-files -- just list files that would be edited by this script +# (usage example: setver -l | xargs git checkout HEAD --) +# --reset -- check out VERSION file from git HEAD before doing anything +# --git-add -- git-add modified files +# --git-commit -- commit changes (commit message: "roverlay <newver>") +# --force-commit -- enforce git commit (allow other files) +# --git-tag -- run git-tag <newver> after git-commit # +set -e set -u -IFS_DEFAULT="${IFS}" +readonly IFS_DEFAULT="${IFS}" -PY_FILES_TO_EDIT="roverlay/core.py setup.py" +readonly PY_FILES_TO_EDIT="roverlay/core.py setup.py" +readonly X_GIT="${X_GIT:-git}" +# get_git_commit_message ( new_version, **commit_msg! ) +# +# Creates a commit message and stores it in $commit_msg. +# An empty str can be set if no commit should be made. +# +get_git_commit_message() { + commit_msg="roverlay ${1:?}" +} + +# get_git_tag ( new_version, **tag! ) +# +# Creates a git tag str and stores it in $tag. +# An empty str suppresses tag creation. +# +get_git_tag() { + tag="${1:?}" +} +# @noreturn die ( [message], [exit_code] ), raises exit($exit_code) +# +# Lets the script die. +# die() { - echo "${1:-unknown error.}" 1>&2; exit ${2:-2}; + echo "${1:+died: }${1:-died.}" 1>&2; exit ${2:-2}; +} + +# autodie ( *cmdv ) +# +# Runs *cmdv and dies on non-zero return. +# ("set -ex" is too verbose) +# +autodie() { + "$@" || die "command '${*}' returned ${?}." ${?} } +# parse_version ( version_str, **major!, **minor!, **plvl!, **suffix! ) +# +# Splits a version_str into its components. +# +# Example: 0.2.6-pre1 => major=0 minor=2 plvl=6 suffix=-pre1 +# parse_version() { + unset -v major minor plvl suffix local IFS="." set -- ${1} IFS="${IFS_DEFAULT}" - [ ${#} -ge 3 ] || return 2 + [ -n "${1-}" ] && [ -n "${2-}" ] && [ -n "${3-}" ] || return 2 major="${1:?}" minor="${2:?}" plvl="${3:?}" shift 3 || die "error in parse_version()" - suffix="${*}" + suffix= + while [ ${#} -gt 0 ]; do suffix="${suffix}.${1}"; shift; done + suffix="${suffix#.}" } +# inc ( k, **v0! ) +# +# Increments $k by one and stores the result in $v0. +# inc() { - v0=$(( ${1} + 1 )) + v0=$(( ${1:?} + 1 )) + # unlikely: [ ${v0} -gt ${1} ] || die "overflow" } +# do_git_add ( *files, **want_gitadd, **X_GIT ) +# +do_git_add() { + ${want_gitadd} || return 0 + printf "git-add: %s\n" "${*}" + ${want_pretend} || autodie "${X_GIT}" add -- "$@" +} + +# do_git_commit_and_tag ( +# version_str, numfiles_changed, +# **want_gitcommit, **want_forcecommit, **want_gittag, **X_GIT +# ) +# +do_git_commit_and_tag() { + ${want_gitcommit} || return 0 + local commit_msg commit_type tag + + autodie get_git_commit_message "${1}" + autodie get_git_tag "${1}" + + if [ -z "${commit_msg}" ]; then + return 0 + elif ${want_pretend}; then + commit_type=maybe + elif \ + [ $(git status --porcelain -- . | grep -c -- ^[MADRCU]) -eq ${2} ] + then + commit_type=clean + elif ${want_forcecommit}; then + commit_type=forced + else + die "cannot commit changes (try --force-commit)." + fi + + printf "git-commit [%s]: %s\n" "${commit_type}" "${commit_msg}" + ${want_pretend} || autodie "${X_GIT}" commit -m "${commit_msg}" + + ${want_gittag} && [ -n "${tag}" ] || return 0 + printf "git-tag: %s\n" "${tag}" + ${want_pretend} || autodie "${X_GIT}" tag "${tag}" +} + + +# set defaults / parse args +autodie hash "${X_GIT}" S="${PWD}" unset -v V unset -v ACTION unset -v new_suffix -unset -v do_pretend + +readonly _boolvars="pretend gitadd gitcommit forcecommit gittag reset" +for iter in ${_boolvars}; do eval "want_${iter}=false"; done doshift= while [ ${#} -gt 0 ]; do @@ -56,15 +157,18 @@ while [ ${#} -gt 0 ]; do case "${1}" in '') : ;; - '--src'|'-S') - [ ${#} -ge 2 ] || die "argparse error" + -S|--src) + [ -n "${2-}" ] || die "one non-empty arg required after '${1}'." doshift=2 S="${2:?}" ;; - pretend|--pretend) - do_pretend=true - ;; + --pretend) want_pretend=true ;; + --reset) want_reset=true ;; + --git-add) want_gitadd=true ;; + --git-commit) want_gitcommit=true ;; + --force-commit) want_forcecommit=true ;; + --git-tag) want_gittag=true ;; [Mmp]bump) ACTION="${1}" ;; '+') ACTION=pbump ;; @@ -72,18 +176,24 @@ while [ ${#} -gt 0 ]; do *.*.*) ACTION=setver; V="${1}" ;; setver) - [ ${#} -ge 2 ] || die "argparse error" + [ -n "${2-}" ] || die "one non-empty arg required after '${1}'." doshift=2 ACTION=setver V="${2:?}" ;; - suffix|--suffix) - [ ${#} -ge 2 ] || die "argparse error" + --suffix) + [ -n "${2+SET}" ] || die "one arg required after '${1}'." doshift=2 new_suffix="${2?}" ;; + -l|--list-files) + for fname in ${PY_FILES_TO_EDIT}; do echo "${fname}"; done + echo "VERSION" + exit 0 + ;; + *) die "unknown arg: ${1}" 64 ;; @@ -91,11 +201,20 @@ while [ ${#} -gt 0 ]; do [ ${doshift} -eq 0 ] || shift ${doshift} || die "argparse: shift failed" done -: ${do_pretend:=false} -OLDVER="$(cat "${S}/VERSION")" -parse_version "${OLDVER}" || die "bad version: ${OLDVER}." -[ -n "${new_suffix+SET}" ] || new_suffix="${suffix}" +! { ${want_gittag} || ${want_forcecommit}; } || want_gitcommit=true +! ${want_gitcommit} || want_gitadd=true + +readonly S ACTION +for iter in ${_boolvars}; do readonly "want_${iter}"; done + +cd "${S}" || die "chdir ${S}" +! ${want_reset} || autodie "${X_GIT}" checkout HEAD -- VERSION +readonly OLDVER="$(cat "${S}/VERSION")" || die "failed to read ${S}/VERSION" +autodie parse_version "${OLDVER}" +: ${new_suffix="${suffix}"} + +# get new version case "${ACTION-}" in pbump) inc "${plvl}" @@ -113,19 +232,34 @@ case "${ACTION-}" in true ;; *) - die "unknown or no action specified." + ${want_reset} || die "unknown or no action specified." + exit 0 ;; esac + +# edit files q="\"\'" re_pyfile_ver="^(\s*version\s*=\s*)[${q}]?([^\s;,${q}]*)[${q}]?(\s*[;,]?\s*)\$" +v0=0 _fmt="edit %-18s: %8s -> %s\n" for fname in ${PY_FILES_TO_EDIT}; do + inc "${v0}" f="${S}/${fname}" fver="$(sed -rn -e "s@${re_pyfile_ver}@\2@p" < "${f}")" printf "${_fmt}" "${fname}" "${fver}" "${V}" - ${do_pretend} || sed -r -e "s@${re_pyfile_ver}@\1\"${V}\"\3@" -i "${f}" + ${want_pretend} || \ + autodie sed -r -e "s@${re_pyfile_ver}@\1\"${V}\"\3@" -i "${f}" + do_git_add "${f}" done + +inc "${v0}" printf "${_fmt}" "VERSION" "${OLDVER}" "${V}" -${do_pretend} || echo "${V}" > "${S}/VERSION" +${want_pretend} || echo "${V}" > "${S}/VERSION" || die "failed to write VERSION" +do_git_add "${S}/VERSION" + +[ ${v0} -gt 0 ] || die "numfiles?" +printf "edited %d files in total.\n" "${v0}" + +autodie do_git_commit_and_tag "${V}" "${v0}" |