aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2017-04-27 19:36:58 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2017-04-28 12:08:08 +0300
commit5bb170316ebad036ee5b8b18dee7ce3d09c72df4 (patch)
treeacb30c55637b40e7fb4ff9679cb9187ffa410c68
parentdad361a3415e88475a78d1b2702133629fb6e548 (diff)
Add support for standard version earliest pre-release
-rw-r--r--butl/standard-version30
-rw-r--r--butl/standard-version.cxx88
-rw-r--r--butl/standard-version.ixx20
-rw-r--r--tests/standard-version/driver.cxx15
-rw-r--r--tests/standard-version/testscript50
5 files changed, 141 insertions, 62 deletions
diff --git a/butl/standard-version b/butl/standard-version
index c9637d8..0c7b9bc 100644
--- a/butl/standard-version
+++ b/butl/standard-version
@@ -16,17 +16,20 @@
namespace butl
{
- // The build2 "standard version":
+ // The build2 "standard version" (specific and earliest):
//
// [<epoch>~]<maj>.<min>.<patch>[-(a|b).<num>[.<snapsn>[.<snapid>]]][+<rev>]
+ // [<epoch>~]<maj>.<min>.<patch>-
//
struct LIBBUTL_EXPORT standard_version
{
// Invariants:
//
- // 1. (E == 0) == (snapshot_sn == 0 && snapshot_id.empty ())
+ // 1. allow_earliest
+ // ? (E == 1) || (snapshot_sn == 0)
+ // : (E == 0) == (snapshot_sn == 0)
//
- // 2. snapshot_sn != latest_sn || snapshot_id.empty ()
+ // 2. snapshot_sn != latest_sn && snapshot_sn != 0 || snapshot_id.empty ()
//
static const std::uint64_t latest_sn = std::uint64_t (~0);
@@ -58,6 +61,13 @@ namespace butl
bool beta () const noexcept;
bool snapshot () const noexcept {return snapshot_sn != 0;}
+ // Is represented by DDDE being 0001 and snapshot_sn being 0.
+ //
+ // Note that the earliest version is a final alpha pre-release.
+ //
+ bool
+ earliest () const noexcept;
+
int
compare (const standard_version&) const noexcept;
@@ -65,23 +75,27 @@ namespace butl
// recognizable or components are invalid.
//
explicit
- standard_version (const std::string&);
+ standard_version (const std::string&, bool allow_earliest = false);
explicit
- standard_version (std::uint64_t version);
+ standard_version (std::uint64_t version, bool allow_earliest = false);
- standard_version (std::uint64_t version, const std::string& snapshot);
+ standard_version (std::uint64_t version,
+ const std::string& snapshot,
+ bool allow_earliest = false);
standard_version (std::uint16_t epoch,
std::uint64_t version,
const std::string& snapshot,
- std::uint16_t revision);
+ std::uint16_t revision,
+ bool allow_earliest = false);
standard_version (std::uint16_t epoch,
std::uint64_t version,
std::uint64_t snapshot_sn,
std::string snapshot_id,
- std::uint16_t revision);
+ std::uint16_t revision,
+ bool allow_earliest = false);
// Create empty version.
//
diff --git a/butl/standard-version.cxx b/butl/standard-version.cxx
index 552aac8..16095c0 100644
--- a/butl/standard-version.cxx
+++ b/butl/standard-version.cxx
@@ -38,7 +38,7 @@ namespace butl
}
static void
- check_version (uint64_t version, bool snapshot)
+ check_version (uint64_t version, bool snapshot, bool allow_earliest)
{
// Check that the version isn't too large.
//
@@ -46,9 +46,18 @@ namespace butl
bool r (version < 10000000000000ULL);
// Check that E version component is consistent with the snapshot flag.
+ // Note that if the allow_earliest flag is true, then E can be 1 for the
+ // snapshot flag being false, denoting the earliest pre-release of the
+ // version.
//
if (r)
- r = (version % 10) == (snapshot ? 1 : 0);
+ {
+ uint64_t e (version % 10);
+ if (!allow_earliest)
+ r = e == (snapshot ? 1 : 0);
+ else
+ r = e == 1 || (e == 0 && !snapshot);
+ }
// Check that pre-release number is consistent with the snapshot flag.
//
@@ -78,7 +87,7 @@ namespace butl
// standard_version
//
standard_version::
- standard_version (const std::string& s)
+ standard_version (const std::string& s, bool allow_earliest)
{
auto bail = [] (const char* m) {throw invalid_argument (m);};
@@ -127,56 +136,66 @@ namespace butl
// Parse the pre-release component if present.
//
+ bool earliest (false);
if (s[p] == '-')
{
char k (s[++p]);
- if (k != 'a' && k != 'b')
- bail ("'a' or 'b' expected in pre-release");
+ if (k == '\0' && allow_earliest) // Dash is the last string character.
+ earliest = true;
+ else
+ {
+ if (k != 'a' && k != 'b')
+ bail ("'a' or 'b' expected in pre-release");
- if (s[++p] != '.')
- bail ("'.' expected after pre-release letter");
+ if (s[++p] != '.')
+ bail ("'.' expected after pre-release letter");
- ab = parse_num (s, ++p, "invalid pre-release", 0, 499);
+ ab = parse_num (s, ++p, "invalid pre-release", 0, 499);
- if (k == 'b')
- ab += 500;
+ if (k == 'b')
+ ab += 500;
- // Parse the snapshot components if present. Note that pre-release number
- // can't be zero for the final pre-release.
- //
- if (s[p] == '.')
- parse_snapshot (s, ++p);
- else if (ab == 0 || ab == 500)
- bail ("invalid final pre-release");
+ // Parse the snapshot components if present. Note that pre-release number
+ // can't be zero for the final pre-release.
+ //
+ if (s[p] == '.')
+ parse_snapshot (s, ++p);
+ else if (ab == 0 || ab == 500)
+ bail ("invalid final pre-release");
+ }
}
if (s[p] == '+')
+ {
+ assert (!earliest); // Would bail out earlier (a or b expected after -).
+
revision = parse_num (s, ++p, "invalid revision", 1, uint16_t (~0));
+ }
if (p != s.size ())
bail ("junk after version");
- if (ab != 0)
+ if (ab != 0 || snapshot_sn != 0 || earliest)
version -= 10000 - ab * 10;
- if (snapshot_sn != 0)
+ if (snapshot_sn != 0 || earliest)
version += 1;
}
standard_version::
- standard_version (uint64_t v)
+ standard_version (uint64_t v, bool allow_earliest)
: version (v)
{
- check_version (v, false);
+ check_version (v, false, allow_earliest);
}
standard_version::
- standard_version (uint64_t v, const std::string& s)
+ standard_version (uint64_t v, const std::string& s, bool allow_earliest)
: version (v)
{
bool snapshot (!s.empty ());
- check_version (version, snapshot);
+ check_version (version, snapshot, allow_earliest);
if (snapshot)
{
@@ -193,14 +212,15 @@ namespace butl
uint64_t vr,
uint64_t sn,
std::string si,
- uint16_t rv)
+ uint16_t rv,
+ bool allow_earliest)
: epoch (ep),
version (vr),
snapshot_sn (sn),
snapshot_id (move (si)),
revision (rv)
{
- check_version (vr, true);
+ check_version (vr, true, allow_earliest);
if (!snapshot_id.empty () && (snapshot_id.size () > 16 ||
snapshot_sn == 0 ||
@@ -244,7 +264,7 @@ namespace butl
{
std::string r;
- if (alpha () || beta ())
+ if ((alpha () && !earliest ()) || beta ())
{
uint64_t ab (version / 10 % 1000);
@@ -360,7 +380,7 @@ namespace butl
try
{
- min_version = standard_version (s.substr (p, e - p));
+ min_version = standard_version (s.substr (p, e - p), true);
}
catch (const invalid_argument& e)
{
@@ -377,7 +397,7 @@ namespace butl
try
{
- max_version = standard_version (s.substr (p, e - p));
+ max_version = standard_version (s.substr (p, e - p), true);
}
catch (const invalid_argument& e)
{
@@ -425,7 +445,7 @@ namespace butl
try
{
- v = standard_version (s.substr (p));
+ v = standard_version (s.substr (p), operation != comparison::eq);
}
catch (const invalid_argument& e)
{
@@ -482,8 +502,14 @@ namespace butl
if (*min_version > *max_version)
throw invalid_argument ("min version is greater than max version");
- if (*min_version == *max_version && (min_open || max_open))
- throw invalid_argument ("equal version endpoints not closed");
+ if (*min_version == *max_version)
+ {
+ if (min_open || max_open)
+ throw invalid_argument ("equal version endpoints not closed");
+
+ if (min_version->earliest ())
+ throw invalid_argument ("equal version endpoints are earliest");
+ }
}
}
diff --git a/butl/standard-version.ixx b/butl/standard-version.ixx
index b01faef..332eb02 100644
--- a/butl/standard-version.ixx
+++ b/butl/standard-version.ixx
@@ -8,8 +8,9 @@ namespace butl
standard_version ( std::uint16_t e,
std::uint64_t v,
const std::string& s,
- std::uint16_t r)
- : standard_version (v, s)
+ std::uint16_t r,
+ bool allow_earliest)
+ : standard_version (v, s, allow_earliest)
{
// Can't initialize above due to ctor delegating.
//
@@ -20,9 +21,10 @@ namespace butl
inline std::uint16_t standard_version::
major () const noexcept
{
+ std::uint64_t e (version % 10);
std::uint64_t v (version / 10);
std::uint64_t ab (v % 1000);
- if (ab != 0)
+ if (ab != 0 || e == 1)
v += 1000 - ab;
return static_cast<std::uint16_t> (v / 1000000000 % 1000);
@@ -31,9 +33,10 @@ namespace butl
inline std::uint16_t standard_version::
minor () const noexcept
{
+ std::uint64_t e (version % 10);
std::uint64_t v (version / 10);
std::uint64_t ab (v % 1000);
- if (ab != 0)
+ if (ab != 0 || e == 1)
v += 1000 - ab;
return static_cast<std::uint16_t> (v / 1000000 % 1000);
@@ -42,9 +45,10 @@ namespace butl
inline std::uint16_t standard_version::
patch () const noexcept
{
+ std::uint64_t e (version % 10);
std::uint64_t v (version / 10);
std::uint64_t ab (v % 1000);
- if (ab != 0)
+ if (ab != 0 || e == 1)
v += 1000 - ab;
return static_cast<std::uint16_t> (v / 1000 % 1000);
@@ -74,6 +78,12 @@ namespace butl
return abe > 5000;
}
+ inline bool standard_version::
+ earliest () const noexcept
+ {
+ return version % 10000 == 1 && !snapshot ();
+ }
+
inline int standard_version::
compare (const standard_version& v) const noexcept
{
diff --git a/tests/standard-version/driver.cxx b/tests/standard-version/driver.cxx
index d301c8c..e6a21ef 100644
--- a/tests/standard-version/driver.cxx
+++ b/tests/standard-version/driver.cxx
@@ -17,9 +17,9 @@ using namespace butl;
// Create standard version from string, and also test another ctors.
//
static standard_version
-version (const string& s)
+version (const string& s, bool allow_earliest = true)
{
- standard_version r (s);
+ standard_version r (s, allow_earliest);
try
{
@@ -28,7 +28,8 @@ version (const string& s)
r.snapshot ()
? r.string_snapshot ()
: string (),
- r.revision);
+ r.revision,
+ allow_earliest);
assert (r == v);
@@ -37,12 +38,13 @@ version (const string& s)
standard_version v (r.version,
r.snapshot ()
? r.string_snapshot ()
- : string ());
+ : string (),
+ allow_earliest);
assert (r == v);
if (!r.snapshot ())
{
- standard_version v (r.version);
+ standard_version v (r.version, allow_earliest);
assert (r == v);
}
}
@@ -53,7 +55,8 @@ version (const string& s)
r.version,
r.snapshot_sn,
r.snapshot_id,
- r.revision);
+ r.revision,
+ allow_earliest);
assert (r == v);
}
diff --git a/tests/standard-version/testscript b/tests/standard-version/testscript
index 9c80ddb..e5e3248 100644
--- a/tests/standard-version/testscript
+++ b/tests/standard-version/testscript
@@ -30,6 +30,12 @@
1.2.3-a.0.456
1.2.3-a.1.456.340c0a26a5ef
EOF
+
+ : earliest
+ :
+ $* <<EOF >>EOF
+ 1.2.3-
+ EOF
}
: revision
@@ -76,11 +82,7 @@
:
$* <'1~0.0.0' 2>'0.0.0 version' == 1
- : a-b-expected1
- :
- $* <'1.2.3-' 2>"'a' or 'b' expected in pre-release" == 1
-
- : a-b-expected2
+ : a-b-expected
:
$* <'1.2.3-k' 2>"'a' or 'b' expected in pre-release" == 1
@@ -122,6 +124,10 @@
: snapshot-id
:
$* <'1.2.3-a.0.1.83jdgsf+0' 2>'invalid revision' == 1
+
+ : earliest-prerelease
+ :
+ $* <'1.2.3-+1' 2>"'a' or 'b' expected in pre-release" == 1
}
: trailing-junk-after
@@ -146,6 +152,7 @@
$* '1.2.3-b.1' >n: beta
$* '1.2.3-a.1' >y: final
$* '1.2.3-a.0.1' >y: snapshot
+ $* '1.2.3-' >y: earliest
}
: beta
@@ -157,6 +164,7 @@
$* '1.2.3-a.1' >n: alpha
$* '1.2.3-b.1' >y: final
$* '1.2.3-b.0.1' >y: snapshot
+ $* '1.2.3-' >n: earliest
}
: compare
@@ -182,10 +190,16 @@
:
{
$* '1.2.3-a.1' '1.2.3-a.1' >'0' : equal
- $* '1.2.3' '1.2.3-a.1' >'1' : release-gt-prereleas
+ $* '1.2.3' '1.2.3-a.1' >'1' : release-gt-prerelease
$* '1.2.3-a.2' '1.2.3-b.1' >'-1' : a-lt-b
$* '1.2.3-a.1' '1.2.3-a.1.2' >'-1' : final-lt-snapshot
$* '1.2.3-a.1.2.xy' '1.2.3-a.1.2' >'0' : ignore-snapshot-id
+ $* '1.2.3' '1.2.3-a.0.1' >'1' : release-gt-snapshot
+ $* '1.2.3-a.0.1' '1.2.3-a.1' >'-1' : snapshot-lt-final
+ $* '1.2.3' '1.2.3-' >'1' : release-gt-earliest
+ $* '1.2.3-a.1' '1.2.3-' >'1' : final-gt-earliest
+ $* '1.2.3-a.0.1' '1.2.3-' >'1' : snapshot-gt-earliest
+ $* '1.2.2-b.499.z' '1.2.3-' >'-1' : prev-max-snapshot-lt-earliest
}
}
@@ -202,11 +216,11 @@
$* <<EOI >>EOE
[1.2.3 1.2.4]
(1.2.3 1.2.4)
- [ 1.2.3 1.2.4 ]
+ [ 1.2.3- 1.2.4- ]
EOI
[1.2.3 1.2.4]
(1.2.3 1.2.4)
- [1.2.3 1.2.4]
+ [1.2.3- 1.2.4-]
EOE
: invalid
@@ -234,6 +248,10 @@
: open-end
:
$* <'[1.2.3 1.2.3)' 2>'equal version endpoints not closed' == 1
+
+ : earliest-prerelease
+ :
+ $* <'[1.2.3- 1.2.3-]' 2>'equal version endpoints are earliest' == 1
}
}
@@ -248,16 +266,20 @@
<= 1.2.3
> 1.2.3
< 1.2.3
- <=1.2.3
- <1.2.3
+ >=1.2.3-
+ <=1.2.3-
+ >1.2.3-
+ <1.2.3-
EOI
== 1.2.3
>= 1.2.3
<= 1.2.3
> 1.2.3
< 1.2.3
- <= 1.2.3
- < 1.2.3
+ >= 1.2.3-
+ <= 1.2.3-
+ > 1.2.3-
+ < 1.2.3-
EOE
: invalid
@@ -265,6 +287,10 @@
{
$* <'>=' 2>'no version' == 1 : no-version
+ : eq-earliest
+ :
+ $* <'==1.2.3-' 2>"invalid version: 'a' or 'b' expected in pre-release" == 1
+
: junk
:
$* <'>= 1.2.3-a.1.1.ads@' 2>'invalid version: junk after version' == 1