Merge pull request #639 from rhansen/version
User-friendly pre-release version strings
This commit is contained in:
commit
07c4e4ad4c
5 changed files with 163 additions and 18 deletions
6
.autom4te.cfg
Normal file
6
.autom4te.cfg
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Disable autom4te cache to ensure that any change to ddclient.in triggers a
|
||||
# rebuild of the configure script (which gets the version of ddclient from
|
||||
# ddclient.in). See <https://lists.gnu.org/r/automake/2019-10/msg00002.html>.
|
||||
begin-language: "Autoconf-without-aclocal-m4"
|
||||
args: --no-cache
|
||||
end-language: "Autoconf-without-aclocal-m4"
|
|
@ -76,6 +76,7 @@ generated_tests = \
|
|||
TESTS = $(handwritten_tests) $(generated_tests)
|
||||
$(TESTS): ddclient
|
||||
EXTRA_DIST += $(handwritten_tests) \
|
||||
.autom4te.cfg \
|
||||
t/lib/Devel/Autoflush.pm \
|
||||
t/lib/Test/Builder.pm \
|
||||
t/lib/Test/Builder/Formatter.pm \
|
||||
|
|
11
configure.ac
11
configure.ac
|
@ -1,5 +1,14 @@
|
|||
AC_PREREQ([2.63])
|
||||
AC_INIT([ddclient], [3.11.3_0])
|
||||
# Get the version from ddclient.in so that the same version string
|
||||
# doesn't have to be maintained in two places. The m4_dquote macro is
|
||||
# used instead of quote characters to ensure that the command is only
|
||||
# run once. The command outputs quote characters to prevent
|
||||
# incidental expansion (the m4_esyscmd macro does not quote the
|
||||
# command output itself, so the command output is subject to
|
||||
# expansion).
|
||||
AC_INIT([ddclient], m4_dquote(m4_esyscmd([printf '[%s]' "$(./ddclient.in --version=short)"])))
|
||||
# Needed because of the above invocation of ddclient.in.
|
||||
AC_SUBST([CONFIGURE_DEPENDENCIES], ['$(top_srcdir)/ddclient.in'])
|
||||
AC_CONFIG_SRCDIR([ddclient.in])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
|
108
ddclient.in
108
ddclient.in
|
@ -21,8 +21,85 @@ use File::Temp;
|
|||
use Getopt::Long;
|
||||
use Sys::Hostname;
|
||||
|
||||
use version 0.77; our $VERSION = version->declare('3.11.3_0');
|
||||
my $version = $VERSION->stringify();
|
||||
# Declare the ddclient version number.
|
||||
#
|
||||
# Perl's version strings do not support pre-release versions (alpha/development, beta, or release
|
||||
# candidate) very well. The best it does is an optional underscore between arbitrary digits in the
|
||||
# final component (e.g., "v1.2.3_4"). The underscore doesn't behave as most developers expect; it
|
||||
# is treated as if it never existed (e.g., "v1.2.3_4" becomes "v1.2.34") except:
|
||||
#
|
||||
# * $v->is_alpha() will return true
|
||||
# * $v->is_strict() will return false
|
||||
# * $v->stringify() preserves the underscore (in its original position)
|
||||
#
|
||||
# Note that version::normal and version::numify lose information because the underscore is
|
||||
# effectively removed.
|
||||
#
|
||||
# To work around Perl's limitations, human-readable versions are translated to/from Perl versions
|
||||
# as follows:
|
||||
#
|
||||
# Human-readable Perl version Notes
|
||||
# -------------------------------------------------------------------------------------------
|
||||
# 1.2.3~alpha v1.2.3.0_0 compares equal to Perl version v1.2.3 (unfortunately)
|
||||
# 1.2.3~betaN v1.2.3.0_N 1 <= N < 900; compares equal to Perl v1.2.3.N
|
||||
# 1.2.3~rcN v1.2.3.0_M 1 <= N < 99; M = N + 900; compares equal to Perl v1.2.3.M
|
||||
# 1.2.3 v1.2.3.999 for releases; no underscore in Perl version string
|
||||
# 1.2.3rN v1.2.3.999.N 1 <= N < 1000; for re-releases, if necessary (rare)
|
||||
#
|
||||
# A tilde is used to separate "alpha", "beta", and "rc" from the version numbers because it has
|
||||
# special meaning for the version comparison algorithms in RPM and Debian:
|
||||
# https://docs.fedoraproject.org/en-US/packaging-guidelines/Versioning/#_handling_non_sorting_versions_with_tilde_dot_and_caret
|
||||
# https://manpages.debian.org/bookworm/dpkg-dev/deb-version.7.en.html
|
||||
#
|
||||
# No period separator is required between "beta", "rc", or "r" and its adjacent number(s); both RPM
|
||||
# and Debian will compare the adjacent number numerically, not lexicographically ("~beta2" sorts
|
||||
# before "~beta10" as expected).
|
||||
#
|
||||
# The Perl version is declared first then converted to a human-readable form. It would be nicer to
|
||||
# declare a human-readable version string and convert that to a Perl version string, but various
|
||||
# tools in the Perl ecosystem require the line of source code that defines the VERSION variable to
|
||||
# be self-contained (because they grep the source code and evaluate only that one line).
|
||||
#
|
||||
# For consistency and to match user expectations, the release part of the version is always three
|
||||
# components: MAJOR.MINOR.PATCH.
|
||||
use version 0.77; our $VERSION = version->declare('v3.11.3.0_0');
|
||||
|
||||
sub parse_version {
|
||||
my ($v) = @_;
|
||||
# Matches a non-negative integer with 1-3 decimal digits (zero padding disallowed).
|
||||
my $n = qr/0|[1-9]\d{0,2}/;
|
||||
my $vre = qr/
|
||||
^
|
||||
v # required "v" prefix
|
||||
((?:$n\.)*?$n) # release version (e.g., 1.2, 1.2.3, or 1.2.3.4)
|
||||
\.(?: # release or pre-release suffix
|
||||
0_(?!999)($n)| # pre-release (alpha, beta, rc) revision
|
||||
999(?:\.($n))? # release with optional re-release revision
|
||||
)
|
||||
$
|
||||
/x;
|
||||
return $v =~ $vre;
|
||||
}
|
||||
|
||||
sub humanize_version {
|
||||
my ($v) = @_;
|
||||
my ($r, $pr, $rr) = parse_version($v);
|
||||
return $v if !defined($r);
|
||||
$v = $r;
|
||||
if (!defined($pr)) {
|
||||
$v .= "r$rr" if defined($rr);
|
||||
} elsif ($pr eq '0') {
|
||||
$v .= '~alpha';
|
||||
} elsif ($pr < 900) {
|
||||
$v .= "~beta$pr";
|
||||
} elsif ($pr < 999) {
|
||||
$v .= '~rc' . ($pr - 900);
|
||||
}
|
||||
return $v;
|
||||
}
|
||||
|
||||
our $version = humanize_version($VERSION);
|
||||
|
||||
my $programd = $0;
|
||||
$programd =~ s%^.*/%%;
|
||||
my $program = $programd;
|
||||
|
@ -1007,6 +1084,17 @@ $opt{'list-web-services'} = sub {
|
|||
printf("%s %s\n", $_, $builtinweb{$_}{url}) for sort(keys(%builtinweb));
|
||||
exit(0);
|
||||
};
|
||||
$opt{'version'} = sub {
|
||||
my (undef, $arg) = @_;
|
||||
if ($arg eq "short") {
|
||||
print("$version\n");
|
||||
} else {
|
||||
print("$program version $version\n");
|
||||
print(" originally written by Paul Burry, paul+ddclient\@burry.ca\n");
|
||||
print(" project now maintained on https://github.com/ddclient/ddclient\n");
|
||||
}
|
||||
exit(0);
|
||||
};
|
||||
|
||||
my @opt = (
|
||||
"usage: ${program} [options]",
|
||||
|
@ -1089,7 +1177,7 @@ my @opt = (
|
|||
["verbose", "!", "--{no}verbose : print {no} verbose information"],
|
||||
["quiet", "!", "--{no}quiet : print {no} messages for unnecessary updates"],
|
||||
["help", "", "--help : display this message and exit"],
|
||||
["version", "", "--version : display version information and exit"],
|
||||
["version", ":s", "--version[=short] : display version information and exit"],
|
||||
["postscript", "", "--postscript : script to run after updating ddclient, has new IP as param"],
|
||||
["query", "!", "--{no}query : print {no} ip addresses and exit"],
|
||||
["fw-banlocal", "!", ""], ## deprecated
|
||||
|
@ -1099,10 +1187,6 @@ my @opt = (
|
|||
["redirect", "=i", "--redirect=<max> : enable and follow at most <max> HTTP 30x redirections"],
|
||||
"",
|
||||
nic_examples(),
|
||||
# Note: These lines are copied below to the -version argument implementation
|
||||
"$program version $version",
|
||||
" originally written by Paul Burry, paul+ddclient\@burry.ca",
|
||||
" project now maintained on https://github.com/ddclient/ddclient"
|
||||
);
|
||||
|
||||
sub main {
|
||||
|
@ -1116,15 +1200,7 @@ sub main {
|
|||
|
||||
if (opt('help')) {
|
||||
printf "%s\n", $opt_usage;
|
||||
exit 0;
|
||||
}
|
||||
|
||||
if (opt('version')) {
|
||||
# Note: Manual copy from the @opt array above!
|
||||
print "$program version $version\n";
|
||||
print " originally written by Paul Burry, paul+ddclient\@burry.ca\n";
|
||||
print " project now maintained on https://github.com/ddclient/ddclient\n";
|
||||
exit 0;
|
||||
$opt{'version'}('', '');
|
||||
}
|
||||
|
||||
## read config file because 'daemon' mode may be defined there.
|
||||
|
|
|
@ -4,6 +4,59 @@ use version;
|
|||
SKIP: { eval { require Test::Warnings; } or skip($@, 1); }
|
||||
eval { require 'ddclient'; } or BAIL_OUT($@);
|
||||
|
||||
is(ddclient->VERSION(), version->parse('v@PACKAGE_VERSION@'), "version matches Autoconf config");
|
||||
ok(ddclient::parse_version($ddclient::VERSION),
|
||||
"module's Perl version string is in opinionated form");
|
||||
|
||||
my $n = qr/0|[1-9]\d{0,2}/;
|
||||
like($ddclient::version, qr/^$n\.$n\.$n(?:~alpha|~beta$n|~rc$n|r$n)?$/,
|
||||
"human-readable version is in opinionated form");
|
||||
|
||||
my @tcs = (
|
||||
['v1.0_0', '1~alpha'],
|
||||
['v1.0.0_0', '1.0~alpha'],
|
||||
['v1.2.3.0_0', '1.2.3~alpha'],
|
||||
['v1.2.3.4.0_0', '1.2.3.4~alpha'],
|
||||
['v1.0_1', '1~beta1'],
|
||||
['v1.0.0_1', '1.0~beta1'],
|
||||
['v1.2.3.0_1', '1.2.3~beta1'],
|
||||
['v1.2.3.4.0_1', '1.2.3.4~beta1'],
|
||||
['v1.2.3.0_899', '1.2.3~beta899'],
|
||||
['v1.0_901', '1~rc1'],
|
||||
['v1.0.0_901', '1.0~rc1'],
|
||||
['v1.2.3.0_901', '1.2.3~rc1'],
|
||||
['v1.2.3.4.0_901', '1.2.3.4~rc1'],
|
||||
['v1.2.3.0_998', '1.2.3~rc98'],
|
||||
['v1.999', '1'],
|
||||
['v1.0.999', '1.0'],
|
||||
['v1.2.3.999', '1.2.3'],
|
||||
['v1.2.3.4.999', '1.2.3.4'],
|
||||
['v1.999.1', '1r1'],
|
||||
['v1.0.999.1', '1.0r1'],
|
||||
['v1.2.3.999.1', '1.2.3r1'],
|
||||
['v1.2.3.4.999.1', '1.2.3.4r1'],
|
||||
['v1.2.3.999.999', '1.2.3r999'],
|
||||
[$ddclient::VERSION, $ddclient::version],
|
||||
);
|
||||
|
||||
subtest 'humanize_version' => sub {
|
||||
for my $tc (@tcs) {
|
||||
my ($pv, $want) = @$tc;
|
||||
is(ddclient::humanize_version($pv), $want, "$pv -> $want");
|
||||
}
|
||||
};
|
||||
|
||||
subtest 'human-readable version can be translated back to Perl version' => sub {
|
||||
for my $tc (@tcs) {
|
||||
my ($want, $hv) = @$tc;
|
||||
my $pv = "v$hv";
|
||||
$pv =~ s/^(?!.*~)(.*?)(?:r(\d+))?$/"$1.999" . (defined($2) ? ".$2" : "")/e;
|
||||
$pv =~ s/~alpha$/.0_0/;
|
||||
$pv =~ s/~beta(\d+)$/.0_$1/;
|
||||
$pv =~ s/~rc(\d+)$/'.0_' . (900 + $1)/e;
|
||||
is($pv, $want, "$hv -> $want");
|
||||
}
|
||||
};
|
||||
|
||||
is($ddclient::version, '@PACKAGE_VERSION@', "version matches version in Autoconf");
|
||||
|
||||
done_testing();
|
||||
|
|
Loading…
Reference in a new issue