18640960 pkgdepend stacktrace with varianted dependencies s12b115
authorMingrui Lyu <mingrui.lyu@oracle.com>
Thu, 08 Dec 2016 11:57:19 -0800
changeset 3476 cc1b291b79d2
parent 3475 1b216ff0fc44
child 3477 03d36c13ce40
18640960 pkgdepend stacktrace with varianted dependencies
src/modules/publish/dependencies.py
src/pkgdep.py
src/tests/api/t_dependencies.py
src/tests/cli/t_pkgdep.py
--- a/src/modules/publish/dependencies.py	Wed Dec 07 22:30:36 2016 -0800
+++ b/src/modules/publish/dependencies.py	Thu Dec 08 11:57:19 2016 -0800
@@ -125,7 +125,7 @@
                             pth=self.path, dep=dep_str)
 
 
-class MissingPackageVariantError(DependencyError):
+class UndeclaredVariantWarning(DependencyError):
         """This exception is used when an action is tagged with a variant or
         variant value which the package is not tagged with."""
 
@@ -135,9 +135,9 @@
                 self.path = pth
 
         def __str__(self):
-                return _("The action delivering {path} is tagged with a "
-                    "variant type or value not tagged on the package. "
-                    "Dependencies on this file may fail to be reported.\n"
+                return _("WARNING: The action delivering {path} is tagged with "
+                    "a variant type or value not declared for the package; use "
+                    "pkglint for details.\n"
                     "The action's variants are: {act}\nThe package's "
                     "variants are: {pkg}").format(
                         path=self.path,
@@ -267,9 +267,9 @@
 
         m, manifest_errs = __make_manifest(file_path, proto_dirs)
         pkg_vars = m.get_all_variants()
-        deps, elist, missing, pkg_attrs = list_implicit_deps_for_manifest(m,
-            proto_dirs, pkg_vars, dyn_tok_conv, run_paths,
-            ignore_bypass=ignore_bypass)
+        deps, elist, warnings, missing, pkg_attrs = \
+            list_implicit_deps_for_manifest(m, proto_dirs, pkg_vars,
+                dyn_tok_conv, run_paths, ignore_bypass=ignore_bypass)
         rid_errs = []
         if remove_internal_deps:
                 deps, rid_errs = resolve_internal_deps(deps, m, proto_dirs,
@@ -277,7 +277,7 @@
         if convert:
                 deps = convert_to_standard_dep_actions(deps)
 
-        return deps, manifest_errs + elist + rid_errs, missing, pkg_attrs
+        return deps, manifest_errs + elist + rid_errs, warnings, missing, pkg_attrs
 
 def convert_to_standard_dep_actions(deps):
         """Convert pkg.base.Dependency objects to
@@ -336,15 +336,7 @@
                 pvars = a.get_variant_template()
                 if not pvars:
                         pvars = pkg_vars
-                else:
-                        if not pvars.issubset(pkg_vars):
-                                # This happens when an action in a package is
-                                # tagged with a variant type or value which the
-                                # package has not been tagged with.
-                                errs.append(
-                                    MissingPackageVariantError(pvars, pkg_vars,
-                                        a.attrs["path"]))
-                        pvars.merge_unknown(pkg_vars)
+                assert pvars.issubset(pkg_vars)
                 pvc = variants.VariantCombinations(pvars, satisfied=True)
                 p = a.attrs["path"]
                 bn = os.path.basename(p)
@@ -400,12 +392,14 @@
         pkg.depend.bypass-generate attributes - this is primarily to aid
         debugging and testing.
 
-        Returns a tuple of three lists.
+        Returns a tuple of four lists.
 
         'deps' is a list of dependencies found for the given Manifest.
 
         'elist' is a list of errors encountered while finding dependencies.
 
+        'warnings' is a list of warnings encountered while finding dependencies.
+
         'missing' is a dictionary mapping a file type that isn't recognized by
         portable.get_file_type to a file which produced that filetype.
 
@@ -416,16 +410,29 @@
         deps = []
         elist = []
         missing = {}
+        warnings = []
         pkg_attrs = {}
         act_list = list(mfst.gen_actions_by_type("file"))
         file_types = portable.get_file_type(act_list)
+        var_dict = dict()
+
+        # Collect all variants that are used and not declared and emit a warning
+        # for each of them.
+        for a in mfst.gen_actions():
+                pvars = a.get_variant_template()
+                for k, v in six.iteritems(pvars):
+                        if k not in pkg_vars or not v.issubset(pkg_vars[k]):
+                                warnings.append(UndeclaredVariantWarning(
+                                    pvars, pkg_vars.copy(), a.attrs["path"]))
+                                var_dict.setdefault(k, set()).update(v)
+        pkg_vars.merge_unknown(var_dict)
 
         if portable.PD_RUN_PATH in mfst:
                 # check for multiple values in a set attribute
                 run_path_str = mfst[portable.PD_RUN_PATH]
                 es = __verify_run_path(run_path_str)
                 if es:
-                        return deps, elist + es, missing, pkg_attrs
+                        return deps, elist + es, warnings, missing, pkg_attrs
                 run_paths = run_path_str.split(":")
 
         mf_bypass = []
@@ -440,7 +447,8 @@
                         a_run_path_str = a.attrs[portable.PD_RUN_PATH]
                         es = __verify_run_path(a_run_path_str)
                         if es:
-                                return deps, elist + es, missing, pkg_attrs
+                                return (deps, elist + es, warnings, missing,
+                                    pkg_attrs)
                         a_run_paths = a_run_path_str.split(":")
 
                 bypass = __makelist(
@@ -477,7 +485,7 @@
                                 elist.append(e)
         for a in mfst.gen_actions_by_type("hardlink"):
                 deps.extend(hardlink.process_hardlink_deps(a, pkg_vars))
-        return deps, elist, missing, pkg_attrs
+        return deps, elist, warnings, missing, pkg_attrs
 
 def __update_pkg_attrs(pkg_attrs, new_attrs):
         """Update the pkg_attrs dictionary with the contents of new_attrs."""
--- a/src/pkgdep.py	Wed Dec 07 22:30:36 2016 -0800
+++ b/src/pkgdep.py	Thu Dec 08 11:57:19 2016 -0800
@@ -174,7 +174,7 @@
                     retcode=EXIT_BADOPT)
 
         try:
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(manf,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(manf,
                     proto_dirs, dyn_tok_conv, run_paths, remove_internal_deps)
         except (actions.MalformedActionError, actions.UnknownActionError) as e:
                 error(_("Could not parse manifest {manifest} because of the "
@@ -200,6 +200,8 @@
         if show_missing:
                 for m in ms:
                         emsg(m)
+        for w in ws:
+                emsg(w)
 
         for e in es:
                 emsg(e)
--- a/src/tests/api/t_dependencies.py	Wed Dec 07 22:30:36 2016 -0800
+++ b/src/tests/api/t_dependencies.py	Thu Dec 08 11:57:19 2016 -0800
@@ -100,12 +100,12 @@
 
         int_hardlink_manf = """ \
 hardlink path=usr/foo target=../{syslog_path}
-file NOHASH group=sys mode=0644 owner=root path={syslog_path} 
+file NOHASH group=sys mode=0644 owner=root path={syslog_path}
 """.format(**paths)
 
         int_hardlink_manf_test_symlink = """ \
 hardlink path=usr/foo target=../{syslog_path}
-file NOHASH group=sys mode=0644 owner=root path=bar/syslog 
+file NOHASH group=sys mode=0644 owner=root path=bar/syslog
 """.format(**paths)
 
         ext_script_manf = """ \
@@ -1144,7 +1144,7 @@
 
                 opts = []
                 # In some cases we want to generate an elf binary with no
-                # dependencies of its own.  We use -c (supress linking) for
+                # dependencies of its own.  We use -c (suppress linking) for
                 # this purpose.
                 if static:
                         opts.extend(["-c"])
@@ -1164,7 +1164,7 @@
                 reported as a dependency."""
 
                 def _check_results(res):
-                        ds, es, ms, pkg_attrs = res
+                        ds, es, ws, ms, pkg_attrs = res
                         if es != []:
                                 raise RuntimeError("Got errors in results:" +
                                     "\n".join([str(s) for s in es]))
@@ -1199,7 +1199,7 @@
 
                 t_path = self.make_manifest(self.int_hardlink_manf)
                 self.make_proto_text_file(self.paths["syslog_path"])
-                ds, es, ms, pkg_attrs = \
+                ds, es, ws, ms, pkg_attrs = \
                     dependencies.list_implicit_deps(t_path, [self.proto_dir],
                         {}, [], convert=False)
                 if es != []:
@@ -1209,7 +1209,7 @@
                 self.assertTrue(len(ds) == 0)
 
                 # Check that internal dependencies are as expected.
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=False,
                     convert=False)
                 if es != []:
@@ -1230,7 +1230,7 @@
                 outside its package is reported as a dependency."""
 
                 def _check_res(res):
-                        ds, es, ms, pkg_attrs = res
+                        ds, es, ws, ms, pkg_attrs = res
                         if es != []:
                                 raise RuntimeError("Got errors in results:" +
                                     "\n".join([str(s) for s in es]))
@@ -1261,7 +1261,7 @@
                 self.make_elf(self.paths["ksh_path"])
                 self.make_proto_text_file(self.paths["script_path"],
                     self.script_text)
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], convert=False)
                 if es != []:
                         raise RuntimeError("Got errors in results:" +
@@ -1276,7 +1276,7 @@
                     "usr/lib"]))
 
                 # Check that internal dependencies are as expected.
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=False,
                     convert=False)
                 self.assertEqual(len(ds), 2)
@@ -1301,7 +1301,7 @@
                 package is reported as a dependency."""
 
                 def _check_res(res):
-                        ds, es, ms, pkg_attrs = res
+                        ds, es, ws, ms, pkg_attrs = res
                         if es != []:
                                 raise RuntimeError("Got errors in results:" +
                                     "\n".join([str(s) for s in es]))
@@ -1334,7 +1334,7 @@
                 internal dependencies is set."""
 
                 def _check_all_res(res):
-                        ds, es, ms, pkg_attrs = res
+                        ds, es, ws, ms, pkg_attrs = res
                         if es != []:
                                 raise RuntimeError("Got errors in results:" +
                                     "\n".join([str(s) for s in es]))
@@ -1355,7 +1355,7 @@
                 t_path = self.make_manifest(self.int_elf_manf)
                 self.make_elf(self.paths["curses_path"])
                 self.make_elf(self.paths["libc_path"], static=True)
-                d_map, es, ms, pkg_attrs = dependencies.list_implicit_deps(
+                d_map, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(
                     t_path, [self.proto_dir], {}, [], convert=False)
                 if es != []:
                         raise RuntimeError("Got errors in results:" +
@@ -1373,7 +1373,7 @@
                 package is reported as a dependency."""
 
                 def _check_all_res(res):
-                        ds, es, ms, pkg_attrs = res
+                        ds, es, ws, ms, pkg_attrs = res
                         mod_pats = [
                             "{0}/__init__.py", "{0}.py", "{0}.pyc", "{0}.pyo",
                             "{0}.so", "{0}module.so",
@@ -1427,7 +1427,7 @@
                 is handled correctly."""
 
                 def _check_all_res(res):
-                        ds, es, ms, pkg_attrs = res
+                        ds, es, ws, ms, pkg_attrs = res
                         mod_pats = [
                             "{0}/__init__.py", "{0}.py", "{0}.pyc", "{0}.pyo",
                             "{0}.so", "{0}module.so",
@@ -1485,7 +1485,7 @@
                 package is handled correctly."""
 
                 def _check_all_res(res):
-                        ds, es, ms, pkg_attrs = res
+                        ds, es, ws, ms, pkg_attrs = res
                         mod_pats = [
                             "{0}/__init__.py", "{0}.py", "{0}.pyc", "{0}.pyo",
                             "{0}.so", "{0}module.so",
@@ -1567,7 +1567,7 @@
                 self.make_python_test_files(3.4)
                 self.make_python_test_files(2.7)
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], convert=False)
                 self.assertTrue(es != 0, "Unexpected errors reported: {0}".format(es))
                 self.assertTrue(ds != 2, "Unexpected deps reported: {0}".format(ds))
@@ -1581,7 +1581,7 @@
                     self.relative_ext_depender_manf)
                 self.make_python_test_files(2.7)
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=True,
                     convert=False)
 
@@ -1616,7 +1616,7 @@
                 self.assertTrue(os.path.exists(os.path.join(self.proto_dir,
                     self.paths["relative_dependee"])))
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=True,
                     convert=False)
                 if es != []:
@@ -1630,7 +1630,7 @@
                             "dependency which wasn't of the expected type:{0}".format(
                             d))
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=False,
                     convert=False)
                 if es != []:
@@ -1657,7 +1657,7 @@
                 t_path = self.make_manifest(self.python_mod_manf)
                 self.make_broken_python_test_file(3.4)
                 self.make_broken_python_test_file(2.7)
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], convert=False)
                 self.assertTrue(es != 2, "Unexpected errors reported: {0}".format(es))
                 self.assertTrue(ds != 0, "Unexpected deps reported: {0}".format(ds))
@@ -1673,7 +1673,7 @@
                 self.make_proto_text_file(self.paths["script_path"],
                     self.script_text)
                 self.make_elf(self.paths["ksh_path"])
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], convert=False)
                 if es != []:
                         raise RuntimeError("Got errors in results:" +
@@ -1720,7 +1720,7 @@
                 self.make_proto_text_file(self.paths["script_path"],
                     self.script_text)
                 self.make_elf(self.paths["ksh_path"])
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], convert=False)
                 if es != []:
                         raise RuntimeError("Got errors in results:" +
@@ -1737,7 +1737,7 @@
                 self.assertEqual(set(d.run_paths), set(["lib", "usr/lib"]))
 
                 # Check that internal dependencies are as expected.
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=False,
                     convert=False)
                 if es != []:
@@ -1778,7 +1778,7 @@
                 self.make_proto_text_file(self.paths["script_path"],
                     self.script_text)
                 self.make_elf(self.paths["ksh_path"])
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], convert=False)
                 if es != []:
                         raise RuntimeError("Got errors in results:" +
@@ -1825,7 +1825,7 @@
                 self.make_elf(self.paths["ksh_path"])
 
                 # Check that we only report a single external dependency
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], convert=False)
                 if es != []:
                         raise RuntimeError("Got errors in results:" +
@@ -1845,7 +1845,7 @@
                 self.assertEqual(set(d.run_paths), set(["lib", "usr/lib"]))
 
                 # Check that internal dependencies are as expected.
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=False,
                     convert=False)
                 if es != []:
@@ -1902,7 +1902,7 @@
 
                 t_path = self.make_manifest(
                     self.int_hardlink_manf_test_symlink)
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], convert=False)
 
         def test_str_methods(self):
@@ -1950,7 +1950,7 @@
 
                 # This should fail because the "foo" directory is not given
                 # as a proto_dir.
-                d_map, es, ms, pkg_attrs = dependencies.list_implicit_deps(
+                d_map, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(
                     t_path, [self.proto_dir], {}, [], convert=False)
                 if len(es) != 1:
                         raise RuntimeError("Got errors in results:" +
@@ -1964,7 +1964,7 @@
 
                 # This should work since the "foo" directory has been added to
                 # the list of proto_dirs to use.
-                d_map, es, ms, pkg_attrs = dependencies.list_implicit_deps(
+                d_map, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(
                     t_path, [self.proto_dir,
                     os.path.join(self.proto_dir, "foo")], {}, [], convert=False)
                 if es:
@@ -1976,7 +1976,7 @@
                 # This should be different because the empty text file
                 # is found before the binary file.
                 self.make_proto_text_file(self.paths["curses_path"])
-                d_map, es, ms, pkg_attrs = dependencies.list_implicit_deps(
+                d_map, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(
                     t_path, [self.proto_dir,
                     os.path.join(self.proto_dir, "foo")], {}, [],
                     remove_internal_deps=False, convert=False)
@@ -1991,7 +1991,7 @@
 
                 # This should find the binary file first and thus produce
                 # a depend action.
-                d_map, es, ms, pkg_attrs = dependencies.list_implicit_deps(
+                d_map, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(
                     t_path, [os.path.join(self.proto_dir, "foo"),
                     self.proto_dir], {}, [], remove_internal_deps=False,
                     convert=False)
@@ -2007,7 +2007,7 @@
                     self.paths["syslog_path"]))
                 # This test should fail because "foo" is not included in the
                 # list of proto_dirs.
-                ds, es, ms, pkg_attrs = \
+                ds, es, ws, ms, pkg_attrs = \
                     dependencies.list_implicit_deps(t_path, [self.proto_dir],
                         {}, [], convert=False)
                 if len(es) != 1:
@@ -2022,7 +2022,7 @@
 
                 # This test should pass because the needed directory has been
                 # added to the list of proto_dirs.
-                ds, es, ms, pkg_attrs = \
+                ds, es, ws, ms, pkg_attrs = \
                     dependencies.list_implicit_deps(t_path,
                         [self.proto_dir, os.path.join(self.proto_dir, "foo")],
                         {}, [], convert=False)
@@ -2036,7 +2036,7 @@
                 # scripts.
 
                 def _py_check_all_res(res):
-                        ds, es, ms, pkg_attrs = res
+                        ds, es, ws, ms, pkg_attrs = res
                         mod_pats = [
                             "{0}/__init__.py", "{0}.py", "{0}.pyc", "{0}.pyo",
                             "{0}.so", "{0}module.so",
@@ -2082,7 +2082,7 @@
                     self.python_text)
                 # This should have an error because it cannot find the file
                 # needed.
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], convert=False)
                 if len(es) != 1:
                         raise RuntimeError("Got errors in results:" +
@@ -2169,7 +2169,7 @@
                 t_path = self.make_manifest(self.int_smf_manf)
                 self.make_smf_test_files()
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=False,
                     convert=False)
                 if es != []:
@@ -2192,7 +2192,7 @@
                     "int_smf_manf")
 
                 # verify that removing internal dependencies works as expected
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=True,
                     convert=False)
                 self.assertTrue(len(ds) == 0, "Expected 0 dependencies, got {0}".format(
@@ -2207,7 +2207,7 @@
                 t_path = self.make_manifest(self.ext_smf_manf)
                 self.make_smf_test_files()
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=False,
                     convert=False)
                 if es != []:
@@ -2239,7 +2239,7 @@
                 t_path = self.make_manifest(self.broken_smf_manf)
                 self.make_smf_test_files()
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=False,
                     convert=False)
 
@@ -2289,7 +2289,7 @@
                 t_path = self.make_manifest(self.faildeps_smf_manf)
                 self.make_smf_test_files()
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=False,
                     convert=False)
 
@@ -2322,7 +2322,7 @@
                 t_path = self.make_manifest(self.delete_smf_manf)
                 self.make_smf_test_files()
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=False,
                     convert=False)
 
@@ -2365,7 +2365,7 @@
                 # multiple SMF manifests.
                 t_path = self.make_manifest(self.int_req_svc_smf_manf)
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(
                     t_path, [self.proto_dir], {}, [],
                     remove_internal_deps=False, convert=False)
                 self.assertTrue(len(es) == 0, "Detected {0} error(s), expected 0".format(
@@ -2388,7 +2388,7 @@
                 # Test the second case: specific dependencies on instances
                 # satisfied by multiple (different) SMF manifests.
                 t_path = self.make_manifest(self.int_req_inst_smf_manf)
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(
                     t_path, [self.proto_dir], {}, [],
                     remove_internal_deps=False, convert=False)
                 self.assertTrue(len(es) == 0, "Detected {0} error(s), expected 0".format(
@@ -2418,7 +2418,7 @@
                 # multiple SMF manifests, but with one bypassed.
                 t_path = self.make_manifest(self.bypassed_int_req_svc_smf_manf)
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(
                     t_path, [self.proto_dir], {}, [],
                     remove_internal_deps=False, convert=False)
                 self.assertTrue(len(es) == 0, "Detected {0} error(s), expected 0".format(
@@ -2442,7 +2442,7 @@
                 t_path = self.make_manifest(self.python_runpath_manf)
                 self.make_python_test_files(2.7)
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=False,
                     convert=False)
                 self.assertTrue(es==[], "Unexpected errors reported: {0}".format(es))
@@ -2467,14 +2467,14 @@
 
                 # test a runpath with multiple values
                 t_path = self.make_manifest(self.python_invalid_runpath_manf)
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=False,
                     convert=False)
                 self.assertTrue(es != [], "No errors reported for broken runpath")
 
                 # test a runpath with multiple $PD_DEFAULT_RUNPATH components
                 t_path = self.make_manifest(self.python_invalid_runpath2_manf)
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=False,
                     convert=False)
                 self.assertTrue(es != [], "No errors reported for broken runpath")
@@ -2485,7 +2485,7 @@
                 t_path = self.make_manifest(self.python_empty_runpath_manf)
                 self.make_python_test_files(2.7)
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=False,
                     convert=False)
                 self.assertTrue(es != [], "No errors reported for empty runpath")
@@ -2582,7 +2582,7 @@
                 t_path = self.make_manifest(self.python_bypass_manf)
                 self.make_python_test_files(2.7)
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=False,
                     convert=False)
                 self.assertTrue(self.verify_bypass(ds, es, [
@@ -2598,7 +2598,7 @@
                     "opt/pkgdep_runpath/pdtest.pyc"]))
 
                 # now run this again as a control, this time skipping bypass
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=False,
                     convert=False, ignore_bypass=True)
                 # the first two items in the list were previously bypassed
@@ -2619,7 +2619,7 @@
                     self.ksh_bypass_dup_manf, self.ksh_bypass_filename_manf]:
                         t_path = self.make_manifest(manifest)
 
-                        ds, es, ms, pkg_attrs = \
+                        ds, es, ws, ms, pkg_attrs = \
                             dependencies.list_implicit_deps(t_path,
                             [self.proto_dir], {}, [],
                             remove_internal_deps=False, convert=False)
@@ -2629,7 +2629,7 @@
                             ["usr/bin/ksh"]), "Ksh script was not bypassed")
 
                         # don't perform bypass
-                        ds, es, ms, pkg_attrs = \
+                        ds, es, ws, ms, pkg_attrs = \
                             dependencies.list_implicit_deps(t_path,
                             [self.proto_dir], {}, [],
                             remove_internal_deps=False, convert=False,
@@ -2645,7 +2645,7 @@
                 t_path = self.make_manifest(self.python_wildcard_bypass_manf)
                 self.make_python_test_files(2.7)
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=False,
                     convert=False)
 
@@ -2659,7 +2659,7 @@
                 t_path = self.make_manifest(
                     self.python_wildcard_dir_bypass_manf)
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=False,
                     convert=False)
 
@@ -2675,7 +2675,7 @@
                 t_path = self.make_manifest(
                     self.python_wildcard_file_bypass_manf)
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=False,
                     convert=False)
                 self.assertTrue(self.verify_bypass(ds, es, [
@@ -2695,7 +2695,7 @@
                 t_path = self.make_manifest(
                     self.python_wildcard_combo_bypass_manf)
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=False,
                     convert=False)
                 self.assertTrue(self.verify_bypass(ds, es, [
@@ -2716,7 +2716,7 @@
                 t_path = self.make_manifest(self.python_bypass_nomatch_manf)
                 self.make_python_test_files(2.7)
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=False,
                     convert=False)
 
@@ -2744,7 +2744,7 @@
                 gen_paths = all_paths(ds)
 
                 # now run again, without trying to perform dependency bypass
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=False,
                     convert=False, ignore_bypass=True)
 
@@ -2772,14 +2772,14 @@
                 self.make_python_test_files(2.7)
                 self.make_elf(self.paths["curses_path"])
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(t_path,
                     [self.proto_dir], {}, [], remove_internal_deps=False,
                     convert=False)
 
                 smf.SMFManifestDependency._clear_cache()
 
                 # now run the same function, this time using our symlinked dir
-                dsl, esl, msl, pkg_attrsl = dependencies.list_implicit_deps(
+                dsl, esl, wsl, msl, pkg_attrsl = dependencies.list_implicit_deps(
                     t_path, [linked_proto], {}, [],
                     remove_internal_deps=False, convert=False)
 
--- a/src/tests/cli/t_pkgdep.py	Wed Dec 07 22:30:36 2016 -0800
+++ b/src/tests/cli/t_pkgdep.py	Thu Dec 08 11:57:19 2016 -0800
@@ -877,6 +877,12 @@
 hardlink path=var/log/foobar target=syslog
 """
 
+        bug_18640960_manf = """\
+set name=variant.opensolaris.zone value=global
+file NOHASH group=bin mode=0755 owner=root path=var/log/syslog variant.opensolaris.zone=nonglobal
+hardlink path=var/log/foobar target=syslog
+"""
+
         bug_15958_manf = """\
 set name=variant.opensolaris.zone value=global value=nonglobal
 """ + bug_16808_manf
@@ -885,10 +891,16 @@
 depend fmri=__TBD pkg.debug.depend.file=syslog pkg.debug.depend.path=var/log pkg.debug.depend.reason=var/log/foobar pkg.debug.depend.type=hardlink type=require variant.opensolaris.zone=nonglobal
 """
 
-        bug_16808_error = """\
-The action delivering var/log/syslog is tagged with a variant type or value not tagged on the package. Dependencies on this file may fail to be reported.
-The action's variants are: variant.opensolaris.zone="global"
-The package's variants are: <none>
+        bug_16808_warning = """\
+WARNING: The action delivering var/log/syslog is tagged with a variant type or value not declared for the package; use pkglint for details.
+The action's variants are:  variant.opensolaris.zone="global"
+The package's variants are: {}
+"""
+
+        bug_18640960_warning = """\
+WARNING: The action delivering var/log/syslog is tagged with a variant type or value not declared for the package; use pkglint for details.
+The action's variants are:  variant.opensolaris.zone="global"
+The package's variants are: {}
 """
 
         res_elf_warning = """\
@@ -1291,7 +1303,7 @@
                     filter_files=[bar_path], shared_lib=True,
                     obj_files=[foo_path])
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(
                     mp, [self.test_proto_dir], {}, [], convert=False)
                 __check_res(es, ms, pkg_attrs)
                 self.assertEqual(len(ds), 2, "\n".join([str(d) for d in ds]))
@@ -1308,7 +1320,7 @@
                     mapfile=mapfile_1_path, obj_files=[foo_path],
                     shared_lib=True)
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(
                     mp, [self.test_proto_dir], {}, [], convert=False)
                 __check_res(es, ms, pkg_attrs)
                 self.assertEqual(len(ds), 2, "\n".join([str(d) for d in ds]))
@@ -1324,7 +1336,7 @@
                     optional_filters=["xxx.so"], obj_files=[foo_path],
                     shared_lib=True)
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(
                     mp, [self.test_proto_dir], {}, [], convert=False)
                 __check_res(es, ms, pkg_attrs)
                 self.assertEqual(len(ds), 1, "\n".join([str(d) for d in ds]))
@@ -1341,7 +1353,7 @@
                     mapfile=mapfile_2_path, obj_files=[foo_path],
                     shared_lib=True)
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(
                     mp, [self.test_proto_dir], {}, [], convert=False)
                 __check_res(es, ms, pkg_attrs)
                 self.assertEqual(len(ds), 1, "\n".join([str(d) for d in ds]))
@@ -1358,7 +1370,7 @@
                     deferred_libs=[bar_path], shared_lib=True,
                     obj_files=[foo_path])
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(
                     mp, [self.test_proto_dir], {}, [], convert=False)
                 __check_res(es, ms, pkg_attrs)
                 self.assertEqual(len(ds), 1, "\n".join([str(d) for d in ds]))
@@ -1374,7 +1386,7 @@
                     lazy_libs=[bar_path], shared_lib=True,
                     obj_files=[foo_path])
 
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(
                     mp, [self.test_proto_dir], {}, [], convert=False)
                 __check_res(es, ms, pkg_attrs)
                 self.assertEqual(len(ds), 2, "\n".join([str(d) for d in ds]))
@@ -1411,7 +1423,7 @@
                 # Test that AUDIT dependency can be detected.
                 self.make_elf(output_path=so_path, program_text=foo_c,
                     shared_lib=True, record_audit=True)
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(
                     manifest1_path, [self.test_proto_dir], {}, [],
                     convert=False)
 
@@ -1424,7 +1436,7 @@
                 # Test that DEPAUDIT dependency can be detected.
                 self.make_elf(output_path=main_path, program_text=main_c,
                     deferred_libs=[so_path])
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(
                     manifest2_path, [self.test_proto_dir], {}, [],
                     convert=False)
                 found_file_deps = sorted(set(itertools.chain.from_iterable(
@@ -2594,7 +2606,7 @@
 file NOHASH group=bin mode=0555 owner=root path=b/bin/perl
 """
                 internal_dep_pth = self.make_manifest(internal_dep_manf)
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(
                     internal_dep_pth, [self.test_proto_dir], {}, [],
                     convert=False)
 
@@ -2620,7 +2632,7 @@
 file NOHASH group=bin mode=0555 owner=root path=b/bin/perl variant.foo=c
 """
                 internal_dep_pth = self.make_manifest(internal_dep_manf)
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(
                     internal_dep_pth, [self.test_proto_dir], {}, [],
                     convert=False)
 
@@ -2657,7 +2669,7 @@
                 foo_path = self.make_proto_text_file("bar/foo",
                     "#!/usr/bin/perl\n\n")
                 internal_dep_pth = self.make_manifest(internal_dep_manf)
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(
                     internal_dep_pth, [self.test_proto_dir], {}, [],
                     convert=False)
 
@@ -2701,7 +2713,7 @@
                 foo_path = self.make_proto_text_file("bar/foo",
                     "#!/usr/bin/perl\n\n")
                 internal_dep_pth = self.make_manifest(internal_dep_manf)
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(
                     internal_dep_pth, [self.test_proto_dir], {}, [],
                     convert=False)
 
@@ -2725,13 +2737,21 @@
 
         def test_bug_16808(self):
                 """Test that if an action uses a variant not declared at the
-                package level, an error is reported."""
+                package level, an warning is reported."""
 
                 tp = self.make_manifest(self.bug_16808_manf)
                 self.make_proto_text_file("var/log/syslog", "text")
-                self.pkgdepend_generate("-d {0} {1}".format(self.test_proto_dir, tp),
-                    exit=1)
-                self.check_res(self.bug_16808_error, self.errout)
+                self.pkgdepend_generate("-d {0} {1}".format(self.test_proto_dir, tp))
+                self.check_res(self.bug_16808_warning, self.errout)
+
+        def test_bug_18640960(self):
+                """Test that if an action uses a variant value not declared at the
+                package level, an warning is reported."""
+
+                tp = self.make_manifest(self.bug_16808_manf)
+                self.make_proto_text_file("var/log/syslog", "text")
+                self.pkgdepend_generate("-d {0} {1}".format(self.test_proto_dir, tp))
+                self.check_res(self.bug_18640960_warning, self.errout)
 
         def test_bug_17808(self):
                 """Test that a 64-bit binary has its runpaths set to /lib/64 and
@@ -2739,7 +2759,7 @@
 
                 self.make_elf(bit64=True, output_path="usr/bin/x64")
                 mp = self.make_manifest(self.test_64bit_manf)
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(
                     mp, [self.test_proto_dir], {}, [], convert=False)
                 self.assertEqual(len(es), 0, "\n".join([str(d) for d in es]))
                 self.assertEqual(len(ds), 1, "\n".join([str(d) for d in ds]))
@@ -2823,7 +2843,7 @@
                     "usr/bin/amd64/python{0}-config".format(py_ver_default),
                      self.python_amd_text)
                 mp = self.make_manifest(self.python_amd_manf)
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(
                     mp, [self.test_proto_dir], {}, [], convert=False)
                 self.assertEqual(len(es), 0, "\n".join([str(d) for d in es]))
                 self.assertEqual(len(ds), 3, "\n".join([str(d) for d in ds]))
@@ -2840,7 +2860,7 @@
                     "usr/bin/sparcv9/python{0}-config".format(py_ver_default),
                     self.python_amd_text)
                 mp = self.make_manifest(self.python_sparcv9_manf)
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(
                     mp, [self.test_proto_dir], {}, [], convert=False)
                 self.assertEqual(len(es), 0, "\n".join([str(d) for d in es]))
                 self.assertEqual(len(ds), 3, "\n".join([str(d) for d in ds]))
@@ -2901,7 +2921,7 @@
 depend fmri=pkg:/a@0,5.11-1 type=conditional
 """
                 manf_path = self.make_manifest(manf)
-                ds, es, ms, pkg_attrs = dependencies.list_implicit_deps(
+                ds, es, ws, ms, pkg_attrs = dependencies.list_implicit_deps(
                     manf_path, [self.test_proto_dir], {}, [],
                     convert=False)
                 self.assertEqual(len(es), 1)