15234 "pkg list -a" doesn't account for pattern versions in137
authorShawn Walker <shawn.walker@oracle.com>
Thu, 08 Apr 2010 17:17:41 -0500
changeset 1853 8f8a90301844
parent 1852 6c7b97cd50d9
child 1854 545154d9edff
15234 "pkg list -a" doesn't account for pattern versions
src/client.py
src/man/pkg.1.txt
src/modules/client/api.py
src/tests/api/t_api_list.py
--- a/src/client.py	Thu Apr 08 14:10:41 2010 -0700
+++ b/src/client.py	Thu Apr 08 17:17:41 2010 -0500
@@ -522,17 +522,17 @@
                         return EXIT_OOPS
 
                 if pkg_list == api.ImageInterface.LIST_ALL:
-                        state = _("known")
+                        error(_("no packages matching '%s' known") % \
+                            ", ".join(e.notfound), cmd="list")
                 elif pkg_list == api.ImageInterface.LIST_INSTALLED_NEWEST:
-                        state = _("known or installed")
+                        error(_("no packages matching '%s' allowed by "
+                            "installed incorporations or image variants that "
+                            "are known or installed") % \
+                            ", ".join(e.notfound), cmd="list")
+                        logger.error("Use -af to allow all versions.")
                 else:
-                        state = _("installed")
-
-                if e.notfound:
-                        error(_("no packages matching "
-                            "'%(pattern)s' %(state)s") % {
-                            "pattern": ", ".join(e.notfound),
-                            "state": state }, cmd="list")
+                        error(_("no packages matching '%s' installed") % \
+                            ", ".join(e.notfound), cmd="list")
 
                 if found and e.notfound:
                         # Only some patterns matched.
--- a/src/man/pkg.1.txt	Thu Apr 08 14:10:41 2010 -0700
+++ b/src/man/pkg.1.txt	Thu Apr 08 17:17:41 2010 -0500
@@ -431,12 +431,18 @@
           With -H, omit the headers from the listing.
 
           With -a, list installed packages and the newest version of
-          packages that are not installed and are available for
-          installation; without -a, list only installed packages.
+          packages that are available for installation.  Packages are
+          considered to be available for installation if they are
+          allowed by the installed incorporations and by the image's
+          variants.  If one or more patterns are specified, then the
+          newest version matching the specified pattern and is also
+          allowed by any installed incorporations and the image's
+          variants will be listed.  Without -a, list only installed
+          packages.
 
-          With -f, include all versions of all packages for all variants
-          regardless of installed state.  This option may only be used
-          with -a.
+          With -f and -a, list all versions of all packages for all
+          variants regardless of incorporation constraints or installed
+          state.
 
           With -n, display the newest versions of all known packages,
           regardless of installed state.
--- a/src/modules/client/api.py	Thu Apr 08 14:10:41 2010 -0700
+++ b/src/modules/client/api.py	Thu Apr 08 17:17:41 2010 -0500
@@ -30,6 +30,7 @@
 
 Refer to pkg.api_common for additional core class documentation."""
 
+import collections
 import copy
 import errno
 import fnmatch
@@ -1176,7 +1177,7 @@
 
                 # Keep track of listed stems for all other packages on a
                 # per-publisher basis.
-                nlist = set()
+                nlist = collections.defaultdict(int)
 
                 def check_state(t, entry):
                         states = entry["metadata"]["states"]
@@ -1243,7 +1244,7 @@
                                         return True
                                 return False
 
-                        pkg_stem = pub + "!" + stem
+                        pkg_stem = "!".join((pub, stem))
                         if pkg_stem in nlist:
                                 # A newer version has already been listed for
                                 # this stem and publisher.
@@ -1332,9 +1333,8 @@
                                                 # Package is for zones only.
                                                 omit_package = True
 
-                        if filter_cb is not None:
-                                pkg_stem = pub + "!" + stem
-                                nlist.add(pkg_stem)
+                        pkg_stem = "!".join((pub, stem))
+                        nlist[pkg_stem] += 1
 
                         if not pkgi and pkgr and stem in inc_vers:
                                 # If the package is not installed, but this is
@@ -1354,6 +1354,7 @@
                         # Pattern filtering has to be applied last so that
                         # renames, incorporations, and everything else is
                         # handled correctly.
+                        omit_ver = False
                         if not omit_package:
                                 for pat in patterns:
                                         (pat_pub, pat_stem, pat_ver), matcher = \
@@ -1389,6 +1390,7 @@
                                                 if not ever.is_successor(pat_ver,
                                                     pkg.version.CONSTRAINT_AUTO):
                                                         omit_package = True
+                                                        omit_ver = True
                                                         continue
 
                                         # If this entry matched at least one
@@ -1397,6 +1399,15 @@
                                         break
 
                         if omit_package:
+                                if filter_cb is not None and omit_ver and \
+                                    nlist[pkg_stem] == 1:
+                                        # If omitting because of version, and
+                                        # no other versions have been returned
+                                        # yet for this stem, then discard
+                                        # tracking entry so that other
+                                        # versions will be listed.
+                                        del nlist[pkg_stem]
+                                        slist.discard(stem)
                                 continue
 
                         if cats is not None:
--- a/src/tests/api/t_api_list.py	Thu Apr 08 14:10:41 2010 -0700
+++ b/src/tests/api/t_api_list.py	Thu Apr 08 17:17:41 2010 -0500
@@ -628,7 +628,6 @@
                 self.assertEqual(len(returned), 10)
                 self.assertPrettyEqual(returned, expected)
 
-
                 # Re-test, including variants.
                 returned = self.__get_returned(api_obj.LIST_INSTALLED_NEWEST,
                     api_obj=api_obj, variants=True)
@@ -656,13 +655,10 @@
                         "1.0,5.11"),
                     self.__get_exp_pub_entry("test1", 16, "quux", "1.0,5.11",
                         installed=True),
-#                    self.__get_exp_pub_entry("test1", 18, "qux", "1.0,5.11",
-#                        installed=True),
                 ]
                 self.assertEqual(len(returned), 12)
                 self.assertPrettyEqual(returned, expected)
 
-
                 # Verify results of LIST_INSTALLED_NEWEST when not including
                 # the publisher of installed packages.
                 returned = self.__get_returned(api_obj.LIST_INSTALLED_NEWEST,
@@ -743,8 +739,7 @@
 
                 # Verify the results for LIST_INSTALLED_NEWEST after
                 # all packages have been uninstalled.
-                api_obj.plan_uninstall(["entire", "apple",
-                    "grault"], False)
+                api_obj.plan_uninstall(["*"], False)
                 api_obj.prepare()
                 api_obj.execute_plan()
                 api_obj.reset()
@@ -813,6 +808,42 @@
                 self.assertPrettyEqual(returned, expected)
                 self.assertEqual(len(returned), 18)
 
+                # Re-test, including only a specific package version, which
+                # should show the requested versions even though newer
+                # versions are available.  'baz' should be omitted because
+                # it doesn't apply to the current image variants.
+                returned = self.__get_returned(api_obj.LIST_INSTALLED_NEWEST,
+                    api_obj=api_obj, patterns=["[email protected],5.11.0", "baz",
+                        "[email protected]"])
+
+                expected = [
+                    self.__get_exp_pub_entry("test1", 1, "apple", "1.0,5.11-0"),
+                    self.__get_exp_pub_entry("test2", 1, "apple", "1.0,5.11-0"),
+                    self.__get_exp_pub_entry("test1", 17, "qux", "0.9,5.11"),
+                    self.__get_exp_pub_entry("test2", 17, "qux", "0.9,5.11"),
+                ]
+                self.assertPrettyEqual(returned, expected)
+                self.assertEqual(len(returned), 4)
+
+                # Re-test, including only a specific package version, which
+                # should show the requested versions even though newer
+                # versions are available, and all variants.  'baz' should be
+                # included this time.
+                returned = self.__get_returned(api_obj.LIST_INSTALLED_NEWEST,
+                    api_obj=api_obj, patterns=["[email protected],5.11.0", "baz",
+                        "[email protected]"], variants=True)
+
+                expected = [
+                    self.__get_exp_pub_entry("test1", 1, "apple", "1.0,5.11-0"),
+                    self.__get_exp_pub_entry("test2", 1, "apple", "1.0,5.11-0"),
+                    self.__get_exp_pub_entry("test1", 10, "baz", "1.3,5.11"),
+                    self.__get_exp_pub_entry("test2", 10, "baz", "1.3,5.11"),
+                    self.__get_exp_pub_entry("test1", 17, "qux", "0.9,5.11"),
+                    self.__get_exp_pub_entry("test2", 17, "qux", "0.9,5.11"),
+                ]
+                self.assertPrettyEqual(returned, expected)
+                self.assertEqual(len(returned), 6)
+
                 # Test results after installing packages and only listing the
                 # installed packages.
                 af = self.__get_pub_entry("test1", 1, "apple", "1.0,5.11-0")[0]
@@ -863,6 +894,18 @@
                 self.assertPrettyEqual(returned, expected)
                 self.assertEqual(len(returned), 9)
 
+                # Re-test last but specify patterns for versions newer than
+                # what is installed; nothing should be returned as
+                # LIST_INSTALLED_NEWEST is supposed to omit versions newer
+                # than what is installed, allowed by installed incorporations,
+                # or doesn't apply to image variants.
+                returned = self.__get_returned(api_obj.LIST_INSTALLED_NEWEST,
+                    api_obj=api_obj, patterns=["[email protected],5.11-1",
+                        "[email protected]", "[email protected]"])
+                expected = []
+                self.assertPrettyEqual(returned, expected)
+                self.assertEqual(len(returned), 0)
+
                 # Remove corge, install grault, retest for
                 # LIST_INSTALLED_NEWEST.  corge, grault, qux, and
                 # quux should be listed since none of them are
@@ -957,6 +1000,26 @@
                 self.assertPrettyEqual(returned, expected)
                 self.assertEqual(len(returned), 11)
 
+                # Re-test, specifying versions older than the newest, with
+                # some older than that allowed by the incorporation (should
+                # be omitted) and with versions allowed by the incorporation
+                # (should be returned).
+                returned = self.__get_returned(api_obj.LIST_INSTALLED_NEWEST,
+                    api_obj=api_obj, patterns=["[email protected],5.11-0", "[email protected]"])
+
+                expected = [
+                    self.__get_exp_pub_entry("test1", 3, "apple",
+                        "1.2.0,5.11-0"),
+                ]
+                self.assertPrettyEqual(returned, expected)
+                self.assertEqual(len(returned), 1)
+
+                # Re-test, specifying versions newer than that allowed by the
+                # incorporation.
+                returned = self.__get_returned(api_obj.LIST_INSTALLED_NEWEST,
+                    api_obj=api_obj, patterns=["[email protected],5.11-1"])
+                self.assertEqual(len(returned), 0)
+
                 # Re-test, only including test1's packages.
                 returned = self.__get_returned(api_obj.LIST_INSTALLED_NEWEST,
                     api_obj=api_obj, pubs=["test1"])