#!/bin/sh
# Print a version string.
scriptversion=2025-01-28.09; # UTC

# Copyright (C) 2007-2025 Free Software Foundation, Inc.
#
# 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 3 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, see <https://www.gnu.org/licenses/>.

# This script is derived from GIT-VERSION-GEN from GIT: https://git-scm.com/.

# It may be run in the following ways, presuming the script is invoked
# like "./git-version-gen .tarball-version":
#
# - from a git repository in which the "git describe" command below
#   produces useful output (thus requiring at least one signed tag)
#
# - from a "make dist" non-git-repo directory containing a
#   .tarball-version file
#
# - from a "git archive" non-git-repo directory containing a
#   .tarball-version-git file

# In order to use intra-version strings in your project, you will need some
# separate generated version string files:
#
# .tarball-version - contains the version number assigned by the maintainer.
#   Present or missing in a checked-out repository, at the discretion of the
#   maintainer/contributor.  Present in a distribution tarball, because the
#   tarball does not include the version control history.
#   Used by git-version-gen as an override.
#   Cannot be used in any dependencies (since it may be absent).
#   GNUmakefile has hooks to force a reconfigure at "make dist" time to get
#   the value correct, without penalizing normal development with extra
#   reconfigures.
#
# .tarball-version-git - a file committed to git containing a single
#   line with the string $Format:%(describe)$ and that the file is
#   marked in .gitattributes with ".tarball-version-git export-subst".
#   If the file doesn't exist or the export-subst keyword wasn't
#   effective, the file is ignored.
#
# Use the following snippet in your configure.ac, so that $(VERSION) will
# automatically be up-to-date each time configure is run (and note that
# since configure.ac no longer includes a version string, Makefile rules
# should not depend on configure.ac for version updates).
#
# AC_INIT([@var{package}], [package])
# AC_CONFIG_SRCDIR([@var{unique-file-in-source-dir}])
# AC_CONFIG_AUX_DIR([build-aux])
# VERSION_NUMBER=`cd $srcdir \
#                 && build-aux/git-version-gen .tarball-version`
# gl_INIT_PACKAGE_VERSION([$VERSION_NUMBER])
# AM_INIT_AUTOMAKE([@var{options}])
#
# Then use the following lines in your Makefile.am, so that
# .tarball-version will exist in distribution tarballs.
#
# dist-hook: dist-tarball-version
# .PHONY: dist-tarball-version
# dist-tarball-version:
#	echo '$(VERSION)' > $(distdir)/.tarball-version
#
# To setup support for "git archive" tarballs, use the following:
#
# echo '$Format:%(describe)$' > .tarball-version-git
# echo '.tarball-version-git export-subst' >> .gitattributes
# git add .tarball-version-git .gitattributes
# git commit -m "Add .tarball-version-git for git-version-gen."

me=$0

year=`expr "$scriptversion" : '\([^-]*\)'`
version="git-version-gen $scriptversion

Copyright (C) ${year} Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law."

usage="\
Usage: $me [OPTION]... \$srcdir/.tarball-version [TAG-NORMALIZATION-SED-SCRIPT]
Print a version string.

Options:

   --prefix PREFIX    prefix of git tags (default 'v')
   --fallback VERSION
                      fallback version to use if \"git --version\" fails

   --help             display this help and exit
   --version          output version information and exit

Send patches and bug reports to <bug-gnulib@gnu.org>."

prefix=v
fallback=

while test $# -gt 0; do
  case $1 in
    --help) echo "$usage"; exit 0;;
    --version) echo "$version"; exit 0;;
    --prefix) shift; prefix=${1?};;
    --fallback) shift; fallback=${1?};;
    -*)
      echo "$0: Unknown option '$1'." >&2
      echo "$0: Try '--help' for more information." >&2
      exit 1;;
    *)
      if test "x$tarball_version_file" = x; then
        tarball_version_file="$1"
      elif test "x$tag_sed_script" = x; then
        tag_sed_script="$1"
      else
        echo "$0: extra non-option argument '$1'." >&2
        exit 1
      fi;;
  esac
  shift
done

if test "x$tarball_version_file" = x; then
    echo "$usage"
    exit 1
fi

tag_sed_script="${tag_sed_script:-s/x/x/}"

nl='
'

# Avoid meddling by environment variable of the same name.
v=
v_from_git=

# First see if there is a tarball-only version file.
# then try "git describe", then default.
if test -f "$tarball_version_file"
then
    v=`cat "$tarball_version_file"` || v=
    case $v in
        *$nl*) v= ;; # reject multi-line output
    esac
    test "x$v" = x \
        && echo "$0: WARNING: $tarball_version_file is damaged" 1>&2
fi

if test "x$v" != x
then
    : # use $v
# Otherwise, if there is at least one git commit involving the working
# directory, and "git describe" output looks sensible, use that to
# derive a version string.
elif test "`git log -1 --pretty=format:x . 2>&1`" = x \
    && v=`git describe --abbrev=4 --match="$prefix*" HEAD 2>/dev/null \
          || git describe --abbrev=4 HEAD 2>/dev/null` \
    && v=`printf '%s\n' "$v" | sed "$tag_sed_script"` \
    && case $v in
         $prefix[0-9]*) ;;
         *) (exit 1) ;;
       esac
then
    # Is this a new git that lists number of commits since the last
    # tag or the previous older version that did not?
    #   Newer: v6.10-77-g0f8faeb
    #   Older: v6.10-g0f8faeb
    vprefix=`expr "X$v" : 'X\(.*\)-g[^-]*$'` || vprefix=$v
    case $vprefix in
        *-*) : git describe is probably okay three part flavor ;;
        *)
            : git describe is older two part flavor
            # Recreate the number of commits and rewrite such that the
            # result is the same as if we were using the newer version
            # of git describe.
            vtag=`echo "$v" | sed 's/-.*//'`
            commit_list=`git rev-list "$vtag"..HEAD 2>/dev/null` \
                || { commit_list=failed;
                     echo "$0: WARNING: git rev-list failed" 1>&2; }
            numcommits=`echo "$commit_list" | wc -l`
            v=`echo "$v" | sed "s/\(.*\)-\(.*\)/\1-$numcommits-\2/"`;
            test "$commit_list" = failed && v=UNKNOWN
            ;;
    esac
    v_from_git=1
elif test "x$fallback" = x || git --version >/dev/null 2>&1; then
    v=UNKNOWN
else
    v=$fallback
fi

if test "x$v" = xUNKNOWN \
        && test -f "$tarball_version_file"-git \
        && v=$(head -1 "$tarball_version_file"-git); then
    case $v in
        *Format*) v=UNKNOWN ;;
    esac
fi

# Change the penultimate "-" to ".", for version-comparing tools.
# Remove the "g" to save a byte.
v=`echo "$v" | sed 's/-\([^-]*\)-g\([^-]*\)$/.\1-\2/'`;

v=`echo "$v" |sed "s/^$prefix//"`

# The "-modified" suffix was previously called "-dirty".  While this term
# was invented by the git people to designate a checkout that is not "clean",
# it has a negative connotation that is not in line with the fact that
# a Free Software developer routinely works with modified source code.
# In fact, modifying source code is the *essence* of Free Software.
# What we need here is a term that is suitable for naming tarballs, without
# shaming the developer.  Giving a name to a tarball is something else than
# describing the state of a git checkout.
#
# Test whether to append the "-modified" suffix only if the version
# string we're using came from git.  I.e., skip the test if it's "UNKNOWN"
# or if it came from .tarball-version.
if test "x$v_from_git" != x; then
  # Don't declare a version "modified" merely because a timestamp has changed.
  git update-index --refresh > /dev/null 2>&1

  modified=`exec 2>/dev/null;git diff-index --name-only HEAD` || modified=
  case "$modified" in
      '') ;;
      *) # Append the suffix only if there isn't one already.
          case $v in
            *-dirty | *-modified) ;;
            *) v="$v-modified" ;;
          esac ;;
  esac
fi

# Omit the trailing newline, so that m4_esyscmd can use the result directly.
printf %s "$v"

# Local variables:
# eval: (add-hook 'before-save-hook 'time-stamp nil t)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:
