File: gitlog2version.sh

package info (click to toggle)
nut 2.8.4%2Breally-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 25,720 kB
  • sloc: ansic: 132,030; sh: 17,256; cpp: 12,566; makefile: 5,646; python: 1,114; perl: 856; xml: 47
file content (510 lines) | stat: -rwxr-xr-x 24,898 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
#!/bin/sh

# Copyright (C) 2016-2025 by Jim Klimov <jimklimov+nut@gmail.com>
#
#   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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
############################################################################
#
# For setup check NUT_VERSION* in script source.
# For more info see docs/nut-versioning.adoc
#
# The NUT SEMVER definition mostly follows https://semver.org/ standard
# except that for development iterations the base version may have up to
# five dot-separated numeric components (SEMVER triplet for base release,
# and additional data described below). Unlike standard semver provisions
# for "pre-release versions" (separated by a minus sign after the triplet),
# which are "less than" that release for comparisons, the fourth and fifth
# components (if present) are "greater than" that release and any preceding
# development iterations made after it.
#
# Helper script to determine the project version in a manner similar to what
# `git describe` produces, but with added numbers after the common triplet
# of semantically versioned numbers: X.Y.Z.T.B(-C+H(+R)) or X.Y.Z.T.B(-R)
#   * X: MAJOR - incompatible API changes
#   * Y: MINOR - new features and/or API
#   * Z: PATCH - small bug fixes
#   * T: Commits on trunk since previous release tag
#   * B: Commits on branch since nearest ancestor which is on trunk
# The optional suffix (only for commits which are not release tags themselves)
# is provided by `git describe`:
#   * C: Commits on branch since previous release tag
#   * H: (Short) Git hash (prefixed by "g" character) of the described commit
# The pre-release information (if provided/known) would either follow the
# optional suffix detailed above, or it would be the suffix itself:
#   * R: If this commit has a non-release tag, it can be optionally reported
#        so we know that the commit 1234 iterations after release N is also
#        a release candidate for N+1. Note that any dash in that tag value will
#        be replaced by a plus, e.g. 2.8.2.2878.1-2879+g882dd4b00+v2.8.3+rc6
#
# Note that historically NUT did not diligently follow the semver triplet,
# primarily because a snapshot of trunk is tested and released, and work
# moves on with the PATCH part (rarely MINOR one) incremented; no actual
# patches are released to some sustaining track of an older release lineage.
# There were large re-designs that got MAJOR up to 2, though.
#
# Occasionally there may be tagged pre-releases, which follow the standard
# semver markup, like `v2.8.0-rc3` (in git), however they would be converted
# to NUT SEMVER here.
#
############################################################################
# Checked with bash 3 and 5, dash, ksh, zsh and even busybox sh;
# OpenIndiana, FreeBSD and OpenBSD sh. Not compatible with csh and tcsh.
# See some examples in https://github.com/networkupstools/nut/issues/1949

LANG=C
LC_ALL=C
TZ=UTC
export LANG LC_ALL TZ

if [ x"${abs_top_srcdir}" = x ]; then
    SCRIPT_DIR="`dirname "$0"`"
    SCRIPT_DIR="`cd "${SCRIPT_DIR}" && pwd`"
    abs_top_srcdir="${SCRIPT_DIR}/.."
fi
if [ x"${abs_top_builddir}" = x ]; then
    abs_top_builddir="${abs_top_srcdir}"
fi

############################################################################
# Numeric-only default version, for AC_INIT and similar consumers
# in case we build without a Git workspace (from tarball, etc.)
# By legacy convention, 3-digit "semver" was for NUT releases, and
# a nominal "semver.1" for any development snapshots afterwards.

# The VERSION_DEFAULT files are absent in Git, but should be provided
# in tarballs. It may be re-generated by NUT autogen.sh script forcibly,
# but is otherwise preferred if present and NUT source dir is not a git
# workspace itself (e.g. when we build from release tarballs in
# a git-tracked repository of distro recipes, do not use that
# distro's own versions for NUT).
# Embedded distros that hack a NUT version are not encouraged to, but
# can, use a NUT_VERSION_FORCED variable or a VERSION_FORCED file with
# higher priority than auto-detection attempts. Unfortunately, some
# appliances tag all software the same with their firmware version;
# if this is required, a NUT_VERSION_FORCED(_SEMVER) envvar from the
# caller environment, or a file setting it reproducibly, can help
# identify the actual NUT release version triplet used on the box.
# Please use it, it immensely helps with community troubleshooting!
if [ x"${NUT_VERSION_QUERY-}" = x"UPDATE_FILE_GIT_RELEASE" ] ; then
    if [ -s "${abs_top_srcdir}/VERSION_FORCED" ] ; then
        echo "NOTE: Ignoring '${abs_top_srcdir}/VERSION_FORCED', will replace with git info" >&2
    fi
    if [ -s "${abs_top_srcdir}/VERSION_FORCED_SEMVER" ] ; then
        echo "NOTE: Ignoring '${abs_top_srcdir}/VERSION_FORCED_SEMVER', will replace with git info" >&2
    fi
else
    if [ -s "${abs_top_srcdir}/VERSION_FORCED" ] ; then
        # Should set NUT_VERSION_FORCED=X.Y.Z(.a.b...)
        . "${abs_top_srcdir}/VERSION_FORCED" || exit
    fi
    if [ -s "${abs_top_srcdir}/VERSION_FORCED_SEMVER" ] ; then
        # Should set NUT_VERSION_FORCED_SEMVER=X.Y.Z
        . "${abs_top_srcdir}/VERSION_FORCED_SEMVER" || exit
    fi
fi
if [ -n "${NUT_VERSION_FORCED-}" ] ; then
    NUT_VERSION_DEFAULT="${NUT_VERSION_FORCED-}"
    NUT_VERSION_PREFER_GIT=false
fi

if [ -z "${NUT_VERSION_DEFAULT-}" -a -s "${abs_top_builddir}/VERSION_DEFAULT" ] ; then
    . "${abs_top_builddir}/VERSION_DEFAULT" || exit
    [ x"${NUT_VERSION_PREFER_GIT-}" = xtrue ] || { [ -e "${abs_top_srcdir}/.git" ] || NUT_VERSION_PREFER_GIT=false ; }
fi

if [ -z "${NUT_VERSION_DEFAULT-}" -a -s "${abs_top_srcdir}/VERSION_DEFAULT" ] ; then
    . "${abs_top_srcdir}/VERSION_DEFAULT" || exit
    [ x"${NUT_VERSION_PREFER_GIT-}" = xtrue ] || { [ -e "${abs_top_srcdir}/.git" ] || NUT_VERSION_PREFER_GIT=false ; }
fi

# Fallback default, to be updated only during release cycle
[ -n "${NUT_VERSION_DEFAULT-}" ] || NUT_VERSION_DEFAULT='2.8.4'

# Default website paths, extended for historic sub-sites for a release
[ -n "${NUT_WEBSITE-}" ] || NUT_WEBSITE="https://www.networkupstools.org/"

# Must be "true" or "false" exactly, interpreted as such below:
[ x"${NUT_VERSION_PREFER_GIT-}" = xfalse ] || { [ -e "${abs_top_srcdir}/.git" ] && NUT_VERSION_PREFER_GIT=true || NUT_VERSION_PREFER_GIT=false ; }

check_shallow_git() {
    if git log --oneline --decorate=short | tail -1 | grep -w grafted >&2 || [ 10 -gt `git log --oneline | wc -l` ] ; then
        echo "$0: $1" >&2
    fi
}

getver_git() {
    # NOTE: The chosen trunk branch must be up to date (may be "origin/master"
    # or "upstream/master", etc.) for resulting version discovery to make sense.
    if [ x"${NUT_VERSION_GIT_TRUNK-}" = x ] ; then
        # Find the newest info, it may be in a fetched branch
        # not yet checked out locally (or long not updated).
        # Currently we repeat the likely branch names in the
        # end, so that if they exist and are still newest -
        # those are the names to report.
        for T in master `git branch -a 2>/dev/null | grep -E '^ *remotes/[^ ]*/master$'` origin/master upstream/master master ; do
            git log -1 "$T" 2>/dev/null >/dev/null || continue
            if [ x"${NUT_VERSION_GIT_TRUNK-}" = x ] ; then
                NUT_VERSION_GIT_TRUNK="$T"
            else
                # T is strictly same or newer
                # Assume no deviations from the one true path in a master branch
                git merge-base --is-ancestor "${NUT_VERSION_GIT_TRUNK}" "${T}" 2>/dev/null >/dev/null \
                && NUT_VERSION_GIT_TRUNK="$T"
            fi
        done
        if [ x"${NUT_VERSION_GIT_TRUNK-}" = x ] ; then
            echo "$0: FAILED to discover a NUT_VERSION_GIT_TRUNK in this workspace" >&2
            check_shallow_git "NOTE: Current checkout is shallow, the workspace may not include enough context to describe it"
            return 1
        fi
    fi

    # By default, only annotated tags are considered
    ALL_TAGS_ARG=""
    if [ x"${NUT_VERSION_GIT_ALL_TAGS-}" = xtrue ] ; then ALL_TAGS_ARG="--tags" ; fi

    # NOTE: "--always" should not be needed in NUT repos normally,
    # but may help other projects who accept such scheme and script:
    # it tells git to return a commit hash if no tag is matched.
    # It may still be needed on CI systems which only fetch the
    # commit they build and no branch names or tags (minimizing the
    # traffic, storage and general potential for creative errors).
    ALWAYS_DESC_ARG=""
    if [ x"${NUT_VERSION_GIT_ALWAYS_DESC-}" = xtrue ] ; then ALWAYS_DESC_ARG="--always" ; fi

    # Praises to old gits and the new, who may --exclude;
    # NOTE: match/exclude by shell glob expressions, not regex!
    DESC="`git describe $ALL_TAGS_ARG $ALWAYS_DESC_ARG --match 'v[0-9]*.[0-9]*.[0-9]' --exclude '*-signed' --exclude '*rc*' --exclude '*alpha*' --exclude '*beta*' --exclude '*Windows*' --exclude '*IPM*' 2>/dev/null`" \
    && [ -n "${DESC}" ] \
    || DESC="`git describe $ALL_TAGS_ARG $ALWAYS_DESC_ARG | grep -Ev '(rc|-signed|alpha|beta|Windows|IPM)' | grep -E 'v[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*'`"
    # Old stripper (also for possible refspec parts like "tags/"):
    #   echo "${DESC}" | sed -e 's/^v\([0-9]\)/\1/' -e 's,^.*/,,'
    # Follow https://semver.org/#spec-item-10 about build metadata:
    # it is (a dot-separated list) separated by a plus sign from preceding
    DESC="`echo "${DESC}" | sed 's/\(-[0-9][0-9]*\)-\(g[0-9a-fA-F][0-9a-fA-F]*\)$/\1+\2/'`"
    if [ x"${DESC}" = x ] ; then
        echo "$0: FAILED to 'git describe' this codebase" >&2
        check_shallow_git "NOTE: Current checkout is shallow, may not include enough history to describe it"
        return 1
    fi

    # Does the current commit correspond to an `(alpha|beta|rc)NUM` git tag
    # (may be un-annotated)? Note that `git describe` picks the value to
    # report in case several tags are attached; as of git-v2.34.1 it seems
    # to go for first alphanumeric hit (picking same or older non-suffixed
    # string over longer ones if available, or older RC over newer release
    # like "v2.8.2-rc8" preferred over "v2.8.3" if they happen to be tagging
    # the same commit):
    DESC_PRERELEASE="`git describe --tags | grep -E '^v[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*([0-9]*|[-](rc|alpha|beta)[-]*[0-9][0-9]*)$'`" \
    || DESC_PRERELEASE=""

    # How much of the known trunk history is in current HEAD?
    # e.g. all of it when we are on that branch or PR made from its tip,
    # some of it if looking at a historic snapshot, or nothing if looking
    # at the tagged commit (it is the merge base for itself and any of
    # its descendants):
    BASE="`git merge-base HEAD "${NUT_VERSION_GIT_TRUNK}"`" || BASE=""
    if [ x"${BASE}" = x ] ; then
        echo "$0: FAILED to get a git merge-base of this codebase vs. '${NUT_VERSION_GIT_TRUNK}'" >&2
        check_shallow_git "NOTE: Current checkout is shallow, may not include enough history to describe it or find intersections with other trees"
        DESC=""
        return 1
    fi

    # Nearest (annotated by default) tag preceding the HEAD in history:
    TAG="`echo "${DESC}" | sed 's/-[0-9][0-9]*[+-]g[0-9a-fA-F][0-9a-fA-F]*$//'`"
    TAG_PRERELEASE=""
    if [ -n "${DESC_PRERELEASE}" ] ; then
        TAG_PRERELEASE="`echo "${DESC_PRERELEASE}" | sed 's/-[0-9][0-9]*[+-]g[0-9a-fA-F][0-9a-fA-F]*$//'`"
        if [ x"${DESC_PRERELEASE}" != x"${TAG_PRERELEASE}" ] ; then
            # We did chop off something, so `git describe` above did not hit
            # exactly the tagged commit, but something later - not interesting
            TAG_PRERELEASE=""
        fi
        if [ x"${TAG}" = x"${TAG_PRERELEASE}" ] ; then
            # Nothing new
            TAG_PRERELEASE=""
        fi
    fi

    # Commit count since the tag, and hash, of the current HEAD commit;
    # empty e.g. when HEAD is the release-tagged commit:
    SUFFIX="`echo "${DESC}" | sed 's/^.*\(-[0-9][0-9]*[+-]g[0-9a-fA-F][0-9a-fA-F]*\)$/\1/'`" \
    && [ x"${SUFFIX}" != x"${TAG}" ] || SUFFIX=""

    # Tack on "this commit is a pre-release!" info, if known
    SUFFIX_PRERELEASE=""
    if [ -n "${TAG_PRERELEASE}" ] ; then
        SUFFIX_PRERELEASE="`echo "${TAG_PRERELEASE}" | tr '-' '+'`"
        if [ -n "${SUFFIX}" ] ; then
            SUFFIX="${SUFFIX}+${SUFFIX_PRERELEASE}"
        else
            SUFFIX="-${SUFFIX_PRERELEASE}"
        fi
    fi

    # 5-digit version, note we strip leading "v" from the expected TAG value
    # Note the commit count will be non-trivial even if this is commit tagged
    # as a final release but it is not (yet?) on the BASE branch!
    VER5="${TAG#v}.`git log --oneline "${TAG}..${BASE}" | wc -l | tr -d ' '`.`git log --oneline "${NUT_VERSION_GIT_TRUNK}..HEAD" | wc -l | tr -d ' '`"
    DESC5="${VER5}${SUFFIX}"

    # Strip up to two trailing zeroes for trunk snapshots and releases
    VER50="`echo "${VER5}" | sed -e 's/\.0$//' -e 's/\.0$//'`"
    DESC50="${VER50}${SUFFIX}"

    # Leave exactly 3 components
    if [ -n "${NUT_VERSION_FORCED_SEMVER-}" ] ; then
        SEMVER="${NUT_VERSION_FORCED_SEMVER-}"
    else
        if [ -n "${TAG_PRERELEASE}" ] ; then
            # Actually report as SEMVER the version of (next) release
            # for which this commit is candidate
            SEMVER="`echo "${TAG_PRERELEASE}" | sed -e 's/^v*//' -e 's/^\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)[^0-9].*$/\1/'`"
        else
            SEMVER="`echo "${VER5}" | sed -e 's/^\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)\..*$/\1/'`"
        fi
    fi
    # FIXME? Add ".0" up to 3 components?
}

getver_default() {
    # We will collect this value as we go
    SEMVER=""
    if [ -n "${NUT_VERSION_FORCED_SEMVER-}" ] ; then
        SEMVER="${NUT_VERSION_FORCED_SEMVER-}"
    fi

    # Similar to DESC_PRERELEASE filtering above, should yield non-trivial
    # "-rc6" given a "v2.8.3-rc6" as input. Unlike git-based knowledge,
    # we can not say that this is a build based off old release N which
    # is a candidate for N+1, probably.
    SUFFIX=""
    SUFFIX_PRERELEASE=""
    case "${NUT_VERSION_DEFAULT}" in
        *-rc*|*-alpha*|*-beta*)
            # Assume triplet (possibly prefixed with `v`) + suffix
            # like `v2.8.3-rc6` or `2.8.2-beta-1`
            # FIXME: Check the assumption better!
            SUFFIX="`echo "${NUT_VERSION_DEFAULT}" | grep -E '^v*[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*([0-9]*|[-](rc|alpha|beta)[-]*[0-9][0-9]*)$' | sed -e 's/^v*//' -e 's/^\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)\([^0-9].*\)$/\2/'`" \
            && [ -n "${SUFFIX}" ] \
            && SUFFIX_PRERELEASE="`echo "${SUFFIX}" | sed 's/^-*//'`" \
            && NUT_VERSION_DEFAULT="`echo "${NUT_VERSION_DEFAULT}" | sed -e 's/'"${SUFFIX}"'$//'`"
            ;;
        *+rc*|*+alpha*|*+beta*)
            # Consider forced `2.8.2.2878.3-2881+g45029249f+v2.8.3+rc6` values

            # We remove up to 5 dot-separated leading numbers, so
            # for the example above, `-2881+g45029249f` remains:
            tmpSUFFIX="`echo "${NUT_VERSION_DEFAULT}" | grep -E '^v*[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*(.*\+(rc|alpha|beta)[+-]*[0-9][0-9]*)$' | sed -e 's/^v*//' -e 's/^\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)\([^0-9].*\)$/\2/' -e 's/^\(\.[0-9][0-9]*\)//' -e 's/^\(\.[0-9][0-9]*\)//'`" \
            || tmpSUFFIX=""
            if [ -n "${tmpSUFFIX}" ] && [ x"${tmpSUFFIX}" != "${NUT_VERSION_DEFAULT}" ] ; then
                # Extract tagged NUT version from that suffix
                SUFFIX="${tmpSUFFIX}"
                # for the example above, `v2.8.3+rc6` remains
                tmpTAG_PRERELEASE="`echo "${tmpSUFFIX}" | sed 's/^.*[^0-9]\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*[+]\(rc\|alpha\|beta\)[+-]*[0-9][0-9]*\)$/\1/'`" \
                || tmpTAG_PRERELEASE=""
                if [ -n "${tmpTAG_PRERELEASE}" ] && [ x"${tmpSUFFIX}" != "${tmpTAG_PRERELEASE}" ] ; then
                    # Replace back pluses to dashes for the tag
                    TAG_PRERELEASE="v`echo "${tmpTAG_PRERELEASE}" | sed -e 's/[+]\(rc\|alpha\|beta\)/-\1/' -e 's/\(rc\|alpha\|beta\)[+]/\1-/'`"
                    if [ -z "${SEMVER}" ] ; then
                        # for the example above, `2.8.3` remains:
                        SEMVER="`echo "${tmpTAG_PRERELEASE}" | sed -e 's/[-+].*$//'`"
                    fi
                    # for the example above, `rc6` remains:
                    SUFFIX_PRERELEASE="`echo "${tmpTAG_PRERELEASE}" | sed 's/^[^+-]*[+-]//'`"
                    # for the example above, `2.8.2.2878.3-2881+g45029249f` remains:
                    NUT_VERSION_DEFAULT="`echo "${NUT_VERSION_DEFAULT}" | sed -e 's/'"${SUFFIX}"'$//'`"
                fi
            fi
            ;;
    esac

    NUT_VERSION_DEFAULT_DOTS="`echo "${NUT_VERSION_DEFAULT}" | sed 's/[^.]*//g' | tr -d '\n' | wc -c`"

    # Ensure at least 4 dots (5 presumed-numeric components)
    NUT_VERSION_DEFAULT5_DOTS="${NUT_VERSION_DEFAULT_DOTS}"
    NUT_VERSION_DEFAULT5="${NUT_VERSION_DEFAULT}"
    while [ "${NUT_VERSION_DEFAULT5_DOTS}" -lt 4 ] ; do
        NUT_VERSION_DEFAULT5="${NUT_VERSION_DEFAULT5}.0"
        NUT_VERSION_DEFAULT5_DOTS="`expr $NUT_VERSION_DEFAULT5_DOTS + 1`"
    done

    # Truncate/extend to exactly 2 dots (3 presumed-numeric components)
    NUT_VERSION_DEFAULT3_DOTS="${NUT_VERSION_DEFAULT_DOTS}"
    NUT_VERSION_DEFAULT3="${NUT_VERSION_DEFAULT}"
    while [ "${NUT_VERSION_DEFAULT3_DOTS}" -lt 2 ] ; do
        NUT_VERSION_DEFAULT3="${NUT_VERSION_DEFAULT3}.0"
        NUT_VERSION_DEFAULT3_DOTS="`expr $NUT_VERSION_DEFAULT3_DOTS + 1`"
    done
    while [ "${NUT_VERSION_DEFAULT3_DOTS}" -gt 2 ] ; do
        NUT_VERSION_DEFAULT3="`echo "${NUT_VERSION_DEFAULT3}" | sed 's,\.[0-9][0-9]*[^.]*$,,'`"
        NUT_VERSION_DEFAULT3_DOTS="`expr $NUT_VERSION_DEFAULT3_DOTS - 1`"
    done

    DESC5="${NUT_VERSION_DEFAULT5}${SUFFIX}"
    DESC50="${NUT_VERSION_DEFAULT}${SUFFIX}"
    VER5="${NUT_VERSION_DEFAULT5}"
    VER50="${NUT_VERSION_DEFAULT}"
    BASE=""
    if [ -z "${SEMVER}" ] ; then
        SEMVER="${NUT_VERSION_DEFAULT3}"
    fi
    TAG="v${NUT_VERSION_DEFAULT3}${SUFFIX}"
    if [ x"${TAG_PRERELEASE-}" = x ] ; then
        if [ x"${SUFFIX_PRERELEASE}" != x ] ; then
            TAG_PRERELEASE="v${NUT_VERSION_DEFAULT3}-${SUFFIX_PRERELEASE}"
        else
            TAG_PRERELEASE=""
        fi
    fi
}

report_debug() {
    # Debug
    echo "SEMVER=${SEMVER}; TRUNK='${NUT_VERSION_GIT_TRUNK-}'; BASE='${BASE}'; DESC='${DESC}' => TAG='${TAG}' + SUFFIX='${SUFFIX}' => VER5='${VER5}' => DESC5='${DESC5}' => VER50='${VER50}' => DESC50='${DESC50}'" >&2
}

report_output() {
    case "${NUT_VERSION_QUERY-}" in
        "DESC5")	echo "${DESC5}" ;;
        "DESC50")	echo "${DESC50}" ;;
        "VER5") 	echo "${VER5}" ;;
        "VER50")	echo "${VER50}" ;;
        "SEMVER")	echo "${SEMVER}" ;;
        "IS_RELEASE")	[ x"${SEMVER}" = x"${VER50}" ] && echo true || echo false ;;
        "IS_PRERELEASE")	[ x"${SUFFIX_PRERELEASE}" != x ] && echo true || echo false ;;
        "TAG")  	echo "${TAG}" ;;
        "TAG_PRERELEASE") echo "${TAG_PRERELEASE}" ;;
        "TRUNK")  	echo "${NUT_VERSION_GIT_TRUNK-}" ;;
        "SUFFIX")	echo "${SUFFIX}" ;;
        "SUFFIX_PRERELEASE") echo "${SUFFIX_PRERELEASE}" ;;
        "BASE") 	echo "${BASE}" ;;
        "URL")
            # Clarify the project website URL - particularly historically
            # frozen snapshots made for releases
            if [ x"${SEMVER}" = x"${VER50}" ] ; then
                echo "${NUT_WEBSITE}historic/v${SEMVER}/index.html"
            else
                echo "${NUT_WEBSITE}"
            fi
            ;;
        "UPDATE_FILE_GIT_RELEASE")
            # NOTE: For maintainers, changes SRCDIR not BUILDDIR; requires GIT
            # Do not "mv" here because maintainer files may be hard-linked from elsewhere
            echo "NUT_VERSION_FORCED='${DESC50}'" > "${abs_top_srcdir}/VERSION_FORCED.tmp" || exit
            if ! cmp "${abs_top_srcdir}/VERSION_FORCED.tmp" "${abs_top_srcdir}/VERSION_FORCED" >/dev/null 2>/dev/null ; then
                cat "${abs_top_srcdir}/VERSION_FORCED.tmp" > "${abs_top_srcdir}/VERSION_FORCED" || exit
            fi
            rm -f "${abs_top_srcdir}/VERSION_FORCED.tmp"

            echo "NUT_VERSION_FORCED_SEMVER='${SEMVER}'" > "${abs_top_srcdir}/VERSION_FORCED_SEMVER.tmp" || exit
            if ! cmp "${abs_top_srcdir}/VERSION_FORCED_SEMVER.tmp" "${abs_top_srcdir}/VERSION_FORCED_SEMVER" >/dev/null 2>/dev/null ; then
                cat "${abs_top_srcdir}/VERSION_FORCED_SEMVER.tmp" > "${abs_top_srcdir}/VERSION_FORCED_SEMVER" || exit
            fi
            rm -f "${abs_top_srcdir}/VERSION_FORCED_SEMVER.tmp"

            grep . "${abs_top_srcdir}/VERSION_FORCED" "${abs_top_srcdir}/VERSION_FORCED_SEMVER"
            ;;
        "UPDATE_FILE")
            if [ x"${abs_top_builddir}" != x"${abs_top_srcdir}" ] \
            && [ -s "${abs_top_srcdir}/VERSION_DEFAULT" ] \
            && [ ! -s "${abs_top_builddir}/VERSION_DEFAULT" ] \
            ; then
                cp -f "${abs_top_srcdir}/VERSION_DEFAULT" "${abs_top_builddir}/VERSION_DEFAULT" || exit
            fi

            echo "NUT_VERSION_DEFAULT='${DESC50}'" > "${abs_top_builddir}/VERSION_DEFAULT.tmp" || exit
            if cmp "${abs_top_builddir}/VERSION_DEFAULT.tmp" "${abs_top_builddir}/VERSION_DEFAULT" >/dev/null 2>/dev/null ; then
                rm -f "${abs_top_builddir}/VERSION_DEFAULT.tmp"
            else
                mv -f "${abs_top_builddir}/VERSION_DEFAULT.tmp" "${abs_top_builddir}/VERSION_DEFAULT" || exit
            fi
            cat "${abs_top_builddir}/VERSION_DEFAULT"
            ;;
        *)		echo "${DESC50}" ;;
    esac
}

DESC=""
NUT_VERSION_TRIED_GIT=false
if $NUT_VERSION_PREFER_GIT ; then
    if (command -v git && git rev-parse --show-toplevel) >/dev/null 2>/dev/null ; then
        getver_git || { echo "$0: Fall back to pre-set default version information" >&2 ; DESC=""; }
        NUT_VERSION_TRIED_GIT=true
    else
        NUT_VERSION_PREFER_GIT=false
    fi
fi

if [ x"$DESC" = x ]; then
    getver_default
    if $NUT_VERSION_TRIED_GIT ; then
        if CURRENT_COMMIT="`git log -1 --format='%h'`" && [ -n "${CURRENT_COMMIT}" ] ; then
            # Cases help rule out values populated via fallbacks from files;
            # try to not add inconsistencies though (only add if nobody has it)
            CAN_TACK=true
            case "$VER5" in
                *"+g"*) CAN_TACK=false ;;
            esac
            case "$VER50" in
                *"+g"*) CAN_TACK=false ;;
            esac
            case "$DESC5" in
                *"+g"*) CAN_TACK=false ;;
            esac
            case "$DESC50" in
                *"+g"*) CAN_TACK=false ;;
            esac

            if ${CAN_TACK} ; then
                echo "$0: Git failed originally, but current commit '${CURRENT_COMMIT}' is known (shallow checkout?); tack it to values that lack it" >&2
                case "$VER5" in
                    *"+g"*) ;;
                    *-{0,1,2,3,4,5,6,7,8,9}*)
                        VER5="${VER5}+g${CURRENT_COMMIT}" ;;
                    *)  VER5="${VER5}-0+g${CURRENT_COMMIT}" ;;
                esac
                case "$VER50" in
                    *"+g"*) ;;
                    *-{0,1,2,3,4,5,6,7,8,9}*)
                        VER50="${VER50}+g${CURRENT_COMMIT}" ;;
                    *)  VER50="${VER50}-0+g${CURRENT_COMMIT}" ;;
                esac
                case "$DESC5" in
                    *"+g"*) ;;
                    *-{0,1,2,3,4,5,6,7,8,9}*)
                        DESC5="${DESC5}+g${CURRENT_COMMIT}" ;;
                    *)  DESC5="${DESC5}-0+g${CURRENT_COMMIT}" ;;
                esac
                case "$DESC50" in
                    *"+g"*) ;;
                    *-{0,1,2,3,4,5,6,7,8,9}*)
                        DESC50="${DESC50}+g${CURRENT_COMMIT}" ;;
                    *)  DESC50="${DESC50}-0+g${CURRENT_COMMIT}" ;;
                esac
            fi
        fi
    fi
fi

report_debug
report_output

# Set exit code based on availability of default version info data point
# Not empty means good
# TOTHINK: consider the stdout of report_output() instead?
[ x"${DESC50}" != x ]