738 "install world" for pkg
authorShawn Walker <shawn.walker@oracle.com>
Tue, 08 Feb 2011 13:04:17 -0800
changeset 2212 9936333985a6
parent 2211 550bbcf39f88
child 2213 1b494e2d56c1
738 "install world" for pkg 17809 get_pkg_list() should filter on all variants set in the image 17822 get_pkg_list() variant filtering for newest versions omits previous acceptable versions
src/modules/client/api.py
src/modules/client/api_errors.py
src/modules/client/imageplan.py
src/tests/api/t_api_list.py
src/tests/cli/t_variants.py
--- a/src/modules/client/api.py	Tue Feb 08 11:43:15 2011 -0800
+++ b/src/modules/client/api.py	Tue Feb 08 13:04:17 2011 -0800
@@ -1549,17 +1549,17 @@
                         # Filtering needs to be applied.
                         filter_cb = check_state
 
-                arch = self.__img.get_arch()
                 excludes = self.__img.list_excludes()
-                is_zone = self.__img.is_zone()
+                img_variants = self.__img.get_variants()
 
                 matched_pats = set()
                 pkg_matching_pats = None
 
                 # Retrieve only the newest package versions for LIST_NEWEST if
-                # none of the patterns have version information.  (This cuts
-                # down on the number of entries that have to be filtered.)
-                use_last = newest and not pat_versioned
+                # none of the patterns have version information and variants are
+                # included.  (This cuts down on the number of entries that have
+                # to be filtered.)
+                use_last = newest and not pat_versioned and variants
 
                 for t, entry, actions in img_cat.entry_actions(cat_info,
                     cb=filter_cb, excludes=excludes, last=use_last,
@@ -1570,9 +1570,8 @@
                         omit_package = None
 
                         pkg_stem = "!".join((pub, stem))
-                        if newest and pat_versioned and pkg_stem in nlist:
-                                # A newer version has already been listed and
-                                # because a pattern with a version was specified
+                        if newest and pkg_stem in nlist:
+                                # A newer version has already been listed, so
                                 # any additional entries need to be marked for
                                 # omission before continuing.
                                 omit_package = True
@@ -1674,6 +1673,7 @@
                         summ = None
                         targets = set()
 
+                        omit_var = False
                         states = entry["metadata"]["states"]
                         pkgi = self.__img.PKG_STATE_INSTALLED in states
                         try:
@@ -1715,29 +1715,24 @@
                                                         pkgr = True
                                                 continue
 
-                                        if variants:
-                                                # No variant filtering.
+                                        if variants or \
+                                            not atname.startswith("variant."):
+                                                # No variant filtering required.
                                                 continue
 
+                                        # For all variants explicitly set in the
+                                        # image, elide packages that are not for
+                                        # a matching variant value.
                                         is_list = type(atvalue) == list
-                                        if atname == "variant.arch":
-                                                if (is_list and
-                                                    arch not in atvalue) or \
-                                                   (not is_list and
-                                                   arch != atvalue):
-                                                        # Package is not for the
-                                                        # image's architecture.
+                                        for vn, vv in img_variants.iteritems():
+                                                if vn == atname and \
+                                                    ((is_list and
+                                                    vv not in atvalue) or \
+                                                    (not is_list and
+                                                    vv != atvalue)):
                                                         omit_package = True
-                                                        continue
-
-                                        if atname == "variant.opensolaris.zone":
-                                                if (is_zone and is_list and
-                                                    "nonglobal" not in atvalue) or \
-                                                   (is_zone and not is_list and
-                                                    atvalue != "nonglobal"):
-                                                        # Package is for zones
-                                                        # only.
-                                                        omit_package = True
+                                                        omit_var = True
+                                                        break
                         except apx.InvalidPackageErrors:
                                 # Ignore errors for packages that have invalid
                                 # or unsupported metadata.  This is necessary so
@@ -1764,7 +1759,16 @@
                                                 tgt = ren_stems.get(tgt, None)
 
                         if omit_package:
-                                # Package didn't match critera; skip it.
+                                # Package didn't match criteria; skip it.
+                                if (filter_cb is not None or newest) and \
+                                    omit_var and nlist[pkg_stem] == 1:
+                                        # If omitting because of variant, 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/modules/client/api_errors.py	Tue Feb 08 11:43:15 2011 -0800
+++ b/src/modules/client/api_errors.py	Tue Feb 08 13:04:17 2011 -0800
@@ -345,7 +345,7 @@
             badarch=EmptyI, installed=EmptyI, multispec=EmptyI,
             no_solution=False, no_version=EmptyI, missing_dependency=EmptyI,
             wrong_publishers=EmptyI, obsolete=EmptyI, nofiles=EmptyI,
-            solver_errors=EmptyI):
+            solver_errors=EmptyI, wrong_variants=EmptyI):
                 ApiException.__init__(self)
                 self.unmatched_fmris       = unmatched_fmris
                 self.multiple_matches      = multiple_matches
@@ -359,6 +359,7 @@
                 self.no_version            = no_version
                 self.missing_dependency    = missing_dependency
                 self.wrong_publishers      = wrong_publishers
+                self.wrong_variants        = wrong_variants
                 self.nofiles               = nofiles
                 self.solver_errors         = solver_errors
 
@@ -371,6 +372,13 @@
                         res += [s]
                         res += ["\t%s" % p for p in self.unmatched_fmris]
 
+                if self.wrong_variants:
+                        s = _("""\
+The following pattern(s) only matched packages that are not available
+for the current image's architecture, zone type, and/or other variant:""")
+                        res += [s]
+                        res += ["\t%s" % p for p in self.wrong_variants]
+
                 if self.wrong_publishers:
                         s = _("The following patterns only matched packages "
                             "that are from publishers other than that which "
--- a/src/modules/client/imageplan.py	Tue Feb 08 11:43:15 2011 -0800
+++ b/src/modules/client/imageplan.py	Tue Feb 08 13:04:17 2011 -0800
@@ -24,7 +24,7 @@
 # Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
 #
 
-from collections import namedtuple
+from collections import defaultdict, namedtuple
 import errno
 import itertools
 import operator
@@ -2055,6 +2055,7 @@
                 not_installed = []
                 multispec     = []
                 wrongpub      = []
+                wrongvar      = set()
 
                 matchers = []
                 fmris    = []
@@ -2063,7 +2064,7 @@
 
                 wildcard_patterns = []
 
-                renamed_fmris = {}
+                renamed_fmris = defaultdict(set)
                 obsolete_fmris = []
 
                 # ignore dups
@@ -2099,6 +2100,9 @@
                 # dictionary of pkg names & fmris that match that pattern.
                 ret = dict(zip(patterns, [dict() for i in patterns]))
 
+                # Track patterns rejected due to variants.
+                rejected_vars = set()
+
                 # keep track of publishers we reject due to implict selection
                 # of installed publisher to produce better error message.
                 rejected_pubs = {}
@@ -2112,6 +2116,7 @@
                             self.image.IMG_CATALOG_INSTALLED)
                         info_needed = []
 
+                variants = self.image.get_variants()
                 for name in cat.names():
                         for pat, matcher, fmri, version, pub in \
                             zip(patterns, matchers, fmris, versions, pubs):
@@ -2123,7 +2128,7 @@
                                             pkg.version.CONSTRAINT_AUTO):
                                                 continue # version doesn't match
                                         for f, metadata in entries:
-                                                fpub = f.get_publisher()
+                                                fpub = f.publisher
                                                 if pub and pub != fpub:
                                                         continue # specified pubs conflict
                                                 elif not pub and match_type != self.MATCH_INST_VERSIONS and \
@@ -2140,14 +2145,67 @@
                                                         # in list of installed
                                                         # stems.
                                                         continue
+
+                                                states = metadata["metadata"]["states"]
+                                                ren_deps = []
+                                                omit_package = False
+                                                for astr in metadata.get("actions",
+                                                    misc.EmptyI):
+                                                        try:
+                                                                a = pkg.actions.fromstr(
+                                                                    astr)
+                                                        except pkg.actions.ActionError:
+                                                                # Unsupported or
+                                                                # invalid package;
+                                                                # drive on and
+                                                                # filter as much as
+                                                                # possible.  The
+                                                                # solver will reject
+                                                                # this package later.
+                                                                continue
+
+                                                        if self.image.PKG_STATE_RENAMED in states and \
+                                                            a.name == "depend" and \
+                                                            a.attrs["type"] == "require":
+                                                                ren_deps.append(pkg.fmri.PkgFmri(
+                                                                    a.attrs["fmri"], "5.11"))
+                                                                continue
+                                                        elif a.name != "set":
+                                                                continue
+
+                                                        atname = a.attrs["name"]
+                                                        if not atname.startswith("variant."):
+                                                                continue
+
+                                                        # For all variants set
+                                                        # in the image, elide
+                                                        # packages that are not
+                                                        # for a matching variant
+                                                        # value.
+                                                        atvalue = a.attrs["value"]
+                                                        is_list = type(atvalue) == list
+                                                        for vn, vv in variants.iteritems():
+                                                                if vn == atname and \
+                                                                    ((is_list and
+                                                                    vv not in atvalue) or \
+                                                                    (not is_list and
+                                                                    vv != atvalue)):
+                                                                        omit_package = True
+                                                                        break
+
+                                                if omit_package:
+                                                        # Package skipped due to
+                                                        # variant.
+                                                        rejected_vars.add(pat)
+                                                        continue
+
                                                 ret[pat].setdefault(f.pkg_name,
                                                     []).append(f)
                                                 states = metadata["metadata"]["states"]
                                                 if self.image.PKG_STATE_OBSOLETE in states:
                                                         obsolete_fmris.append(f)
-                                                if self.image.PKG_STATE_RENAMED in states and \
-                                                    "actions" in metadata:
-                                                        renamed_fmris[f] = metadata["actions"]
+                                                if self.image.PKG_STATE_RENAMED in states:
+                                                        renamed_fmris[f] = ren_deps
 
                 # remove multiple matches if all versions are obsolete
                 for p in patterns:
@@ -2176,16 +2234,11 @@
                                     for pfmri in ret[p][pkg_name]
                                     if pfmri in renamed_fmris
                                     )
-                                for f in renamed_matches:
-                                        for a in renamed_fmris[f]:
-                                                a = pkg.actions.fromstr(a)
-                                                if a.name != "depend":
-                                                        continue
-                                                if a.attrs["type"] != "require":
-                                                        continue
-                                                targets.append(pkg.fmri.PkgFmri(
-                                                    a.attrs["fmri"], "5.11"
-                                                    ).pkg_name)
+                                targets.extend(
+                                    pf.pkg_name
+                                    for pf in renamed_fmris[f]
+                                    for f in renamed_matches
+                                )
 
                                 for pkg_name in ret[p].keys():
                                         if pkg_name in targets:
@@ -2195,7 +2248,9 @@
                 for p in patterns:
                         l = len(ret[p])
                         if l == 0: # no matches at all
-                                if match_type != self.MATCH_INST_VERSIONS or \
+                                if p in rejected_vars:
+                                        wrongvar.add(p)
+                                elif match_type != self.MATCH_INST_VERSIONS or \
                                     p not in rejected_pubs:
                                         nonmatch.append(p)
                                 elif p in rejected_pubs:
@@ -2222,12 +2277,12 @@
                         not_installed, nonmatch = nonmatch, not_installed
 
                 if illegals or nonmatch or multimatch or not_installed or \
-                    multispec or wrongpub:
+                    multispec or wrongpub or wrongvar:
                         raise api_errors.PlanCreationException(
                             unmatched_fmris=nonmatch,
                             multiple_matches=multimatch, illegal=illegals,
                             missing_matches=not_installed, multispec=multispec,
-                            wrong_publishers=wrongpub)
+                            wrong_publishers=wrongpub, wrong_variants=wrongvar)
 
                 # merge patterns together now that there are no conflicts
                 proposed_dict = {}
@@ -2239,9 +2294,9 @@
                         # no point for installed pkgs....
                         for pkg_name in proposed_dict:
                                 pubs_found = set([
-                                                f.get_publisher()
-                                                for f in proposed_dict[pkg_name]
-                                                ])
+                                    f.publisher
+                                    for f in proposed_dict[pkg_name]
+                                ])
                                 # 1000 is hack for installed but unconfigured
                                 # publishers
                                 best_pub = sorted([
--- a/src/tests/api/t_api_list.py	Tue Feb 08 11:43:15 2011 -0800
+++ b/src/tests/api/t_api_list.py	Tue Feb 08 13:04:17 2011 -0800
@@ -32,7 +32,6 @@
 import calendar
 import difflib
 import os
-import platform
 import pprint
 import re
 import shutil
@@ -72,6 +71,8 @@
             "[email protected]",
             "[email protected]",
             "[email protected]",
+            "[email protected]",
+            "[email protected]",
         ]
 
         @staticmethod
@@ -88,24 +89,18 @@
                 bver = version.Version(bver, "5.11")
                 return cmp(aver, bver) * -1
 
-        @staticmethod
-        def __get_pkg_arch(stem, ver):
-                # Attempt to determine current arch and opposite arch.
-                # This is so that the tests will see the set of packages
-                # they expect to be omitted.
-                parch = platform.processor()
-                if parch == "i386":
-                        oparch = "sparc"
-                else:
-                        oparch = "i386"
-
+        def __get_pkg_variant(self, stem, ver):
+                var = "true"
+                opvar = "false"
                 if stem == "apple":
-                        return [parch]
+                        return [var]
                 elif stem in ("entire", "bat/bar", "obsolete"):
                         return
                 elif stem in ("corge", "grault", "qux", "quux"):
-                        return [parch, oparch]
-                return [oparch]
+                        return [var, opvar]
+                elif stem == "zoo" and ver.startswith("1.0"):
+                        return [var]
+                return [opvar]
 
         @staticmethod
         def __get_pkg_cats(stem, ver):
@@ -157,6 +152,12 @@
                                 states.append(api.PackageInfo.UPGRADABLE)
                         if ver == nver:
                                 states.append(api.PackageInfo.RENAMED)
+                elif stem == "zoo":
+                        # Compare with newest version entry for this stem.
+                        nver = str(self.dlist1[20].version)
+                        if ver != nver:
+                                states.append(api.PackageInfo.UPGRADABLE)
+
                 return frozenset(states)
 
         def __get_pub_entry(self, pub, idx, name, ver):
@@ -207,11 +208,11 @@
                                         pkg_data += ' value="%s"' % cat
                                 pkg_data += "\n"
 
-                        arch = self.__get_pkg_arch(stem, sver)
-                        if arch:
+                        var = self.__get_pkg_variant(stem, sver)
+                        if var:
                                 adata = "value="
-                                adata += " value=".join(arch)
-                                pkg_data += "add set name=variant.arch " \
+                                adata += " value=".join(var)
+                                pkg_data += "add set name=variant.mumble " \
                                     "%s\n" % adata
 
                         if stem == "corge" and sver.startswith("1.0"):
@@ -267,7 +268,8 @@
                 # published to.
 
                 # Next, create the image and configure publishers.
-                self.image_create(rurl1, prefix="test1")
+                self.image_create(rurl1, prefix="test1",
+                    variants={ "variant.mumble": "true" })
                 rurl2 = self.dcs[2].get_repo_url()
                 self.pkg("set-publisher -g " + rurl2 + " test2")
 
@@ -315,8 +317,16 @@
                         for plist in (self.dlist1, self.dlist2):
                                 for f in plist:
                                         pstem = f.get_pkg_stem()
+                                        pub, stem, ver = f.tuple()
+                                        ver = str(f.version)
+                                        sver = ver.split(":", 1)[0]
+
+                                        var = self.__get_pkg_variant(stem, sver)
                                         if pstem not in nlist:
                                                 nlist[pstem] = f
+                                        elif not variants and var and \
+                                            "true" not in var:
+                                                continue
                                         elif f.version > nlist[pstem]:
                                                 nlist[pstem] = f
                 nlist = sorted(nlist.values())
@@ -330,9 +340,8 @@
                                         continue
 
                                 sver = ver.split(":", 1)[0]
-                                arch = self.__get_pkg_arch(stem, sver)
-                                parch = platform.processor()
-                                if not variants and arch and parch not in arch:
+                                var = self.__get_pkg_variant(stem, sver)
+                                if not variants and var and "true" not in var:
                                         continue
 
                                 if newest and f not in nlist:
@@ -472,15 +481,18 @@
                     self.__get_exp_pub_entry("test1", 17, "qux", "0.9,5.11"),
                     self.__get_exp_pub_entry("test2", 18, "qux", "1.0,5.11"),
                     self.__get_exp_pub_entry("test2", 17, "qux", "0.9,5.11"),
+                    self.__get_exp_pub_entry("test1", 20, "zoo", "2.0,5.11"),
+                    self.__get_exp_pub_entry("test1", 19, "zoo", "1.0,5.11"),
+                    self.__get_exp_pub_entry("test2", 20, "zoo", "2.0,5.11"),
+                    self.__get_exp_pub_entry("test2", 19, "zoo", "1.0,5.11"),
                 ]
                 self.assertPrettyEqual(returned, expected)
-                self.assertEqual(len(returned), 38)
+                self.assertEqual(len(returned), 42)
 
                 # Next, check no variants case (which has to be done
-                # programatically to deal with unit test running on
-                # different platforms).
+                # programatically).
                 self.__test_list(api.ImageInterface.LIST_ALL, api_obj=api_obj,
-                    num_expected=32, variants=False)
+                    num_expected=34, variants=False)
 
         def test_list_02_newest(self):
                 """Verify the sort order and content of a list excluding
@@ -488,14 +500,15 @@
                 the newest versions of each package for each publisher."""
 
                 self.__test_list(api.ImageInterface.LIST_NEWEST,
-                    num_expected=16, variants=False)
+                    num_expected=18, variants=False)
 
                 # Verify that LIST_NEWEST will allow version-specific
                 # patterns such that the newest version allowed by the
                 # pattern is what is listed.
                 progresstracker = progress.NullProgressTracker()
-                api_obj = api.ImageInterface(self.get_img_path(), CLIENT_API_VERSION,
-                    progresstracker, lambda x: False, PKG_CLIENT_NAME)
+                api_obj = api.ImageInterface(self.get_img_path(),
+                    CLIENT_API_VERSION, progresstracker, lambda x: False,
+                    PKG_CLIENT_NAME)
 
                 returned = self.__get_returned(api_obj.LIST_NEWEST,
                     api_obj=api_obj, patterns=["[email protected]", "bat/bar",
@@ -544,7 +557,7 @@
                     ([
                         ("", "food")
                     ], 2),
-                    ([], 16) # Only packages with no category assigned.
+                    ([], 18) # Only packages with no category assigned.
                 ]
 
                 for combo, expected in combos:
@@ -556,16 +569,16 @@
                 various publisher and variant combinations."""
 
                 combos = [
-                    (["test1", "test2"], 32, False),
-                    (["test1", "test2"], 38, True),
-                    (["test2"], 16, False),
-                    (["test2"], 19, True),
-                    (["test1"], 16, False),
-                    (["test1"], 19, True),
+                    (["test1", "test2"], 34, False),
+                    (["test1", "test2"], 42, True),
+                    (["test2"], 17, False),
+                    (["test2"], 21, True),
+                    (["test1"], 17, False),
+                    (["test1"], 21, True),
                     (["test3"], 0, False),
                     (["test3"], 0, True),
-                    ([], 32, False),
-                    ([], 38, True)
+                    ([], 34, False),
+                    ([], 42, True)
                 ]
 
                 for combo, expected, variants in combos:
@@ -628,9 +641,7 @@
                     self.__get_exp_pub_entry("test1", 12, "corge", "1.0,5.11",
                         installed=False),
                     self.__get_exp_pub_entry("test2", 12, "corge", "1.0,5.11",
-
                         installed=False),
-
                     self.__get_exp_pub_entry("test1", 13, "entire", "1.0,5.11",
                         installed=True),
                     self.__get_exp_pub_entry("test1", 14, "grault", "1.0,5.11",
@@ -641,9 +652,13 @@
                         "1.0,5.11"),
                     self.__get_exp_pub_entry("test1", 16, "quux", "1.0,5.11",
                         installed=True),
+                    self.__get_exp_pub_entry("test1", 19, "zoo", "1.0,5.11",
+                        installed=False),
+                    self.__get_exp_pub_entry("test2", 19, "zoo", "1.0,5.11",
+                        installed=False),
                 ]
 
-                self.assertEqual(len(returned), 10)
+                self.assertEqual(len(returned), 12)
                 self.assertPrettyEqual(returned, expected)
 
                 # Re-test, including variants.
@@ -673,8 +688,11 @@
                         "1.0,5.11"),
                     self.__get_exp_pub_entry("test1", 16, "quux", "1.0,5.11",
                         installed=True),
+                    self.__get_exp_pub_entry("test1", 20, "zoo", "2.0,5.11",
+                        installed=False),
+                    self.__get_exp_pub_entry("test2", 20, "zoo", "2.0,5.11",
+                        installed=False),
                 ]
-                self.assertEqual(len(returned), 12)
                 self.assertPrettyEqual(returned, expected)
 
                 # Verify results of LIST_INSTALLED_NEWEST when not including
@@ -689,9 +707,10 @@
                         "1.0,5.11"),
                     self.__get_exp_pub_entry("test2", 15, "obsolete",
                         "1.0,5.11"),
+                    self.__get_exp_pub_entry("test2", 19, "zoo",
+                        "1.0,5.11"),
                 ]
                 self.assertPrettyEqual(returned, expected)
-                self.assertEqual(len(returned), 3)
 
                 returned = self.__get_returned(api_obj.LIST_INSTALLED_NEWEST,
                     api_obj=api_obj)
@@ -717,9 +736,12 @@
                         "1.0,5.11"),
                     self.__get_exp_pub_entry("test1", 16, "quux", "1.0,5.11",
                         installed=True),
+                    self.__get_exp_pub_entry("test1", 19, "zoo",
+                        "1.0,5.11"),
+                    self.__get_exp_pub_entry("test2", 19, "zoo",
+                        "1.0,5.11"),
                 ]
                 self.assertPrettyEqual(returned, expected)
-                self.assertEqual(len(returned), 10)
 
                 # Verify the results for LIST_INSTALLED_NEWEST after
                 # uninstalling 'quux' and 'qux'.
@@ -751,9 +773,10 @@
                     self.__get_exp_pub_entry("test2", 15, "obsolete",
                         "1.0,5.11"),
                     self.__get_exp_pub_entry("test1", 16, "quux", "1.0,5.11"),
+                    self.__get_exp_pub_entry("test1", 19, "zoo", "1.0,5.11"),
+                    self.__get_exp_pub_entry("test2", 19, "zoo", "1.0,5.11"),
                 ]
                 self.assertPrettyEqual(returned, expected)
-                self.assertEqual(len(returned), 10)
 
                 # Verify the results for LIST_INSTALLED_NEWEST after
                 # all packages have been uninstalled.
@@ -788,9 +811,10 @@
                     self.__get_exp_pub_entry("test2", 16, "quux", "1.0,5.11"),
                     self.__get_exp_pub_entry("test1", 18, "qux", "1.0,5.11"),
                     self.__get_exp_pub_entry("test2", 18, "qux", "1.0,5.11"),
+                    self.__get_exp_pub_entry("test1", 19, "zoo", "1.0,5.11"),
+                    self.__get_exp_pub_entry("test2", 19, "zoo", "1.0,5.11"),
                 ]
                 self.assertPrettyEqual(returned, expected)
-                self.assertEqual(len(returned), 16)
 
                 # Re-test, including variants.
                 returned = self.__get_returned(api_obj.LIST_INSTALLED_NEWEST,
@@ -822,17 +846,19 @@
                     self.__get_exp_pub_entry("test2", 16, "quux", "1.0,5.11"),
                     self.__get_exp_pub_entry("test1", 18, "qux", "1.0,5.11"),
                     self.__get_exp_pub_entry("test2", 18, "qux", "1.0,5.11"),
+                    self.__get_exp_pub_entry("test1", 20, "zoo", "2.0,5.11"),
+                    self.__get_exp_pub_entry("test2", 20, "zoo", "2.0,5.11"),
                 ]
                 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.
+                # it doesn't apply to the current image variants; so should
+                # [email protected].
                 returned = self.__get_returned(api_obj.LIST_INSTALLED_NEWEST,
                     api_obj=api_obj, patterns=["[email protected],5.11.0", "baz",
-                        "[email protected]"])
+                        "[email protected]", "[email protected]"])
 
                 expected = [
                     self.__get_exp_pub_entry("test1", 1, "apple", "1.0,5.11-0"),
@@ -841,15 +867,14 @@
                     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.
+                # included this time; as should [email protected].
                 returned = self.__get_returned(api_obj.LIST_INSTALLED_NEWEST,
                     api_obj=api_obj, patterns=["[email protected],5.11.0", "baz",
-                        "[email protected]"], variants=True)
+                        "[email protected]", "[email protected]"], variants=True)
 
                 expected = [
                     self.__get_exp_pub_entry("test1", 1, "apple", "1.0,5.11-0"),
@@ -858,9 +883,10 @@
                     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.__get_exp_pub_entry("test1", 20, "zoo", "2.0,5.11"),
+                    self.__get_exp_pub_entry("test2", 20, "zoo", "2.0,5.11"),
                 ]
                 self.assertPrettyEqual(returned, expected)
-                self.assertEqual(len(returned), 6)
 
                 # Test results after installing packages and only listing the
                 # installed packages.
@@ -908,9 +934,10 @@
                         "1.0,5.11"),
                     self.__get_exp_pub_entry("test1", 17, "qux", "0.9,5.11",
                         installed=True),
+                    self.__get_exp_pub_entry("test1", 19, "zoo", "1.0,5.11"),
+                    self.__get_exp_pub_entry("test2", 19, "zoo", "1.0,5.11"),
                 ]
                 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
@@ -922,27 +949,18 @@
                         "[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
                 # listed in an installed incorporation.
-
-                # XXX due to bug 12898 attempting to install
-                # any more packages after this would result
-                # in quux being installed even when the
-                # requested packages do not have quux as a
-                # dependency.  As such, uninstall all packages
-                # here and then install apple, qux and grault.
-                api_obj.plan_uninstall(["*"], False)
+                api_obj.plan_uninstall(["corge"], False)
                 api_obj.prepare()
                 api_obj.execute_plan()
                 api_obj.reset()
 
                 af = self.__get_pub_entry("test1", 1, "apple", "1.0,5.11-0")[0]
-                api_obj.plan_install([af.get_fmri(), "[email protected]",
-                    "pkg://test2/grault"])
+                api_obj.plan_install(["pkg://test2/grault"])
                 api_obj.prepare()
                 api_obj.execute_plan()
                 api_obj.reset()
@@ -969,9 +987,10 @@
                         "1.0,5.11"),
                     self.__get_exp_pub_entry("test1", 17, "qux", "0.9,5.11",
                         installed=True),
+                    self.__get_exp_pub_entry("test1", 19, "zoo", "1.0,5.11"),
+                    self.__get_exp_pub_entry("test2", 19, "zoo", "1.0,5.11"),
                 ]
                 self.assertPrettyEqual(returned, expected)
-                self.assertEqual(len(returned), 11)
 
                 # Now verify that publisher search order determines the entries
                 # that are listed when those entries are part of an installed
@@ -1014,9 +1033,10 @@
                     self.__get_exp_pub_entry("test2", 15, "obsolete",
                         "1.0,5.11"),
                     self.__get_exp_pub_entry("test1", 16, "quux", "1.0,5.11"),
+                    self.__get_exp_pub_entry("test1", 19, "zoo", "1.0,5.11"),
+                    self.__get_exp_pub_entry("test2", 19, "zoo", "1.0,5.11"),
                 ]
                 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
@@ -1030,7 +1050,6 @@
                         "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.
@@ -1054,9 +1073,9 @@
                     self.__get_exp_pub_entry("test1", 15, "obsolete",
                         "1.0,5.11"),
                     self.__get_exp_pub_entry("test1", 16, "quux", "1.0,5.11"),
+                    self.__get_exp_pub_entry("test1", 19, "zoo", "1.0,5.11"),
                 ]
                 self.assertPrettyEqual(returned, expected)
-                self.assertEqual(len(returned), 7)
 
                 # Re-test, only including test2's packages.  Since none of
                 # the other packages are installed for test1, and they meet
@@ -1075,9 +1094,9 @@
                     self.__get_exp_pub_entry("test2", 15, "obsolete",
                         "1.0,5.11"),
                     self.__get_exp_pub_entry("test2", 16, "quux", "1.0,5.11"),
+                    self.__get_exp_pub_entry("test2", 19, "zoo", "1.0,5.11"),
                 ]
                 self.assertPrettyEqual(returned, expected)
-                self.assertEqual(len(returned), 6)
 
                 # Change test2 to be ranked higher than test1.
                 api_obj.set_pub_search_before("test2", "test1")
@@ -1105,9 +1124,10 @@
                     self.__get_exp_pub_entry("test2", 15, "obsolete",
                         "1.0,5.11"),
                     self.__get_exp_pub_entry("test2", 16, "quux", "1.0,5.11"),
+                    self.__get_exp_pub_entry("test1", 19, "zoo", "1.0,5.11"),
+                    self.__get_exp_pub_entry("test2", 19, "zoo", "1.0,5.11"),
                 ]
                 self.assertPrettyEqual(returned, expected)
-                self.assertEqual(len(returned), 11)
 
                 # Now install one of the incorporated packages and check
                 # that test2 is still listed for the remaining package
@@ -1138,9 +1158,10 @@
                     self.__get_exp_pub_entry("test2", 15, "obsolete",
                         "1.0,5.11"),
                     self.__get_exp_pub_entry("test2", 16, "quux", "1.0,5.11"),
+                    self.__get_exp_pub_entry("test1", 19, "zoo", "1.0,5.11"),
+                    self.__get_exp_pub_entry("test2", 19, "zoo", "1.0,5.11"),
                 ]
                 self.assertPrettyEqual(returned, expected)
-                self.assertEqual(len(returned), 11)
 
                 # Reset publisher search order and re-test.
                 api_obj.set_pub_search_before("test1", "test2")
@@ -1166,9 +1187,10 @@
                     self.__get_exp_pub_entry("test2", 15, "obsolete",
                         "1.0,5.11"),
                     self.__get_exp_pub_entry("test1", 16, "quux", "1.0,5.11"),
+                    self.__get_exp_pub_entry("test1", 19, "zoo", "1.0,5.11"),
+                    self.__get_exp_pub_entry("test2", 19, "zoo", "1.0,5.11"),
                 ]
                 self.assertPrettyEqual(returned, expected)
-                self.assertEqual(len(returned), 11)
 
                 # Reset image state for following tests.
                 api_obj.plan_uninstall(["*"], False)
@@ -1284,19 +1306,13 @@
                 ]
 
                 for combo in combos:
-                        import time
-                        self.debug("combo: %s, time: %s" % (combo, time.ctime()))
                         pkgs = [
                             f.get_fmri(anarchy=True, include_scheme=False)
                             for f in combo
                         ]
-                        self.debug("plan install: %s" % time.ctime())
                         api_obj.plan_install(pkgs)
-                        self.debug("prepare install: %s" % time.ctime())
                         api_obj.prepare()
-                        self.debug("execute install: %s" % time.ctime())
                         api_obj.execute_plan()
-                        self.debug("1reset: %s" % time.ctime())
                         api_obj.reset()
 
                         returned = api_obj.get_pkg_categories(installed=True)
@@ -1308,20 +1324,15 @@
                         self.assertPrettyEqual(returned, expected)
 
                         # Prepare for next test.
-                        self.debug("plan uninstall: %s" % time.ctime())
                         # skip corge since it's renamed
                         api_obj.plan_uninstall([
                                                 p
                                                 for p in pkgs
                                                 if not p.startswith("[email protected]")
                                                 ], False)
-                        self.debug("prepare uninstall: %s" % time.ctime())
                         api_obj.prepare()
-                        self.debug("execute uninstall: %s" % time.ctime())
                         api_obj.execute_plan()
-                        self.debug("2reset: %s" % time.ctime())
                         api_obj.reset()
-                self.debug("test finished: %s" % time.ctime())
 
         def test_list_08_patterns(self):
                 """Verify that pattern filtering works as expected."""
--- a/src/tests/cli/t_variants.py	Tue Feb 08 11:43:15 2011 -0800
+++ b/src/tests/cli/t_variants.py	Tue Feb 08 13:04:17 2011 -0800
@@ -20,7 +20,7 @@
 # CDDL HEADER END
 #
 
-# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
 
 import testutils
 if __name__ == "__main__":
@@ -32,8 +32,6 @@
 
 
 class TestPkgVariants(pkg5unittest.SingleDepotTestCase):
-        # Only start/stop the depot once (instead of for every test)
-        persistent_setup = True
 
         bronze10 = """
         open [email protected],5.11-0
@@ -61,6 +59,14 @@
         add file tmp/bronze_i386/etc/motd mode=0555 owner=root group=bin path=etc/motd variant.arch=i386
         close"""
 
+        mumble10 = """
+        open [email protected],5.11-0
+        add set name=variant.mumble value=true
+        close
+        open [email protected],5.11-0
+        add set name=variant.mumble value=false
+        close"""
+
         misc_files = [ 
             "tmp/bronze_sparc/etc/motd",
             "tmp/bronze_i386/etc/motd",
@@ -79,11 +85,22 @@
 
         def setUp(self):
                 pkg5unittest.SingleDepotTestCase.setUp(self)
+                self.pkgsend_bulk(self.rurl, self.mumble10)
                 self.make_misc_files(self.misc_files)
 
         def test_variant_1(self):
                 self.__test_common("no-change", "no-change")
 
+        def test_variant_2_matching(self):
+                """Verify that install matching allows '*' even when some
+                packages are not supported by image variant."""
+
+                self.image_create(self.rurl,
+                    variants={ "variant.mumble": "false" })
+                self.pkg("install \*")
+                self.pkg("info mumble-true", exit=1)
+                self.pkg("info mumble-false")
+
         def test_old_zones_pkgs(self):
                 self.__test_common("variant.opensolaris.zone",
                     "opensolaris.zone")