aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libbpkg/manifest.cxx470
-rw-r--r--libbpkg/manifest.hxx54
-rw-r--r--tests/manifest/driver.cxx87
-rw-r--r--tests/manifest/testscript134
4 files changed, 592 insertions, 153 deletions
diff --git a/libbpkg/manifest.cxx b/libbpkg/manifest.cxx
index b94b4da..7180875 100644
--- a/libbpkg/manifest.cxx
+++ b/libbpkg/manifest.cxx
@@ -622,10 +622,15 @@ namespace bpkg
bail (no_max_version);
version min_version;
+ string mnv (s, p, e - p);
+ // Leave the min version empty if it refers to the dependent package
+ // version.
+ //
+ if (mnv != "$")
try
{
- min_version = version (string (s, p, e - p));
+ min_version = version (mnv);
}
catch (const invalid_argument& e)
{
@@ -645,10 +650,15 @@ namespace bpkg
bail (invalid_range);
version max_version;
+ string mxv (s, p, e - p);
+ // Leave the max version empty if it refers to the dependent package
+ // version.
+ //
+ if (mxv != "$")
try
{
- max_version = version (string (s, p, e - p));
+ max_version = version (mxv);
}
catch (const invalid_argument& e)
{
@@ -677,36 +687,51 @@ namespace bpkg
}
else if (c == '~' || c == '^') // The shortcut operator.
{
- // To be used in the shortcut operator the package version must
- // be a standard version.
+ // If the shortcut operator refers to the dependent package version (the
+ // '$' character), then create an incomplete constraint. Otherwise,
+ // assume the version is standard and parse the operator representation
+ // as the standard version constraint.
//
- standard_version_constraint vc;
+ size_t p (s.find_first_not_of (spaces, 1));
- try
+ if (p != string::npos && s[p] == '$' && p + 1 == s.size ())
{
- vc = standard_version_constraint (s);
+ *this = dependency_constraint (version (), c == '~',
+ version (), c == '^');
}
- catch (const invalid_argument& e)
+ else
{
- bail (string ("invalid dependency constraint: ") + e.what ());
- }
+ // To be used in the shortcut operator the package version must be
+ // standard.
+ //
+ standard_version_constraint vc;
- try
- {
- assert (vc.min_version && vc.max_version);
+ try
+ {
+ vc = standard_version_constraint (s);
+ }
+ catch (const invalid_argument& e)
+ {
+ bail (string ("invalid dependency constraint: ") + e.what ());
+ }
- *this = dependency_constraint (
- version (vc.min_version->string ()),
- vc.min_open,
- version (vc.max_version->string ()),
- vc.max_open);
- }
- catch (const invalid_argument&)
- {
- // The standard version is a package version, so the conversion
- // should never fail.
- //
- assert (false);
+ try
+ {
+ assert (vc.min_version && vc.max_version);
+
+ *this = dependency_constraint (
+ version (vc.min_version->string ()),
+ vc.min_open,
+ version (vc.max_version->string ()),
+ vc.max_open);
+ }
+ catch (const invalid_argument&)
+ {
+ // Any standard version is a valid package version, so the
+ // conversion should never fail.
+ //
+ assert (false);
+ }
}
}
else // The version comparison notation.
@@ -741,7 +766,14 @@ namespace bpkg
try
{
- version v (string (s, p));
+ version v;
+ string vs (s, p);
+
+ // Leave the version empty if it refers to the dependent package
+ // version.
+ //
+ if (vs != "$")
+ v = version (vs);
switch (operation)
{
@@ -783,50 +815,208 @@ namespace bpkg
//
(min_version || max_version) &&
- // Version should be non-empty.
- //
- (!min_version || !min_version->empty ()) &&
- (!max_version || !max_version->empty ()) &&
-
// Absent version endpoint (infinity) should be open.
//
(min_version || min_open) && (max_version || max_open));
if (min_version && max_version)
{
- if (*min_version > *max_version)
+ bool mxe (max_version->empty ());
+
+ // If endpoint versions do not refer to the dependent package version
+ // then the min version must (naturally) be lower than or equal to the
+ // max version.
+ //
+ if (*min_version > *max_version && !mxe)
throw invalid_argument ("min version is greater than max version");
if (*min_version == *max_version)
{
- if (min_open || max_open)
+ // For non-empty versions, both endpoints must be closed, representing
+ // the `== <version>` constraint. For empty versions no greater than
+ // one endpoint can be open, representing the `== $`, `~$`, or `^$`
+ // constraints.
+ //
+ if ((!mxe && (min_open || max_open)) || (mxe && min_open && max_open))
throw invalid_argument ("equal version endpoints not closed");
- if (min_version->release && min_version->release->empty ())
+ // If endpoint versions do not refer to the dependent package version
+ // then they can't be earliest. Note: an empty version is earliest.
+ //
+ if (!mxe && max_version->release && max_version->release->empty ())
throw invalid_argument ("equal version endpoints are earliest");
}
}
}
+ dependency_constraint dependency_constraint::
+ effective (version v) const
+ {
+ // The dependent package version can't be empty or earliest.
+ //
+ if (v.empty ())
+ throw invalid_argument ("empty version");
+
+ if (v.release && v.release->empty ())
+ throw invalid_argument ("earliest version");
+
+ // For the more detailed description of the following semantics refer to
+ // the depends value documentation.
+
+ // Strip the revision and iteration.
+ //
+ v = version (v.epoch,
+ move (v.upstream),
+ move (v.release),
+ 0 /* revision */,
+ 0 /* iteration */);
+
+ // Calculate effective constraint for a shortcut operator.
+ //
+ if (min_version &&
+ min_version->empty () &&
+ max_version == min_version &&
+ (min_open || max_open))
+ {
+ assert (!min_open || !max_open); // Endpoints cannot be both open.
+
+ string vs (v.string ());
+
+ if (optional<standard_version> sv = parse_standard_version (vs))
+ try
+ {
+ char op (min_open ? '~' : '^');
+ standard_version_constraint vc (op + vs);
+
+ // The shortcut operators' representation is a range.
+ //
+ assert (vc.min_version && vc.max_version);
+
+ standard_version& mnv (*vc.min_version);
+ standard_version& mxv (*vc.max_version);
+
+ // For a release adjust the min version endpoint, setting its patch to
+ // zero. For ^ also set the minor version to zero, unless the major
+ // version is zero (reduced to ~).
+ //
+ if (sv->release ())
+ {
+ mnv = standard_version (
+ sv->epoch,
+ sv->major (),
+ op == '^' && sv->major () != 0 ? 0 : sv->minor (),
+ 0 /* patch */);
+ }
+ //
+ // For a final pre-release or a patch snapshot we check if there has
+ // been a compatible final release (patch is not zero for ~ and
+ // minor/patch are not zero for ^). If that's the case, then fallback
+ // to the release case and start the range from the first alpha
+ // otherwise.
+ //
+ else if (sv->final () || (sv->snapshot () && sv->patch () != 0))
+ {
+ mnv = standard_version (
+ sv->epoch,
+ sv->major (),
+ op == '^' && sv->major () != 0 ? 0 : sv->minor (),
+ 0 /* patch */,
+ sv->patch () != 0 || (op == '^' && sv->minor () != 0)
+ ? 0
+ : 1 /* pre-release */);
+ }
+ //
+ // For a major/minor snapshot we assume that all the packages are
+ // developed in the lockstep and convert the constraint range to
+ // represent this "snapshot series".
+ //
+ else
+ {
+ assert (sv->snapshot () && sv->patch () == 0);
+
+ uint16_t pr (*sv->pre_release ());
+
+ mnv = standard_version (sv->epoch,
+ sv->major (),
+ sv->minor (),
+ 0 /* patch */,
+ pr,
+ 1 /* snapshot_sn */,
+ "" /* snapshot_id */);
+
+ // Note: the max version endpoint is already open.
+ //
+ mxv = standard_version (sv->epoch,
+ sv->major (),
+ sv->minor (),
+ 0 /* patch */,
+ pr + 1);
+ }
+
+ return dependency_constraint (version (mnv.string ()), vc.min_open,
+ version (mxv.string ()), vc.max_open);
+ }
+ catch (const invalid_argument&)
+ {
+ // There shouldn't be a reason for dependency_constraint() to throw.
+ //
+ assert (false);
+ }
+
+ throw invalid_argument (vs + " is not a standard version");
+ }
+
+ // Calculate effective constraint for a range.
+ //
+ return dependency_constraint (
+ min_version && min_version->empty () ? v : min_version, min_open,
+ max_version && max_version->empty () ? v : max_version, max_open);
+ }
+
ostream&
operator<< (ostream& o, const dependency_constraint& c)
{
assert (!c.empty ());
+ auto print = [&o] (const version& v) -> ostream&
+ {
+ return v.empty () ? (o << '$') : (o << v);
+ };
+
if (!c.min_version)
- return o << (c.max_open ? "< " : "<= ") << *c.max_version;
+ {
+ o << (c.max_open ? "< " : "<= ");
+ return print (*c.max_version);
+ }
if (!c.max_version)
- return o << (c.min_open ? "> " : ">= ") << *c.min_version;
+ {
+ o << (c.min_open ? "> " : ">= ");
+ return print (*c.min_version);
+ }
if (*c.min_version == *c.max_version)
- return o << "== " << *c.min_version;
+ {
+ const version& v (*c.min_version);
+
+ if (!c.min_open && !c.max_open)
+ {
+ o << "== ";
+ return print (v);
+ }
+
+ assert (v.empty () && (!c.min_open || !c.max_open));
+ return o << (c.min_open ? "~$" : "^$");
+ }
// If the range can potentially be represented as a range shortcut
// operator (^ or ~), having the [<standard-version> <standard-version>)
// form, then print it using the standard version constraint code.
//
- if (!c.min_open && c.max_open)
+ if (!c.min_open &&
+ c.max_open &&
+ !c.min_version->empty () &&
+ !c.max_version->empty ())
{
if (optional<standard_version> mnv =
parse_standard_version (c.min_version->string (),
@@ -852,8 +1042,11 @@ namespace bpkg
// Print as a range.
//
- return o << (c.min_open ? '(' : '[') << *c.min_version << " "
- << *c.max_version << (c.max_open ? ')' : ']');
+ o << (c.min_open ? '(' : '[');
+ print (*c.min_version);
+ o << ' ';
+ print (*c.max_version);
+ return o << (c.max_open ? ')' : ']');
}
ostream&
@@ -1258,6 +1451,7 @@ namespace bpkg
parse_package_manifest (parser& p,
name_value nv,
bool iu,
+ bool cd,
package_manifest_flags fl,
package_manifest& m)
{
@@ -1323,6 +1517,11 @@ namespace bpkg
return (fl & f) != package_manifest_flags::none;
};
+ // We will cache the depends manifest values to parse and, if requested,
+ // complete the dependency constraints later, after the version value is
+ // parsed.
+ //
+ vector<name_value> dependencies;
for (nv = p.next (); !nv.empty (); nv = p.next ())
{
string& n (nv.name);
@@ -1622,78 +1821,7 @@ namespace bpkg
}
else if (n == "depends")
{
- // Allow specifying ?* in any order.
- //
- size_t n (v.size ());
- size_t cond ((n > 0 && v[0] == '?') || (n > 1 && v[1] == '?') ? 1 : 0);
- size_t btim ((n > 0 && v[0] == '*') || (n > 1 && v[1] == '*') ? 1 : 0);
-
- auto vc (parser::split_comment (v));
-
- const string& vl (vc.first);
- dependency_alternatives da (cond != 0, btim != 0, move (vc.second));
-
- string::const_iterator b (vl.begin ());
- string::const_iterator e (vl.end ());
-
- if (da.conditional || da.buildtime)
- {
- string::size_type p (vl.find_first_not_of (spaces, cond + btim));
- b = p == string::npos ? e : b + p;
- }
-
- list_parser lp (b, e, '|');
- for (string lv (lp.next ()); !lv.empty (); lv = lp.next ())
- {
- using iterator = string::const_iterator;
-
- iterator b (lv.begin ());
- iterator i (b);
- iterator ne (b); // End of name.
- iterator e (lv.end ());
-
- // Find end of name (ne).
- //
- const string cb ("=<>([~^");
- for (char c; i != e && cb.find (c = *i) == string::npos; ++i)
- {
- if (!space (c))
- ne = i + 1;
- }
-
- package_name nm;
-
- try
- {
- nm = package_name (i == e ? move (lv) : string (b, ne));
- }
- catch (const invalid_argument& e)
- {
- bad_value (
- string ("invalid prerequisite package name: ") + e.what ());
- }
-
- if (i == e)
- da.push_back (dependency {move (nm), nullopt});
- else
- {
- try
- {
- da.push_back (
- dependency {move (nm), dependency_constraint (string (i, e))});
- }
- catch (const invalid_argument& e)
- {
- bad_value (
- string ("invalid dependency constraint: ") + e.what ());
- }
- }
- }
-
- if (da.empty ())
- bad_value ("empty package dependency specification");
-
- m.dependencies.push_back (da);
+ dependencies.push_back (move (nv));
}
else if (n == "location")
{
@@ -1761,6 +1889,99 @@ namespace bpkg
else if (m.license_alternatives.empty ())
bad_value ("no project license specified");
+ // Now, when the version manifest value is parsed, we can parse the
+ // dependencies and complete their constrains, if requested.
+ //
+ for (name_value& d: dependencies)
+ {
+ nv = move (d); // Restore as bad_value() uses its line/column.
+
+ const string& v (nv.value);
+
+ // Allow specifying ?* in any order.
+ //
+ size_t n (v.size ());
+ size_t cond ((n > 0 && v[0] == '?') || (n > 1 && v[1] == '?') ? 1 : 0);
+ size_t btim ((n > 0 && v[0] == '*') || (n > 1 && v[1] == '*') ? 1 : 0);
+
+ auto vc (parser::split_comment (v));
+
+ const string& vl (vc.first);
+ dependency_alternatives da (cond != 0, btim != 0, move (vc.second));
+
+ string::const_iterator b (vl.begin ());
+ string::const_iterator e (vl.end ());
+
+ if (da.conditional || da.buildtime)
+ {
+ string::size_type p (vl.find_first_not_of (spaces, cond + btim));
+ b = p == string::npos ? e : b + p;
+ }
+
+ list_parser lp (b, e, '|');
+ for (string lv (lp.next ()); !lv.empty (); lv = lp.next ())
+ {
+ using iterator = string::const_iterator;
+
+ iterator b (lv.begin ());
+ iterator i (b);
+ iterator ne (b); // End of name.
+ iterator e (lv.end ());
+
+ // Find end of name (ne).
+ //
+ const string cb ("=<>([~^");
+ for (char c; i != e && cb.find (c = *i) == string::npos; ++i)
+ {
+ if (!space (c))
+ ne = i + 1;
+ }
+
+ package_name nm;
+
+ try
+ {
+ nm = package_name (i == e ? move (lv) : string (b, ne));
+ }
+ catch (const invalid_argument& e)
+ {
+ bad_value (
+ string ("invalid prerequisite package name: ") + e.what ());
+ }
+
+ if (i == e)
+ da.push_back (dependency {move (nm), nullopt});
+ else
+ {
+ try
+ {
+ dependency_constraint dc (string (i, e));
+
+ if (!dc.complete () &&
+ flag (package_manifest_flags::forbid_incomplete_depends))
+ bad_value ("$ not allowed");
+
+ // Complete the constraint.
+ //
+ if (cd)
+ dc = dc.effective (m.version);
+
+ da.push_back (dependency {move (nm), move (dc)});
+ }
+ catch (const invalid_argument& e)
+ {
+ bad_value (
+ string ("invalid dependency constraint: ") + e.what ());
+ }
+ }
+ }
+
+ if (da.empty ())
+ bad_value ("empty package dependency specification");
+
+ m.dependencies.push_back (da);
+ }
+
if (!m.location && flag (package_manifest_flags::require_location))
bad_name ("no package location specified");
@@ -1771,20 +1992,26 @@ namespace bpkg
package_manifest
pkg_package_manifest (parser& p, name_value nv, bool iu)
{
- return package_manifest (p,
- move (nv),
- iu,
- package_manifest_flags::forbid_file |
- package_manifest_flags::require_location |
- package_manifest_flags::forbid_fragment);
+ return package_manifest (
+ p,
+ move (nv),
+ iu,
+ false /* complete_depends */,
+ package_manifest_flags::forbid_file |
+ package_manifest_flags::require_location |
+ package_manifest_flags::forbid_fragment |
+ package_manifest_flags::forbid_incomplete_depends);
}
// package_manifest
//
package_manifest::
- package_manifest (manifest_parser& p, bool iu, package_manifest_flags fl)
+ package_manifest (manifest_parser& p,
+ bool iu,
+ bool cd,
+ package_manifest_flags fl)
{
- parse_package_manifest (p, p.next (), iu, fl, *this);
+ parse_package_manifest (p, p.next (), iu, cd, fl, *this);
// Make sure this is the end.
//
@@ -1798,9 +2025,10 @@ namespace bpkg
package_manifest (manifest_parser& p,
name_value nv,
bool iu,
+ bool cd,
package_manifest_flags fl)
{
- parse_package_manifest (p, move (nv), iu, fl, *this);
+ parse_package_manifest (p, move (nv), iu, cd, fl, *this);
}
static const string description_file ("description-file");
diff --git a/libbpkg/manifest.hxx b/libbpkg/manifest.hxx
index 3d8f5f5..b7216fc 100644
--- a/libbpkg/manifest.hxx
+++ b/libbpkg/manifest.hxx
@@ -35,7 +35,8 @@ namespace bpkg
{
public:
// Let's keep the members in the order they appear in the string
- // representation.
+ // representation. We also make them const to make sure things stay
+ // consistent.
//
const std::uint16_t epoch;
const std::string upstream;
@@ -279,6 +280,17 @@ namespace bpkg
// depends
//
+ // Represented as a version range. Note that the versions may refer to the
+ // dependent package version and can be completed with the actual versions
+ // using the effective() function. Such versions are represented as an empty
+ // version object and have the dollar character string representation.
+ //
+ // If the version endpoints are equal and both are closed, then this is the
+ // `== <version>` constraint (in particular, `== $` if empty endpoints). If
+ // both endpoints are empty and one of them is open, then this is either
+ // `~$` (min endpoint is open) or `^$` (max endpoint is open). Note that
+ // equal endpoints can never be both open.
+ //
class LIBBPKG_EXPORT dependency_constraint
{
public:
@@ -299,6 +311,21 @@ namespace bpkg
bool
empty () const noexcept {return !min_version && !max_version;}
+
+ bool
+ complete () const noexcept
+ {
+ return (!min_version || !min_version->empty ()) &&
+ (!max_version || !max_version->empty ());
+ }
+
+ // Return the completed constraint if it refers to the dependent package
+ // version and copy of itself otherwise. Throw std::invalid_argument if
+ // the resulting constraint is invalid (max version is less than min
+ // version in range, non-standard version for a shortcut operator, etc.).
+ //
+ dependency_constraint
+ effective (version) const;
};
LIBBPKG_EXPORT std::ostream&
@@ -382,7 +409,7 @@ namespace bpkg
comment (std::move (c)) {}
};
- // Package manifest value forbid/require flags.
+ // Package manifest value validation forbid/require flags.
//
// Some package manifest values can be forbidden or required for certain
// repository types and in specific contexts (for example, when parsing an
@@ -393,15 +420,16 @@ namespace bpkg
//
enum class package_manifest_flags: std::uint16_t
{
- none = 0x0,
+ none = 0x00,
- forbid_file = 0x1, // Forbid *-file manifest values.
- forbid_location = 0x2,
- forbid_sha256sum = 0x4,
- forbid_fragment = 0x8,
+ forbid_file = 0x01, // Forbid *-file manifest values.
+ forbid_location = 0x02,
+ forbid_sha256sum = 0x04,
+ forbid_fragment = 0x08,
+ forbid_incomplete_depends = 0x10,
- require_location = 0x10,
- require_sha256sum = 0x20
+ require_location = 0x20,
+ require_sha256sum = 0x40
};
inline package_manifest_flags
@@ -616,6 +644,7 @@ namespace bpkg
//
package_manifest (butl::manifest_parser&,
bool ignore_unknown = false,
+ bool complete_depends = true,
package_manifest_flags =
package_manifest_flags::forbid_location |
package_manifest_flags::forbid_sha256sum |
@@ -626,6 +655,7 @@ namespace bpkg
package_manifest (butl::manifest_parser&,
butl::manifest_name_value start,
bool ignore_unknown,
+ bool complete_depends,
package_manifest_flags);
void
@@ -654,9 +684,11 @@ namespace bpkg
// Create individual package manifest.
//
inline package_manifest
- pkg_package_manifest (butl::manifest_parser& p, bool ignore_unknown = false)
+ pkg_package_manifest (butl::manifest_parser& p,
+ bool ignore_unknown = false,
+ bool complete_depends = true)
{
- return package_manifest (p, ignore_unknown);
+ return package_manifest (p, ignore_unknown, complete_depends);
}
LIBBPKG_EXPORT package_manifest
diff --git a/tests/manifest/driver.cxx b/tests/manifest/driver.cxx
index 0f2262f..de03606 100644
--- a/tests/manifest/driver.cxx
+++ b/tests/manifest/driver.cxx
@@ -16,10 +16,14 @@ using namespace std;
using namespace butl;
using namespace bpkg;
-// Usage: argv[0] (-pp|-dp|-gp|-pr|-dr|-gr|-s)
+// Usages:
//
-// Read and parse manifest from STDIN and serialize it to STDOUT. The
-// following options specify the manifest type.
+// argv[0] (-pp|-dp|-gp|-pr|-dr|-gr|-s)
+// argv[0] [-c] -p
+// argv[0] -ec <version>
+//
+// In the first form read and parse manifest list from stdin and serialize it
+// to stdout. The following options specify the manifest type.
//
// -pp parse pkg package manifest list
// -dp parse dir package manifest list
@@ -29,13 +33,30 @@ using namespace bpkg;
// -gr parse git repository manifest list
// -s parse signature manifest
//
+// In the second form read and parse the package manifest from stdin and
+// serialize it to stdout. Complete the dependency constraints if -c is
+// specified. Note: -c, if specified, should go before -p on the command line.
+//
+// In the third form read and parse dependency constraints from stdin and
+// roundtrip them to stdout together with their effective constraints,
+// calculated using version passed as an argument.
+//
int
main (int argc, char* argv[])
{
- assert (argc == 2);
+ assert (argc <= 3);
string opt (argv[1]);
- cin.exceptions (ios_base::failbit | ios_base::badbit);
+ bool complete_depends (opt == "-c");
+
+ if (complete_depends)
+ {
+ opt = argv[2];
+ assert (opt == "-p");
+ }
+
+ assert ((opt == "-ec" || complete_depends) == (argc == 3));
+
cout.exceptions (ios_base::failbit | ios_base::badbit);
manifest_parser p (cin, "stdin");
@@ -43,22 +64,48 @@ main (int argc, char* argv[])
try
{
- if (opt == "-pp")
- pkg_package_manifests (p).serialize (s);
- else if (opt == "-dp")
- dir_package_manifests (p).serialize (s);
- else if (opt == "-gp")
- git_package_manifests (p).serialize (s);
- else if (opt == "-pr")
- pkg_repository_manifests (p).serialize (s);
- else if (opt == "-dr")
- dir_repository_manifests (p).serialize (s);
- else if (opt == "-gr")
- git_repository_manifests (p).serialize (s);
- else if (opt == "-s")
- signature_manifest (p).serialize (s);
+ if (opt == "-ec")
+ {
+ version v (argv[2]);
+
+ cin.exceptions (ios_base::badbit);
+
+ string s;
+ while (!eof (getline (cin, s)))
+ {
+ dependency_constraint c (s);
+ dependency_constraint ec (c.effective (v));
+
+ assert (c.complete () == (c == ec));
+
+ cout << c << " " << ec << endl;
+ }
+ }
else
- assert (false);
+ {
+ cin.exceptions (ios_base::failbit | ios_base::badbit);
+
+ if (opt == "-p")
+ pkg_package_manifest (p,
+ false /* ignore_unknown */,
+ complete_depends).serialize (s);
+ else if (opt == "-pp")
+ pkg_package_manifests (p).serialize (s);
+ else if (opt == "-dp")
+ dir_package_manifests (p).serialize (s);
+ else if (opt == "-gp")
+ git_package_manifests (p).serialize (s);
+ else if (opt == "-pr")
+ pkg_repository_manifests (p).serialize (s);
+ else if (opt == "-dr")
+ dir_repository_manifests (p).serialize (s);
+ else if (opt == "-gr")
+ git_repository_manifests (p).serialize (s);
+ else if (opt == "-s")
+ signature_manifest (p).serialize (s);
+ else
+ assert (false);
+ }
}
catch (const manifest_parsing& e)
{
diff --git a/tests/manifest/testscript b/tests/manifest/testscript
index b77740f..fa0de85 100644
--- a/tests/manifest/testscript
+++ b/tests/manifest/testscript
@@ -74,13 +74,40 @@
: dependency
:
- $* -pp <<EOI 2>'stdin:5:10: error: invalid prerequisite package name: length is less than two characters' != 0
+ $* -pp <<EOI 2>'stdin:8:10: error: invalid prerequisite package name: length is less than two characters' != 0
: 1
sha256sum: a2b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
:
name: foo
+ version: 2.0.0
+ summary: Modern C++ parser
+ license: LGPLv2
depends: b
EOI
+
+ : dependency-constraint
+ :
+ $* -pp <<EOI 2>'stdin:8:10: error: $ not allowed' != 0
+ : 1
+ sha256sum: a2b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
+ :
+ name: foo
+ version: 2.0.0
+ summary: Modern C++ parser
+ license: LGPLv2
+ depends: bar == $
+ EOI
+
+ : dependency-constraint-version
+ :
+ $* -c -p <<EOI 2>'stdin:6:10: error: invalid dependency constraint: min version is greater than max version' != 0
+ : 1
+ name: foo
+ version: 2.0.0
+ summary: Modern C++ parser
+ license: LGPLv2
+ depends: bar [$ 1.0.0]
+ EOI
}
}
@@ -89,6 +116,39 @@
{
: manifest
:
+ {
+ : complete
+ :
+ $* -c -p <<EOI >>EOO
+ : 1
+ name: foo
+ version: 2.0.0
+ summary: Modern C++ parser
+ license: LGPLv2
+ depends: bar == $ | libbaz ~$ | libbox ^$ | libfox [1.0 $)
+ EOI
+ : 1
+ name: foo
+ version: 2.0.0
+ summary: Modern C++ parser
+ license: LGPLv2
+ depends: bar == 2.0.0 | libbaz ~2.0.0 | libbox ^2.0.0 | libfox [1.0 2.0.0)
+ EOO
+
+ : incomplete
+ :
+ $* -p <<EOF >>EOF
+ : 1
+ name: foo
+ version: 2.0.0
+ summary: Modern C++ parser
+ license: LGPLv2
+ depends: bar == $ | libbaz ~$ | libbox ^$ | libfox [1.0 $)
+ EOF
+ }
+
+ : manifest-list
+ :
: Roundtrip the pkg package manifest list.
:
$* -pp <<EOF >>EOF
@@ -515,3 +575,75 @@
\
EOF
}
+
+: effective-constraints
+:
+{
+ : regular
+ :
+ $* -ec '1.2.3+1' <<EOI >>EOO
+ [1.0 $)
+ [1.0 $]
+ [$ 1.2.4)
+ [$ 1.2.4]
+ == $
+ >= $
+ EOI
+ [1.0 $) [1.0 1.2.3)
+ [1.0 $] [1.0 1.2.3]
+ [$ 1.2.4) [1.2.3 1.2.4)
+ [$ 1.2.4] [1.2.3 1.2.4]
+ == $ == 1.2.3
+ >= $ >= 1.2.3
+ EOO
+
+ : shortcut
+ :
+ {
+ : final
+ :
+ {
+ $* -ec '1.2.3+1' <'~$' >'~$ ~1.2.0' : tilda
+ $* -ec '1.2.3+1' <'^$' >'^$ ^1.0.0' : carrot
+ }
+
+ : pre-release
+ :
+ {
+ : tilda
+ :
+ {
+ $* -ec '1.2.0-b.2' <'~$' >'~$ ~1.2.0-a.1' : no-final
+ $* -ec '1.2.1-a.1' <'~$' >'~$ ~1.2.0' : final-patch
+ }
+
+ : carrot
+ :
+ {
+ $* -ec '1.0.0-b.2' <'^$' >'^$ ^1.0.0-a.1' : no-final
+ $* -ec '1.0.1-a.1' <'^$' >'^$ ^1.0.0' : final-patch
+ $* -ec '1.1.0-b.2' <'^$' >'^$ ^1.0.0' : final-minor
+ }
+ }
+
+ : snapshot
+ :
+ {
+ : tilda
+ :
+ {
+ $* -ec '1.2.1-a.2.345' <'~$' >'~$ ~1.2.0' : patch
+ $* -ec '1.2.0-a.0.345' <'~$' >'~$ [1.2.0-a.0.1 1.2.0-a.1)' : minor
+ $* -ec '1.0.0-a.0.345' <'~$' >'~$ [1.0.0-a.0.1 1.0.0-a.1)' : major
+ }
+
+ : carrot
+ :
+ {
+ $* -ec '1.2.1-a.2.345' <'^$' >'^$ ^1.0.0' : patch
+ $* -ec '1.2.0-a.0.345' <'^$' >'^$ [1.2.0-a.0.1 1.2.0-a.1)' : minor
+ $* -ec '1.0.0-a.0.345' <'^$' >'^$ [1.0.0-a.0.1 1.0.0-a.1)' : major
+ }
+ }
+ }
+}