]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
build: Improve versioning support
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Mon, 10 Apr 2023 04:36:22 +0000 (21:36 -0700)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Mon, 10 Apr 2023 06:27:46 +0000 (23:27 -0700)
RELEASE=0 or RELEASE=1 can now be used to influence the default state of enable-developer when making archives, running configure, and building packages.

All versioning values are now produced by version.sh instead of being spread between our Makefile and configure.

Commit and commit depth are inserted into into tar/gz files so that developer builds are automatically enabled for non-release builds, and the commit is embedded in version strings for all builds.

.gitignore
Make.inc.in
Makefile
configure
configure.ac
src/include/autoconf.h.in
version.sh [new file with mode: 0755]

index 43457c057bface4de229abdf0582e8f275801b1d..dce14334ef46d8a3d4cd1a358e83a52226bd2fb8 100644 (file)
 *.profraw
 .pc
 
+# Version markers
+VERSION_COMMIT
+VERSION_COMMIT_DEPTH
+RELEASE
+
 # Editor projects
 *.kdev4
 *.cproject
index 11d1dcb01ffc80936f6b08c2a2e6a20eefcd5dff..2f58eb71653b7401c5c6d539a3e75841d7d82a8d 100644 (file)
@@ -149,6 +149,7 @@ RADIUSD_VERSION = @RADIUSD_VERSION@
 RADIUSD_VERSION_MAJOR = @RADIUSD_VERSION_MAJOR@
 RADIUSD_VERSION_MINOR = @RADIUSD_VERSION_MINOR@
 RADIUSD_VERSION_INCRM = @RADIUSD_VERSION_INCRM@
+RADIUSD_VERSION_COMMIT = @RADIUSD_VERSION_COMMIT@
 
 #
 #  This allows dlopen to do runtime checks for version mismatches
index feb004414272d794d7989c37d17091ddaa8177d1..69241946ac43747120e1f2fa0454097583236536 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -55,15 +55,15 @@ endif
 #  'configure' was not run?  Get the version number from the file.
 #
 ifeq "$(RADIUSD_VERSION)" ""
-  RADIUSD_VERSION_MAJOR := $(shell cat VERSION | cut -f1 -d.)
-  RADIUSD_VERSION_MINOR := $(shell cat VERSION | cut -f2 -d.)
+  RADIUSD_VERSION_MAJOR := $(shell ./version.sh major)
+  RADIUSD_VERSION_MINOR := $(shell ./version.sh minor)
 
   # Default to an incremental version of 0 if we're not building from git
-  RADIUSD_VERSION_INCRM := $(shell git status > /dev/null 2>&1 && git describe --tags --match 'branch_*' --match 'release_*' | cut -d '-' -f 2)
+  RADIUSD_VERSION_INCRM := $(shell ./version.sh commit_depth)
 endif
 
 ifeq "$(RADIUSD_VERSION_INCRM)" ""
-  RADIUSD_VERSION_INCRM := $(shell cat VERSION | cut -d '.' -f 3)
+  RADIUSD_VERSION_INCRM := $(shell ./version.sh incrm)
   PKG_VERSION_SUFFIX :=
   ifeq "$(RADIUSD_VERSION_INCRM)" ""
     RADIUSD_VERSION_SEP :=
@@ -339,7 +339,7 @@ endif
 #  the configure script.
 #
 ifneq "$(wildcard config.log)" ""
-  CONFIGURE_ARGS          := $(shell head -10 config.log | grep '^  \$$' | sed 's/^....//;s:.*configure ::')
+  CONFIGURE_ARGS := $(shell head -10 config.log | grep '^  \$$' | sed 's/^....//;s:.*configure ::')
 
 #
 #  ONLY re-run "configure" if we're told to do that.  Otherwise every
@@ -392,21 +392,34 @@ certs:
 #  BEFORE running this command!
 #
 ######################################################################
-BRANCH = $(shell git rev-parse --abbrev-ref HEAD)
-
 .PHONY: freeradius-server-$(PKG_VERSION).tar
 
+#
 # This can't depend on .git/ (dirs don't work) or .git/HEAD (not present in submodules)
 # so it's just left as a phony target.
+#
+# Do NOT move calculation of BRANCH outside of the recipe.  Every shell expansion
+# carries with it a performance penalty, that is felt every time make is executed.
+#
+BRANCH_CMD := git rev-parse --abbrev-ref HEAD
 freeradius-server-$(PKG_VERSION).tar:
        rm -rf $(top_srcdir)/$(BUILD_DIR)/freeradius-server-$(PKG_VERSION)
        mkdir -p $(top_srcdir)/$(BUILD_DIR)
-       git archive --format=tar --prefix=freeradius-server-$(PKG_VERSION)/ $(BRANCH) | tar -C $(top_srcdir)/$(BUILD_DIR) -xf -
+       BRANCH=$$(${BRANCH_CMD}); \
+       [ $$(./version.sh is_release) -eq 1 ] && release_arg="--add-virtual-file=freeradius-server-$(PKG_VERSION)/RELEASE:"; \
+       git archive \
+               --format=tar \
+               --prefix=freeradius-server-$(PKG_VERSION)/ \
+               --add-virtual-file=freeradius-server-$(PKG_VERSION)/VERSION_COMMIT:$$(./version.sh commit) \
+               --add-virtual-file=freeradius-server-$(PKG_VERSION)/VERSION_COMMIT_DEPTH:$$(./version.sh commit_depth) \
+               $${release_arg} \
+               $${BRANCH} | tar -C $(top_srcdir)/$(BUILD_DIR) -xf -; \
        git submodule foreach --recursive 'git archive --format=tar --prefix=freeradius-server-$(PKG_VERSION)/$$sm_path/ $$sha1 | tar -C $(top_srcdir)/$(BUILD_DIR) -xf -'
 ifneq "$(EXT_MODULES)" ""
+       BRANCH=$$(${BRANCH_CMD}); \
        for x in $(subst _ext,,$(EXT_MODULES)); do \
                cd $(top_srcdir)/$${x}_ext && \
-               git archive --format=tar --prefix=freeradius-server-$(PKG_VERSION)/$$x/ $(BRANCH) | tar -C $(top_srcdir)/$(BUILD_DIR) -xf -; \
+               git archive --format=tar --prefix=freeradius-server-$(PKG_VERSION)/$$x/ $${BRANCH} | tar -C $(top_srcdir)/$(BUILD_DIR) -xf -; \
        done
 endif
        tar -cf $@ -C $(top_srcdir)/$(BUILD_DIR) freeradius-server-$(PKG_VERSION)
@@ -448,6 +461,9 @@ dist-publish: freeradius-server-$(PKG_VERSION).tar.gz.sig freeradius-server-$(PK
 dist-tag: freeradius-server-$(PKG_VERSION).tar.gz freeradius-server-$(PKG_VERSION).tar.bz2
        @echo "git tag release_`echo $(PKG_VERSION) | tr .- __`"
 
+.PHONY: tar
+tar: freeradius-server-$(PKG_VERSION).tar.gz
+
 #
 #      Build a debian package
 #
index dcafea3848d81f4e92c703c3b6266c54fee600e9..ee52c292c64df6d52654ca7b7bbc3deeadd90cbe 100755 (executable)
--- a/configure
+++ b/configure
@@ -725,6 +725,7 @@ build_os
 build_vendor
 build_cpu
 build
+RADIUSD_VERSION_COMMIT
 ANTORA
 GRAPHVIZ_DOT
 DOXYGEN
@@ -2820,12 +2821,12 @@ ac_config_headers="$ac_config_headers src/include/autoconf.h"
 
 
 
-RADIUSD_VERSION_MAJOR=`cat VERSION | cut -f1 -d.`
-RADIUSD_VERSION_MINOR=`cat VERSION | cut -f2 -d.`
-RADIUSD_VERSION_INCRM=`git status > /dev/null 2>&1 && git describe --tags --match 'branch_*' --match 'release_*' | cut -d '-' -f 2`
+RADIUSD_VERSION_MAJOR=`./version.sh major`
+RADIUSD_VERSION_MINOR=`./version.sh minor`
+RADIUSD_VERSION_INCRM=`./version.sh commit_depth`
 
 if test "x$RADIUSD_VERSION_INCRM" = "x"; then
-       RADIUSD_VERSION_INCRM=`cat VERSION | cut -f3 -d.`
+       RADIUSD_VERSION_INCRM=`./version.sh incrm`
 fi
 if test "x$RADIUSD_VERSION_INCRM" = "x"; then
        RADIUSD_VERSION_INCRM=65535
@@ -3254,37 +3255,35 @@ fi
 if test ${enable_developer+y}
 then :
   enableval=$enable_developer;  case "$enableval" in
+  yes)
+    developer=yes
+    ;;
   no)
     developer=no
     ;;
   *)
-    developer=yes
+    ;;
   esac
+else $as_nop
+   developer=`([ "$(./version.sh is_release)" -eq 0 ] && echo 'yes') || echo 'no'`
 
 fi
 
 
-if test "x$GIT" = "xyes" && git --git-dir=.git status 2>&1 > /dev/null; then
-  if test "x$RADIUSD_VERSION_COMMIT" = "x"; then
-    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build commit" >&5
-printf %s "checking build commit... " >&6; }
-    RADIUSD_VERSION_COMMIT=`git rev-parse --short=8 HEAD`
-    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RADIUSD_VERSION_COMMIT" >&5
-printf "%s\n" "$RADIUSD_VERSION_COMMIT" >&6; }
-  fi
-
-  if test "x$developer" != "xno"; then
-    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: in git repository, enabling developer build implicitly, disable with --disable-developer" >&5
-printf "%s\n" "$as_me: in git repository, enabling developer build implicitly, disable with --disable-developer" >&6;}
-    developer="yes"
-  fi
+if test "x$developer" = "xyes"; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Enabling developer build implicitly, disable with --disable-developer" >&5
+printf "%s\n" "$as_me: Enabling developer build implicitly, disable with --disable-developer" >&6;}
 fi
 
-if test "x$RADIUSD_VERSION_COMMIT" != "x"; then
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build commit" >&5
+printf %s "checking build commit... " >&6; }
+RADIUSD_VERSION_COMMIT=`./version.sh commit`
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RADIUSD_VERSION_COMMIT" >&5
+printf "%s\n" "$RADIUSD_VERSION_COMMIT" >&6; }
 
 printf "%s\n" "#define RADIUSD_VERSION_COMMIT ${RADIUSD_VERSION_COMMIT}" >>confdefs.h
 
-fi
+
 
 if test "x$developer" = "xyes"; then
   CFLAGS="$CFLAGS -g3"
index 059bc532d5e12e97f11b94a071e6404c5af7322a..7cdf672afc8dc4af33af6421e9e6d761fc406622 100644 (file)
@@ -36,14 +36,14 @@ dnl #  Custom hackery to discover version at configure time
 dnl #
 dnl #############################################################
 
-RADIUSD_VERSION_MAJOR=`cat VERSION | cut -f1 -d.`
-RADIUSD_VERSION_MINOR=`cat VERSION | cut -f2 -d.`
-RADIUSD_VERSION_INCRM=`git status > /dev/null 2>&1 && git describe --tags --match 'branch_*' --match 'release_*' | cut -d '-' -f 2`
+RADIUSD_VERSION_MAJOR=`./version.sh major`
+RADIUSD_VERSION_MINOR=`./version.sh minor`
+RADIUSD_VERSION_INCRM=`./version.sh commit_depth`
 
 dnl #  To handle tarballs and GitHub downloads, we can also put the incremental
 dnl #  patch number in VERSION, or it gets set to FFFF.
 if test "x$RADIUSD_VERSION_INCRM" = "x"; then
-       RADIUSD_VERSION_INCRM=`cat VERSION | cut -f3 -d.`
+       RADIUSD_VERSION_INCRM=`./version.sh incrm`
 fi
 if test "x$RADIUSD_VERSION_INCRM" = "x"; then
        RADIUSD_VERSION_INCRM=65535
@@ -143,38 +143,30 @@ dnl #
 AC_ARG_ENABLE(developer,
 [  --enable-developer      enables features of interest to developers.],
 [ case "$enableval" in
+  yes)
+    developer=yes
+    ;;
   no)
     developer=no
     ;;
   *)
-    developer=yes
-  esac ]
+    ;;
+  esac ],
+[ developer=`([[ "$(./version.sh is_release)" -eq 0 ]] && echo 'yes') || echo 'no'` ]
 )
 
-dnl #
-dnl #  Turn on the developer flag when taken from a git checkout (not a release)
-dnl #
-dnl #  Passing --git-dir explicitly limits the search to the CWD.  Without it
-dnl #  git will search back up the directory tree for a git repository.
-dnl #  This can cause the configure script to erroneously determine that it's
-dnl #  running in a git repo.
-dnl #
-if test "x$GIT" = "xyes" && git --git-dir=.git status 2>&1 > /dev/null; then
-  if test "x$RADIUSD_VERSION_COMMIT" = "x"; then
-    AC_MSG_CHECKING([build commit])
-    RADIUSD_VERSION_COMMIT=`git rev-parse --short=8 HEAD`
-    AC_MSG_RESULT($RADIUSD_VERSION_COMMIT)
-  fi
-
-  if test "x$developer" != "xno"; then
-    AC_MSG_NOTICE([in git repository, enabling developer build implicitly, disable with --disable-developer])
-    developer="yes"
-  fi
+if test "x$developer" = "xyes"; then
+  AC_MSG_NOTICE([Enabling developer build implicitly, disable with --disable-developer])
 fi
 
-if test "x$RADIUSD_VERSION_COMMIT" != "x"; then
-  AC_DEFINE_UNQUOTED([RADIUSD_VERSION_COMMIT],[${RADIUSD_VERSION_COMMIT}],[Commit HEAD at time of configuring])
-fi
+dnl #
+dnl #  Write the current commit into Make.inc
+dnl #
+AC_MSG_CHECKING([build commit])
+RADIUSD_VERSION_COMMIT=`./version.sh commit`
+AC_MSG_RESULT($RADIUSD_VERSION_COMMIT)
+AC_DEFINE_UNQUOTED([RADIUSD_VERSION_COMMIT],[${RADIUSD_VERSION_COMMIT}],[Commit HEAD at time of configuring])
+AC_SUBST(RADIUSD_VERSION_COMMIT)
 
 dnl #
 dnl #  Autoconf sets -O2 and -g by default, but this is a PITA for debugging
index e6d0764e347112cb5694c96bd8b6fd532f8353ab..bb86434ae41d42aa3d3ec3f40bdf26cc50859084 100644 (file)
 /* Define to 1 if you have the `mallopt' function. */
 #undef HAVE_MALLOPT
 
-/* Define to 1 if you have the <memory.h> header file. */
-#undef HAVE_MEMORY_H
-
 /* Define to 1 if you have the `memrchr' function. */
 #undef HAVE_MEMRCHR
 
+/* Define to 1 if you have the <minix/config.h> header file. */
+#undef HAVE_MINIX_CONFIG_H
+
 /* Define to 1 if you have the `mkdirat' function. */
 #undef HAVE_MKDIRAT
 
 /* Define to 1 if you have the `vsnprintf' function. */
 #undef HAVE_VSNPRINTF
 
+/* Define to 1 if you have the <wchar.h> header file. */
+#undef HAVE_WCHAR_H
+
 /* Define if the compiler supports -Wdocumentation */
 #undef HAVE_WDOCUMENTATION
 
    int64 */
 #undef SSIZE_SAME_AS_INT64
 
-/* Define to 1 if you have the ANSI C header files. */
+/* Define to 1 if all of the C90 standard headers exist (not just the ones
+   required in a freestanding environment). This macro is provided for
+   backward compatibility; new code need not use it. */
 #undef STDC_HEADERS
 
 /* SYSV-Style get*byaddr_r */
 #ifndef _ALL_SOURCE
 # undef _ALL_SOURCE
 #endif
+/* Enable general extensions on macOS.  */
+#ifndef _DARWIN_C_SOURCE
+# undef _DARWIN_C_SOURCE
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
 /* Enable GNU extensions on systems that have them.  */
 #ifndef _GNU_SOURCE
 # undef _GNU_SOURCE
 #endif
-/* Enable threading extensions on Solaris.  */
+/* Enable X/Open compliant socket functions that do not require linking
+   with -lxnet on HP-UX 11.11.  */
+#ifndef _HPUX_ALT_XOPEN_SOCKET_API
+# undef _HPUX_ALT_XOPEN_SOCKET_API
+#endif
+/* Identify the host operating system as Minix.
+   This macro does not affect the system headers' behavior.
+   A future release of Autoconf may stop defining this macro.  */
+#ifndef _MINIX
+# undef _MINIX
+#endif
+/* Enable general extensions on NetBSD.
+   Enable NetBSD compatibility extensions on Minix.  */
+#ifndef _NETBSD_SOURCE
+# undef _NETBSD_SOURCE
+#endif
+/* Enable OpenBSD compatibility extensions on NetBSD.
+   Oddly enough, this does nothing on OpenBSD.  */
+#ifndef _OPENBSD_SOURCE
+# undef _OPENBSD_SOURCE
+#endif
+/* Define to 1 if needed for POSIX-compatible behavior.  */
+#ifndef _POSIX_SOURCE
+# undef _POSIX_SOURCE
+#endif
+/* Define to 2 if needed for POSIX-compatible behavior.  */
+#ifndef _POSIX_1_SOURCE
+# undef _POSIX_1_SOURCE
+#endif
+/* Enable POSIX-compatible threading on Solaris.  */
 #ifndef _POSIX_PTHREAD_SEMANTICS
 # undef _POSIX_PTHREAD_SEMANTICS
 #endif
+/* Enable extensions specified by ISO/IEC TS 18661-5:2014.  */
+#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
+# undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-1:2014.  */
+#ifndef __STDC_WANT_IEC_60559_BFP_EXT__
+# undef __STDC_WANT_IEC_60559_BFP_EXT__
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-2:2015.  */
+#ifndef __STDC_WANT_IEC_60559_DFP_EXT__
+# undef __STDC_WANT_IEC_60559_DFP_EXT__
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-4:2015.  */
+#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__
+# undef __STDC_WANT_IEC_60559_FUNCS_EXT__
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-3:2015.  */
+#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
+# undef __STDC_WANT_IEC_60559_TYPES_EXT__
+#endif
+/* Enable extensions specified by ISO/IEC TR 24731-2:2010.  */
+#ifndef __STDC_WANT_LIB_EXT2__
+# undef __STDC_WANT_LIB_EXT2__
+#endif
+/* Enable extensions specified by ISO/IEC 24747:2009.  */
+#ifndef __STDC_WANT_MATH_SPEC_FUNCS__
+# undef __STDC_WANT_MATH_SPEC_FUNCS__
+#endif
 /* Enable extensions on HP NonStop.  */
 #ifndef _TANDEM_SOURCE
 # undef _TANDEM_SOURCE
 #endif
-/* Enable general extensions on Solaris.  */
-#ifndef __EXTENSIONS__
-# undef __EXTENSIONS__
+/* Enable X/Open extensions.  Define to 500 only if necessary
+   to make mbstate_t available.  */
+#ifndef _XOPEN_SOURCE
+# undef _XOPEN_SOURCE
 #endif
 
 
 # endif
 #endif
 
-/* Enable large inode numbers on Mac OS X 10.5.  */
-#ifndef _DARWIN_USE_64_BIT_INODE
-# define _DARWIN_USE_64_BIT_INODE 1
-#endif
-
 /* Number of bits in a file offset, on hosts where this is settable. */
 #undef _FILE_OFFSET_BITS
 
 /* Define for large files, on AIX-style hosts. */
 #undef _LARGE_FILES
 
-/* Define to 1 if on MINIX. */
-#undef _MINIX
-
-/* Define to 2 if the system does not provide POSIX.1 features except with
-   this defined. */
-#undef _POSIX_1_SOURCE
-
-/* Define to 1 if you need to in order for `stat' and other things to work. */
-#undef _POSIX_SOURCE
-
 /* Force OSX >= 10.7 Lion to use RFC2292 IPv6 socket options */
 #undef __APPLE_USE_RFC_3542
 
 /* Define to `long int' if <sys/types.h> does not define. */
 #undef off_t
 
-/* Define to `int' if <sys/types.h> does not define. */
+/* Define as a signed integer type capable of holding a process identifier. */
 #undef pid_t
 
 /* Define to `unsigned int' if <sys/types.h> does not define. */
diff --git a/version.sh b/version.sh
new file mode 100755 (executable)
index 0000000..e35ba1a
--- /dev/null
@@ -0,0 +1,158 @@
+#!/bin/sh
+
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+#
+#  Copyright 2023 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
+#
+
+# Files
+version_file=VERSION
+commit_file=VERSION_COMMIT
+commit_depth_file=VERSION_COMMIT_DEPTH
+release_file=RELEASE
+
+# Defaults
+version_major=4
+version_minor=0
+version_incrm=
+commit=
+commit_depth=
+is_release=0
+in_repo=
+
+#
+#  Don't allow git to search in directories above this one, as we may
+#  be operating in an extracted version of the source and not a repo.
+#
+git="git --git-dir=.git"
+
+#
+#  Check if we're operating in a repo
+#
+in_repo=$(${git} rev-parse > /dev/null 2>&1 && echo true || echo false)
+
+usage()
+{
+       echo "$(basename "$0") [-h|-d] [component [component...]] - Create a FreeRADIUS version string from one or more components"
+       echo
+       echo "component may be one of:"
+       echo "major             Major version component from ${version_file}."
+       echo "minor             Minor version component from ${version_file}."
+       echo "commit            Short (8 hexit) commit hash."
+       echo "commit_depth      How many commit since the last tag."
+       echo "is_release        true if the current commit has been tagged as a release, else false."
+       echo "*                 Any other string.  Will be echoed directly to stdout."
+       echo
+       echo "arguments:"
+       echo "-h                Print helptext"
+       echo "-c                Remove ${commit_file}, ${commit_depth_file} and ${release_file} files."
+       echo "-d                Write commit, commit_depth, is_release to ${commit_file}, ${commit_depth_file}, ${release_file} respectively."
+}
+
+version_component()
+{
+       for c in "$@"; do
+       case "$c" in
+       major)
+               out=$(cut -f1 -d. 2>/dev/null < ${version_file})
+               if [ -z "${out}" ]; then out="${version_major}"; fi
+       ;;
+
+       minor)
+               out=$(cut -f2 -d. 2>/dev/null < ${version_file})
+               if [ -z "${out}" ]; then out="${version_minor}"; fi
+       ;;
+
+       incrm)
+               out=$(cut -f3 -d. 2>/dev/null < ${version_file})
+               if [ -z "${out}" ]; then out="${version_incrm}"; fi
+       ;;
+
+       commit)
+               out=$(\
+                       cat ${commit_file} 2> /dev/null || \
+                       (${in_repo} && ${git} rev-parse --short=8 HEAD) || \
+                       echo "${commit}"\
+               )
+       ;;
+
+       commit_depth)
+               out=$(\
+                       cat ${commit_depth_file} 2> /dev/null || \
+                       (${in_repo} && ${git} describe --tags --match 'branch_*' --match 'release_*' | cut -d '-' -f 2) || \
+                       echo "${commit_depth}" \
+               )
+       ;;
+
+       # - If $RELEASE is set, that takes precendence
+       # - Otherwise if a RELEASE file is present, then release = 1.
+       # - If we're in a git repo
+       #    - If there's a release_* tag matching the current commit,
+       #      and there are no uncommented changes then release = 1, and if not release = 0
+       # - else release is 1
+       is_release)
+               out=$(\
+                       ([ -n "${RELEASE}" ] && echo "${RELEASE}" ) || \
+                       ([ -e "${release_file}" ] && echo 1) || \
+                       (${in_repo} && ( (${git} describe --match='release_*' --exact-match > /dev/null 2>&1 && ${git} status > /dev/null && echo 1) || echo 0) ) || \
+                       echo "${is_release}" \
+               )
+       ;;
+
+       *)
+               out="$c"
+       ;;
+       esac
+       printf '%s' "${out}" | tr -d '\n'
+       done
+}
+
+#
+#  Parse any arguments
+#
+while getopts "hcd" arg; do
+       case $arg in
+       h)
+               usage
+       ;;
+
+       c)
+               [ ! -e "${commit_file}" ] || rm "${commit_file}"
+               [ ! -e "${commit_depth_file}" ] || rm "${commit_depth_file}"
+               [ ! -e "${release_file}" ] || rm "${release_file}"
+               exit 0
+       ;;
+
+       d)
+               # Intermediary variables to quite shellcheck SC2005 as it doesn't
+               # seem to be able to differentiate between functions are other
+               # commands.
+               commit="$(version_component commit)"
+               echo "$commit" > "${commit_file}"
+               commit_depth="$(version_component commit_depth)"
+               echo "$commit_depth" > "${commit_depth_file}"
+               if [ "$(version_component is_release)" = 'true' ]; then touch "${release_file}"; fi
+               exit 0
+       ;;
+
+       *)
+               exit 64
+       esac
+done
+shift $((OPTIND-1))
+
+version_component "$@"
+echo