aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2018-03-12 21:41:06 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2018-03-16 13:43:22 +0300
commitd969a5985a8d6bcbb6625b2a99c0ad2637916f42 (patch)
tree040c9d2586200fc2cd6e26643086aa1afc45a718
parent2bcd53b098967db5ca0ee069c1475fd5ddc8c890 (diff)
Add support for version iteration
-rw-r--r--libbpkg/manifest.cxx35
-rw-r--r--libbpkg/manifest.hxx44
-rw-r--r--tests/package-version/driver.cxx60
3 files changed, 107 insertions, 32 deletions
diff --git a/libbpkg/manifest.cxx b/libbpkg/manifest.cxx
index a61dd82..03bf689 100644
--- a/libbpkg/manifest.cxx
+++ b/libbpkg/manifest.cxx
@@ -134,11 +134,16 @@ namespace bpkg
// version
//
version::
- version (uint16_t e, std::string u, optional<std::string> l, uint16_t r)
+ version (uint16_t e,
+ std::string u,
+ optional<std::string> l,
+ uint16_t r,
+ uint32_t i)
: epoch (e),
upstream (move (u)),
release (move (l)),
revision (r),
+ iteration (i),
canonical_upstream (
data_type (upstream.c_str (), data_type::parse::upstream).
canonical_upstream),
@@ -159,11 +164,14 @@ namespace bpkg
if (revision != 0)
throw invalid_argument ("revision for empty version");
+
+ if (iteration != 0)
+ throw invalid_argument ("iteration for empty version");
}
- else if (release && release->empty () && revision != 0)
- // Empty release signifies the earliest possible release. Revision is
- // meaningless in such a context.
- //
+ // Empty release signifies the earliest possible release. Revision and/or
+ // iteration are meaningless in such a context.
+ //
+ else if (release && release->empty () && (revision != 0 || iteration != 0))
throw invalid_argument ("revision for earliest possible release");
}
@@ -444,7 +452,7 @@ namespace bpkg
}
string version::
- string (bool ignore_revision) const
+ string (bool ignore_revision, bool ignore_iteration) const
{
using std::to_string; // Hidden by to_string (repository_type).
@@ -459,10 +467,19 @@ namespace bpkg
v += *release;
}
- if (!ignore_revision && revision != 0)
+ if (!ignore_revision)
{
- v += '+';
- v += to_string (revision);
+ if (revision != 0)
+ {
+ v += '+';
+ v += to_string (revision);
+ }
+
+ if (!ignore_iteration && iteration != 0)
+ {
+ v += '#';
+ v += to_string (iteration);
+ }
}
return v;
diff --git a/libbpkg/manifest.hxx b/libbpkg/manifest.hxx
index 4d21588..a44ffcc 100644
--- a/libbpkg/manifest.hxx
+++ b/libbpkg/manifest.hxx
@@ -37,6 +37,7 @@ namespace bpkg
const std::string upstream;
const butl::optional<std::string> release;
const std::uint16_t revision;
+ const std::uint32_t iteration;
// Upstream part canonical representation.
//
@@ -49,7 +50,7 @@ namespace bpkg
// Create a special empty version. It is less than any other valid
// version (and is conceptually equivalent to 0-).
//
- version (): epoch (0), release (""), revision (0) {}
+ version (): epoch (0), release (""), revision (0), iteration (0) {}
// Throw std::invalid_argument if the passed string is not a valid
// version representation.
@@ -60,24 +61,28 @@ namespace bpkg
explicit
version (const char* v): version (data_type (v, data_type::parse::full)) {}
- // Create the version object from separate epoch, upstream, release, and
- // revision parts.
+ // Create the version object from separate epoch, upstream, release,
+ // revision, and iteration parts.
//
// Note that it is possible (and legal) to create the special empty
- // version via this interface as version(0, string(), string(), 0).
+ // version via this interface as version(0, string(), string(), 0, 0).
//
version (std::uint16_t epoch,
std::string upstream,
butl::optional<std::string> release,
- std::uint16_t revision);
+ std::uint16_t revision,
+ std::uint32_t iteration);
version (version&&) = default;
version (const version&) = default;
version& operator= (version&&);
version& operator= (const version&);
+ // If the revision is ignored, then the iteration (that semantically
+ // extends the revision) is also ignored, regardless of the argument.
+ //
std::string
- string (bool ignore_revision = false) const;
+ string (bool ignore_revision = false, bool ignore_iteration = false) const;
bool
operator< (const version& v) const noexcept {return compare (v) < 0;}
@@ -97,8 +102,13 @@ namespace bpkg
bool
operator!= (const version& v) const noexcept {return compare (v) != 0;}
+ // If the revision is ignored, then the iteration is also ignored,
+ // regardless of the argument (see above for details).
+ //
int
- compare (const version& v, bool ignore_revision = false) const noexcept
+ compare (const version& v,
+ bool ignore_revision = false,
+ bool ignore_iteration = false) const noexcept
{
if (epoch != v.epoch)
return epoch < v.epoch ? -1 : 1;
@@ -109,8 +119,14 @@ namespace bpkg
if (int c = canonical_release.compare (v.canonical_release))
return c;
- if (!ignore_revision && revision != v.revision)
- return revision < v.revision ? -1 : 1;
+ if (!ignore_revision)
+ {
+ if (revision != v.revision)
+ return revision < v.revision ? -1 : 1;
+
+ if (!ignore_iteration && iteration != v.iteration)
+ return iteration < v.iteration ? -1 : 1;
+ }
return 0;
}
@@ -119,8 +135,12 @@ namespace bpkg
empty () const noexcept
{
bool e (upstream.empty ());
+
assert (!e ||
- (epoch == 0 && release && release->empty () && revision == 0));
+ (epoch == 0 &&
+ release && release->empty () &&
+ revision == 0 && iteration == 0));
+
return e;
}
@@ -131,6 +151,9 @@ namespace bpkg
data_type (const char*, parse);
+ // Note that there is no iteration component as it can't be present in
+ // the string representation passed to the ctor.
+ //
std::uint16_t epoch;
std::string upstream;
butl::optional<std::string> release;
@@ -145,6 +168,7 @@ namespace bpkg
upstream (std::move (d.upstream)),
release (std::move (d.release)),
revision (d.revision),
+ iteration (0),
canonical_upstream (std::move (d.canonical_upstream)),
canonical_release (std::move (d.canonical_release)) {}
};
diff --git a/tests/package-version/driver.cxx b/tests/package-version/driver.cxx
index 1cfad1e..4925711 100644
--- a/tests/package-version/driver.cxx
+++ b/tests/package-version/driver.cxx
@@ -40,11 +40,12 @@ namespace bpkg
bad_version (uint16_t e,
const string& u,
const optional<string>& l,
- uint16_t r)
+ uint16_t r,
+ uint32_t i = 0)
{
try
{
- version bv (e, u, l, r);
+ version bv (e, u, l, r, i);
return false;
}
catch (const invalid_argument&)
@@ -54,15 +55,20 @@ namespace bpkg
}
static bool
- bad_version (uint16_t e, const string& u, const char* l, uint16_t r)
+ bad_version (uint16_t e,
+ const string& u,
+ const char* l,
+ uint16_t r,
+ uint32_t i = 0)
{
- return bad_version (e, u, string (l), r);
+ return bad_version (e, u, string (l), r, i);
}
static bool
test_constructor (const version& v)
{
- return v == version (v.epoch, v.upstream, v.release, v.revision);
+ return v ==
+ version (v.epoch, v.upstream, v.release, v.revision, v.iteration);
}
int
@@ -111,6 +117,7 @@ namespace bpkg
assert (bad_version ("1.2.3-~")); // Invalid release.
assert (bad_version ("0-")); // Illegal version.
assert (bad_version ("0.0-")); // Same.
+ assert (bad_version ("1.2.3+1#1")); // Unexpected iteration.
assert (bad_version (0, "1", "", 1)); // Revision for empty release.
assert (bad_version (1, "1~1.1", "", 2)); // Epoch in upstream.
@@ -120,9 +127,10 @@ namespace bpkg
assert (bad_version (1, "1", "1.1-1", 2)); // Release in release.
assert (bad_version (1, "1", "1.1+1", 2)); // Revision in release.
- assert (bad_version (1, "", "", 0)); // Unexpected epoch.
- assert (bad_version (0, "", "1", 0)); // Unexpected release.
- assert (bad_version (0, "", "", 1)); // Unexpected revision.
+ assert (bad_version (1, "", "", 0)); // Unexpected epoch.
+ assert (bad_version (0, "", "1", 0)); // Unexpected release.
+ assert (bad_version (0, "", "", 1)); // Unexpected revision.
+ assert (bad_version (0, "", "", 0, 1)); // Unexpected iteration.
{
version v1;
@@ -280,7 +288,7 @@ namespace bpkg
}
{
- version v (1, "1", nullopt, 2);
+ version v (1, "1", nullopt, 2, 0);
assert (v.string () == "1~1+2");
assert (!v.release);
assert (v.canonical_release == "~");
@@ -288,13 +296,24 @@ namespace bpkg
}
{
- version v (1, "1", string (), 0);
+ version v (1, "1", string (), 0, 0);
assert (v.string () == "1~1-");
assert (v.release && v.release->empty ());
assert (v.canonical_release.empty ());
assert (test_constructor (v));
}
+ {
+ version v (1, "2.0", nullopt, 3, 4);
+ assert (v.string (false, false) == "1~2.0+3#4");
+ assert (v.string (true, true) == "1~2.0");
+ assert (v.string (true, false) == "1~2.0");
+ assert (v.string (false, true) == "1~2.0+3");
+
+ assert (version (1, "2.0", nullopt, 0, 3).string () == "1~2.0#3");
+ assert (version (1, "2.0", nullopt, 3, 0).string () == "1~2.0+3");
+ }
+
assert (version ("a") == version ("a"));
assert (version ("a") < version ("b"));
assert (version ("a") < version ("aa"));
@@ -335,9 +354,24 @@ namespace bpkg
assert (version ("1.0-alpha") > version ("1.0-1"));
assert (version ("1.0-alpha") == version ("1.0-alpha.0"));
- assert (version (1, "2.0", nullopt, 3) == version ("1~2+3"));
- assert (version (1, "2.0", string (), 0) == version ("1~2-"));
- assert (version (0, "", string (), 0) == version ());
+ assert (version (1, "2.0", nullopt, 3, 0) == version ("1~2+3"));
+ assert (version (1, "2.0", string (), 0, 0) == version ("1~2-"));
+ assert (version (0, "", string (), 0, 0) == version ());
+
+ assert (version (1, "2.0", nullopt, 3, 4).compare (
+ version (1, "2.0", nullopt, 3, 4)) == 0);
+
+ assert (version (1, "2.0", nullopt, 3, 4).compare (
+ version (1, "2.0", nullopt, 4, 3)) < 0);
+
+ assert (version (1, "2.0", nullopt, 3, 4).compare (
+ version (1, "2.0", nullopt, 3, 5)) < 0);
+
+ assert (version (1, "2.0", nullopt, 3, 4).compare (
+ version (1, "2.0", nullopt, 3, 5), false, true) == 0);
+
+ assert (version (1, "2.0", nullopt, 3, 4).compare (
+ version (1, "2.0", nullopt, 5, 6), true) == 0);
}
catch (const exception& e)
{