aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bpkg/common.cli76
-rw-r--r--bpkg/options-types.hxx6
-rw-r--r--bpkg/pkg-status.cli95
-rw-r--r--bpkg/pkg-status.cxx437
-rw-r--r--bpkg/types-parsers.cxx18
-rw-r--r--bpkg/types-parsers.hxx10
-rw-r--r--tests/pkg-status.testscript337
-rw-r--r--tests/pkg-status/testing/libbar-1.0.0+1.tar.gzbin325 -> 363 bytes
-rw-r--r--tests/pkg-status/testing/libbar-1.1.0.tar.gzbin322 -> 373 bytes
-rw-r--r--tests/pkg-status/testing/libbaz-1.0.0.tar.gzbin0 -> 360 bytes
10 files changed, 719 insertions, 260 deletions
diff --git a/bpkg/common.cli b/bpkg/common.cli
index dd0417d..cccf1d3 100644
--- a/bpkg/common.cli
+++ b/bpkg/common.cli
@@ -80,6 +80,14 @@ namespace bpkg
\li|Even more detailed information.||"
}
+ bpkg::stdout_format --stdout-format = bpkg::stdout_format::lines
+ {
+ "<format>",
+ "Representation format to use for printing to \cb{stdout}. Valid values
+ for this option are \cb{lines} (default) and \cb{json}. See the JSON
+ OUTPUT section below for details on the \cb{json} format."
+ }
+
size_t --jobs|-j
{
"<num>",
@@ -409,4 +417,72 @@ namespace bpkg
"Don't load default options files."
}
};
+
+ {
+ "",
+ "
+ \h|JSON OUTPUT|
+
+ Commands that support the JSON output specify their formats as a
+ serialized representation of a C++ \cb{struct} or an array thereof. For
+ example:
+
+ \
+ struct package
+ {
+ string name;
+ };
+
+ struct configuration
+ {
+ uint64_t id;
+ string path;
+ optional<string> name;
+ bool default;
+ vector<package> packages;
+ };
+ \
+
+ An example of the serialized JSON representation of \cb{struct}
+ \cb{configuration}:
+
+ \
+ {
+ \"id\": 1,
+ \"path\": \"/tmp/hello-gcc\",
+ \"name\": \"gcc\",
+ \"default\": true,
+ \"packages\": [
+ {
+ \"name\": \"hello\"
+ }
+ ]
+ }
+ \
+
+ This sections provides details on the overall properties of such formats
+ and the semantics of the \cb{struct} serialization.
+
+ The order of members in a JSON object is fixed as specified in the
+ corresponding \cb{struct}. While new members may be added in the
+ future (and should be ignored by older consumers), the semantics of the
+ existing members (including whether the top-level entry is an object or
+ array) may not change.
+
+ An object member is required unless its type is \cb{optional<>},
+ \cb{bool}, or \cb{vector<>} (array). For \cb{bool} members absent means
+ \cb{false}. For \cb{vector<>} members absent means empty. An empty
+ top-level array is always present.
+
+ For example, the following JSON text is a possible serialization of
+ the above \cb{struct} \cb{configuration}:
+
+ \
+ {
+ \"id\": 1,
+ \"path\": \"/tmp/hello-gcc\"
+ }
+ \
+ "
+ }
}
diff --git a/bpkg/options-types.hxx b/bpkg/options-types.hxx
index 741e93c..6576060 100644
--- a/bpkg/options-types.hxx
+++ b/bpkg/options-types.hxx
@@ -21,6 +21,12 @@ namespace bpkg
all
};
+ enum class stdout_format
+ {
+ lines,
+ json
+ };
+
// Qualified options.
//
// An option that uses this type can have its values qualified using the
diff --git a/bpkg/pkg-status.cli b/bpkg/pkg-status.cli
index d2eb644..59319bf 100644
--- a/bpkg/pkg-status.cli
+++ b/bpkg/pkg-status.cli
@@ -32,12 +32,13 @@ namespace bpkg
\c{\b{--recursive}|\b{-r}} options, respectively. Note that the status is
written to \cb{stdout}, not \cb{stderr}.
- The status output format is regular with components separated with
- spaces. Each line starts with the package name followed by one of the
- status words listed below. Some of them can be optionally followed by
- '\cb{,}' (no spaces) and a sub-status word. Lines corresponding to
- dependencies from linked configurations will additionally mention the
- configuration directory in square brackets after the package name.
+ The default output format (see the \cb{--stdout-format} common option) is
+ regular with components separated with spaces. Each line starts with the
+ package name followed by one of the status words listed below. Some of
+ them can be optionally followed by '\cb{,}' (no spaces) and a sub-status
+ word. Lines corresponding to dependencies from linked configurations will
+ additionally mention the configuration directory in square brackets after
+ the package name.
\dl|
@@ -83,11 +84,13 @@ namespace bpkg
package may or may not be available from the system and that its version
is unknown.
- If the package version was specified, then the status word is always
- followed by this version (or its revision).
+ The \cb{fetched}, \cb{unpacked}, \cb{configured}, and \cb{broken} status
+ words are followed by the version of the package. If the package version
+ was specified, then the \cb{unknown} status word is also followed by the
+ version.
If the status is \cb{fetched}, \cb{unpacked}, \cb{configured}, or
- \cb{broken} and newer versions are available, then this version is
+ \cb{broken} and newer versions are available, then the package version is
followed by the \cb{available} status word and the list of newer
versions. To instead see a list of all versions, including the older
ones, specify the \c{\b{--old-available}|\b{-o}} option. In this case the
@@ -160,6 +163,80 @@ namespace bpkg
libbar configured 2.0.0
\
+ If the output format is \cb{json}, then the output is a JSON array of
+ objects which are the serialized representation of the following C++
+ \cb{struct} \cb{package_status}:
+
+ \
+ struct available_version
+ {
+ string version;
+ bool system;
+ bool dependency;
+ };
+
+ struct package_status
+ {
+ string name;
+ optional<string> configuration;
+ optional<string> constraint;
+ string status;
+ optional<string> sub_status;
+ optional<string> version;
+ bool hold_package;
+ bool hold_version;
+ vector<available_version> available_versions;
+ vector<package_status> dependencies;
+ };
+ \
+
+ For example:
+
+ \
+ [
+ {
+ \"name\": \"hello\",
+ \"status\": \"configured\",
+ \"version\": \"1.0.0\",
+ \"hold_package\": true,
+ \"available_versions\": [
+ {
+ \"version\": \"1.0.1\"
+ },
+ {
+ \"version\": \"2.0.0\"
+ }
+ ],
+ \"dependencies\": [
+ {
+ \"name\": \"libhello\",
+ \"status\": \"configured\",
+ \"version\": \"1.0.2\",
+ }
+ ]
+ }
+ ]
+ \
+
+ See the JSON OUTPUT section in \l{bdep-common-options(1)} for details on
+ the overall properties of this format and the semantics of the
+ \cb{struct} serialization.
+
+ In \cb{package_status}, the \cb{configuration} member contains the
+ absolute directory of a linked configuration if this package resides in a
+ linked configuration. The \cb{constraint} member is present only if the
+ \cb{--constraint} option is specified. The \cb{version} member is absent
+ if the \cb{status} member is \cb{unknown} or \cb{available} and no
+ package version is specified on the command line. If the \cb{sub_status}
+ member is \cb{system}, then the \cb{version} member can be special
+ \cb{*}. The \cb{dependencies} member is present only if the
+ \cb{--immediate|-i} or \cb{--recursive|-r} options are specified.
+
+ In \cb{available_version}, if the \cb{system} member is \cb{true}, then
+ this version is available from the system, in which case the \cb{version}
+ member can be special \cb{?} or \cb{*}. If the \cb{dependency} member is
+ \cb{true}, then this version is only available as a dependency from
+ prerequisite repositories of other repositories.
"
}
diff --git a/bpkg/pkg-status.cxx b/bpkg/pkg-status.cxx
index 2475fa1..93008a8 100644
--- a/bpkg/pkg-status.cxx
+++ b/bpkg/pkg-status.cxx
@@ -5,6 +5,8 @@
#include <iostream> // cout
+#include <libbutl/json/serializer.hxx>
+
#include <bpkg/package.hxx>
#include <bpkg/package-odb.hxx>
#include <bpkg/database.hxx>
@@ -27,102 +29,147 @@ namespace bpkg
};
using packages = vector<package>;
- // If recursive or immediate is true, then print status for dependencies
- // indented by two spaces.
- //
- static void
- pkg_status (const pkg_status_options& o,
- const packages& pkgs,
- string& indent,
- bool recursive,
- bool immediate)
+ struct available_package_status
{
- tracer trace ("pkg_status");
+ shared_ptr<available_package> package;
- for (const package& p: pkgs)
- {
- l4 ([&]{trace << "package " << p.name << "; version " << p.version;});
+ // Can only be built as a dependency.
+ //
+ // True if this package version doesn't belong to the repositories that
+ // were explicitly added to the configuration and their complements,
+ // recursively.
+ //
+ bool dependency;
+ };
+
+ class available_package_statuses: public vector<available_package_status>
+ {
+ public:
+ // Empty if the package is not available from the system. Can be `?`.
+ //
+ string system_package_version;
+
+ // Can only be built as a dependency.
+ //
+ // True if there are no package versions available from the repositories
+ // that were explicitly added to the configuration and their complements,
+ // recursively.
+ //
+ bool dependency = true;
+ };
- database& pdb (p.pdb);
- database& rdb (p.rdb);
+ static available_package_statuses
+ pkg_statuses (const pkg_status_options& o, const package& p)
+ {
+ database& rdb (p.rdb);
+ const shared_ptr<selected_package>& s (p.selected);
- // Can't be both.
- //
- assert (p.version.empty () || !p.constraint);
+ available_package_statuses r;
- const shared_ptr<selected_package>& s (p.selected);
+ bool known (false);
+
+ shared_ptr<repository_fragment> root (
+ rdb.load<repository_fragment> (""));
- // Look for available packages.
+ using query = query<available_package>;
+
+ query q (query::id.name == p.name);
+ {
+ auto qr (rdb.query<available_package> (q));
+ known = !qr.empty ();
+ r.dependency = (filter_one (root, move (qr)).first == nullptr);
+ }
+
+ if (known)
+ {
+ // If the user specified the version, then only look for that
+ // specific version (we still do it since there might be other
+ // revisions).
//
- // Some of them are only available to upgrade/downgrade as dependencies.
+ if (!p.version.empty ())
+ q = q && compare_version_eq (query::id.version,
+ canonical_version (p.version),
+ p.version.revision.has_value (),
+ false /* iteration */);
+
+ // And if we found an existing package, then only look for versions
+ // greater than to what already exists unless we were asked to show
+ // old versions.
//
- struct apkg
- {
- shared_ptr<available_package> package;
- bool build;
- };
- vector<apkg> apkgs;
-
- // A package with this name is known in available packages potentially
- // for build.
+ // Note that for a system wildcard version we will always show all
+ // available versions (since it is 0).
//
- bool known (false);
- bool build (false);
+ if (s != nullptr && !o.old_available ())
+ q = q && query::id.version > canonical_version (s->version);
+
+ q += order_by_version_desc (query::id.version);
+
+ for (shared_ptr<available_package> ap:
+ pointer_result (rdb.query<available_package> (q)))
{
- shared_ptr<repository_fragment> root (
- rdb.load<repository_fragment> (""));
+ bool dependency (filter (root, ap) == nullptr);
+ r.push_back (available_package_status {move (ap), dependency});
+ }
- using query = query<available_package>;
+ // The idea is that in the future we will try to auto-discover a system
+ // version. For now we just say "maybe available from the system" even
+ // if the version was specified by the user. We will later compare it if
+ // the user did specify the version.
+ //
+ if (o.system ())
+ r.system_package_version = "?";
- query q (query::id.name == p.name);
+ // Get rid of stubs.
+ //
+ for (auto i (r.begin ()); i != r.end (); ++i)
+ {
+ if (i->package->stub ())
{
- auto r (rdb.query<available_package> (q));
- known = !r.empty ();
- build = filter_one (root, move (r)).first != nullptr;
+ // All the rest are stubs so bail out.
+ //
+ r.erase (i, r.end ());
+ break;
}
+ }
+ }
- if (known)
- {
- // If the user specified the version, then only look for that
- // specific version (we still do it since there might be other
- // revisions).
- //
- if (!p.version.empty ())
- q = q && compare_version_eq (query::id.version,
- canonical_version (p.version),
- p.version.revision.has_value (),
- false /* iteration */);
+ return r;
+ }
- // And if we found an existing package, then only look for versions
- // greater than to what already exists unless we were asked to show
- // old versions.
- //
- // Note that for a system wildcard version we will always show all
- // available versions (since it is 0).
- //
- if (s != nullptr && !o.old_available ())
- q = q && query::id.version > canonical_version (s->version);
+ static packages
+ pkg_prerequisites (const shared_ptr<selected_package>& s, database& rdb)
+ {
+ packages r;
+ for (const auto& pair: s->prerequisites)
+ {
+ shared_ptr<selected_package> d (pair.first.load ());
+ database& db (pair.first.database ());
+ const optional<version_constraint>& c (pair.second);
+ r.push_back (package {db, rdb, d->name, version (), move (d), c});
+ }
+ return r;
+ }
- q += order_by_version_desc (query::id.version);
+ static void
+ pkg_status_lines (const pkg_status_options& o,
+ const packages& pkgs,
+ string& indent,
+ bool recursive,
+ bool immediate)
+ {
+ tracer trace ("pkg_status_lines");
- // Packages that are in repositories that were explicitly added to
- // the configuration and their complements, recursively, are also
- // available to build.
- //
- for (shared_ptr<available_package> ap:
- pointer_result (
- rdb.query<available_package> (q)))
- {
- bool build (filter (root, ap));
- apkgs.push_back (apkg {move (ap), build});
- }
- }
- }
+ for (const package& p: pkgs)
+ {
+ l4 ([&]{trace << "package " << p.name << "; version " << p.version;});
+
+ available_package_statuses ps (pkg_statuses (o, p));
cout << indent;
// Selected.
//
+ const shared_ptr<selected_package>& s (p.selected);
// Hold package status.
//
@@ -134,7 +181,7 @@ namespace bpkg
// If the package name is selected, then print its exact spelling.
//
- cout << (s != nullptr ? s->name : p.name) << pdb;
+ cout << (s != nullptr ? s->name : p.name) << p.pdb;
if (o.constraint () && p.constraint)
cout << ' ' << *p.constraint;
@@ -158,77 +205,188 @@ namespace bpkg
// Available.
//
- bool available (false);
- if (known)
+ if (!ps.empty () || !ps.system_package_version.empty ())
{
- // Available from the system.
- //
- // The idea is that in the future we will try to auto-discover a
- // system version and then print that. For now we just say "maybe
- // available from the system" even if the version was specified by
- // the user. We will later compare it if the user did specify the
- // version.
- //
- string sys;
- if (o.system ())
+ cout << (s != nullptr ? " " : "") << "available";
+
+ for (const available_package_status& a: ps)
{
- sys = "?";
- available = true;
+ const version& v (a.package->version);
+
+ // Show the currently selected version in parenthesis.
+ //
+ bool cur (s != nullptr && v == s->version);
+
+ cout << ' '
+ << (cur ? "(" : a.dependency ? "[" : "")
+ << v
+ << (cur ? ")" : a.dependency ? "]" : "");
}
- // Get rid of stubs.
+ if (!ps.system_package_version.empty ())
+ cout << ' '
+ << (ps.dependency ? "[" : "")
+ << "sys:" << ps.system_package_version
+ << (ps.dependency ? "]" : "");
+ }
+ //
+ // Unknown.
+ //
+ else if (s == nullptr)
+ {
+ cout << "unknown";
+
+ // Print the user's version if specified.
//
- for (auto i (apkgs.begin ()); i != apkgs.end (); ++i)
+ if (!p.version.empty ())
+ cout << ' ' << p.version;
+ }
+
+ cout << endl;
+
+ if (recursive || immediate)
+ {
+ // Collect and recurse.
+ //
+ // Let's propagate the repository information source database from the
+ // dependent to its prerequisites.
+ //
+ if (s != nullptr)
{
- if (i->package->stub ())
+ packages dpkgs (pkg_prerequisites (s, p.rdb));
+
+ if (!dpkgs.empty ())
{
- // All the rest are stubs so bail out.
- //
- apkgs.erase (i, apkgs.end ());
- break;
+ indent += " ";
+ pkg_status_lines (o, dpkgs, indent, recursive, false /* immediate */);
+ indent.resize (indent.size () - 2);
}
+ }
+ }
+ }
+ }
+
+ static void
+ pkg_status_json (const pkg_status_options& o,
+ const packages& pkgs,
+ json::stream_serializer& ss,
+ bool recursive,
+ bool immediate)
+ {
+ tracer trace ("pkg_status_json");
+
+ ss.begin_array ();
+
+ for (const package& p: pkgs)
+ {
+ l4 ([&]{trace << "package " << p.name << "; version " << p.version;});
+
+ available_package_statuses ps (pkg_statuses (o, p));
+
+ const shared_ptr<selected_package>& s (p.selected);
+
+ // Note that we won't check some values for being valid UTF-8 (package
+ // names, etc), since their characters belong to even stricter character
+ // sets.
+ //
+ ss.begin_object ();
+
+ // If the package name is selected, then print its exact spelling.
+ //
+ ss.member ("name",
+ (s != nullptr ? s->name : p.name).string (),
+ false /* check */);
+
+ if (!p.pdb.string.empty ())
+ ss.member ("configuration", p.pdb.string);
+
+ if (o.constraint () && p.constraint)
+ ss.member ("constraint", p.constraint->string (), false /* check */);
+
+ // Selected.
+ //
+ if (s != nullptr)
+ {
+ ss.member ("status", to_string (s->state), false /* check */);
+
+ if (s->substate != package_substate::none)
+ ss.member ("sub_status", to_string (s->substate), false /* check */);
+
+ ss.member ("version", s->version_string (), false /* check */);
+
+ if (s->hold_package)
+ ss.member ("hold_package", true);
+
+ if (s->hold_version)
+ ss.member ("hold_version", true);
+ }
+
+ // Available.
+ //
+ if (!ps.empty () || !ps.system_package_version.empty ())
+ {
+ if (s == nullptr)
+ {
+ ss.member ("status", "available", false /* check */);
- available = true;
+ // Print the user's version if specified.
+ //
+ if (!p.version.empty ())
+ ss.member ("version", p.version.string (), false /* check */);
}
- if (available)
+ // Print the list of available versions, unless a specific available
+ // version is already printed.
+ //
+ if (s != nullptr || p.version.empty ())
{
- cout << (s != nullptr ? " " : "") << "available";
+ ss.member_name ("available_versions");
- for (const apkg& a: apkgs)
+ // Serialize an available package version.
+ //
+ auto serialize = [&ss] (const string& v, bool s, bool d)
{
- const version& v (a.package->version);
+ ss.begin_object ();
- // Show the currently selected version in parenthesis.
- //
- bool cur (s != nullptr && v == s->version);
+ ss.member ("version", v, false /* check */);
- cout << ' '
- << (cur ? "(" : a.build ? "" : "[")
- << v
- << (cur ? ")" : a.build ? "" : "]");
- }
+ if (s)
+ ss.member ("system", s);
+
+ if (d)
+ ss.member ("dependency", d);
+
+ ss.end_object ();
+ };
+
+ ss.begin_array ();
+
+ for (const available_package_status& a: ps)
+ serialize (a.package->version.string (),
+ false /* system */,
+ a.dependency);
+
+ if (!ps.system_package_version.empty ())
+ serialize (ps.system_package_version,
+ true /* system */,
+ ps.dependency);
- if (!sys.empty ())
- cout << ' '
- << (build ? "" : "[")
- << "sys:" << sys
- << (build ? "" : "]");
+ ss.end_array ();
}
}
-
- if (s == nullptr && !available)
+ //
+ // Unknown.
+ //
+ else if (s == nullptr)
{
- cout << "unknown";
+ ss.member ("status", "unknown", false /* check */);
// Print the user's version if specified.
//
if (!p.version.empty ())
- cout << ' ' << p.version;
+ ss.member ("version", p.version.string (), false /* check */);
}
- cout << endl;
-
if (recursive || immediate)
{
// Collect and recurse.
@@ -236,27 +394,22 @@ namespace bpkg
// Let's propagate the repository information source database from the
// dependent to its prerequisites.
//
- packages dpkgs;
if (s != nullptr)
{
- for (const auto& pair: s->prerequisites)
+ packages dpkgs (pkg_prerequisites (s, p.rdb));
+
+ if (!dpkgs.empty ())
{
- shared_ptr<selected_package> d (pair.first.load ());
- database& db (pair.first.database ());
- const optional<version_constraint>& c (pair.second);
- dpkgs.push_back (
- package {db, rdb, d->name, version (), move (d), c});
+ ss.member_name ("dependencies");
+ pkg_status_json (o, dpkgs, ss, recursive, false /* immediate */);
}
}
-
- if (!dpkgs.empty ())
- {
- indent += " ";
- pkg_status (o, dpkgs, indent, recursive, false /* immediate */);
- indent.resize (indent.size () - 2);
- }
}
+
+ ss.end_object ();
}
+
+ ss.end_array ();
}
int
@@ -377,8 +530,22 @@ namespace bpkg
}
}
- string indent;
- pkg_status (o, pkgs, indent, o.recursive (), o.immediate ());
+ switch (o.stdout_format ())
+ {
+ case stdout_format::lines:
+ {
+ string indent;
+ pkg_status_lines (o, pkgs, indent, o.recursive (), o.immediate ());
+ break;
+ }
+ case stdout_format::json:
+ {
+ json::stream_serializer s (cout);
+ pkg_status_json (o, pkgs, s, o.recursive (), o.immediate ());
+ cout << endl;
+ break;
+ }
+ }
t.commit ();
return 0;
diff --git a/bpkg/types-parsers.cxx b/bpkg/types-parsers.cxx
index 97ebafe..e27f050 100644
--- a/bpkg/types-parsers.cxx
+++ b/bpkg/types-parsers.cxx
@@ -141,6 +141,24 @@ namespace bpkg
throw invalid_value (o, v);
}
+ void parser<stdout_format>::
+ parse (stdout_format& x, bool& xs, scanner& s)
+ {
+ xs = true;
+ const char* o (s.next ());
+
+ if (!s.more ())
+ throw missing_value (o);
+
+ const string v (s.next ());
+ if (v == "lines")
+ x = stdout_format::lines;
+ else if (v == "json")
+ x = stdout_format::json;
+ else
+ throw invalid_value (o, v);
+ }
+
void parser<repository_type>::
parse (repository_type& x, bool& xs, scanner& s)
{
diff --git a/bpkg/types-parsers.hxx b/bpkg/types-parsers.hxx
index 007d754..dba459a 100644
--- a/bpkg/types-parsers.hxx
+++ b/bpkg/types-parsers.hxx
@@ -84,6 +84,16 @@ namespace bpkg
};
template <>
+ struct parser<stdout_format>
+ {
+ static void
+ parse (stdout_format&, bool&, scanner&);
+
+ static void
+ merge (stdout_format& b, const stdout_format& a) {b = a;}
+ };
+
+ template <>
struct parser<repository_type>
{
static void
diff --git a/tests/pkg-status.testscript b/tests/pkg-status.testscript
index 86a85d4..e90e3bf 100644
--- a/tests/pkg-status.testscript
+++ b/tests/pkg-status.testscript
@@ -54,183 +54,288 @@
$git_extract $src/git/style-basic.tar &$out_git/state0/***
end
-pkg_fetch += 2>!
-pkg_purge += -d cfg 2>!
rep_add += -d cfg 2>!
rep_fetch += -d cfg --auth all --trust-yes 2>!
+pkg_fetch += 2>!
+pkg_build += -d cfg --yes 2>!
+pkg_purge += -d cfg 2>!
+pkg_drop += -d cfg --yes 2>!
-: basics
+: lines
:
{
+$clone_cfg
- : not-fetched
+ : basics
:
{
+$clone_cfg
- : libfoo-1.0.0
- :
- $clone_cfg;
- $* libfoo/1.0.0 >'libfoo unknown 1.0.0'
-
- : libfoo
- :
- $clone_cfg;
- $* libfoo >'libfoo unknown'
- }
-
- : rep-fetched
- :
- {
- +$clone_cfg && $rep_add $rep/stable && $rep_fetch
-
- +cp -r cfg ./fetched
- +$pkg_fetch libfoo/1.0.0 -d fetched &fetched/libfoo-1.0.0.tar.gz
-
- : libfoo-1.0.0
+ : not-fetched
:
- $clone_cfg;
- $* libfoo/1.0.0 >'libfoo available 1.0.0'
+ {
+ +$clone_cfg
- : libfoo-1.0.0+0
- :
- $clone_cfg;
- $* libfoo/1.0.0+0 >'libfoo available 1.0.0'
+ : libfoo-1.0.0
+ :
+ $clone_cfg;
+ $* libfoo/1.0.0 >'libfoo unknown 1.0.0'
- : libfoo
- :
- $clone_cfg;
- $* libfoo >'libfoo available 1.0.0'
+ : libfoo
+ :
+ $clone_cfg;
+ $* libfoo >'libfoo unknown'
+ }
- : pkg-fetched
+ : rep-fetched
:
{
- clone_cfg = cp -r ../../fetched cfg
+ +$clone_cfg && $rep_add $rep/stable && $rep_fetch
+
+ +cp -r cfg ./fetched
+ +$pkg_fetch libfoo/1.0.0 -d fetched &fetched/libfoo-1.0.0.tar.gz
: libfoo-1.0.0
:
$clone_cfg;
- $* libfoo/1.0.0 >'libfoo fetched 1.0.0'
+ $* libfoo/1.0.0 >'libfoo available 1.0.0'
+
+ : libfoo-1.0.0+0
+ :
+ $clone_cfg;
+ $* libfoo/1.0.0+0 >'libfoo available 1.0.0'
: libfoo
:
$clone_cfg;
- $* libfoo >'libfoo fetched 1.0.0'
+ $* libfoo >'libfoo available 1.0.0'
+
+ : pkg-fetched
+ :
+ {
+ clone_cfg = cp -r ../../fetched cfg
+
+ : libfoo-1.0.0
+ :
+ $clone_cfg;
+ $* libfoo/1.0.0 >'libfoo fetched 1.0.0'
+
+ : libfoo
+ :
+ $clone_cfg;
+ $* libfoo >'libfoo fetched 1.0.0'
+ }
}
}
-}
-
-: multiple-versions
-{
- # Prepare the nested tests to copy the root configuration. Note that they
- # must provide the destination directory name as an argument.
- #
- clone_cfg = cp -r $~/../cfg
- : extra
- :
+ : multiple-versions
{
- # Here we, first, prepare 2 configurations that derive from each other, and
- # then spawn 2 tests on them.
+ # Prepare the nested tests to copy the root configuration. Note that they
+ # must provide the destination directory name as an argument.
#
- +$clone_cfg extra && $rep_add -d extra $rep/extra && $rep_fetch -d extra
+ clone_cfg = cp -r $~/../cfg
- +cp -r extra extra-stable
- +$rep_add -d extra-stable $rep/stable && $rep_fetch -d extra-stable
-
- : libbar
+ : extra
:
- $* -d ../extra libbar >'libbar available 1.1.0+1 [1.0.0]'
-
- : libbar-stable
- :
- $* -d ../extra-stable libbar >'libbar available 1.1.0+1 1.0.0'
- }
+ {
+ # Here we, first, prepare 2 configurations that derive from each other,
+ # and then spawn 2 tests on them.
+ #
+ +$clone_cfg extra && $rep_add -d extra $rep/extra && $rep_fetch -d extra
- : testing
- :
- {
- +$clone_cfg ./ && $rep_add $rep/testing && $rep_fetch
+ +cp -r extra extra-stable
+ +$rep_add -d extra-stable $rep/stable && $rep_fetch -d extra-stable
- clone_cfg = cp -r ../cfg ./
+ : libbar
+ :
+ $* -d ../extra libbar >'libbar available 1.1.0+1 [1.0.0]'
- : no-version
- :
- {
- $clone_cfg;
- $* libbar >'libbar available [1.1.0+1] 1.1.0 1.0.0+1 1.0.0'
+ : libbar-stable
+ :
+ $* -d ../extra-stable libbar >'libbar available 1.1.0+1 1.0.0'
}
- : no-revision
+ : testing
:
{
- $clone_cfg;
- $* libbar/1.0.0 >'libbar available 1.0.0+1 1.0.0'
+ +$clone_cfg ./ && $rep_add $rep/testing && $rep_fetch
+
+ clone_cfg = cp -r ../cfg ./
+
+ : no-version
+ :
+ {
+ $clone_cfg;
+ $* libbar >'libbar available [1.1.0+1] 1.1.0 1.0.0+1 1.0.0'
+ }
+
+ : no-revision
+ :
+ {
+ $clone_cfg;
+ $* libbar/1.0.0 >'libbar available 1.0.0+1 1.0.0'
+ }
+
+ : zero-revision
+ :
+ {
+ $clone_cfg;
+ $* libbar/1.0.0+0 >'libbar available 1.0.0'
+ }
+
+ : recursive
+ :
+ {
+ $clone_cfg;
+
+ $pkg_build libbar;
+
+ $* libbar --recursive >>EOO;
+ !libbar configured 1.1.0 available [1.1.0+1]
+ libbaz configured 1.0.0
+ EOO
+
+ $pkg_drop libbar
+ }
}
- : zero-revision
+ : unstable
:
{
- $clone_cfg;
- $* libbar/1.0.0+0 >'libbar available 1.0.0'
+ # Here we, first, prepare 3 configurations that derive from each other,
+ # and then spawn 3 tests on them.
+ #
+ +$clone_cfg ./ && $rep_add $rep/unstable && $rep_fetch
+
+ +cp -r cfg fetched1
+ +$pkg_fetch libbar/1.0.0+1 -d fetched1 &fetched1/libbar-1.0.0+1.tar.gz
+
+ +cp -r fetched1 fetched2
+ +$pkg_purge -d fetched2 libbar &!fetched2/libbar-1.0.0+1.tar.gz
+ +$pkg_fetch libbar/2.0.0 -d fetched2 &fetched2/libbar-2.0.0.tar.gz
+
+ : not-fetched
+ :
+ $* -d ../cfg libbar >'libbar available 2.0.0 [1.1.0+1] 1.1.0 1.0.0+1 1.0.0'
+
+ : fetched-1
+ :
+ $* -d ../fetched1 libbar >'libbar fetched 1.0.0+1 available 2.0.0 [1.1.0+1] 1.1.0'
+
+ : fetched-2
+ :
+ $* -d ../fetched2 libbar >'libbar fetched 2.0.0'
}
}
- : unstable
+ : git-rep
:
+ if! $git_supported
{
- # Here we, first, prepare 3 configurations that derive from each other, and
- # then spawn 3 tests on them.
+ # Skip git repository tests.
#
- +$clone_cfg ./ && $rep_add $rep/unstable && $rep_fetch
-
- +cp -r cfg fetched1
- +$pkg_fetch libbar/1.0.0+1 -d fetched1 &fetched1/libbar-1.0.0+1.tar.gz
-
- +cp -r fetched1 fetched2
- +$pkg_purge -d fetched2 libbar &!fetched2/libbar-1.0.0+1.tar.gz
- +$pkg_fetch libbar/2.0.0 -d fetched2 &fetched2/libbar-2.0.0.tar.gz
+ }
+ else
+ {
+ rep = "$rep_git/state0"
+ test.cleanups += &cfg/.bpkg/repos/*/***
- : not-fetched
+ : complement-cycle
:
- $* -d ../cfg libbar >'libbar available 2.0.0 [1.1.0+1] 1.1.0 1.0.0+1 1.0.0'
-
- : fetched-1
+ : Make sure that we properly handle the root<->style repository dependency
+ : cycle while searching for the style-basic package, that is an available
+ : package but not from the user-added repository (or its complement), and
+ : so is not detected as buildable by the status command. Note that the root
+ : repository is the default complement for git repositories (see
+ : rep_fetch() implementation for the reasoning).
:
- $* -d ../fetched1 libbar >'libbar fetched 1.0.0+1 available 2.0.0 [1.1.0+1] 1.1.0'
+ $clone_root_cfg;
+ $rep_add "$rep/libbar.git#master" && $rep_add "$rep/style.git#master";
- : fetched-2
- :
- $* -d ../fetched2 libbar >'libbar fetched 2.0.0'
+ $rep_fetch 2>!;
+
+ $* style-basic >~'%style-basic available \[1\.1\.0-a\.0\..+\]%'
}
}
-: git-rep
+: json
:
-if! $git_supported
{
- # Skip git repository tests.
- #
-}
-else
-{
- rep = "$rep_git/state0"
- test.cleanups += &cfg/.bpkg/repos/*/***
+ test.arguments += --stdout-format json
+
+ +$clone_cfg
- : complement-cycle
+ : not-fetched
:
- : Make sure that we properly handle the root<->style repository dependency
- : cycle while searching for the style-basic package, that is an available
- : package but not from the user-added repository (or its complement), and so
- : is not detected as buildable by the status command. Note that the root
- : repository is the default complement for git repositories (see rep_fetch()
- : implementation for the reasoning).
+ {
+ +$clone_cfg
+
+ : libfoo-1.0.0
+ :
+ $clone_cfg;
+ $* libfoo/1.0.0 >>EOO
+ [
+ {
+ "name": "libfoo",
+ "status": "unknown",
+ "version": "1.0.0"
+ }
+ ]
+ EOO
+
+ : libfoo
+ :
+ $clone_cfg;
+ $* libfoo >>EOO
+ [
+ {
+ "name": "libfoo",
+ "status": "unknown"
+ }
+ ]
+ EOO
+ }
+
+ : fetched
:
- $clone_root_cfg;
- $rep_add "$rep/libbar.git#master" && $rep_add "$rep/style.git#master";
+ {
+ +$clone_cfg
- $rep_fetch 2>!;
+ +$rep_add $rep/testing && $rep_fetch
- $* style-basic >~'%style-basic available \[1\.1\.0-a\.0\..+\]%'
+ : recursive
+ :
+ {
+ $clone_cfg;
+
+ $pkg_build libbar;
+
+ $* libbar --recursive --constraint >>EOO;
+ [
+ {
+ "name": "libbar",
+ "status": "configured",
+ "version": "1.1.0",
+ "hold_package": true,
+ "available_versions": [
+ {
+ "version": "1.1.0+1",
+ "dependency": true
+ }
+ ],
+ "dependencies": [
+ {
+ "name": "libbaz",
+ "constraint": "^1.0.0",
+ "status": "configured",
+ "version": "1.0.0"
+ }
+ ]
+ }
+ ]
+ EOO
+
+ $pkg_drop libbar
+ }
+ }
}
diff --git a/tests/pkg-status/testing/libbar-1.0.0+1.tar.gz b/tests/pkg-status/testing/libbar-1.0.0+1.tar.gz
index 9c2d0ed..d38cbbd 100644
--- a/tests/pkg-status/testing/libbar-1.0.0+1.tar.gz
+++ b/tests/pkg-status/testing/libbar-1.0.0+1.tar.gz
Binary files differ
diff --git a/tests/pkg-status/testing/libbar-1.1.0.tar.gz b/tests/pkg-status/testing/libbar-1.1.0.tar.gz
index 6ca773a..a5e060d 100644
--- a/tests/pkg-status/testing/libbar-1.1.0.tar.gz
+++ b/tests/pkg-status/testing/libbar-1.1.0.tar.gz
Binary files differ
diff --git a/tests/pkg-status/testing/libbaz-1.0.0.tar.gz b/tests/pkg-status/testing/libbaz-1.0.0.tar.gz
new file mode 100644
index 0000000..8d4c2f3
--- /dev/null
+++ b/tests/pkg-status/testing/libbaz-1.0.0.tar.gz
Binary files differ