From 546391dab6173660acceba6404136e9411ce1388 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 1 Feb 2023 11:42:31 +0200 Subject: Implement system package manager query and install support for Debian --- bpkg/system-package-manager-debian.test.cxx | 348 ++++++++++++++++++++++++++++ 1 file changed, 348 insertions(+) create mode 100644 bpkg/system-package-manager-debian.test.cxx (limited to 'bpkg/system-package-manager-debian.test.cxx') diff --git a/bpkg/system-package-manager-debian.test.cxx b/bpkg/system-package-manager-debian.test.cxx new file mode 100644 index 0000000..a033400 --- /dev/null +++ b/bpkg/system-package-manager-debian.test.cxx @@ -0,0 +1,348 @@ +// file : bpkg/system-package-manager-debian.test.cxx -*- C++ -*- +// license : MIT; see accompanying LICENSE file + +#include + +#include +#include + +#include +#include + +#undef NDEBUG +#include + +#include + +using namespace std; + +namespace bpkg +{ + using package_status = system_package_status_debian; + using package_policy = package_status::package_policy; + + using butl::manifest_parser; + using butl::manifest_parsing; + + // Usage: args[0] ... + // + // Where is one of: + // + // apt-cache-policy ... result comes from stdin + // + // apt-cache-show result comes from stdin + // + // parse-name-value debian-name value from stdin + // + // main-from-dev depends comes from stdin + // + // build ... [--install [--no-fetch] ...] + // + // The stdin of the build command is used to read the simulation description + // which consists of lines in the following forms (blanks are ignored): + // + // manifest: + // + // Available package manifest for one of . If none is + // specified, then a stub is automatically added. + // + // apt-cache-policy[-{fetched,installed}]: ... + // + // Values for simulation::apt_cache_policy_*. If is the special `!` + // value, then make the entry empty. + // + // apt-cache-show[-fetched]: + // + // Values for simulation::apt_cache_show_*. If is the special `!` + // value, then make the entry empty. + // + // apt-get-update-fail: true + // apt-get-install-fail: true + // + // Values for simulation::apt_get_{update,install}_fail_. + // + int + main (int argc, char* argv[]) + try + { + assert (argc >= 2); // + + string cmd (argv[1]); + + // @@ TODO: add option to customize? Maybe option before command? + // + os_release osr {"debian", {}, "10", "", "Debian", "", ""}; + + if (cmd == "apt-cache-policy") + { + assert (argc >= 3); // ... + + strings key; + vector pps; + for (int i (2); i != argc; ++i) + { + key.push_back (argv[i]); + pps.push_back (package_policy (argv[i])); + } + + system_package_manager_debian::simulation s; + s.apt_cache_policy_.emplace (move (key), path ("-")); + + system_package_manager_debian m (move (osr), + host_triplet, + false /* install */, + false /* fetch */, + nullopt /* progress */, + false /* yes */, + "sudo"); + m.simulate_ = &s; + + m.apt_cache_policy (pps); + + for (const package_policy& pp: pps) + { + cout << pp.name << " '" + << pp.installed_version << "' '" + << pp.candidate_version << "'\n"; + } + } + else if (cmd == "apt-cache-show") + { + assert (argc == 4); // + + pair key (argv[2], argv[3]); + + system_package_manager_debian::simulation s; + s.apt_cache_show_.emplace (key, path ("-")); + + system_package_manager_debian m (move (osr), + host_triplet, + false /* install */, + false /* fetch */, + nullopt /* progress */, + false /* yes */, + "sudo"); + m.simulate_ = &s; + + cout << m.apt_cache_show (key.first, key.second) << '\n'; + } + else if (cmd == "parse-name-value") + { + assert (argc == 3); // + + package_name pn (argv[2]); + + string v; + getline (cin, v); + + package_status s ( + system_package_manager_debian::parse_name_value (pn, v, false, false)); + + if (!s.main.empty ()) cout << "main: " << s.main << '\n'; + if (!s.dev.empty ()) cout << "dev: " << s.dev << '\n'; + if (!s.doc.empty ()) cout << "doc: " << s.doc << '\n'; + if (!s.dbg.empty ()) cout << "dbg: " << s.dbg << '\n'; + if (!s.common.empty ()) cout << "common: " << s.common << '\n'; + if (!s.extras.empty ()) + { + cout << "extras:"; + for (const string& e: s.extras) + cout << ' ' << e; + cout << '\n'; + } + } + else if (cmd == "main-from-dev") + { + assert (argc == 4); // + + string n (argv[2]); + string v (argv[3]); + string d; + getline (cin, d); + + cout << system_package_manager_debian::main_from_dev (n, v, d) << '\n'; + } + else if (cmd == "build") + { + assert (argc >= 3); // ... + + strings qps; + map aps; + + // Parse ... + // + int argi (2); + for (; argi != argc; ++argi) + { + string a (argv[argi]); + + if (a.compare (0, 2, "--") == 0) + break; + + aps.emplace (a, available_packages {}); + qps.push_back (move (a)); + } + + // Parse --install [--no-fetch] + // + bool install (false); + bool fetch (true); + + for (; argi != argc; ++argi) + { + string a (argv[argi]); + + if (a == "--install") install = true; + else if (a == "--no-fetch") fetch = false; + else break; + } + + // Parse the description. + // + system_package_manager_debian::simulation s; + + for (string l; !eof (getline (cin, l)); ) + { + if (l.empty ()) + continue; + + size_t p (l.find (':')); assert (p != string::npos); + string k (l, 0, p); + + if (k == "manifest") + { + size_t q (l.rfind (' ')); assert (q != string::npos); + string n (l, p + 2, q - p - 2); trim (n); + string f (l, q + 1); trim (f); + + auto i (aps.find (n)); + if (i == aps.end ()) + fail << "unknown package " << n << " in '" << l << "'"; + + i->second.push_back (make_available_from_manifest (n, f)); + } + else if ( + map* policy = + k == "apt-cache-policy" ? &s.apt_cache_policy_ : + k == "apt-cache-policy-fetched" ? &s.apt_cache_policy_fetched_ : + k == "apt-cache-policy-installed" ? &s.apt_cache_policy_installed_ : + nullptr) + { + size_t q (l.rfind (' ')); assert (q != string::npos); + string n (l, p + 2, q - p - 2); trim (n); + string f (l, q + 1); trim (f); + + strings ns; + for (size_t b (0), e (0); next_word (n, b, e); ) + ns.push_back (string (n, b, e - b)); + + if (f == "!") + f.clear (); + + policy->emplace (move (ns), path (move (f))); + } + else if (map, path>* show = + k == "apt-cache-show" ? &s.apt_cache_show_ : + k == "apt-cache-show-fetched" ? &s.apt_cache_show_fetched_ : + nullptr) + { + size_t q (l.rfind (' ')); assert (q != string::npos); + string n (l, p + 2, q - p - 2); trim (n); + string f (l, q + 1); trim (f); + + q = n.find (' '); assert (q != string::npos); + pair nv (string (n, 0, q), string (n, q + 1)); + trim (nv.second); + + if (f == "!") + f.clear (); + + show->emplace (move (nv), path (move (f))); + } + else if (k == "apt-get-update-fail") + { + s.apt_get_update_fail_ = true; + } + else if (k == "apt-get-install-fail") + { + s.apt_get_install_fail_ = true; + } + else + fail << "unknown keyword '" << k << "' in simulation description"; + } + + // Fallback to stubs and sort in the version descending order. + // + for (pair& p: aps) + { + if (p.second.empty ()) + p.second.push_back (make_available_stub (p.first)); + + sort_available (p.second); + } + + system_package_manager_debian m (move (osr), + host_triplet, + install, + fetch, + nullopt /* progress */, + false /* yes */, + "sudo"); + m.simulate_ = &s; + + // Query each package. + // + for (const string& n: qps) + { + package_name pn (n); + + const system_package_status* s (*m.pkg_status (pn, &aps[n])); + + assert (*m.pkg_status (pn, nullptr) == s); // Test caching. + + if (s == nullptr) + fail << "no installed " << (install ? "or available " : "") + << "system package for " << pn; + + cout << pn << ' ' << s->version + << " (" << s->system_name << ' ' << s->system_version << ") "; + + switch (s->status) + { + case package_status::installed: cout << "installed"; break; + case package_status::partially_installed: cout << "part installed"; break; + case package_status::not_installed: cout << "not installed"; break; + } + + cout << '\n'; + } + + // Install if requested. + // + if (install) + { + assert (argi != argc); // ... + + vector ips; + for (; argi != argc; ++argi) + ips.push_back (package_name (argv[argi])); + + m.pkg_install (ips); + } + } + else + fail << "unknown command '" << cmd << "'"; + + return 0; + } + catch (const failed&) + { + return 1; + } +} + +int +main (int argc, char* argv[]) +{ + return bpkg::main (argc, argv); +} -- cgit v1.1