#!/bin/ksh
#
# NAME:
#    reltag
#
# SYNOPSIS:
#    reltag [-cdhinuvw] [NUM]
#
# DESCRIPTION:
#    Abuses RCS to set or shows a release tag (two-digit semantic
#    version number) for use with Git or Mercurial.
#
#    For version X.Y, X is the major release and Y is the minor release.
#    0.0 is displayed if no version file exists.
#
# OPTIONS:
#    -c, --clean    remove RCS file.
#    -d, --debug    prints debug information.
#    -h, --help     prints usage information and exits.
#    -i, --inc      increments minor version number.
#    -n, --new      sets or increments major (new) version number.
#    -u, --uuid     print UUID and exit.
#    -v, --version  print the version and exit.
#    -w, --where    print script location and exit.
#
#    "-i" displays 1.0 if no version file exists, or increments the
#    minor version and displays it.
#
#    "-n" displays 1.0 if no version file exists, or increments the
#    major version and displays it.  If a numeric argument is present
#    and greater than the major version, use it for the major version.
#
# EXAMPLES:
#    me% reltag
#    0.0
#    me% reltag -i
#    1.0
#    me% reltag -c
#    DATE reltag: Cleaning out all version files
#    me% reltag -n
#    1.0
#    me% reltag -i
#    1.1
#    me% reltag -i
#    1.2
#    me% reltag -n
#    2.1
#    me% reltag -i
#    2.2
#    me% reltag -n 4
#    4.1
#    me% reltag -i
#    4.2
#    me% reltag -n 3
#    DATE reltag: FATAL: new version must be >= current version
#    me% reltag -c
#    DATE reltag: Cleaning out all version files
#
# AUTHOR:
#    Karl Vogel <vogelke+unix@pobox.com>

export PATH=/usr/local/bin:/bin:/usr/bin
export RCSINIT=-zLT
umask 022
tag=${0##*/}

# Where we hide the version info.
vfile='.version'
rfile='.version,v'
test -d 'RCS' && rfile='RCS/.version,v'

# ======================== FUNCTIONS =============================
# General logging.

logmsg () { echo "$(date '+%T') $tag: $@"; }
die ()    { logmsg "FATAL: $@"; exit 1; }

# usage: prints an optional string plus part of the comment
# header (if any) to stderr, and exits with code 1.

usage () {
    PAGER=${PAGER:-cat}

    (
        case "$#" in
            0)  ;;
            *)  echo "usage error: $*"; echo ;;
        esac

        awk '/^# NAME/,/^# AUTHOR/ {
             if ($2 == "AUTHOR:") exit
             print substr($0, 2)
        }' $0
    ) | $PAGER

    exit 0
}

# Print the UUID for this script.  Should be based on
# something unique, like date-time-hostname.
myuuid () {
    awk '{print $2}' <<'EOU'
    $UUID: f7b908e4-3e7e-36d8-b89f-7a436f1c84b1 $
EOU
}

# Print the current version and source location.
version () {
    awk '/RCS/{n=$2; v=$5; }
         /Date:/{m=split($0,a); d=a[2]; for (i=3; i<m; i++) d = d " " a[i]}
         END {printf "%s %s %s\n", n, v, d}' <<'EOV'
    $RCSfile: reltag $ $Revision: d7156e5109b9 $
    $Date: Sun, 31 Mar 2024 20:18:32 -0400 $
EOV
    exit 0
}

where () {
    awk '/Host:/ {h=$2}; /Source:/ {s=$2};
          END {print "file://" h s}' <<'EOW'
    $Host: furbag.my.domain $
    $Source: /doc/html/htdocs/dotfiles/bin/reltag $
EOW
}

# Show the complete version.
showvers () {
    if test -f "${rfile}"; then
        set X $(head -1 "${rfile}" | tr ';.' '  ')
        case "$#" in
            4) echo $3.$4 ;;
            *) echo 0.0 ;;
        esac
    else
        echo 0.0
    fi

    test -f "${vfile}" && rm "${vfile}"
}

# Create version 1.0 file.
docreate () {
    echo "$$ $RANDOM" > "${vfile}"
    echo checkin | ci -q -r1.0 "${vfile}"
    rcs -q -U "${rfile}"
}

# Increment or set major version
incmajor () {
    x=
    test -n "$1" && x=$1

    if test -f "${rfile}"; then
        set X $(head -1 "${rfile}" | tr ';.' '  ')
        minor=1
        major=$(($3 + 1))

        if test -n "$x"; then
            if test "$x" -ge "$major"; then
                major="$x"
            else
                die "new version must be >= current version"
            fi
        fi

        echo "$$ $RANDOM" > "${vfile}"
        echo checkin | ci -q -r"${major}.${minor}" "${vfile}"
        rcs -q -U "${rfile}"
    else
        docreate
    fi
}

# Increment minor version -- don't bother trying to reset it.
incminor () {
    if test -f "${rfile}"; then
        echo "$$ $RANDOM" > "${vfile}"
        echo checkin | ci -q "${vfile}"
        rcs -q -U "${rfile}"
    else
        docreate
    fi
}

# Remove the version stuff completely.
cleanup() {
    logmsg "Cleaning out all version files"
    rm -f "${rfile}" "${vfile}"
    exit 0
}

# ======================== MAIN PROGRAM ==========================
# Handle command line arguments.
# Initialize some variables set by options.
dbg='no'
action='show'

# START command-line options generated by kshopt.
while getopts cdhinuvw-: arg; do
    case $arg in
        c)  cleanup ;;
        d)  dbg='yes'; set -x ;;
        h)  usage ;;
        i)  action='inc' ;;
        n)  action='new' ;;
        u)  myuuid; exit 0 ;;
        v)  version ;;
        w)  where; exit 0 ;;

        -)  LONG_OPTARG="${OPTARG#*=}"
            case $OPTARG in
                clean|clea|cle|cl|c) cleanup ;;
                debug|debu|deb|de|d) dbg='yes'; set -x ;;
                help|hel|he|h) usage ;;
                inc|in|i) action='inc' ;;
                new|ne|n) action='new' ;;
                uuid|uui|uu|u) myuuid; exit 0 ;;
                version|versio|versi|vers|ver|ve|v) version ;;
                where|wher|whe|wh|w) where; exit 0 ;;

                clean*|debug*|help*|inc*|new*|uuid*|version*|where*)
                    die "No arg allowed for --$OPTARG option" ;;

                # "--" terminates argument processing
                '') break ;;
                *)  die "Illegal option --$OPTARG" ;;
            esac
            ;;

        \?) echo "$tag -h prints help."
            exit 2 ;;  # getopts already reported the illegal option
    esac
done

# END command-line options generated by kshopt.
shift $(($OPTIND - 1))

# Allow an optional positive integer.
if test "$#" -gt 0; then
    if test "$1" -eq "$1" ; then
        num=$1
    else
        die "argument must be an integer"
    fi
else
    num=
fi

# All that for 6 lines.
case "$action" in
    show) showvers ;;
    inc)  incminor $num; showvers ;;
    new)  incmajor $num; showvers ;;
    *)    echo "action [$action]" ;;
esac

exit 0
