15843 pkgdepend can't handle more than one proto area
authorBrock Pytlik <bpytlik@sun.com>
Thu, 20 May 2010 21:32:54 -0700
changeset 1908 4bdaf0463bae
parent 1907 a6564f3c8f3d
child 1909 7b234f0eff79
15843 pkgdepend can't handle more than one proto area 15886 t_dependencies creates more python files than are needed
src/man/pkgdepend.1.txt
src/modules/actions/__init__.py
src/modules/flavor/base.py
src/modules/flavor/elf.py
src/modules/flavor/hardlink.py
src/modules/flavor/python.py
src/modules/flavor/script.py
src/modules/portable/__init__.py
src/modules/portable/os_sunos.py
src/modules/publish/dependencies.py
src/pkgdep.py
src/tests/api/t_dependencies.py
src/tests/cli/t_pkgdep.py
src/tests/pkg5unittest.py
--- a/src/man/pkgdepend.1.txt	Thu May 20 21:07:51 2010 -0700
+++ b/src/man/pkgdepend.1.txt	Thu May 20 21:32:54 2010 -0700
@@ -7,8 +7,8 @@
 SYNOPSIS
      /usr/bin/pkgdepend [options] command [cmd_options] [operands]
 
-     /usr/bin/pkgdepend generate [-IMm] [-D name=value] [-k path] manifest_path
-         proto_dir
+     /usr/bin/pkgdepend generate [-IMm] -d dir [...] [-D name=value]
+         [-k path] manifest_path
 
      /usr/bin/pkgdepend resolve [-dmosSv] manifest_path ...
 
@@ -40,9 +40,9 @@
 SUBCOMMANDS
      The following subcommands are supported:
 
-     generate [-IMm] [-D name=value] [-k path] manifest_path proto_dir
+     generate [-IMm] -d dir [-d dir] [-D name=value] [-k path] manifest_path
           Produce the dependencies on files of the manifest specified by
-          manifest_path, whose contents are found in proto_dir.
+          manifest_path.
 
           With -I, the dependencies which are satisfied within the
           manifest given will be shown.
@@ -53,6 +53,9 @@
           With -m, the original manifest will be repeated with any
           discovered dependencies added after.
 
+          With -d, add the directory provided to a list of directories 
+          to search for the manifest's files.
+
           For each -D, add the 'value' as a way to expand the token
           'name' in run paths for elf file dependencies.
 
--- a/src/modules/actions/__init__.py	Thu May 20 21:07:51 2010 -0700
+++ b/src/modules/actions/__init__.py	Thu May 20 21:32:54 2010 -0700
@@ -21,8 +21,7 @@
 #
 
 #
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 """
@@ -300,7 +299,7 @@
         if ahash:
                 action.hash = ahash
 
-        local_path = set_action_data(data, action, basedirs)
+        local_path, used_basedir = set_action_data(data, action, basedirs)
         return action, local_path
 
 def internalizestr(string, basedirs=None, load_data=True):
@@ -328,14 +327,15 @@
         action = fromstr(string)
 
         if atype not in ("file", "license") or not load_data:
-                return action, None
+                return action, None, None
 
-        local_path = set_action_data(args[0], action, basedirs)
-        return action, local_path
+        local_path, used_basedir = set_action_data(args[0], action, basedirs)
+        return action, local_path, used_basedir
 
 def set_action_data(payload, action, basedirs):
         """Sets the data field of an action using the information in the
-        payload and returns the actual path used to set the data.
+        payload and returns the actual path used to set the data and the basedir
+        used to find the path to the data.
 
         The "payload" parameter is the representation of the data to assign to
         the action's data field. It can either be NOHASH or a path to the file.
@@ -346,22 +346,24 @@
         the payload in."""
 
         if not payload:
-                return None
-        
+                return None, None
+
         if payload == "NOHASH":
                 filepath = os.path.sep + action.attrs["path"]
         else:
                 filepath = payload
 
+        used_basedir = None
         if basedirs:
                 path = filepath.lstrip(os.path.sep)
                 # look for file in specified dirs
                 for d in basedirs:
                         data = os.path.join(d, path)
                         if os.path.isfile(data):
+                                used_basedir = d
                                 break
         else:
                 data = filepath
 
         action.set_data(data)
-        return data
+        return data, used_basedir
--- a/src/modules/flavor/base.py	Thu May 20 21:07:51 2010 -0700
+++ b/src/modules/flavor/base.py	Thu May 20 21:32:54 2010 -0700
@@ -21,8 +21,7 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 import os
@@ -182,15 +181,25 @@
                 delivering the action was published.
 
                 'proto_dir' is the proto area where the file the action delivers
-                lives.
+                lives.  It may be None if the notion of a proto_dir is
+                meaningless for a particular PublishingDependency.
 
                 'kind' is the kind of dependency that this is.
                 """
 
                 self.base_names = sorted(base_names)
-                self.run_paths = sorted([
-                    self.make_relative(rp, proto_dir) for rp in run_paths
-                ])
+
+                if proto_dir is None:
+                        self.run_paths = sorted(run_paths)
+                        # proto_dir is set to "" so that the proto_dir can be
+                        # joined unconditionally with other paths.  This makes
+                        # the code path in _check_path simpler.
+                        proto_dir = ""
+                else:
+                        self.run_paths = sorted([
+                            self.make_relative(rp, proto_dir)
+                            for rp in run_paths
+                        ])
 
                 attrs = {
                     "%s.file" % self.DEPEND_DEBUG_PREFIX: self.base_names,
--- a/src/modules/flavor/elf.py	Thu May 20 21:07:51 2010 -0700
+++ b/src/modules/flavor/elf.py	Thu May 20 21:32:54 2010 -0700
@@ -21,8 +21,7 @@
 #
 
 #
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 import os
@@ -30,7 +29,7 @@
 import pkg.elf as elf
 import pkg.flavor.base as base
 
-from pkg.portable import PD_LOCAL_PATH
+from pkg.portable import PD_LOCAL_PATH, PD_PROTO_DIR
 
 class BadElfFile(base.DependencyAnalysisError):
         """Exception that is raised when the elf dependency checker is given
@@ -143,7 +142,7 @@
 
 default_run_paths = ["/lib", "/usr/lib"]
 
-def process_elf_dependencies(action, proto_dir, pkg_vars, dyn_tok_conv,
+def process_elf_dependencies(action, pkg_vars, dyn_tok_conv,
     kernel_paths, **kwargs):
         """Produce the elf dependencies for the file delivered in the action
         provided.
@@ -153,8 +152,6 @@
         'pkg_vars' is the list of variants against which the package delivering
         the action was published.
 
-        'proto_dir' is the proto area where the file the action delivers lives.
-
         'dyn_tok_conv' is the dictionary which maps the dynamic tokens, like
         $PLATFORM, to the values they should be expanded to.
 
@@ -264,6 +261,6 @@
                         if head:
                                 pathlist.append(head)
                 res.append(ElfDependency(action, fn, pathlist, pkg_vars,
-                    proto_dir))
+                    action.attrs[PD_PROTO_DIR]))
         del dyn_tok_conv["$ORIGIN"]
         return res, elist
--- a/src/modules/flavor/hardlink.py	Thu May 20 21:07:51 2010 -0700
+++ b/src/modules/flavor/hardlink.py	Thu May 20 21:32:54 2010 -0700
@@ -21,8 +21,7 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 import os
@@ -32,21 +31,21 @@
 class HardlinkDependency(base.PublishingDependency):
         """Class representing the dependency by having an action that's a
         hardlink to a path."""
-        def __init__(self, action, path, pkg_vars, proto_dir):
+        def __init__(self, action, path, pkg_vars):
                 base_names = [os.path.basename(path)]
                 paths = [os.path.dirname(path)]
                 base.PublishingDependency.__init__(self, action,
-                    base_names, paths, pkg_vars, proto_dir, "hardlink")
+                    base_names, paths, pkg_vars, None, "hardlink")
 
         def __repr__(self):
                 return "HLDep(%s, %s, %s, %s, %s)" % (self.action,
                     self.base_names, self.run_paths, self.pkg_vars,
                     self.dep_vars)
 
-def process_hardlink_deps(action, pkg_vars, proto_dir):
-        """Given an action, the variants against which the action's package was
-        published, and the proto area, produce a list with one
-        HardlinkDependency object in it."""
+def process_hardlink_deps(action, pkg_vars):
+        """Given an action, and the variants against which the action's package
+        was published, produce a list with one HardlinkDependency object in
+        it."""
 
         target = action.get_target_path()
-        return [HardlinkDependency(action, target, pkg_vars, proto_dir)]
+        return [HardlinkDependency(action, target, pkg_vars)]
--- a/src/modules/flavor/python.py	Thu May 20 21:07:51 2010 -0700
+++ b/src/modules/flavor/python.py	Thu May 20 21:32:54 2010 -0700
@@ -21,8 +21,7 @@
 #
 
 #
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 import os
@@ -33,7 +32,7 @@
 import pkg.flavor.base as base
 import pkg.flavor.depthlimitedmf as modulefinder
 
-from pkg.portable import PD_LOCAL_PATH
+from pkg.portable import PD_LOCAL_PATH, PD_PROTO_DIR
 
 class PythonModuleMissingPath(base.DependencyAnalysisError):
         """Exception that is raised when a module reports a module as a
@@ -128,12 +127,9 @@
 py_bin_re = re.compile(r"^\#\!\s*/usr/bin/python(?P<major>\d+)\.(?P<minor>\d+)")
 py_lib_re = re.compile(r"^usr/lib/python(?P<major>\d+)\.(?P<minor>\d+)/")
 
-def process_python_dependencies(proto_dir, action, pkg_vars, script_path):
+def process_python_dependencies(action, pkg_vars, script_path):
         """Analyze the file delivered by the action for any python dependencies.
 
-        The 'proto_dir' parameter points to the proto area containing the file
-        which 'action' uses.
-
         The 'action' parameter contain the action which delivers the file.
 
         The 'pkg_vars' parameter contains the variants against which
@@ -227,7 +223,8 @@
         # If the version implied by the directory hierarchy matches the version
         # of python running, use the default analyzer and don't fork and exec.
         if cur_major == analysis_major and cur_minor == analysis_minor:
-                mf = modulefinder.DepthLimitedModuleFinder(proto_dir)
+                mf = modulefinder.DepthLimitedModuleFinder(
+                    action.attrs[PD_PROTO_DIR])
                 loaded_modules = mf.run_script(local_file)
 
                 for names, dirs in set([
@@ -235,7 +232,7 @@
                     for m in loaded_modules
                 ]):
                         deps.append(PythonDependency(action, names, dirs,
-                            pkg_vars, proto_dir))
+                            pkg_vars, action.attrs[PD_PROTO_DIR]))
                 missing, maybe = mf.any_missing_maybe()
                 for name in missing:
                         errs.append(PythonModuleMissingPath(name,
@@ -249,7 +246,7 @@
         exec_file = os.path.join(root_dir,
             "depthlimitedmf%s%s.py" % (analysis_major, analysis_minor))
         cmd = ["python%s.%s" % (analysis_major, analysis_minor), exec_file,
-            proto_dir, local_file]
+            action.attrs[PD_PROTO_DIR], local_file]
         try:
                 sp = subprocess.Popen(cmd, stdout=subprocess.PIPE,
                     stderr=subprocess.PIPE)
@@ -269,7 +266,7 @@
                                 bad_lines.append(l)
                         else:
                                 deps.append(PythonDependency(action, names,
-                                    dirs, pkg_vars, proto_dir))
+                                    dirs, pkg_vars, action.attrs[PD_PROTO_DIR]))
                 elif l.startswith("ERR "):
                         errs.append(PythonModuleMissingPath(l[4:],
                             action.attrs[PD_LOCAL_PATH]))
--- a/src/modules/flavor/script.py	Thu May 20 21:07:51 2010 -0700
+++ b/src/modules/flavor/script.py	Thu May 20 21:32:54 2010 -0700
@@ -21,8 +21,7 @@
 #
 
 #
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 import os
@@ -31,7 +30,7 @@
 import pkg.flavor.base as base
 import pkg.flavor.python as python
 
-from pkg.portable import PD_LOCAL_PATH
+from pkg.portable import PD_LOCAL_PATH, PD_PROTO_DIR
 
 class ScriptNonAbsPath(base.DependencyAnalysisError):
         """Exception that is raised when a file uses a relative path for the
@@ -61,11 +60,11 @@
                     self.base_names, self.run_paths, self.pkg_vars,
                     self.dep_vars)
 
-def process_script_deps(action, proto_dir, pkg_vars, **kwargs):
-        """Given an action and a place to find the file it references, if the
-        file starts with #! a list containing a ScriptDependency is returned.
-        Further, if the file is of a known type, it is further analyzed and
-        any dependencies found are added to the list returned."""
+def process_script_deps(action, pkg_vars, **kwargs):
+        """Given an action, if the file starts with #! a list containing a
+        ScriptDependency is returned.  Further, if the file is of a known type,
+        it is further analyzed and any dependencies found are added to the list
+        returned."""
 
         if action.name != "file":
                 return []
@@ -96,10 +95,10 @@
                                         # Use p[1:] to strip off the leading /.
                                         p = os.path.join("/usr", p[1:])
                                 deps.append(ScriptDependency(action, p,
-                                    pkg_vars, proto_dir))
+                                    pkg_vars, action.attrs[PD_PROTO_DIR]))
                                 script_path = l
                 if "python" in l:
-                        ds, errs = python.process_python_dependencies(proto_dir,
+                        ds, errs = python.process_python_dependencies(
                             action, pkg_vars, script_path)
                         elist.extend(errs)
                         deps.extend(ds)
--- a/src/modules/portable/__init__.py	Thu May 20 21:07:51 2010 -0700
+++ b/src/modules/portable/__init__.py	Thu May 20 21:32:54 2010 -0700
@@ -19,8 +19,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 # The portable module provide access to methods that require operating system-
@@ -74,7 +73,7 @@
         information, e.g. "i86pc"."""
         raise NotImplementedError
 
-def get_file_type(paths):
+def get_file_type(actions):
         """ Return a list containing the file type for each file in paths."""
         raise NotImplementedError
 
@@ -215,6 +214,7 @@
 # String to be used for an action attribute created for the internal use of
 # dependency analysis.
 PD_LOCAL_PATH = "pkg.internal.depend.localpath"
+PD_PROTO_DIR = "pkg.internal.depend.protodir"
 
 
 import platform
--- a/src/modules/portable/os_sunos.py	Thu May 20 21:07:51 2010 -0700
+++ b/src/modules/portable/os_sunos.py	Thu May 20 21:32:54 2010 -0700
@@ -19,8 +19,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 """
@@ -49,7 +48,7 @@
 def get_platform():
         return arch.get_platform()
 
-def get_file_type(actions, proto_dir):
+def get_file_type(actions):
         t_fd, t_path = tempfile.mkstemp()
         t_fh = os.fdopen(t_fd, "w")
         for a in actions:
--- a/src/modules/publish/dependencies.py	Thu May 20 21:07:51 2010 -0700
+++ b/src/modules/publish/dependencies.py	Thu May 20 21:32:54 2010 -0700
@@ -90,7 +90,7 @@
                         for grp in self.pvars.get_unsatisfied()
                     ]))
 
-def list_implicit_deps(file_path, proto_dir, dyn_tok_conv, kernel_paths,
+def list_implicit_deps(file_path, proto_dirs, dyn_tok_conv, kernel_paths,
     remove_internal_deps=True):
         """Given the manifest provided in file_path, use the known dependency
         generators to produce a list of dependencies the files delivered by
@@ -98,7 +98,7 @@
 
         'file_path' is the path to the manifest for the package.
 
-        'proto_dir' is the path to the proto area which holds the files that
+        'proto_dirs' is a list of paths to proto areas which hold the files that
         will be delivered by the package.
 
         'dyn_tok_conv' is the dictionary which maps the dynamic tokens, like
@@ -107,16 +107,15 @@
         'kernel_paths' contains the run paths which kernel modules should use.
         """
 
-        proto_dir = os.path.abspath(proto_dir)
-        m, missing_manf_files = __make_manifest(file_path, [proto_dir])
+        m, missing_manf_files = __make_manifest(file_path, proto_dirs)
         pkg_vars = m.get_all_variants()
-        deps, elist, missing = list_implicit_deps_for_manifest(m, proto_dir,
+        deps, elist, missing = list_implicit_deps_for_manifest(m, proto_dirs,
             pkg_vars, dyn_tok_conv, kernel_paths)
         if remove_internal_deps:
-                deps = resolve_internal_deps(deps, m, proto_dir, pkg_vars)
+                deps = resolve_internal_deps(deps, m, proto_dirs, pkg_vars)
         return deps, missing_manf_files + elist, missing
 
-def resolve_internal_deps(deps, mfst, proto_dir, pkg_vars):
+def resolve_internal_deps(deps, mfst, proto_dirs, pkg_vars):
         """Given a list of dependencies, remove those which are satisfied by
         others delivered by the same package.
 
@@ -139,7 +138,7 @@
                         pvars = pkg_vars
                 p = a.attrs["path"]
                 delivered.setdefault(p, variants.VariantSets()).merge(pvars)
-                p = os.path.join(proto_dir, p)
+                p = os.path.join(a.attrs[portable.PD_PROTO_DIR], p)
                 np = os.path.normpath(p)
                 rp = os.path.realpath(p)
                 # adding the normalized path
@@ -171,7 +170,7 @@
     portable.UNFOUND: no_such_file
 }
 
-def list_implicit_deps_for_manifest(mfst, proto_dir, pkg_vars, dyn_tok_conv,
+def list_implicit_deps_for_manifest(mfst, proto_dirs, pkg_vars, dyn_tok_conv,
     kernel_paths):
         """For a manifest, produce the list of dependencies generated by the
         files it installs.
@@ -202,7 +201,7 @@
         elist = []
         missing = {}
         act_list = list(mfst.gen_actions_by_type("file"))
-        file_types = portable.get_file_type(act_list, proto_dir)
+        file_types = portable.get_file_type(act_list)
 
         for i, file_type in enumerate(file_types):
                 a = act_list[i]
@@ -210,11 +209,11 @@
                         func = dispatch_dict[file_type]
                 except KeyError:
                         if file_type not in missing:
-                                missing[file_type] = os.path.join(proto_dir,
-                                    a.attrs["path"])
+                                missing[file_type] = \
+                                    a.attrs[portable.PD_LOCAL_PATH]
                 else:
                         try:
-                                ds, errs = func(action=a, proto_dir=proto_dir,
+                                ds, errs = func(action=a,
                                     pkg_vars=pkg_vars,
                                     dyn_tok_conv=dyn_tok_conv,
                                     kernel_paths=kernel_paths)
@@ -223,8 +222,7 @@
                         except base.DependencyAnalysisError, e:
                                 elist.append(e)
         for a in mfst.gen_actions_by_type("hardlink"):
-                deps.extend(hardlink.process_hardlink_deps(a, pkg_vars,
-                    proto_dir))
+                deps.extend(hardlink.process_hardlink_deps(a, pkg_vars))
         return deps, elist, missing
 
 def __make_manifest(fp, basedirs=None, load_data=True):
@@ -246,15 +244,16 @@
                 if not l or l[0] == '#':
                         continue
                 try:
-                        a, local_path = actions.internalizestr(l,
+                        a, local_path, used_bd = actions.internalizestr(l,
                             basedirs=basedirs,
                             load_data=load_data)
                         if local_path:
                                 assert portable.PD_LOCAL_PATH not in a.attrs
                                 a.attrs[portable.PD_LOCAL_PATH] = local_path
+                                a.attrs[portable.PD_PROTO_DIR] = used_bd
                         acts.append(a)
                 except actions.ActionDataError, e:
-                        new_a, local_path = actions.internalizestr(
+                        new_a, local_path, used_bd = actions.internalizestr(
                             l, basedirs=basedirs, load_data=False)
                         if new_a.name == "license":
                                 acts.append(new_a)
--- a/src/pkgdep.py	Thu May 20 21:07:51 2010 -0700
+++ b/src/pkgdep.py	Thu May 20 21:32:54 2010 -0700
@@ -24,7 +24,6 @@
 # Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
-import errno
 import getopt
 import gettext
 import locale
@@ -77,7 +76,8 @@
         pkgdepend [options] command [cmd_options] [operands]
 
 Subcommands:
-        pkgdepend generate [-DIkMm] manifest proto_dir
+        pkgdepend generate [-IMm] -d dir [-d dir] [-D name=value] [-k path]
+            manifest_path
         pkgdepend [options] resolve [-dmosv] manifest ...
 
 Options:
@@ -92,7 +92,7 @@
         """Produce a list of file dependencies from a manfiest and a proto
         area."""
         try:
-                opts, pargs = getopt.getopt(args, "D:Ik:Mm?",
+                opts, pargs = getopt.getopt(args, "d:D:Ik:Mm?",
                     ["help"])
         except getopt.GetoptError, e:
                 usage(_("illegal global option -- %s") % e.opt)
@@ -105,9 +105,15 @@
         kernel_paths = []
         platform_paths = []
         dyn_tok_conv = {}
+        proto_dirs = []
 
         for opt, arg in opts:
-                if opt == "-D":
+                if opt == "-d":
+                        if not os.path.isdir(arg):
+                                usage(_("The proto directory %s could not be "
+                                    "found." % arg), retcode=2)
+                        proto_dirs.append(os.path.abspath(arg))
+                elif opt == "-D":
                         try:
                                 dyn_tok_name, dyn_tok_val = arg.split("=", 1)
                         except:
@@ -129,8 +135,8 @@
                         show_usage = True
         if show_usage:
                 usage(retcode=0)
-        if len(pargs) != 2:
-                usage(_("Generate only accepts exactly two arguments."))
+        if len(pargs) > 2 or len(pargs) < 1:
+                usage(_("Generate only accepts one or two arguments."))
 
         if not kernel_paths:
                 kernel_paths = ["/kernel", "/usr/kernel"]
@@ -142,18 +148,22 @@
         retcode = 0
 
         manf = pargs[0]
-        proto_dir = pargs[1]
 
         if not os.path.isfile(manf):
                 usage(_("The manifest file %s could not be found." % manf),
                     retcode=2)
 
-        if not os.path.isdir(proto_dir):
-                usage(_("The proto directory %s could not be found." %
-                    proto_dir), retcode=2)
+        if len(pargs) > 1:
+                if not os.path.isdir(pargs[1]):
+                        usage(_("The proto directory %s could not be found." %
+                            pargs[1]), retcode=2)
+                proto_dirs.insert(0, os.path.abspath(pargs[1]))
+        if not proto_dirs:
+                usage(_("At least one proto directory must be provided."),
+                    retcode=2)
 
         try:
-                ds, es, ms = dependencies.list_implicit_deps(manf, proto_dir,
+                ds, es, ms = dependencies.list_implicit_deps(manf, proto_dirs,
                     dyn_tok_conv, kernel_paths, remove_internal_deps)
         except (actions.MalformedActionError, actions.UnknownActionError), e:
                 error(_("Could not parse manifest %(manifest)s because of the "
--- a/src/tests/api/t_dependencies.py	Thu May 20 21:07:51 2010 -0700
+++ b/src/tests/api/t_dependencies.py	Thu May 20 21:32:54 2010 -0700
@@ -20,8 +20,7 @@
 # CDDL HEADER END
 #
 
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
 
 import testutils
 if __name__ == "__main__":
@@ -157,13 +156,11 @@
 
         def make_python_test_files(self, py_version):
                 pdir = "usr/lib/python%s/vendor-packages" % py_version
-                for p in ["pkg_test/indexer_test/foobar",
-                    "pkg_test/search_storage_test", "pkg_test/misc_test"]:
-                        self.make_proto_text_file("%s/%s.py" % (pdir, p))
                 self.make_proto_text_file("%s/pkg_test/__init__.py" % pdir,
                     "#!/usr/bin/python\n")
-                self.make_proto_text_file("%s/pkg_test/indexer_test/__init__.py" %
-                    pdir, "#!/usr/bin/python")
+                self.make_proto_text_file(
+                    "%s/pkg_test/indexer_test/__init__.py" % pdir,
+                    "#!/usr/bin/python")
                 
         def make_elf(self, final_path, static=False):
                 out_file = os.path.join(self.proto_dir, final_path)
@@ -213,9 +210,9 @@
                                             d.action.attrs["path"], "baz")
                 t_path = self.make_manifest(self.ext_hardlink_manf)
                 _check_results(dependencies.list_implicit_deps(t_path,
-                    self.proto_dir, {}, []))
+                    [self.proto_dir], {}, []))
                 _check_results(dependencies.list_implicit_deps(t_path,
-                    self.proto_dir, {}, [],
+                    [self.proto_dir], {}, [],
                     remove_internal_deps=False))
 
         def test_int_hardlink(self):
@@ -226,8 +223,8 @@
                 t_path = self.make_manifest(self.int_hardlink_manf)
                 self.make_proto_text_file(self.paths["syslog_path"])
                 ds, es, ms = \
-                    dependencies.list_implicit_deps(t_path, self.proto_dir, {},
-                        [])
+                    dependencies.list_implicit_deps(t_path, [self.proto_dir],
+                        {}, [])
                 if es != []:
                         raise RuntimeError("Got errors in results:" +
                             "\n".join([str(s) for s in es]))
@@ -236,7 +233,7 @@
 
                 # Check that internal dependencies are as expected.
                 ds, es, ms = dependencies.list_implicit_deps(t_path,
-                    self.proto_dir, {}, [], remove_internal_deps=False)
+                    [self.proto_dir], {}, [], remove_internal_deps=False)
                 if es != []:
                         raise RuntimeError("Got errors in results:" +
                             "\n".join([str(s) for s in es]))
@@ -268,11 +265,12 @@
                         self.assertEqual(d.action.attrs["path"],
                             self.paths["script_path"])
                 t_path = self.make_manifest(self.ext_script_manf)
-                self.make_proto_text_file(self.paths["script_path"], self.script_text)
+                self.make_proto_text_file(self.paths["script_path"],
+                    self.script_text)
                 _check_res(dependencies.list_implicit_deps(t_path,
-                    self.proto_dir, {}, []))
+                    [self.proto_dir], {}, []))
                 _check_res(dependencies.list_implicit_deps(t_path,
-                    self.proto_dir, {}, [], remove_internal_deps=False))
+                    [self.proto_dir], {}, [], remove_internal_deps=False))
 
         def test_int_script(self):
                 """Check that a file that starts with #! and references a file
@@ -281,9 +279,10 @@
 
                 t_path = self.make_manifest(self.int_script_manf)
                 self.make_elf(self.paths["ksh_path"])
-                self.make_proto_text_file(self.paths["script_path"], self.script_text)
+                self.make_proto_text_file(self.paths["script_path"],
+                    self.script_text)
                 ds, es, ms = dependencies.list_implicit_deps(t_path,
-                    self.proto_dir, {}, [])
+                    [self.proto_dir], {}, [])
                 if es != []:
                         raise RuntimeError("Got errors in results:" +
                             "\n".join([str(s) for s in es]))
@@ -298,7 +297,7 @@
 
                 # Check that internal dependencies are as expected.
                 ds, es, ms = dependencies.list_implicit_deps(t_path,
-                    self.proto_dir, {}, [], remove_internal_deps=False)
+                    [self.proto_dir], {}, [], remove_internal_deps=False)
                 self.assertEqual(len(ds), 2)
                 for d in ds:
                         self.assert_(d.is_error())
@@ -341,9 +340,9 @@
                 t_path = self.make_manifest(self.ext_elf_manf)
                 self.make_elf(self.paths["curses_path"])
                 _check_res(dependencies.list_implicit_deps(t_path,
-                    self.proto_dir, {}, []))
+                    [self.proto_dir], {}, []))
                 _check_res(dependencies.list_implicit_deps(t_path,
-                    self.proto_dir, {}, [], remove_internal_deps=False))
+                    [self.proto_dir], {}, [], remove_internal_deps=False))
 
         def test_int_elf(self):
                 """Check that an elf file that requires a library inside its
@@ -372,7 +371,7 @@
                 self.make_elf(self.paths["curses_path"])
                 self.make_elf(self.paths["libc_path"], static=True)
                 d_map, es, ms = dependencies.list_implicit_deps(t_path,
-                    self.proto_dir, {}, [])
+                    [self.proto_dir], {}, [])
                 if es != []:
                         raise RuntimeError("Got errors in results:" +
                             "\n".join([str(s) for s in es]))
@@ -381,7 +380,7 @@
 
                 # Check that internal dependencies are as expected.
                 _check_all_res(dependencies.list_implicit_deps(t_path,
-                    self.proto_dir, {}, [], remove_internal_deps=False))
+                    [self.proto_dir], {}, [], remove_internal_deps=False))
 
         def test_ext_python_dep(self):
                 """Check that a python file that imports a module outside its
@@ -427,9 +426,9 @@
                 self.make_proto_text_file(self.paths["indexer_path"],
                     self.python_text)
                 _check_all_res(dependencies.list_implicit_deps(t_path,
-                    self.proto_dir, {}, []))
+                    [self.proto_dir], {}, []))
                 _check_all_res(dependencies.list_implicit_deps(t_path,
-                    self.proto_dir, {}, [], remove_internal_deps=False))
+                    [self.proto_dir], {}, [], remove_internal_deps=False))
 
         def test_ext_python_abs_import_dep(self):
                 """Check that a python file that uses absolute imports a module
@@ -478,9 +477,9 @@
                 self.make_proto_text_file(self.paths["indexer_path"],
                     self.python_abs_text)
                 _check_all_res(dependencies.list_implicit_deps(t_path,
-                    self.proto_dir, {}, []))
+                    [self.proto_dir], {}, []))
                 _check_all_res(dependencies.list_implicit_deps(t_path,
-                    self.proto_dir, {}, [], remove_internal_deps=False))
+                    [self.proto_dir], {}, [], remove_internal_deps=False))
 
         def test_ext_python_pkg_dep(self):
                 """Check that a python file that is the __init__.py file for a
@@ -523,11 +522,12 @@
                 self.__debug = True
                 t_path = self.make_manifest(self.ext_python_pkg_manf)
                 self.make_python_test_files(2.6)
-                self.make_proto_text_file(self.paths["pkg_path"], self.python_text)
+                self.make_proto_text_file(self.paths["pkg_path"],
+                    self.python_text)
                 _check_all_res(dependencies.list_implicit_deps(t_path,
-                    self.proto_dir, {}, []))
+                    [self.proto_dir], {}, []))
                 _check_all_res(dependencies.list_implicit_deps(t_path,
-                    self.proto_dir, {}, [], remove_internal_deps=False))
+                    [self.proto_dir], {}, [], remove_internal_deps=False))
 
         def test_variants_1(self):
                 """Test that a file which satisfies a dependency only under a
@@ -535,10 +535,11 @@
                 for the other set of variants."""
 
                 t_path = self.make_manifest(self.variant_manf_1)
-                self.make_proto_text_file(self.paths["script_path"], self.script_text)
+                self.make_proto_text_file(self.paths["script_path"],
+                    self.script_text)
                 self.make_elf(self.paths["ksh_path"])
                 ds, es, ms = dependencies.list_implicit_deps(t_path,
-                    self.proto_dir, {}, [])
+                    [self.proto_dir], {}, [])
                 if es != []:
                         raise RuntimeError("Got errors in results:" +
                             "\n".join([str(s) for s in es]))
@@ -581,7 +582,7 @@
                 self.make_proto_text_file(self.paths["script_path"], self.script_text)
                 self.make_elf(self.paths["ksh_path"])
                 ds, es, ms = dependencies.list_implicit_deps(t_path,
-                    self.proto_dir, {}, [])    
+                    [self.proto_dir], {}, [])    
                 if es != []:
                         raise RuntimeError("Got errors in results:" +
                             "\n".join([str(s) for s in es]))
@@ -596,7 +597,7 @@
 
                 # Check that internal dependencies are as expected.
                 ds, es, ms = dependencies.list_implicit_deps(t_path,
-                    self.proto_dir, {}, [], remove_internal_deps=False)
+                    [self.proto_dir], {}, [], remove_internal_deps=False)
                 if es != []:
                         raise RuntimeError("Got errors in results:" +
                             "\n".join([str(s) for s in es]))
@@ -627,10 +628,11 @@
                 reported as an external dependency."""
 
                 t_path = self.make_manifest(self.variant_manf_3)
-                self.make_proto_text_file(self.paths["script_path"], self.script_text)
+                self.make_proto_text_file(self.paths["script_path"],
+                    self.script_text)
                 self.make_elf(self.paths["ksh_path"])
                 ds, es, ms = dependencies.list_implicit_deps(t_path,
-                    self.proto_dir, {}, [])
+                    [self.proto_dir], {}, [])
                 if es != []:
                         raise RuntimeError("Got errors in results:" +
                             "\n".join([str(s) for s in es]))
@@ -683,7 +685,7 @@
                 t_path = self.make_manifest(
                     self.int_hardlink_manf_test_symlink)
                 ds, es, ms = dependencies.list_implicit_deps(t_path,
-                    self.proto_dir, {}, [])
+                    [self.proto_dir], {}, [])
 
         def test_str_methods(self):
                 """Test the str methods of objects in the flavor space."""
@@ -700,5 +702,178 @@
                 str(mi)
                 mi.make_package()
                 str(mi)
+
+        def test_multi_proto_dirs(self):
+                """Check that analysis works correctly when multiple proto_dirs
+                are given."""
+
+                def _check_all_res(res):
+                        ds, es, ms = res
+                        if es != []:
+                                raise RuntimeError("Got errors in results:" +
+                                    "\n".join([str(s) for s in es]))
+                        self.assertEqual(ms, {})
+                        self.assertEqual(len(ds), 1)
+                        d = ds[0]
+                        self.assert_(d.is_error())
+                        self.assert_(d.dep_vars.is_satisfied())
+                        self.assertEqual(d.base_names[0], "libc.so.1")
+                        self.assertEqual(set(d.run_paths),
+                            set(["lib", "usr/lib"]))
+                        self.assertEqual(d.dep_key(),
+                            self.__path_to_key(self.paths["libc_path"]))
+                        self.assertEqual(d.action.attrs["path"],
+                            self.paths["curses_path"])
+
+                t_path = self.make_manifest(self.int_elf_manf)
+                self.make_elf(os.path.join("foo", self.paths["curses_path"]))
+                self.make_elf(self.paths["libc_path"], static=True)
+
+                # This should fail because the "foo" directory is not given
+                # as a proto_dir.
+                d_map, es, ms = dependencies.list_implicit_deps(t_path,
+                    [self.proto_dir], {}, [])
+                if len(es) != 1:
+                        raise RuntimeError("Got errors in results:" +
+                            "\n".join([str(s) for s in es]))
+                if es[0].file_path != \
+                    os.path.join(self.proto_dir, self.paths["curses_path"]):
+                        raise RuntimeError("Wrong file was found missing:\n%s" %
+                            es[0])
+                self.assertEqual(ms, {})
+                self.assert_(len(d_map) == 0)
+
+                # This should work since the "foo" directory has been added to
+                # the list of proto_dirs to use.
+                d_map, es, ms = dependencies.list_implicit_deps(t_path,
+                    [self.proto_dir, os.path.join(self.proto_dir, "foo")],
+                    {}, [])
+                if es:
+                        raise RuntimeError("Got errors in results:" +
+                            "\n".join([str(s) for s in es]))
+                self.assertEqual(ms, {})
+                self.assert_(len(d_map) == 0)
+
+                # 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 = dependencies.list_implicit_deps(t_path,
+                    [self.proto_dir, os.path.join(self.proto_dir, "foo")],
+                    {}, [], remove_internal_deps=False)
+                if es:
+                        raise RuntimeError("Got errors in results:" +
+                            "\n".join([str(s) for s in es]))
+                if len(ms) != 1:
+                        raise RuntimeError("Didn't get expected types of "
+                            "missing files:\n%s" % ms)
+                self.assertEqual(ms.keys()[0], "empty file")
+                self.assert_(len(d_map) == 0)
+
+                # This should find the binary file first and thus produce
+                # a depend action.
+                d_map, es, ms = dependencies.list_implicit_deps(t_path,
+                    [os.path.join(self.proto_dir, "foo"), self.proto_dir],
+                    {}, [], remove_internal_deps=False)
+                if es:
+                        raise RuntimeError("Got errors in results:" +
+                            "\n".join([str(s) for s in es]))
+                self.assertEqual(ms, {})
+                self.assert_(len(d_map) == 1)
+
+                # Check alternative proto_dirs with hardlinks.
+                t_path = self.make_manifest(self.int_hardlink_manf)
+                self.make_proto_text_file(os.path.join("foo",
+                    self.paths["syslog_path"]))
+                # This test should fail because "foo" is not included in the
+                # list of proto_dirs.
+                ds, es, ms = \
+                    dependencies.list_implicit_deps(t_path, [self.proto_dir],
+                        {}, [])
+                if len(es) != 1:
+                        raise RuntimeError("Got errors in results:" +
+                            "\n".join([str(s) for s in es]))
+                if es[0].file_path != \
+                    os.path.join(self.proto_dir, self.paths["syslog_path"]):
+                        raise RuntimeError("Wrong file was found missing:\n%s" %
+                            es[0])
+                self.assert_(len(ms) == 0)
+                self.assert_(len(ds) == 1)
+
+                # This test should pass because the needed directory has been
+                # added to the list of proto_dirs.
+                ds, es, ms = \
+                    dependencies.list_implicit_deps(t_path,
+                        [self.proto_dir, os.path.join(self.proto_dir, "foo")],
+                        {}, [])
+                if es != []:
+                        raise RuntimeError("Got errors in results:" +
+                            "\n".join([str(s) for s in es]))
+                self.assert_(len(ms) == 1)
+                self.assert_(len(ds) == 0)
+
+                # Check alternative proto_dirs work with python files and
+                # scripts.
+
+                def _py_check_all_res(res):
+                        ds, es, ms = res
+                        mod_suffs = ["/__init__.py", ".py", ".pyc", ".pyo"]
+                        mod_names = ["foobar", "misc_test", "os",
+                            "search_storage"]
+                        pkg_names = ["indexer_test", "pkg", "pkg_test"]
+                        expected_deps = set([("python",)] +
+                            [tuple(sorted([
+                                "%s%s" % (n,s) for s in mod_suffs
+                            ]))
+                            for n in mod_names] +
+                            [("%s/__init__.py" % n,) for n in pkg_names])
+                        if es != []:
+                                raise RuntimeError("Got errors in results:" +
+                                    "\n".join([str(s) for s in es]))
+
+                        self.assertEqual(ms, {})
+                        for d in ds:
+                                self.assert_(d.is_error())
+                                if d.dep_vars is None:
+                                        raise RuntimeError("This dep had "
+                                            "depvars of None:%s" % d)
+                                self.assert_(d.dep_vars.is_satisfied())
+                                if not d.dep_key()[0] in expected_deps:
+                                        raise RuntimeError("Got this "
+                                            "unexpected dep:%s\n\nd:%s" %
+                                            (d.dep_key()[0], d))
+                                expected_deps.remove(d.dep_key()[0])
+                                self.assertEqual(d.action.attrs["path"],
+                                        self.paths["indexer_path"])
+                        if expected_deps:
+                                raise RuntimeError("Couldn't find these "
+                                    "dependencies:\n" + "\n".join(
+                                    [str(s) for s in sorted(expected_deps)]))
+                self.__debug = True
+                t_path = self.make_manifest(self.ext_python_manf)
+
+                self.make_proto_text_file(
+                    os.path.join("d5", self.paths["indexer_path"]),
+                    self.python_text)
+                # This should have an error because it cannot find the file
+                # needed.
+                ds, es, ms = dependencies.list_implicit_deps(t_path,
+                    [self.proto_dir], {}, [])
+                if len(es) != 1:
+                        raise RuntimeError("Got errors in results:" +
+                            "\n".join([str(s) for s in es]))
+                if es[0].file_path != \
+                    os.path.join(self.proto_dir, self.paths["indexer_path"]):
+                        raise RuntimeError("Wrong file was found missing:\n%s" %
+                            es[0])
+                self.assertEqual(len(ds), 0)
+                self.assertEqual(len(ms), 0)
+
+                # Because d5 is in the list of proto dirs, this test should work
+                # normally.
+                _py_check_all_res(dependencies.list_implicit_deps(t_path,
+                    [self.proto_dir, os.path.join(self.proto_dir, "d5")], {},
+                    []))
+
+
 if __name__ == "__main__":
         unittest.main()
--- a/src/tests/cli/t_pkgdep.py	Thu May 20 21:07:51 2010 -0700
+++ b/src/tests/cli/t_pkgdep.py	Thu May 20 21:32:54 2010 -0700
@@ -407,7 +407,8 @@
         pkgdepend [options] command [cmd_options] [operands]
 
 Subcommands:
-        pkgdepend generate [-DIkMm] manifest proto_dir
+        pkgdepend generate [-IMm] -d dir [-d dir] [-D name=value] [-k path]
+            manifest_path
         pkgdepend [options] resolve [-dmosv] manifest ...
 
 Options:
@@ -674,13 +675,13 @@
                 """Ensure that incorrect arguments don't cause a traceback."""
 
                 proto = pkg5unittest.g_proto_area
-                self.pkgdepend_generate("", proto=proto, exit=2)
-                self.pkgdepend_generate("foo", proto="", exit=2)
-                self.pkgdepend_generate("-z foo bar", proto=proto, exit=2)
-                self.pkgdepend_generate("no_such_file_should_exist",
-                    proto=proto, exit=2)
-                self.pkgdepend_generate("-\?", proto="")
-                self.pkgdepend_generate("--help", proto="")
+                self.pkgdepend_generate("-d %s" % proto, exit=2)
+                self.pkgdepend_generate("foo", exit=2)
+                self.pkgdepend_generate("-d %s -z foo bar" % proto, exit=2)
+                self.pkgdepend_generate("-d %s no_such_file_should_exist" %
+                    proto, exit=2)
+                self.pkgdepend_generate("-\?")
+                self.pkgdepend_generate("--help")
 
         def test_output(self):
                 """Check that the output is in the format expected."""
@@ -688,16 +689,16 @@
                 tp = self.make_manifest(self.test_manf_1)
                 fp = "usr/lib/python2.6/vendor-packages/pkg/client/indexer.py"
 
-                self.pkgdepend_generate("%s" % tp,
-                    proto=pkg5unittest.g_proto_area, exit=1)
+                self.pkgdepend_generate("-d %s %s" %
+                    (pkg5unittest.g_proto_area, tp), exit=1)
                 self.check_res(self.make_res_manf_1(
                         pkg5unittest.g_proto_area) % {"reason": fp},
                     self.output)
                 self.check_res(self.err_manf_1 % pkg5unittest.g_proto_area,
                     self.errout)
 
-                self.pkgdepend_generate("-m %s" % tp,
-                    proto=pkg5unittest.g_proto_area, exit=1)
+                self.pkgdepend_generate("-m -d %s %s" %
+                    (pkg5unittest.g_proto_area, tp), exit=1)
                 self.check_res(
                     self.make_full_res_manf_1(
                         pkg5unittest.g_proto_area) % {"reason": fp},
@@ -708,7 +709,8 @@
                 self.make_proto_text_file(fp, self.python_text)
                 self.make_elf([], "usr/xpg4/lib/libcurses.so.1")
 
-                self.pkgdepend_generate("-m %s" % tp, proto=self.test_proto_dir)
+                self.pkgdepend_generate("-m -d %s %s" %
+                    (self.test_proto_dir, tp))
                 self.check_res(
                     self.make_full_res_manf_1_mod_proto(
                         pkg5unittest.g_proto_area)  % {"reason": fp},
@@ -718,7 +720,7 @@
                 tp = self.make_manifest(self.test_manf_2)
                 self.make_proto_text_file("etc/pam.conf", "text")
 
-                self.pkgdepend_generate("%s" % tp, proto=self.test_proto_dir)
+                self.pkgdepend_generate("-d %s %s" % (self.test_proto_dir, tp))
                 self.check_res(self.res_manf_2, self.output)
                 self.check_res("", self.errout)
 
@@ -734,7 +736,8 @@
                         "dummy_fmri":base.Dependency.DUMMY_FMRI
                     }, self.errout)
 
-                self.pkgdepend_generate("-M %s" % tp, proto=self.test_proto_dir)
+                self.pkgdepend_generate("-M -d %s %s" %
+                    (self.test_proto_dir, tp))
                 self.check_res(self.res_manf_2, self.output)
                 self.check_res(self.res_manf_2_missing, self.errout)
 
@@ -745,11 +748,12 @@
 
                 self.make_proto_text_file("var/log/syslog", "text")
 
-                self.pkgdepend_generate("%s" % tp, proto=self.test_proto_dir)
+                self.pkgdepend_generate("-d %s %s" % (self.test_proto_dir, tp))
                 self.check_res("", self.output)
                 self.check_res("", self.errout)
 
-                self.pkgdepend_generate("-I %s" % tp, proto=self.test_proto_dir)
+                self.pkgdepend_generate("-I -d %s %s" %
+                    (self.test_proto_dir, tp))
                 self.check_res(self.res_int_manf, self.output)
                 self.check_res("", self.errout)
 
@@ -792,7 +796,7 @@
                     {"py_ver":"2.4"})
                 fp = "usr/lib/python2.4/vendor-packages/pkg/client/indexer.py"
                 self.make_proto_text_file(fp, self.pyver_python_text % "2.6")
-                self.pkgdepend_generate("%s" % tp, proto=self.test_proto_dir,
+                self.pkgdepend_generate("-d %s %s" % (self.test_proto_dir, tp),
                      exit=1)
                 self.check_res(self.pyver_mismatch_results +
                     self.make_pyver_python_res("2.4", self.test_proto_dir) %
@@ -806,7 +810,8 @@
                     {"py_ver":"2.4"})
                 fp = "usr/lib/python2.4/vendor-packages/pkg/client/indexer.py"
                 self.make_proto_text_file(fp, self.pyver_python_text % "")
-                self.pkgdepend_generate("-m %s" % tp, proto=self.test_proto_dir)
+                self.pkgdepend_generate("-m -d %s %s" %
+                    (self.test_proto_dir, tp))
                 self.check_res(
                     self.pyver_res_full_manf_1("2.4", self.test_proto_dir) %
                         {"reason": fp, "bin_ver": ""},
@@ -817,7 +822,8 @@
                 tp = self.make_manifest(self.py_in_usr_bin_manf)
                 fp = "usr/bin/pkg"
                 self.make_proto_text_file(fp, self.pyver_python_text % "2.4")
-                self.pkgdepend_generate("-m %s" % tp, proto=self.test_proto_dir)
+                self.pkgdepend_generate("-m -d %s %s" %
+                    (self.test_proto_dir, tp))
                 self.check_res(
                     self.pyver_res_full_manf_1("2.4", self.test_proto_dir) %
                         {"reason": fp, "bin_ver": "2.4"},
@@ -828,21 +834,21 @@
                 tp = self.make_manifest(self.py_in_usr_bin_manf)
                 fp = "usr/bin/pkg"
                 self.make_proto_text_file(fp, self.pyver_python_text % "")
-                self.pkgdepend_generate("-m %s" % tp, proto=self.test_proto_dir,
-                    exit=1)
+                self.pkgdepend_generate("-m -d %s %s" %
+                    (self.test_proto_dir, tp), exit=1)
                 self.check_res(
                     self.pyver_24_script_full_manf_1 %
                         {"reason": fp, "bin_ver": ""},
                     self.output)
-                self.check_res(self.pyver_unspecified_ver_err % self.test_proto_dir,
-                    self.errout)
+                self.check_res(self.pyver_unspecified_ver_err %
+                    self.test_proto_dir, self.errout)
 
                 # Test line 5 (!X D F)
                 tp = self.make_manifest(self.pyver_test_manf_1_non_ex %
                     {"py_ver":"2.4"})
                 fp = "usr/lib/python2.4/vendor-packages/pkg/client/indexer.py"
                 self.make_proto_text_file(fp, self.pyver_python_text % "2.6")
-                self.pkgdepend_generate("%s" % tp, proto=self.test_proto_dir)
+                self.pkgdepend_generate("-d %s %s" % (self.test_proto_dir, tp))
                 self.check_res(
                     self.make_pyver_python_res("2.4", self.test_proto_dir) %
                         {"reason": fp},
@@ -854,7 +860,7 @@
                     {"py_ver":"2.4"})
                 fp = "usr/lib/python2.4/vendor-packages/pkg/client/indexer.py"
                 self.make_proto_text_file(fp, self.pyver_python_text % "")
-                self.pkgdepend_generate("%s" % tp, proto=self.test_proto_dir)
+                self.pkgdepend_generate("-d %s %s" % (self.test_proto_dir, tp))
                 self.check_res(
                     self.make_pyver_python_res("2.4", self.test_proto_dir) %
                         {"reason": fp},
@@ -865,7 +871,7 @@
                 tp = self.make_manifest(self.py_in_usr_bin_manf_non_ex)
                 fp = "usr/bin/pkg"
                 self.make_proto_text_file(fp, self.pyver_python_text % "2.4")
-                self.pkgdepend_generate("%s" % tp, proto=self.test_proto_dir)
+                self.pkgdepend_generate("-d %s %s" % (self.test_proto_dir, tp))
                 self.check_res("", self.output)
                 self.check_res("", self.errout)
 
@@ -873,7 +879,7 @@
                 tp = self.make_manifest(self.py_in_usr_bin_manf_non_ex)
                 fp = "usr/bin/pkg"
                 self.make_proto_text_file(fp, self.pyver_python_text % "")
-                self.pkgdepend_generate("%s" % tp, proto=self.test_proto_dir)
+                self.pkgdepend_generate("-d %s %s" % (self.test_proto_dir, tp))
                 self.check_res("", self.output)
                 self.check_res("", self.errout)
 
@@ -891,10 +897,11 @@
                         self.make_proto_text_file(fp, self.python_text)
 
                         # Run generate and check the output.
-                        self.pkgdepend_generate("-m %s" % tp,
-                            proto=self.test_proto_dir)
+                        self.pkgdepend_generate("-m -d %s %s" %
+                            (self.test_proto_dir, tp))
                         self.check_res(
-                            self.pyver_res_full_manf_1(py_ver, self.test_proto_dir) %
+                            self.pyver_res_full_manf_1(py_ver,
+                                self.test_proto_dir) %
                                 {"bin_ver": "", "reason":fp},
                             self.output)
                         self.check_res("", self.errout)
@@ -969,7 +976,7 @@
                 # Try feeding a directory where a manifest should be--
                 # a typical scenario we play out here is a user
                 # inverting the first and second args.
-                self.pkgdepend_generate("/", proto=m_path, exit=2)
+                self.pkgdepend_generate("/", exit=2)
                 self.check_res(
                     "pkgdepend: The manifest file / could not be found.\n" +
                     self.usage_msg, self.errout)
@@ -1003,7 +1010,7 @@
 
                 proto = pkg5unittest.g_proto_area
                 tp = self.make_manifest(self.payload_manf)
-                self.pkgdepend_generate("%s" % tp, proto=proto)
+                self.pkgdepend_generate("-d %s %s" % (proto, tp))
                 self.check_res(self.make_res_payload_1(proto) %\
                         {"reason": "usr/lib/python2.6/foo/bar.py"},
                     self.output)
@@ -1016,8 +1023,8 @@
                 nonsense = "This is a nonsense manifest"
                 m_path = self.make_manifest(nonsense)
 
-                self.pkgdepend_generate("%s" % m_path,
-                    proto=self.test_proto_dir, exit=1)
+                self.pkgdepend_generate("-d %s %s" %
+                    (self.test_proto_dir, m_path), exit=1)
                 self.check_res('pkgdepend: Could not parse manifest ' +
                     '%s because of the following line:\n' % m_path +
                     nonsense, self.errout)
@@ -1035,8 +1042,8 @@
                 elf_path = self.make_elf(run_paths)
                 m_path = self.make_manifest(self.elf_sub_manf %
                     {"file_loc": elf_path})
-                self.pkgdepend_generate("%s %s" % (dep_args, m_path),
-                    proto=self.test_proto_dir)
+                self.pkgdepend_generate("%s -d %s %s" %
+                    (dep_args, self.test_proto_dir, m_path))
                 self.check_res(self.payload_elf_sub_stdout %
                     {"replaced_path": \
                         (" %s.path=%s" %
@@ -1054,21 +1061,22 @@
                 elf_path = self.make_elf([])
                 m_path = self.make_manifest(self.kernel_manf %
                     {"file_loc":elf_path})
-                self.pkgdepend_generate("%s" % m_path,
-                    proto=self.test_proto_dir)
+                self.pkgdepend_generate("-d %s %s" %
+                    (self.test_proto_dir, m_path))
                 self.check_res("", self.errout)
                 self.check_res(self.kernel_manf_stdout, self.output)
 
-                self.pkgdepend_generate("-k baz -k foo/bar %s" % m_path,
-                    proto=self.test_proto_dir)
+                self.pkgdepend_generate("-k baz -k foo/bar -d %s %s" %
+                    (self.test_proto_dir, m_path))
                 self.check_res("", self.errout)
                 self.check_res(self.kernel_manf_stdout2, self.output)
 
                 self.debug("Test for platform substitution in kernel " \
                     "module paths. Bug 13057")
 
-                self.pkgdepend_generate("-D PLATFORM=baz -D PLATFORM=tp %s" %
-                    m_path, proto=self.test_proto_dir)
+                self.pkgdepend_generate(
+                    "-D PLATFORM=baz -D PLATFORM=tp -d %s %s" %
+                    (self.test_proto_dir, m_path))
                 self.check_res("", self.errout)
                 self.check_res(self.kernel_manf_stdout_platform, self.output)
 
@@ -1078,11 +1086,12 @@
                 elf_path = self.make_elf(rp)
                 m_path = self.make_manifest(self.elf_sub_manf %
                     {"file_loc": elf_path})
-                self.pkgdepend_generate("%s" % m_path, proto=self.test_proto_dir,
-                    exit=1)
+                self.pkgdepend_generate("-d %s %s" %
+                    (self.test_proto_dir, m_path), exit=1)
                 self.check_res((self.payload_elf_sub_error %
                     {
-                        "payload_path": os.path.join(self.test_proto_dir, elf_path),
+                        "payload_path": os.path.join(self.test_proto_dir,
+                            elf_path),
                         "installed_path": "bar/foo",
                         "tok": "$PLATFORM",
                         "rp": rp[0]
@@ -1117,21 +1126,21 @@
                 elf_path = self.make_elf(rp)
                 m_path = self.make_manifest(self.elf_sub_manf %
                     {"file_loc": elf_path})
-                self.pkgdepend_generate("-D ISALIST=isadir %s" % m_path,
-                    proto=self.test_proto_dir, exit=1)
+                self.pkgdepend_generate("-D ISALIST=isadir -d %s %s" %
+                    (self.test_proto_dir, m_path), exit=1)
                 self.check_res(self.double_plat_error %
                     {"proto_dir": self.test_proto_dir}, self.errout)
                 self.check_res(self.double_plat_stdout, self.output)
 
-                self.pkgdepend_generate("-D PLATFORM=pfoo %s" % m_path,
-                    proto=self.test_proto_dir, exit=1)
+                self.pkgdepend_generate("-D PLATFORM=pfoo -d %s %s" %
+                    (self.test_proto_dir, m_path), exit=1)
                 self.check_res(self.double_plat_isa_error %
                     {"proto_dir": self.test_proto_dir}, self.errout)
                 self.check_res(self.double_plat_isa_stdout, self.output)
 
                 self.pkgdepend_generate("-D PLATFORM=pfoo -D PLATFORM=pfoo2 "
-                    "-D ISALIST=isadir -D ISALIST=isadir %s" % m_path,
-                    proto=self.test_proto_dir)
+                    "-D ISALIST=isadir -D ISALIST=isadir -d %s %s" %
+                    (self.test_proto_dir, m_path))
                 self.check_res("", self.errout)
                 self.check_res(self.double_double_stdout, self.output)
 
@@ -1140,8 +1149,8 @@
                 uses the right path."""
 
                 m_path = self.make_manifest(self.miss_payload_manf)
-                self.pkgdepend_generate("%s" % m_path,
-                    proto=self.test_proto_dir, exit=1)
+                self.pkgdepend_generate("-d %s %s" %
+                    (self.test_proto_dir, m_path), exit=1)
                 self.check_res(self.miss_payload_manf_error %
                     {"path_pref":self.test_proto_dir}, self.errout)
                 self.check_res("", self.output)
@@ -1173,8 +1182,8 @@
                 foo_path = self.make_proto_text_file("bar/foo", "#!perl -w\n\n")
                 m_path = self.make_manifest(self.elf_sub_manf %
                     {"file_loc": "bar/foo"})
-                self.pkgdepend_generate(m_path, proto=self.test_proto_dir,
-                    exit=1)
+                self.pkgdepend_generate("-d %s %s" %
+                    (self.test_proto_dir, m_path), exit=1)
                 self.check_res(self.output, "")
                 self.check_res(self.errout, "%s/bar/foo says it should be run "
                     "with 'perl' which is a relative path." %
@@ -1300,6 +1309,61 @@
                 self.pkgdepend_resolve("-o -S %s %s" % (m1_path, m2_path),
                     exit=1)
 
+        def test_bug_15843(self):
+                """Test that multiple proto_dirs work as expected."""
+
+                curses = "usr/xpg4/lib/libcurses.so.1"
+                pam = "etc/pam.conf"
+                self.make_elf([], "d1/%s" % curses)
+                self.make_proto_text_file("d2/%s" % pam, "text")
+                tp = self.make_manifest(self.test_manf_2)
+
+                # Check that files are not found.
+                self.pkgdepend_generate("-d %s %s" % (self.test_proto_dir, tp),
+                    exit=1)
+                self.check_res("", self.output)
+                self.check_res("\n".join([
+                    "Couldn't find %s" % os.path.join(self.test_proto_dir, d)
+                    for d in (curses, pam)]),
+                    self.errout)
+
+                # Check that the files are now correctly found.
+                self.pkgdepend_generate("-d %s -d %s -d %s %s" %
+                    (self.test_proto_dir,
+                    os.path.join(self.test_proto_dir, "d1"),
+                    os.path.join(self.test_proto_dir, "d2"), tp))
+                self.check_res(self.res_manf_2, self.output)
+                self.check_res("", self.errout)
+
+                # Check that ordering among proto_dirs is correct.
+                # This should produce no dependencies because the text file
+                # in self.test_proto_dir should be found first.
+                self.make_proto_text_file("usr/xpg4/lib/libcurses.so.1", "text")
+                self.pkgdepend_generate("-d %s -d %s -d %s %s" %
+                    (self.test_proto_dir,
+                    os.path.join(self.test_proto_dir, "d1"),
+                    os.path.join(self.test_proto_dir, "d2"), tp))
+                self.check_res("", self.output)
+                self.check_res("", self.errout)
+
+                # This should produce the normal results for this manifest
+                # because the compiled elf file should be found before the
+                # text file.
+                self.pkgdepend_generate("-d %s -d %s -d %s %s" %
+                    (os.path.join(self.test_proto_dir, "d2"),
+                    os.path.join(self.test_proto_dir, "d1"),
+                    self.test_proto_dir, tp))
+                self.check_res(self.res_manf_2, self.output)
+                self.check_res("", self.errout)
+
+                # Check the ordering among -d dirs is correct.
+                self.pkgdepend_generate("-d %s -d %s -d %s %s" %
+                    (os.path.join(self.test_proto_dir, "d2"),
+                    self.test_proto_dir,
+                    os.path.join(self.test_proto_dir, "d1"), tp))
+                self.check_res("", self.output)
+                self.check_res("", self.errout)
+
 
 if __name__ == "__main__":
         unittest.main()
--- a/src/tests/pkg5unittest.py	Thu May 20 21:07:51 2010 -0700
+++ b/src/tests/pkg5unittest.py	Thu May 20 21:32:54 2010 -0700
@@ -1335,11 +1335,11 @@
                             exit, retcode, self.output, comment)
                 return retcode
 
-        def pkgdepend_generate(self, args, proto, exit=0, comment=""):
+        def pkgdepend_generate(self, args, exit=0, comment=""):
                 wrapper = self.coverage_cmd
 
-                cmdline = "%s %s/usr/bin/pkgdepend generate %s %s" % (wrapper,
-                    g_proto_area, args, proto)
+                cmdline = "%s %s/usr/bin/pkgdepend generate %s" % \
+                    (wrapper, g_proto_area, args)
                 self.debugcmd(cmdline)
 
                 newenv = os.environ.copy()