From 36026ec0a05d74776114ddf5aee096fbda9bc7ee Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 16 Mar 2018 14:25:17 +0200 Subject: Redo pkg-status output --- bpkg/package.cxx | 12 ++-- bpkg/package.hxx | 5 ++ bpkg/pkg-status.cli | 97 ++++++++++++++++--------- bpkg/pkg-status.cxx | 202 ++++++++++++++++++++++++++++++++-------------------- 4 files changed, 198 insertions(+), 118 deletions(-) (limited to 'bpkg') diff --git a/bpkg/package.cxx b/bpkg/package.cxx index 966be72..da862ef 100644 --- a/bpkg/package.cxx +++ b/bpkg/package.cxx @@ -104,10 +104,10 @@ namespace bpkg return nullptr; } - static inline shared_ptr - find (const shared_ptr& r, - const shared_ptr& ap, - bool prereq) + shared_ptr + filter (const shared_ptr& r, + const shared_ptr& ap, + bool prereq) { repositories chain; return find (r, ap, chain, prereq); @@ -122,7 +122,7 @@ namespace bpkg for (shared_ptr ap: pointer_result (apr)) { - if (find (r, ap, prereq) != nullptr) + if (filter (r, ap, prereq) != nullptr) aps.push_back (move (ap)); } @@ -138,7 +138,7 @@ namespace bpkg for (shared_ptr ap: pointer_result (apr)) { - if (shared_ptr pr = find (r, ap, prereq)) + if (shared_ptr pr = filter (r, ap, prereq)) return result (move (ap), move (pr)); } diff --git a/bpkg/package.hxx b/bpkg/package.hxx index 8c714c4..58338bd 100644 --- a/bpkg/package.hxx +++ b/bpkg/package.hxx @@ -499,6 +499,11 @@ namespace bpkg odb::result&&, bool prereq = true); + shared_ptr + filter (const shared_ptr&, + const shared_ptr&, + bool prereq = true); + // package_state // enum class package_state diff --git a/bpkg/pkg-status.cli b/bpkg/pkg-status.cli index 6157c4d..09c6b2c 100644 --- a/bpkg/pkg-status.cli +++ b/bpkg/pkg-status.cli @@ -32,11 +32,11 @@ namespace bpkg respectively. Note that the status is written to \cb{STDOUT}, not \cb{STDERR}. - The status output format is regular. If several packages were specified, - then each line starts with the package name (and version, if specified) - followed by '\cb{:}'. Then comes one of the status words listed below. - Some of them can be optionally followed by '\cb{,}' (no spaces) and a - sub-status word. + The status output format is regular with components separated with + spaces. Each line starts with the package name (and version, if + specified) 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. \dl| @@ -73,58 +73,65 @@ namespace bpkg If only the package name was specified without the package version, then the \cb{available} status word is followed by the list of available - versions. The last version on this list may have the \cb{sys:} prefix - indicating an available system version. Such a system version may be - the special '\cb{?}' value indicating that a package may or may not - be available from the system and its version is unknown. + versions. If the \cb{--system} option is specified, then the last version + in this list may have the \cb{sys:} prefix indicating an available system + version. Such a system version may be the special '\cb{?}' value + indicating that a package may or may not be available from the system and + that its version is unknown. Similarly, if only the package name was specified, then the \cb{fetched}, \cb{unpacked}, \cb{configured}, and \cb{broken} status words are followed - by the version of the package. After the package version, these status - words may be followed by one or more sub-status words. Currently, these - can be \cb{hold_package} (package should not be automatically dropped) and - \cb{hold_version} (package should not be automatically upgraded). Finally, - if only the package name was specified and newer versions are available - from some of the repositories, then the sub-status word is followed - by '\cb{;}', the \cb{available} status word, and the list of newer - versions. + by the version of the package. If newer versions are available, then the + package version is followed by the \cb{available} status word and the + list of newer versions. + + If the package name was specified with the version, then only the status + (such as, \cb{configured}, \cb{available}, etc.) of this version is + printed. + + If a package is being held, then its name is printed prefixed with + '\cb{!}'. Similarly, if a package version is being held, then the version + is printed prefixed with '\cb{!}'. Held packages and held versions were + selected by the user and are not automatically dropped and upgraded, + respectively. Below are some examples, assuming the configuration has \cb{libfoo} - \cb{1.0.0} configured and held as well as \cb{libfoo} \cb{1.1.0} and - \cb{1.1.1} available from source and \cb{1.1.0} from the system. + \cb{1.0.0} configured and held (both package and version) as well as + \cb{libfoo} \cb{1.1.0} and \cb{1.1.1} available from source and + \cb{1.1.0} from the system. \ bpkg status libbar - unknown + libbar unknown bpkg status libbar/1.0.0 - unknown + libbar/1.0.0 unknown bpkg status libfoo/1.0.0 - configured hold_package + !libfoo/1.0.0 configured !1.0.0 bpkg status libfoo/1.1.0 - available 1.1.0 sys:1.1.0 + libfoo/1.1.0 available 1.1.0 - bpkg status libfoo/1.1.1 - available + bpkg status --system libfoo/1.1.0 + libfoo/1.1.0 available 1.1.0 sys:1.1.0 bpkg status libfoo - configured 1.0.0 hold_package; available 1.1.0 1.1.1 sys:1.1.0 + !libfoo configured !1.0.0 available 1.1.0 1.1.1 - bpkg status libfoo/1.0.0 libbar - libfoo/1.0.0: configured hold_package - libbar: unknown + bpkg status libfoo/1.1.1 libbar + libfoo/1.1.1 available 1.1.1 + libbar unknown \ Assuming now that we dropped \cb{libfoo} from the configuration: \ bpkg status libfoo/1.0.0 - unknown + libfoo/1.0.0 unknown bpkg status libfoo - available 1.1.0 1.1.1 sys:1.1.0 + libfoo available 1.1.0 1.1.1 \ And assuming now that we built \cb{libfoo} as a system package with @@ -132,8 +139,7 @@ namespace bpkg \ bpkg status libfoo - configured,system * hold_package; available 1.1.0 1.1.1 sys:1.1.0 - unknown + !libfoo configured,system * available 1.1.0 1.1.1 \ " @@ -152,5 +158,30 @@ namespace bpkg { "Also print the status of all dependencies, recursively." } + + bool --constraint + { + "Print version constraints for dependencies." + } + + bool --system + { + "Check the availability of packages from the system." + } + + bool --no-hold + { + "Don't print the package or version hold status." + } + + bool --no-hold-package + { + "Don't print the package hold status." + } + + bool --no-hold-version + { + "Don't print the version hold status." + } }; } diff --git a/bpkg/pkg-status.cxx b/bpkg/pkg-status.cxx index e5144ca..a93322e 100644 --- a/bpkg/pkg-status.cxx +++ b/bpkg/pkg-status.cxx @@ -19,19 +19,20 @@ namespace bpkg { struct package { - string name; - bpkg::version version; // Empty if unspecified. - shared_ptr selected; // NULL if none selected. + string name; + bpkg::version version; // Empty if unspecified. + shared_ptr selected; // NULL if none selected. + optional constraint; // Version constraint, if any. }; using packages = vector; - // If single is true, then omit the package name. If recursive or immediate - // is true, then print status for dependencies indented by two spaces. + // If recursive or immediate is true, then print status for dependencies + // indented by two spaces. // static void - pkg_status (database& db, + pkg_status (const pkg_status_options& o, + database& db, const packages& pkgs, - bool single, string& indent, bool recursive, bool immediate) @@ -42,21 +43,41 @@ namespace bpkg { l4 ([&]{trace << "package " << p.name << "; version " << p.version;}); + // Can't be both. + // + assert (p.version.empty () || !p.constraint); + + const shared_ptr& s (p.selected); + // Look for available packages. // - bool available; // At least one vailable package (stub or not). - vector> apkgs; + // Some of them are only available to upgrade/downgrade as dependencies. + // + struct apkg + { + shared_ptr package; + bool build; + }; + vector apkgs; + + // A package with this name is known in available packages potentially + // for build. + // + bool known (false); + bool build (false); { shared_ptr rep (db.load ("")); // Root. using query = query; query q (query::id.name == p.name); + { + auto r (db.query (q)); + known = !r.empty (); + build = filter_one (rep, move (r)).first != nullptr; + } - available = - filter_one (rep, db.query (q)).first != nullptr; - - if (available) + if (known) { // If the user specified the version, then only look for that // specific version (we still do it since there might be other @@ -69,103 +90,127 @@ namespace bpkg false); // And if we found an existing package, then only look for versions - // greater than what already exists. Note that for a system wildcard - // version we will always show all available versions (since it's - // 0). + // greater than to what already exists. Note that for a system + // wildcard version we will always show all available versions + // (since it's 0). // - if (p.selected != nullptr) - q = q && query::id.version > p.selected->version; + if (s != nullptr) + q = q && query::id.version > s->version; q += order_by_version_desc (query::id.version); - // Only consider packages that are in repositories that were - // explicitly added to the configuration and their complements, - // recursively. + // Packages that are in repositories that were explicitly added to + // the configuration and their complements, recursively, are also + // available to build. // - apkgs = filter (rep, db.query (q)); + for (shared_ptr ap: + pointer_result ( + db.query (q))) + { + bool build (filter (rep, ap)); + apkgs.push_back (apkg {move (ap), build}); + } } } cout << indent; - // Suppress printing the package name if there is only one and it was - // specified by the user. + // Selected. + // + + // Hold package status. // - if (!single || immediate || recursive) + if (s != nullptr) { - cout << p.name; + if (s->hold_package && !o.no_hold () && !o.no_hold_package ()) + cout << '!'; + } - if (!p.version.empty ()) - cout << '/' << p.version; + cout << p.name; - cout << ": "; - } + if (o.constraint () && p.constraint) + cout << ' ' << *p.constraint; - bool found (false); + cout << ' '; - if (const shared_ptr& s = p.selected) + if (s != nullptr) { cout << s->state; if (s->substate != package_substate::none) cout << ',' << s->substate; - // Also print the version of the package unless the user specified it. - // - if (p.version != s->version) - cout << ' ' << s->version_string (); - - if (s->hold_package) - cout << " hold_package"; + cout << ' '; - if (s->hold_version) - cout << " hold_version"; + if (s->hold_version && !o.no_hold () && !o.no_hold_version ()) + cout << '!'; - found = true; + cout << s->version_string (); } - if (available) + // Available. + // + bool available (false); + if (known) { - cout << (found ? "; " : "") << "available"; - + // 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" but only if no version was specified by + // 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. // - bool sys (p.version.empty ()); + string sys; + if (o.system ()) + { + sys = "?"; + available = true; + } - if (!apkgs.empty ()) + // Get rid of stubs. + // + for (auto i (apkgs.begin ()); i != apkgs.end (); ++i) { - // If the user specified the version, then there might only be one - // entry in which case it is useless to repeat it. But we do want - // to print it if there is also a system one. - // - if (sys || - p.version.empty () || - apkgs.size () > 1 || - p.version != apkgs[0]->version) + if (i->package->stub ()) { - for (const shared_ptr& a: apkgs) - { - if (a->stub ()) - break; // All the rest are stubs so bail out. - - cout << ' ' << a->version; - } + // All the rest are stubs so bail out. + // + apkgs.erase (i, apkgs.end ()); + break; } - } - if (sys) - cout << " sys:?"; + available = true; + } - found = true; + if (available) + { + cout << (s != nullptr ? " " : "") << "available"; + + for (const apkg& a: apkgs) + cout << ' ' + << (a.build ? "" : "[") + << a.package->version + << (a.build ? "" : "]"); + + if (!sys.empty ()) + cout << ' ' + << (build ? "" : "[") + << "sys:" << sys + << (build ? "" : "]"); + } } - if (!found) + if (s == nullptr && !available) + { cout << "unknown"; + // Print the user's version if specified. + // + if (!p.version.empty ()) + cout << ' ' << p.version; + } + cout << endl; if (recursive || immediate) @@ -173,21 +218,22 @@ namespace bpkg // Collect and recurse. // packages dpkgs; - if (p.selected != nullptr) + if (s != nullptr) { - for (const auto& pair: p.selected->prerequisites) + for (const auto& pair: s->prerequisites) { shared_ptr d (pair.first.load ()); - dpkgs.push_back (package {d->name, version (), move (d)}); + const optional& c (pair.second); + dpkgs.push_back (package {d->name, version (), move (d), c}); } } if (!dpkgs.empty ()) { indent += " "; - pkg_status (db, + pkg_status (o, + db, dpkgs, - false /* single */, indent, recursive, false /* immediate */); @@ -213,7 +259,6 @@ namespace bpkg session s; packages pkgs; - bool single (false); // True if single package specified by the user. { using query = query; @@ -224,7 +269,8 @@ namespace bpkg const char* arg (args.next ()); package p {parse_package_name (arg), parse_package_version (arg), - nullptr}; + nullptr /* selected */, + nullopt /* constraint */}; // Search in the packages that already exist in this configuration. // @@ -242,8 +288,6 @@ namespace bpkg pkgs.push_back (move (p)); } - - single = (pkgs.size () == 1); } else { @@ -253,7 +297,7 @@ namespace bpkg pointer_result ( db.query (query::hold_package))) { - pkgs.push_back (package {s->name, version (), move (s)}); + pkgs.push_back (package {s->name, version (), move (s), nullopt}); } if (pkgs.empty ()) @@ -265,7 +309,7 @@ namespace bpkg } string indent; - pkg_status (db, pkgs, single, indent, o.recursive (), o.immediate ()); + pkg_status (o, db, pkgs, indent, o.recursive (), o.immediate ()); t.commit (); return 0; -- cgit v1.1