From 566916d41bbb1c0f57b9f708b37759129bc3fbc4 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Fri, 20 Jan 2023 13:50:18 +0300 Subject: Install binary distribution packages --- bpkg/pkg-build-collect.cxx | 25 +++ bpkg/pkg-build-collect.hxx | 11 +- bpkg/pkg-build.cxx | 391 ++++++++++++++++++++++++++++----------------- bpkg/system-repository.hxx | 2 +- 4 files changed, 281 insertions(+), 148 deletions(-) diff --git a/bpkg/pkg-build-collect.cxx b/bpkg/pkg-build-collect.cxx index 12db3ba..11d1848 100644 --- a/bpkg/pkg-build-collect.cxx +++ b/bpkg/pkg-build-collect.cxx @@ -29,6 +29,31 @@ namespace bpkg { // build_package // + const system_package_status* build_package:: + system_install () const + { + assert (action); + + if (*action != build_package::drop && system) + { + const optional& sys_rep (db.get ().system_repository); + assert (sys_rep); + + if (const system_package* sys_pkg = sys_rep->find (name ())) + { + const system_package_status* s (sys_pkg->system_status); + + return s != nullptr && + (s->status == system_package_status::partially_installed || + s->status == system_package_status::not_installed) + ? s + : nullptr; + } + } + + return nullptr; + } + bool build_package:: user_selection () const { diff --git a/bpkg/pkg-build-collect.hxx b/bpkg/pkg-build-collect.hxx index e47d9fa..f88e3c3 100644 --- a/bpkg/pkg-build-collect.hxx +++ b/bpkg/pkg-build-collect.hxx @@ -19,8 +19,9 @@ #include #include -#include // find_database_function() +#include // find_database_function() #include +#include namespace bpkg { @@ -210,6 +211,14 @@ namespace bpkg // bool system; + // Return the binary distribution package status if this is a system + // package (re-)configuration, the package version has been resolved via + // the system package manager, and the binary distribution package needs + // to be installed. Otherwise, return NULL. So can be used as bool. + // + const system_package_status* + system_install () const; + // If this flag is set and the external package is being replaced with an // external one, then keep its output directory between upgrades and // downgrades. diff --git a/bpkg/pkg-build.cxx b/bpkg/pkg-build.cxx index ca27770..08aa1b0 100644 --- a/bpkg/pkg-build.cxx +++ b/bpkg/pkg-build.cxx @@ -4397,6 +4397,21 @@ namespace bpkg o.plan_specified () || o.rebuild_checksum_specified ()) { + // Map the system package statuses of the binary distribution packages + // that needs to be installed to the system packages which require their + // installation (see build_package::system_install() for details). + // + using sys_installs_map = + map>; + + sys_installs_map sys_installs; + + for (const build_package& p: pkgs) + { + if (const system_package_status* s = p.system_install ()) + sys_installs[s].insert (p.name ()); + } + // Start the transaction since we may query available packages for // skeleton initializations. // @@ -4404,200 +4419,250 @@ namespace bpkg bool first (true); // First entry in the plan. - for (build_package& p: reverse_iterate (pkgs)) + // Print the bpkg package action lines. + // + // Also print the sys_install action lines for system packages which + // require the binary distribution package installation. Print them + // before the respected system package action lines, but only once per + // binary distribution package. For example: + // + // system_install libssl1.1/1.1.1l (required by sys:libssl, sys:libcrypto) + // configure sys:libssl/1.1.1 (required by foo) + // configure sys:libcrypto/1.1.1 (required by bar) + // + for (auto i (pkgs.rbegin ()); i != pkgs.rend (); ) { + build_package& p (*i); assert (p.action); - database& pdb (p.db); - const shared_ptr& sp (p.selected); - string act; - if (*p.action == build_package::drop) + const system_package_status* s; + sys_installs_map::iterator j; + + if ((s = p.system_install ()) != nullptr && + (j = sys_installs.find (s)) != sys_installs.end ()) { - act = "drop " + sp->string (pdb) + " (unused)"; + act = "system_install "; + act += s->system_name; + act += '/'; + act += s->system_version; + act += " (required by "; + + bool first (true); + for (const package_name& n: j->second) + { + if (first) + first = false; + else + act += ", "; + + act += "sys:"; + act += n.string (); + } + + act += ')'; + need_prompt = true; + + // Make sure that we print this system_install action just once. + // + sys_installs.erase (j); } else { - // Print configuration variables. - // - // The idea here is to only print configuration for those packages - // for which we call pkg_configure*() in execute_plan(). - // - package_skeleton* cfg (nullptr); + ++i; - string cause; - if (*p.action == build_package::adjust) - { - assert (sp != nullptr && (p.reconfigure () || p.unhold ())); + database& pdb (p.db); + const shared_ptr& sp (p.selected); - // This is a dependent needing reconfiguration. + if (*p.action == build_package::drop) + { + act = "drop " + sp->string (pdb) + " (unused)"; + need_prompt = true; + } + else + { + // Print configuration variables. // - // This is an implicit reconfiguration which requires the plan to - // be printed. Will flag that later when composing the list of - // prerequisites. + // The idea here is to only print configuration for those packages + // for which we call pkg_configure*() in execute_plan(). // - if (p.reconfigure ()) - { - act = "reconfigure"; - cause = "dependent of"; - - if (!o.configure_only ()) - update_dependents = true; - } + package_skeleton* cfg (nullptr); - // This is a held package needing unhold. - // - if (p.unhold ()) + string cause; + if (*p.action == build_package::adjust) { - if (act.empty ()) - act = "unhold"; - else - act += "/unhold"; - } + assert (sp != nullptr && (p.reconfigure () || p.unhold ())); - act += ' ' + sp->name.string (); - - const string& s (pdb.string); - if (!s.empty ()) - act += ' ' + s; + // This is a dependent needing reconfiguration. + // + // This is an implicit reconfiguration which requires the plan + // to be printed. Will flag that later when composing the list + // of prerequisites. + // + if (p.reconfigure ()) + { + act = "reconfigure"; + cause = "dependent of"; - // This is an adjustment and so there is no available package - // specified for the build package object and thus the skeleton - // cannot be present. - // - assert (p.available == nullptr && !p.skeleton); + if (!o.configure_only ()) + update_dependents = true; + } - // We shouldn't be printing configurations for plain unholds. - // - if (p.reconfigure ()) - { - // Since there is no available package specified we need to find - // it (or create a transient one). + // This is a held package needing unhold. // - cfg = &p.init_skeleton (o, find_available (o, pdb, sp)); - } - } - else - { - assert (p.available != nullptr); // This is a package build. + if (p.unhold ()) + { + if (act.empty ()) + act = "unhold"; + else + act += "/unhold"; + } - // Even if we already have this package selected, we have to - // make sure it is configured and updated. - // - if (sp == nullptr) - { - act = p.system ? "configure" : "new"; + act += ' ' + sp->name.string (); + + const string& s (pdb.string); + if (!s.empty ()) + act += ' ' + s; - // For a new non-system package the skeleton must already be - // initialized. + // This is an adjustment and so there is no available package + // specified for the build package object and thus the skeleton + // cannot be present. // - assert (p.system || p.skeleton.has_value ()); + assert (p.available == nullptr && !p.skeleton); - // Initialize the skeleton if it is not initialized yet. + // We shouldn't be printing configurations for plain unholds. // - cfg = &(p.skeleton ? *p.skeleton : p.init_skeleton (o)); + if (p.reconfigure ()) + { + // Since there is no available package specified we need to + // find it (or create a transient one). + // + cfg = &p.init_skeleton (o, find_available (o, pdb, sp)); + } } - else if (sp->version == p.available_version ()) + else { - // If this package is already configured and is not part of the - // user selection (or we are only configuring), then there is - // nothing we will be explicitly doing with it (it might still - // get updated indirectly as part of the user selection update). + assert (p.available != nullptr); // This is a package build. + + // Even if we already have this package selected, we have to + // make sure it is configured and updated. // - if (!p.reconfigure () && - sp->state == package_state::configured && - (!p.user_selection () || - o.configure_only () || - p.configure_only ())) - continue; + if (sp == nullptr) + { + act = p.system ? "configure" : "new"; - act = p.system - ? "reconfigure" - : (p.reconfigure () - ? (o.configure_only () || p.configure_only () - ? "reconfigure" - : "reconfigure/update") - : "update"); + // For a new non-system package the skeleton must already be + // initialized. + // + assert (p.system || p.skeleton.has_value ()); - if (p.reconfigure ()) - { // Initialize the skeleton if it is not initialized yet. // cfg = &(p.skeleton ? *p.skeleton : p.init_skeleton (o)); } - } - else - { - act = p.system - ? "reconfigure" - : sp->version < p.available_version () - ? "upgrade" - : "downgrade"; - - // For a non-system package up/downgrade the skeleton must - // already be initialized. - // - assert (p.system || p.skeleton.has_value ()); + else if (sp->version == p.available_version ()) + { + // If this package is already configured and is not part of + // the user selection (or we are only configuring), then there + // is nothing we will be explicitly doing with it (it might + // still get updated indirectly as part of the user selection + // update). + // + if (!p.reconfigure () && + sp->state == package_state::configured && + (!p.user_selection () || + o.configure_only () || + p.configure_only ())) + continue; - // Initialize the skeleton if it is not initialized yet. - // - cfg = &(p.skeleton ? *p.skeleton : p.init_skeleton (o)); + act = p.system + ? "reconfigure" + : (p.reconfigure () + ? (o.configure_only () || p.configure_only () + ? "reconfigure" + : "reconfigure/update") + : "update"); - need_prompt = true; - } + if (p.reconfigure ()) + { + // Initialize the skeleton if it is not initialized yet. + // + cfg = &(p.skeleton ? *p.skeleton : p.init_skeleton (o)); + } + } + else + { + act += p.system + ? "reconfigure" + : sp->version < p.available_version () + ? "upgrade" + : "downgrade"; + + // For a non-system package up/downgrade the skeleton must + // already be initialized. + // + assert (p.system || p.skeleton.has_value ()); + + // Initialize the skeleton if it is not initialized yet. + // + cfg = &(p.skeleton ? *p.skeleton : p.init_skeleton (o)); - if (p.unhold ()) - act += "/unhold"; + need_prompt = true; + } - act += ' ' + p.available_name_version_db (); - cause = p.required_by_dependents ? "required by" : "dependent of"; + if (p.unhold ()) + act += "/unhold"; - if (p.configure_only ()) - update_dependents = true; - } + act += ' ' + p.available_name_version_db (); + cause = p.required_by_dependents ? "required by" : "dependent of"; - // Also list dependents for the newly built user-selected - // dependencies. - // - bool us (p.user_selection ()); - string rb; - if (!us || (!p.user_selection (hold_pkgs) && sp == nullptr)) - { - // Note: if we are ever tempted to truncate this, watch out for - // the --rebuild-checksum functionality which uses this. But then - // it's not clear this information is actually important: can a - // dependent-dependency structure change without any of the - // package versions changing? Doesn't feel like it should. + if (p.configure_only ()) + update_dependents = true; + } + + // Also list dependents for the newly built user-selected + // dependencies. // - for (const package_key& pk: p.required_by) + bool us (p.user_selection ()); + string rb; + if (!us || (!p.user_selection (hold_pkgs) && sp == nullptr)) { - // Skip the command-line dependent. + // Note: if we are ever tempted to truncate this, watch out for + // the --rebuild-checksum functionality which uses this. But + // then it's not clear this information is actually important: + // can a dependent-dependency structure change without any of + // the package versions changing? Doesn't feel like it should. + // + for (const package_key& pk: p.required_by) + { + // Skip the command-line dependent. + // + if (!pk.name.empty ()) + rb += (rb.empty () ? " " : ", ") + pk.string (); + } + + // If not user-selected, then there should be another (implicit) + // reason for the action. // - if (!pk.name.empty ()) - rb += (rb.empty () ? " " : ", ") + pk.string (); + assert (!rb.empty ()); } - // If not user-selected, then there should be another (implicit) - // reason for the action. - // - assert (!rb.empty ()); - } + if (!rb.empty ()) + act += " (" + cause + rb + ')'; - if (!rb.empty ()) - act += " (" + cause + rb + ')'; + if (cfg != nullptr && !cfg->empty_print ()) + { + ostringstream os; + cfg->print_config (os, o.print_only () ? " " : " "); + act += '\n'; + act += os.str (); + } - if (cfg != nullptr && !cfg->empty_print ()) - { - ostringstream os; - cfg->print_config (os, o.print_only () ? " " : " "); - act += '\n'; - act += os.str (); + if (!us) + need_prompt = true; } - - if (!us) - need_prompt = true; } if (first) @@ -4773,6 +4838,40 @@ namespace bpkg size_t prog_i, prog_n, prog_percent; + // system_install + // + // Install the binary distribution packages required by the respective + // system packages (see build_package::system_install() for details). + // + if (!simulate) + { + // Collect the names of the system packages which require installation + // of the binary distribution packages, suppressing duplicates. + // + vector install_pkgs; + + for (build_package& p: build_pkgs) + { + if (p.system_install ()) + { + if (find (install_pkgs.begin (), install_pkgs.end (), p.name ()) != + install_pkgs.end ()) + install_pkgs.push_back (p.name ()); + } + } + + // Install the binary distribution packages, if any. + // + if (!install_pkgs.empty ()) + { + // Otherwise, we wouldn't get any package statuses. + // + assert (sys_pkg_mgr && *sys_pkg_mgr != nullptr); + + (*sys_pkg_mgr)->pkg_install (install_pkgs); + } + } + // disfigure // // Note: similar code in pkg-drop. diff --git a/bpkg/system-repository.hxx b/bpkg/system-repository.hxx index 8171a0c..31e14d1 100644 --- a/bpkg/system-repository.hxx +++ b/bpkg/system-repository.hxx @@ -50,7 +50,7 @@ namespace bpkg const system_package_status* = nullptr); const system_package* - find (const package_name& name) + find (const package_name& name) const { auto i (map_.find (name)); return i != map_.end () ? &i->second : nullptr; -- cgit v1.1