aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-04-29 08:01:41 +0200
committerKaren Arutyunov <karen@codesynthesis.com>2017-04-29 14:46:13 +0300
commit332c4e09b11b010a6ad50468230758d0874dbd60 (patch)
tree40b4b8a07269a1e4733f7c94242752c8c00a275d
parentdb275fa010229b26086f75f0dd533fdfce8751b4 (diff)
Add support for stub standard version
-rw-r--r--butl/standard-version41
-rw-r--r--butl/standard-version.cxx161
-rw-r--r--butl/standard-version.ixx32
-rw-r--r--tests/standard-version/driver.cxx14
-rw-r--r--tests/standard-version/testscript24
5 files changed, 190 insertions, 82 deletions
diff --git a/butl/standard-version b/butl/standard-version
index c198d3e..ae26d71 100644
--- a/butl/standard-version
+++ b/butl/standard-version
@@ -16,10 +16,11 @@
namespace butl
{
- // The build2 "standard version" (specific and earliest):
+ // The build2 "standard version" (specific, earliest and stub):
//
// [<epoch>~]<maj>.<min>.<patch>[-(a|b).<num>[.<snapsn>[.<snapid>]]][+<rev>]
// [<epoch>~]<maj>.<min>.<patch>-
+ // 0[+<revision>]
//
struct LIBBUTL_EXPORT standard_version
{
@@ -29,7 +30,9 @@ namespace butl
// ? (E == 1) || (snapshot_sn == 0)
// : (E == 0) == (snapshot_sn == 0)
//
- // 2. snapshot_sn != latest_sn && snapshot_sn != 0 || snapshot_id.empty ()
+ // 2. version != 0 || allow_stub && epoch == 0 && snapshot_sn == 0
+ //
+ // 3. snapshot_sn != latest_sn && snapshot_sn != 0 || snapshot_id.empty ()
//
static const std::uint64_t latest_sn = std::uint64_t (~0);
@@ -62,13 +65,16 @@ 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.
+ // Represented by DDDE in version being 0001 and snapshot_sn being 0.
//
// Note that the earliest version is a final alpha pre-release.
//
bool
earliest () const noexcept;
+ bool
+ stub () const noexcept {return version == 0;}
+
int
compare (const standard_version& v) const noexcept
{
@@ -90,28 +96,35 @@ namespace butl
// Parse the version. Throw std::invalid_argument if the format is not
// recognizable or components are invalid.
//
+ enum flags
+ {
+ none = 0,
+ allow_earliest = 0x01, // Allow <major>.<minor>.<patch>- form.
+ allow_stub = 0x02 // Allow 0[+<revision>] form.
+ };
+
explicit
- standard_version (const std::string&, bool allow_earliest = false);
+ standard_version (const std::string&, flags = none);
explicit
- standard_version (std::uint64_t version, bool allow_earliest = false);
+ standard_version (std::uint64_t version, flags = none);
standard_version (std::uint64_t version,
const std::string& snapshot,
- bool allow_earliest = false);
+ flags = none);
standard_version (std::uint16_t epoch,
std::uint64_t version,
const std::string& snapshot,
std::uint16_t revision,
- bool allow_earliest = false);
+ flags = none);
standard_version (std::uint16_t epoch,
std::uint64_t version,
std::uint64_t snapshot_sn,
std::string snapshot_id,
std::uint16_t revision,
- bool allow_earliest = false);
+ flags = none);
// Create empty version.
//
@@ -164,6 +177,18 @@ namespace butl
return o << x.string ();
}
+ inline standard_version::flags
+ operator& (standard_version::flags, standard_version::flags);
+
+ inline standard_version::flags
+ operator| (standard_version::flags, standard_version::flags);
+
+ inline standard_version::flags
+ operator&= (standard_version::flags&, standard_version::flags);
+
+ inline standard_version::flags
+ operator|= (standard_version::flags&, standard_version::flags);
+
// The build2 "standard version" constraint:
//
// ('==' | '>' | '<' | '>=' | '<=') <version>
diff --git a/butl/standard-version.cxx b/butl/standard-version.cxx
index 1952653..74a5848 100644
--- a/butl/standard-version.cxx
+++ b/butl/standard-version.cxx
@@ -38,32 +38,32 @@ namespace butl
}
static void
- check_version (uint64_t version, bool snapshot, bool allow_earliest)
+ check_version (uint64_t vr, bool sn, standard_version::flags fl)
{
// Check that the version isn't too large.
//
- // AAABBBCCCDDDE
- bool r (version < 10000000000000ULL);
+ // AAABBBCCCDDDE
+ bool r (vr < 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
+ // Note that if the allow_earliest flag is set, then E can be 1 for the
// snapshot flag being false, denoting the earliest pre-release of the
// version.
//
if (r)
{
- uint64_t e (version % 10);
- if (!allow_earliest)
- r = e == (snapshot ? 1 : 0);
+ uint64_t e (vr % 10);
+ if ((fl & standard_version::allow_earliest) == 0)
+ r = e == (sn ? 1 : 0);
else
- r = e == 1 || (e == 0 && !snapshot);
+ r = e == 1 || (e == 0 && !sn);
}
// Check that pre-release number is consistent with the snapshot flag.
//
if (r)
{
- uint64_t ab (version / 10 % 1000);
+ uint64_t ab (vr / 10 % 1000);
// Note that if ab is 0, it can either mean non-pre-release version in
// the absence of snapshot number, or 'a.0' pre-release otherwise. If ab
@@ -71,14 +71,16 @@ namespace butl
// number.
//
if (ab != 0)
- r = ab != 500 || snapshot;
+ r = ab != 500 || sn;
}
- // Check that the major, the minor and the bugfix versions are not
- // simultaneously zeros.
+ // Check that the major, the minor and the patch versions are not
+ // simultaneously zeros, unless stub is allowed, in which case the snapshot
+ // flag must be false.
//
if (r)
- r = (version / 10000) != 0;
+ r = (vr / 10000) != 0 ||
+ ((fl & standard_version::allow_stub) != 0 && !sn);
if (!r)
throw invalid_argument ("invalid project version");
@@ -87,7 +89,7 @@ namespace butl
// standard_version
//
standard_version::
- standard_version (const std::string& s, bool allow_earliest)
+ standard_version (const std::string& s, flags f)
{
auto bail = [] (const char* m) {throw invalid_argument (m);};
@@ -101,7 +103,10 @@ namespace butl
ep = *e == '~';
}
- size_t p (0);
+ // Note that here and below p is less or equal n, and so s[p] is always
+ // valid.
+ //
+ size_t p (0), n (s.size ());
if (ep)
{
@@ -110,59 +115,70 @@ namespace butl
}
uint16_t ma, mi, bf, ab (0);
+ bool earliest (false);
ma = parse_num (s, p, "invalid major version");
- // Note that here and below p is less or equal n, and so s[p] is always
- // valid.
+ // The only valid version that has no epoch, contains only the major
+ // version being equal to zero, that is optionally followed by the plus
+ // character, is the stub version, unless forbidden. For such a version
+ // we go straight to the package revision parsing.
//
- if (s[p] != '.')
- bail ("'.' expected after major version");
+ bool stub ((f & allow_stub) != 0 && !ep && ma == 0 &&
+ (p == n || s[p] == '+'));
- mi = parse_num (s, ++p, "invalid minor version");
+ if (!stub)
+ {
+ if (s[p] != '.')
+ bail ("'.' expected after major version");
- if (s[p] != '.')
- bail ("'.' expected after minor version");
+ mi = parse_num (s, ++p, "invalid minor version");
- bf = parse_num (s, ++p, "invalid bugfix version");
+ if (s[p] != '.')
+ bail ("'.' expected after minor version");
- // AAABBBCCCDDDE
- version = ma * 10000000000ULL +
- mi * 10000000ULL +
- bf * 10000ULL;
+ bf = parse_num (s, ++p, "invalid patch version");
- if (version == 0)
- bail ("0.0.0 version");
+ // AAABBBCCCDDDE
+ version = ma * 10000000000ULL +
+ mi * 10000000ULL +
+ bf * 10000ULL;
- // Parse the pre-release component if present.
- //
- bool earliest (false);
- if (s[p] == '-')
- {
- char k (s[++p]);
+ if (version == 0)
+ bail ("0.0.0 version");
- if (k == '\0' && allow_earliest) // Dash is the last string character.
- earliest = true;
- else
+ // Parse the pre-release component if present.
+ //
+ if (s[p] == '-')
{
- if (k != 'a' && k != 'b')
- bail ("'a' or 'b' expected in pre-release");
-
- if (s[++p] != '.')
- bail ("'.' expected after pre-release letter");
-
- ab = parse_num (s, ++p, "invalid pre-release", 0, 499);
-
- if (k == 'b')
- ab += 500;
+ char k (s[++p]);
- // Parse the snapshot components if present. Note that pre-release number
- // can't be zero for the final pre-release.
+ // If the last character in the string is dash, then this is the
+ // earliest version pre-release, unless forbidden.
//
- if (s[p] == '.')
- parse_snapshot (s, ++p);
- else if (ab == 0 || ab == 500)
- bail ("invalid final pre-release");
+ if (k == '\0' && (f & allow_earliest) != 0)
+ 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");
+
+ ab = parse_num (s, ++p, "invalid pre-release", 0, 499);
+
+ 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");
+ }
}
}
@@ -173,7 +189,7 @@ namespace butl
revision = parse_num (s, ++p, "invalid revision", 1, uint16_t (~0));
}
- if (p != s.size ())
+ if (p != n)
bail ("junk after version");
if (ab != 0 || snapshot_sn != 0 || earliest)
@@ -184,18 +200,18 @@ namespace butl
}
standard_version::
- standard_version (uint64_t v, bool allow_earliest)
+ standard_version (uint64_t v, flags f)
: version (v)
{
- check_version (v, false, allow_earliest);
+ check_version (v, false, f);
}
standard_version::
- standard_version (uint64_t v, const std::string& s, bool allow_earliest)
+ standard_version (uint64_t v, const std::string& s, flags f)
: version (v)
{
bool snapshot (!s.empty ());
- check_version (version, snapshot, allow_earliest);
+ check_version (version, snapshot, f);
if (snapshot)
{
@@ -213,14 +229,23 @@ namespace butl
uint64_t sn,
std::string si,
uint16_t rv,
- bool allow_earliest)
+ flags fl)
: epoch (ep),
version (vr),
snapshot_sn (sn),
snapshot_id (move (si)),
revision (rv)
{
- check_version (vr, true, allow_earliest);
+ check_version (vr, true, fl);
+
+ if (stub ())
+ {
+ if (ep != 0)
+ throw invalid_argument ("epoch for stub");
+
+ if (sn != 0)
+ throw invalid_argument ("snapshot for stub");
+ }
if (!snapshot_id.empty () && (snapshot_id.size () > 16 ||
snapshot_sn == 0 ||
@@ -286,6 +311,9 @@ namespace butl
string standard_version::
string_version () const
{
+ if (stub ())
+ return "0";
+
std::string r (to_string (major ()) + '.' + to_string (minor ()) + '.' +
to_string (patch ()));
@@ -395,7 +423,8 @@ namespace butl
try
{
- min_version = standard_version (s.substr (p, e - p), true);
+ min_version = standard_version (s.substr (p, e - p),
+ standard_version::allow_earliest);
}
catch (const invalid_argument& e)
{
@@ -412,7 +441,8 @@ namespace butl
try
{
- max_version = standard_version (s.substr (p, e - p), true);
+ max_version = standard_version (s.substr (p, e - p),
+ standard_version::allow_earliest);
}
catch (const invalid_argument& e)
{
@@ -460,7 +490,10 @@ namespace butl
try
{
- v = standard_version (s.substr (p), operation != comparison::eq);
+ v = standard_version (s.substr (p),
+ operation != comparison::eq
+ ? standard_version::allow_earliest
+ : standard_version::none);
}
catch (const invalid_argument& e)
{
diff --git a/butl/standard-version.ixx b/butl/standard-version.ixx
index a2de26c..c732c20 100644
--- a/butl/standard-version.ixx
+++ b/butl/standard-version.ixx
@@ -9,8 +9,8 @@ namespace butl
std::uint64_t v,
const std::string& s,
std::uint16_t r,
- bool allow_earliest)
- : standard_version (v, s, allow_earliest)
+ flags f)
+ : standard_version (v, s, f)
{
// Can't initialize above due to ctor delegating.
//
@@ -83,4 +83,32 @@ namespace butl
{
return version % 10000 == 1 && !snapshot ();
}
+
+ inline standard_version::flags
+ operator& (standard_version::flags x, standard_version::flags y)
+ {
+ return x &= y;
+ }
+
+ inline standard_version::flags
+ operator| (standard_version::flags x, standard_version::flags y)
+ {
+ return x |= y;
+ }
+
+ inline standard_version::flags
+ operator&= (standard_version::flags& x, standard_version::flags y)
+ {
+ return x = static_cast<standard_version::flags> (
+ static_cast<std::uint16_t> (x) &
+ static_cast<std::uint16_t> (y));
+ }
+
+ inline standard_version::flags
+ operator|= (standard_version::flags& x, standard_version::flags y)
+ {
+ return x = static_cast<standard_version::flags> (
+ static_cast<std::uint16_t> (x) |
+ static_cast<std::uint16_t> (y));
+ }
}
diff --git a/tests/standard-version/driver.cxx b/tests/standard-version/driver.cxx
index 86d9621..677ea8e 100644
--- a/tests/standard-version/driver.cxx
+++ b/tests/standard-version/driver.cxx
@@ -17,9 +17,11 @@ using namespace butl;
// Create standard version from string, and also test another ctors.
//
static standard_version
-version (const string& s, bool allow_earliest = true)
+version (const string& s,
+ standard_version::flags f =
+ standard_version::allow_earliest | standard_version::allow_stub)
{
- standard_version r (s, allow_earliest);
+ standard_version r (s, f);
try
{
@@ -29,7 +31,7 @@ version (const string& s, bool allow_earliest = true)
? r.string_snapshot ()
: string (),
r.revision,
- allow_earliest);
+ f);
assert (r == v);
@@ -39,12 +41,12 @@ version (const string& s, bool allow_earliest = true)
r.snapshot ()
? r.string_snapshot ()
: string (),
- allow_earliest);
+ f);
assert (r == v);
if (!r.snapshot ())
{
- standard_version v (r.version, allow_earliest);
+ standard_version v (r.version, f);
assert (r == v);
}
}
@@ -56,7 +58,7 @@ version (const string& s, bool allow_earliest = true)
r.snapshot_sn,
r.snapshot_id,
r.revision,
- allow_earliest);
+ f);
assert (r == v);
}
diff --git a/tests/standard-version/testscript b/tests/standard-version/testscript
index b6bc1a0..6a585a5 100644
--- a/tests/standard-version/testscript
+++ b/tests/standard-version/testscript
@@ -53,6 +53,13 @@
$* <<EOF >>EOF
4~1.2.3
EOF
+
+ : stub
+ :
+ $* <<EOF >>EOF
+ 0
+ 0+1
+ EOF
}
: invalid
@@ -74,9 +81,9 @@
:
$* <'1.2' 2>"'.' expected after minor version" == 1
- : bugfix
+ : patch
:
- $* <'1.2.a' 2>'invalid bugfix version' == 1
+ $* <'1.2.a' 2>'invalid patch version' == 1
: zero-version
:
@@ -153,6 +160,8 @@
$* '1.2.3-a.1' >y: final
$* '1.2.3-a.0.1' >y: snapshot
$* '1.2.3-' >y: earliest
+ $* '0' >n: stub
+
}
: beta
@@ -165,6 +174,7 @@
$* '1.2.3-b.1' >y: final
$* '1.2.3-b.0.1' >y: snapshot
$* '1.2.3-' >n: earliest
+ $* '0+1' >n: stub
}
: compare
@@ -201,6 +211,12 @@
$* '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
}
+
+ : stub
+ :
+ {
+ $* '0+1' '0.0.1-' >'-1' : stub-lt-earliest
+ }
}
: constraints
@@ -291,6 +307,10 @@
:
$* <'==1.2.3-' 2>"invalid version: 'a' or 'b' expected in pre-release" == 1
+ : eq-stub
+ :
+ $* <'==0' 2>"invalid version: '.' expected after major version" == 1
+
: junk
:
$* <'>= 1.2.3-a.1.1.ads@' 2>'invalid version: junk after version' == 1