#!/bin/sh
#
# getversion.sh
#
# Home page of code is: https://www.smartmontools.org
#
# Copyright (C) 2024-26 Christian Franke
#
# SPDX-License-Identifier: GPL-2.0-or-later
#

set -e
myname=$0

usage()
{
  cat <<EOF
Usage: $myname -n [REV] [--] [PATH]
       $myname -g [REV] [--] [PATH] >> \$GITHUB_ENV
       $myname -s [REV] [--] [PATH] > version.sh
       $myname -i [REV] [--] [PATH] < version.sh > version.h

  -n          Print version string suitable for filenames
  -g          Create version information for \$GITHUB_ENV
  -s          Create commented shell script which sets version information
  -i          Create include file from shell script
EOF
  exit 1
}

error()
{
  echo "$myname: Error: $*" >&2
  exit 1
}

warning()
{
  echo "$myname: (Warning) $*" >&2
}

g_opt=false; i_opt=false; n_opt=false; s_opt=false
while :; do case $1 in
  -g) g_opt=true ;;
  -i) i_opt=true ;;
  -n) n_opt=true ;;
  -s) s_opt=true ;;
  --) break ;;
  -*) usage ;;
  *) break ;;
esac; shift; done
case "$g_opt$i_opt$n_opt$s_opt" in
  *true*true*) usage ;; *true*) ;; *) usage ;;
esac

if $i_opt; then
  # version.sh -> version.h
  echo "// version.h.  Generated by ${myname##*/} from version.sh."
  sed -e 's/#/\/\//' -e 's/=/ /' -e 's/'\''/"/g' \
      -e 's/^unset /#undef /' \
      -e 's/^SMART/#define SMART/'
  exit 0
fi

srcdir=${myname%/*}
test "$srcdir" != "$myname" || error "unknown \$srcdir"
top_srcdir="$srcdir/.."

# Get PACKAGE_VERSION from configure.ac
ver=$(sed -n 's|^AC_INIT[^,]*, *\[\([0-9.]*\)\] *,.*$|\1|p' "$top_srcdir/configure.ac") || exit 1
test -n "$ver" || error "$top_srcdir/configure.ac: package version not found"

# Missing release date indicates pre-release
pre=
x=$(sed -n 's|^smartmontools_release_date=\(.*\)$|\1|p' "$top_srcdir/configure.ac") || exit 1
case $x in
  20*) ;;
  \ \#*) pre="pre-" ;;
  *) error "$top_srcdir/configure.ac: unable to detect pre-release state" ;;
esac

# Check whether this is a git checkout
is_git_co=true
test -n "$(cd "$top_srcdir" && git ls-files README.md 2>/dev/null)" || is_git_co=false

# Check for the copy of 'version.sh' generated by 'make distdir'
dist_version_sh="$srcdir/dist-version.sh"
if [ -f "$dist_version_sh" ]; then
  ! $is_git_co || error "$dist_version_sh: must not exist in a git checkout"
  test $# -eq 0 || error "git log is required for '$*'"

  x=$(
    sed -e '/^#/d' -e 's/ *#.*$//'\
        -e '/^unset SMARTMONTOOLS_GIT_[A-Z_]*$/d' \
        -e '/^SMARTMONTOOLS_PKG_VER='"'[^'][^']*'"'$/d' \
        -e '/^SMARTMONTOOLS_GIT_[A-Z_]*='"'[^'][^']*'"'$/d' \
        -e '/^SMARTMONTOOLS_GIT_[A-Z_]*=[0-9][0-9]*$/d' "$dist_version_sh"
  ) || exit 1
  test -z "${x:+t}" || error "$dist_version_sh: syntax error"

  if $n_opt; then
    unset SMARTMONTOOLS_GIT_VER_FNAME
    # shellcheck disable=SC1090
    . "$dist_version_sh" || exit 1
    test -n "$SMARTMONTOOLS_GIT_VER_FNAME" \
    || error "$dist_version_sh: missing SMARTMONTOOLS_GIT_VER_FNAME"
    echo "$SMARTMONTOOLS_GIT_VER_FNAME"
  else
    cat "$dist_version_sh"
  fi
  exit 0
fi

# svn r5714 - RELEASE_7_5 svn/trunk commit
base_svn_rev=5714
base_git_rev="943adaeda55c2d534c722fe66c6b4613a782caa1"

rev=; rev_date=; rev_time=; pre_revs=; svn_rev=
ver_desc="$pre$ver-unknown"
ver_fname="$ver-unknown"
ver_win="$ver.0.999"
origin="(git log not available)"

if $is_git_co; then
  # Query specific revision if requested
  head="HEAD"
  if [ $# -gt 0 ]; then
    # Stay in current directory to keep PATH names valid
    # shellcheck disable=SC2015
    head=$(git log -1 --format='format:%H' "$@" 2>/dev/null) \
    && [ -n "$head" ] || error "git revision not found for '$*'"
  fi

  # Get hash, date and time of head revision
  # Note: don't use 'format:%h' because its length depends on clone depth
  x=$(
    cd "$top_srcdir" \
    && TZ='' LC_ALL=C git log -1 --date=iso-local --format='format:%H %ct %cd' "$head" 2>/dev/null
  ) || exit 1
  rev=${x%% *}; x=${x#* }
  rev_epoch=${x%% *}; x=${x#* }
  rev_date=${x%% *}; x=${x#* }
  rev_time=${x%% *}
  rev=$(echo "$rev" | cut -c 1-12)

  # Check for modifications
  # (may be incorrect positive if a REV or PATH is specified
  x="$(cd "$top_srcdir" && git status -s -uno)" || exit 1
  modified=${x:+-modified}
  rev="$rev$modified"

  # Emulate a svn revision number
  if x=$(cd "$top_srcdir" && git rev-list --count "$base_git_rev..$head" 2>/dev/null) \
     && [ "$x" -gt 0 ]; then
    svn_rev=$((base_svn_rev + x))
  fi

  if [ -n "$pre" ]; then
    # Determine git revision of previous PACKAGE_VERSION
    # Note: this assumes that future versions will be tagged "smartmontools-X.Y"
    major=${ver%%.*}; minor=${ver##*.}
    test "$major.$minor" = "$ver" || error "$ver: invalid package version"
    test "$major" -ge 8 || error "$ver: package versions below 8.0 are not supported"
    if [ "$minor" -gt 0 ]; then
      prev_release="smartmontools-$major.$((minor - 1))"
    elif [ "$major" -gt 8 ]; then
      pattern="smartmontools-$((major - 1)).*"
      prev_release=$(cd "$top_srcdir" &&
                     git tag -l --sort=-authordate --no-column "$pattern" 2>/dev/null | head -n 1)
      test -n "$prev_release" || warning "$pattern: no matching revisions found"
    else
      prev_release=$base_git_rev # 7.5
    fi
    pre_revs=
    pre_revs_win=999
    if [ -n "$prev_release" ]; then
      # Get number of revisions since previous PACKAGE_VERSION
      if x=$(cd "$top_srcdir" && git rev-list --count "$prev_release..$head" 2>/dev/null)
      then
        if [ 0 -lt "$x" ] && [ "$x" -lt 5600 ]; then
          pre_revs=$x
          pre_revs3=$(printf '%03d' "$pre_revs");
          pre_revs_win=$x
          test -z "$modified" || pre_revs_win=$((pre_revs_win + 500))
        else
          warning "$prev_release: is not a previous release"
        fi
      else
        warning "$prev_release: revision not found"
      fi
    fi

    # "pre-X.Y[-NNN][-modified]"
    ver_desc="pre-$ver${pre_revs3:+-}$pre_revs3$modified"
    # "X.Y[-NNN]-gREV[-modified]"
    ver_fname="$ver${pre_revs3:+-}$pre_revs3-g$rev"
    # "X.Y.0.N[+500]"
    ver_win="$ver.0.$pre_revs_win"

  else
    # Release
    ver_desc="$ver$modified"
    ver_fname=$ver_desc
    if [ -z "$modified" ]; then
      ver_win="$ver.0.1000"
    else
      ver_win="$ver.0.1500"
    fi
  fi
  origin="and git log"

else
  test $# -eq 0 || error "git log is required for '$*'"
  msg="no '$dist_version_sh' or git log available"
  if [ "$SMARTMONTOOLS_TEST_BUILD" != "1" ]; then
    echo "$myname: Error: $msg" >&2
    echo "Use this to override:" >&2
    echo "export SMARTMONTOOLS_TEST_BUILD=1" >&2
    exit 1
  fi
  warning "$msg"
fi

if $n_opt; then
  echo "$ver_fname"

else
  if $g_opt; then
    varout()  { test -z "$2" || echo "$1=$2"; }
    varoutq() { test -z "$2" || echo "$1=$2"; }
  else
    varout() {
      if [ -z "$2" ]; then
        echo "unset $1 # $3"
      else
        echo "$1=$2 # $3"
      fi
    }
    varoutq() {
      if [ -z "$2" ]; then
        echo "unset $1 # $3"
      else
        echo "$1='$2' # $3"
      fi
    }
  fi

  $g_opt || echo "# version.sh.  Generated by ${myname##*/} from configure.ac $origin."
  varoutq SMARTMONTOOLS_PKG_VER "$ver" "package version from configure.ac"
  varoutq SMARTMONTOOLS_GIT_REV "$rev" "git revision"
  varout  SMARTMONTOOLS_GIT_REV_EPOCH "$rev_epoch" "commit time (seconds since the epoch)"
  varoutq SMARTMONTOOLS_GIT_REV_DATE "$rev_date" "commit date"
  varoutq SMARTMONTOOLS_GIT_REV_TIME "$rev_time" "commit time (UTC)"
  varout  SMARTMONTOOLS_GIT_PRE_REVS "$pre_revs" "commits since previous release"
  varout  SMARTMONTOOLS_GIT_SVN_REV "$svn_rev" "emulated svn revision number"
  varoutq SMARTMONTOOLS_GIT_VER_DESC "$ver_desc" "version description"
  varoutq SMARTMONTOOLS_GIT_VER_FNAME "$ver_fname"  "version string for filenames"
  varoutq SMARTMONTOOLS_GIT_VER_WIN "$ver_win" "version for Windows VERSIONINFO"
fi
