[PATCH setup] Handle '--packages package=version'

Jon Turney jon.turney@dronecode.org.uk
Sun Apr 18 13:34:44 GMT 2021


Handle '--packages package=version' to allow specifing the version of a
package to install on the command line.

isManuallyWanted() now returns the target packageversion (if specified),
or an empty packageversion (which is translated into an instruction to
the solver to choose the version).

In the 'upgrade' case, this changes from using the complex logic of
packagemeta::trustp() to determine the target version, when unspecified
on the command line, to allowing the solver to make that decision (which
should be broadly the same i.e. not downgrading test versions, etc.).

This also subtly changes the behaviour when the package version is not
specified.  Instead of forcing the current version, we allow the solver
to choose the version, so it may not pick that version, if other
constraints exist, which prevent a solution containing that version.

There's probably some future work which can be done to simplify the
remaining uses packagemeta::trustp(), which are only related to the UI.
---
 choose.cc       |  9 ++++---
 package_meta.cc | 71 +++++++++++++++++++++++++++++++++++++++++++++----
 package_meta.h  |  3 ++-
 3 files changed, 73 insertions(+), 10 deletions(-)

diff --git a/choose.cc b/choose.cc
index 4fa0c74..7632bba 100644
--- a/choose.cc
+++ b/choose.cc
@@ -289,7 +289,8 @@ ChooserPage::applyCommandLinePackageSelection()
        i != db.packages.end (); ++i)
     {
       packagemeta &pkg = *(i->second);
-      bool wanted    = pkg.isManuallyWanted();
+      packageversion wanted_version;
+      bool wanted    = pkg.isManuallyWanted(wanted_version);
       bool deleted   = pkg.isManuallyDeleted();
       bool base      = pkg.categories.find ("Base") != pkg.categories.end ();
       bool orphaned  = pkg.categories.find ("Orphaned") != pkg.categories.end ();
@@ -299,15 +300,15 @@ ChooserPage::applyCommandLinePackageSelection()
       bool uninstall = (!(wanted  || base) && (deleted || PruneInstallOption))
 		     || (orphaned && CleanOrphansOption);
       if (install)
-        pkg.set_action (packagemeta::Install_action, UpgradeAlsoOption ? packageversion () : pkg.curr, true);
+        pkg.set_action (packagemeta::Install_action, UpgradeAlsoOption ? packageversion () : wanted_version, true);
       else if (reinstall)
-	pkg.set_action (packagemeta::Reinstall_action, pkg.curr);
+	pkg.set_action (packagemeta::Reinstall_action, !wanted ? pkg.curr : wanted_version);
       else if (uninstall)
 	pkg.set_action (packagemeta::Uninstall_action, packageversion ());
       else if (PruneInstallOption)
 	pkg.set_action (packagemeta::NoChange_action, pkg.curr);
       else if (upgrade)
-	pkg.set_action (packagemeta::Install_action, pkg.trustp(true, TRUST_UNKNOWN));
+	pkg.set_action (packagemeta::Install_action, !wanted ? packageversion () : wanted_version);
       else
 	pkg.set_action (packagemeta::NoChange_action, pkg.installed);
     }
diff --git a/package_meta.cc b/package_meta.cc
index 73239f1..1c6183c 100644
--- a/package_meta.cc
+++ b/package_meta.cc
@@ -214,6 +214,20 @@ packagemeta::add_version (const SolverPool::addPackageData &inpkgdata)
   return thepkg;
 }
 
+const packageversion *
+packagemeta::findVersion(std::string &version) const
+{
+  for (std::set <packageversion>::iterator i = versions.begin();
+       i != versions.end();
+       i++)
+    {
+      if (i->Canonical_version() == version)
+        return &(*i);
+    }
+
+  return NULL;
+}
+
 bool
 packagemeta::isBlacklisted(const packageversion &version) const
 {
@@ -310,10 +324,10 @@ validatePackageNames (std::set<std::string> &names)
     }
 }
 
-bool packagemeta::isManuallyWanted() const
+bool packagemeta::isManuallyWanted(packageversion &version) const
 {
   static bool parsed_yet = false;
-  static std::set<std::string> parsed_names;
+  static std::map<std::string, std::string> parsed_names;
   hasManualSelections |= parsed_names.size ();
   static std::set<std::string> parsed_categories;
   hasManualSelections |= parsed_categories.size ();
@@ -325,12 +339,40 @@ bool packagemeta::isManuallyWanted() const
   {
     std::vector<std::string> packages_options = PackageOption;
     std::vector<std::string> categories_options = CategoryOption;
+
+    std::set<std::string> items;
     for (std::vector<std::string>::iterator n = packages_options.begin ();
 		n != packages_options.end (); ++n)
       {
-	parseNames (parsed_names, *n);
+	parseNames (items, *n);
       }
-    validatePackageNames (parsed_names);
+
+    std::set<std::string> packages;
+    /* Separate any 'package=version' into package and version parts */
+    for (std::set<std::string>::iterator n = items.begin();
+         n != items.end();
+         ++n)
+      {
+        std::string package;
+        std::string version;
+        std::string::size_type loc = n->find ("=", 0);
+        if (loc != std::string::npos)
+          {
+            package = n->substr(0, loc);
+            version = n->substr(loc+1);
+          }
+        else
+          {
+            package = *n;
+            version = "";
+          }
+        Log (LOG_BABBLE) << "package: " << package << " version: " << version << endLog;
+        parsed_names[package] = version;
+        packages.insert(package);
+      }
+
+    validatePackageNames (packages);
+
     for (std::vector<std::string>::iterator n = categories_options.begin ();
 		n != categories_options.end (); ++n)
       {
@@ -341,7 +383,25 @@ bool packagemeta::isManuallyWanted() const
 
   /* Once we've already parsed the option string, just do
     a lookup in the cache of already-parsed names.  */
-  bReturn = parsed_names.find(name) != parsed_names.end();
+  std::map<std::string, std::string>::iterator i = parsed_names.find(name);
+  if (i != parsed_names.end())
+    {
+      bReturn = true;
+
+      /* Wanted version is unspecified */
+      version = packageversion();
+
+      /* ... unless a version was explicitly specified */
+      std::string v = i->second;
+      if (!v.empty())
+        {
+          const packageversion *pv = findVersion(v);
+          if (pv)
+            version = *pv;
+          else
+            Log (LOG_PLAIN) << "package: " << name << " version: " << v << " not found" << endLog;
+        }
+    }
 
   /* If we didn't select the package manually, did we select any
      of the categories it is in? */
@@ -352,6 +412,7 @@ bool packagemeta::isManuallyWanted() const
 	if (parsed_categories.find (*curcat) != parsed_categories.end ())
 	  {
 	    Log (LOG_BABBLE) << "Found category " << *curcat << " in package " << name << endLog;
+	    version = packageversion();
 	    bReturn = true;
 	  }
     }
diff --git a/package_meta.h b/package_meta.h
index 4faff41..fee385b 100644
--- a/package_meta.h
+++ b/package_meta.h
@@ -107,7 +107,7 @@ public:
   std::string name;			/* package name, like "cygwin" */
 
   /* true if package was selected on command-line. */
-  bool isManuallyWanted() const;
+  bool isManuallyWanted(packageversion &version) const;
   /* true if package was deleted on command-line. */
   bool isManuallyDeleted() const;
 
@@ -163,6 +163,7 @@ private:
   std::string trustLabel(packageversion const &) const;
   std::vector <Script> scripts_;
   static bool scan (const packageversion &pkg, bool mirror_mode);
+  const packageversion * findVersion(std::string &version) const;
 
   _actions _action;
 
-- 
2.31.1



More information about the Cygwin-apps mailing list