13059 pkgdep generate should analyze python modules using the version of python they use
13835 api_inst no longer needed by find_package
13843 ModuleInfo __str__ should work
13838 make_paths in dependencies.py needs to cope with rp's which are a string, instead of a list
--- a/src/modules/flavor/depthlimitedmf.py Wed Jan 20 15:05:44 2010 +0000
+++ b/src/modules/flavor/depthlimitedmf.py Wed Jan 20 16:09:18 2010 -0800
@@ -2,7 +2,7 @@
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Python
# Software Foundation; All Rights Reserved
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
@@ -10,9 +10,6 @@
modules and discovers where a module might be loaded instead of determining
which path contains a module to be loaded."""
-import dis
-import imp
-import marshal
import modulefinder
import os
import sys
@@ -59,8 +56,8 @@
return ["%s%s" % (self.name, suf) for suf in self.suffixes]
def __str__(self):
- return "name:%s py:%s pyc:%s pkg:%s dirs:%s" % (self.name,
- self.py, self.pyc, self.pkg, len(self.dirs))
+ return "name:%s suffixes:%s dirs:%s" % (self.name,
+ " ".join(self.suffixes), len(self.dirs))
class DepthLimitedModuleFinder(modulefinder.ModuleFinder):
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/modules/flavor/depthlimitedmf24.py Wed Jan 20 16:09:18 2010 -0800
@@ -0,0 +1,296 @@
+#!/usr/bin/python
+# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Python
+# Software Foundation; All Rights Reserved
+#
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+
+
+"""A standalone version of ModuleFinder which limits the depth of exploration
+for loaded modules and discovers where a module might be loaded instead of
+determining which path contains a module to be loaded. It is designed to be run
+by python2.4 or python2.5 against 2.4 or 2.5 modules. To communicate its
+results to the process which ran it, it prints output to stdout. The format is
+to start a line with 'DEP ' if it contains information about a dependency, and
+'ERR ' if it contains information about a module it couldn't analyze."""
+
+# This module cannot import other pkg modules because running the 2.4 or 2.5
+# interpreter will overwrite the pyc files for some of the other flavor modules.
+# With 2.6, the -B option can be added to the command line invocation for the
+# subprocess and the interpreter won't overwrite pyc files.
+
+import dis
+import modulefinder
+import os
+import sys
+
+from modulefinder import LOAD_CONST, IMPORT_NAME, STORE_NAME, STORE_GLOBAL, \
+ STORE_OPS
+
+python_path = "PYTHONPATH"
+
+class ModuleInfo(object):
+ """This class contains information about from where a python module
+ might be loaded."""
+
+ def __init__(self, name, dirs, builtin=False):
+ """Build a ModuleInfo object.
+
+ The 'name' parameter is the name of the module.
+
+ The 'dirs' parameter is the list of directories where the module
+ might be found.
+
+ The 'builtin' parameter sets whether the module is a python
+ builtin (like sys)."""
+
+ self.name = name
+ self.builtin = builtin
+ self.suffixes = [".py", ".pyc", ".pyo", "/__init__.py"]
+ self.dirs = sorted(dirs)
+
+ def make_package(self):
+ """Declare that this module is a package."""
+
+ if self.dirs:
+ self.suffixes = ["/__init__.py"]
+ else:
+ self.suffixes = []
+
+ def get_package_dirs(self):
+ """Get the directories where this package might be defined."""
+
+ return [os.path.join(p, self.name) for p in self.dirs]
+
+ def get_file_names(self):
+ """Return all the file names under which this module might be
+ found."""
+
+ return ["%s%s" % (self.name, suf) for suf in self.suffixes]
+
+ def __str__(self):
+ return "name:%s suffixes:%s dirs:%s" % (self.name,
+ " ".join(self.suffixes), len(self.dirs))
+
+class DepthLimitedModuleFinder(modulefinder.ModuleFinder):
+
+ def __init__(self, proto_dir, *args, **kwargs):
+ """Produce a module finder that ignores PYTHONPATH and only
+ reports the direct imports of a module."""
+
+ # Check to see whether a python path has been set.
+ if python_path in os.environ:
+ py_path = [
+ os.path.normpath(fp)
+ for fp in os.environ[python_path].split(os.pathsep)
+ ]
+ else:
+ py_path = []
+
+ # Remove any paths that start with the defined python paths.
+ new_path = [
+ fp
+ for fp in sys.path
+ if not self.startswith_path(fp, py_path)
+ ]
+
+ # Map the standard system paths into the proto area.
+ new_path = [
+ os.path.join(proto_dir, fp.lstrip("/"))
+ for fp in new_path
+ ]
+
+ modulefinder.ModuleFinder.__init__(self, path=new_path,
+ *args, **kwargs)
+ self.proto_dir = proto_dir
+
+ @staticmethod
+ def startswith_path(path, lst):
+ for l in lst:
+ if path.startswith(l):
+ return True
+ return False
+
+ def run_script(self, pathname):
+ """Find all the modules the module at pathname directly
+ imports."""
+
+ fp = open(pathname, "r")
+ return self.load_module('__main__', fp, pathname)
+
+ def load_module(self, fqname, fp, pathname):
+ """This code has been slightly modified from the function of
+ the parent class. Specifically, it checks the current depth
+ of the loading and halts if it exceeds the depth that was given
+ to run_script."""
+
+ self.msgin(2, "load_module", fqname, fp and "fp", pathname)
+ co = compile(fp.read()+'\n', pathname, 'exec')
+ m = self.add_module(fqname)
+ m.__file__ = pathname
+ res = []
+ if co:
+ if self.replace_paths:
+ co = self.replace_paths_in_code(co)
+ m.__code__ = co
+ res.extend(self.scan_code(co, m))
+ self.msgout(2, "load_module ->", m)
+ return res
+
+ def scan_code(self, co, m):
+ res = []
+ code = co.co_code
+ n = len(code)
+ i = 0
+ fromlist = None
+ while i < n:
+ c = code[i]
+ i = i+1
+ op = ord(c)
+ if op >= dis.HAVE_ARGUMENT:
+ oparg = ord(code[i]) + ord(code[i+1])*256
+ i = i+2
+ if op == LOAD_CONST:
+ # An IMPORT_NAME is always preceded by a
+ # LOAD_CONST, it's a tuple of "from" names, or
+ # None for a regular import. The tuple may
+ # contain "*" for "from <mod> import *"
+ fromlist = co.co_consts[oparg]
+ elif op == IMPORT_NAME:
+ assert fromlist is None or \
+ type(fromlist) is tuple
+ name = co.co_names[oparg]
+ have_star = 0
+ if fromlist is not None:
+ if "*" in fromlist:
+ have_star = 1
+ fromlist = [
+ f for f in fromlist if f != "*"
+ ]
+ res.extend(self._safe_import_hook(name, m,
+ fromlist))
+ elif op in STORE_OPS:
+ # keep track of all global names that are
+ # assigned to
+ name = co.co_names[oparg]
+ m.globalnames[name] = 1
+ for c in co.co_consts:
+ if isinstance(c, type(co)):
+ res.extend(self.scan_code(c, m))
+ return res
+
+
+ def _safe_import_hook(self, name, caller, fromlist, level=-1):
+ """Wrapper for self.import_hook() that won't raise ImportError.
+ """
+
+ res = []
+ if name in self.badmodules:
+ self._add_badmodule(name, caller)
+ return
+ try:
+ res.extend(self.import_hook(name, caller, level=level))
+ except ImportError, msg:
+ self.msg(2, "ImportError:", str(msg))
+ self._add_badmodule(name, caller)
+ else:
+ if fromlist:
+ for sub in fromlist:
+ if sub in self.badmodules:
+ self._add_badmodule(sub, caller)
+ continue
+ res.extend(self.import_hook(name,
+ caller, [sub], level=level))
+ return res
+
+ def import_hook(self, name, caller=None, fromlist=None, level=-1):
+ """Find all the modules that importing name will import."""
+
+ self.msg(3, "import_hook", name, caller, fromlist, level)
+ parent = self.determine_parent(caller)
+ q, tail = self.find_head_package(parent, name)
+ if not tail:
+ # If q is a builtin module, don't report it because it
+ # doesn't live in the normal module space and it's part
+ # of python itself, which is handled by a different
+ # kind of dependency.
+ if q.builtin:
+ return []
+ else:
+ return [q]
+ res = self.load_tail(name, q, tail)
+ q.make_package()
+ res.append(q)
+ return res
+
+ def import_module(self, partname, fqname, parent):
+ """Find where this module lives relative to its parent."""
+
+ parent_dirs = None
+ self.msgin(3, "import_module", partname, fqname, parent)
+ try:
+ m = self.modules[fqname]
+ except KeyError:
+ pass
+ else:
+ self.msgout(3, "import_module ->", m)
+ return m
+ if fqname in self.badmodules:
+ self.msgout(3, "import_module -> None")
+ return None
+ if parent:
+ if not parent.dirs:
+ self.msgout(3, "import_module -> None")
+ return None
+ else:
+ parent_dirs = parent.get_package_dirs()
+ try:
+ mod = self.find_module(partname, parent_dirs, parent)
+ except ImportError:
+ self.msgout(3, "import_module ->", None)
+ return None
+ return mod
+
+ def find_module(self, name, path, parent=None):
+ """Calculate the potential paths on the file system where the
+ module could be found."""
+
+ if path is None:
+ if name in sys.builtin_module_names or name == "__future__":
+ return ModuleInfo(name, [], builtin=True)
+ path = self.path
+ return ModuleInfo(name, path)
+
+ def load_tail(self, name, q, tail):
+ """Determine where each component of a multilevel import would
+ be found on the file system."""
+
+ self.msgin(4, "load_tail", q, tail)
+ m = q
+ res = []
+ while tail:
+ i = tail.find('.')
+ if i < 0: i = len(tail)
+ head, tail = tail[:i], tail[i+1:]
+ new_name = "%s.%s" % (name, head)
+ r = self.import_module(head, new_name, q)
+ res.append(r)
+ name = new_name
+ # All but the last module found must be packages because they
+ # contained other packages.
+ for i in range(0, len(res) - 1):
+ res[i].make_package()
+ self.msgout(4, "load_tail ->", m)
+ return res
+
+
+if __name__ == "__main__":
+ mf = DepthLimitedModuleFinder(sys.argv[1])
+ loaded_modules = mf.run_script(sys.argv[2])
+ for res in set([
+ (tuple(m.get_file_names()), tuple(m.dirs)) for m in loaded_modules
+ ]):
+ print "DEP %s" % (res,)
+ missing, maybe = mf.any_missing_maybe()
+ for name in missing:
+ print "ERR %s" % name,
--- a/src/modules/flavor/python.py Wed Jan 20 15:05:44 2010 +0000
+++ b/src/modules/flavor/python.py Wed Jan 20 16:09:18 2010 -0800
@@ -21,10 +21,15 @@
#
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+import os
+import re
+import subprocess
+import sys
+
import pkg.flavor.base as base
import pkg.flavor.depthlimitedmf as modulefinder
@@ -44,6 +49,69 @@
"in %(localpath)s") % self.__dict__
+class PythonMismatchedVersion(base.DependencyAnalysisError):
+ """Exception that is raised when a module is installed into a path
+ associated with a known version of python (/usr/lib/python2.4 for
+ example) but has a different version of python specified in its
+ #! line (#!/usr/bin/python2.5 for example)."""
+
+ def __init__(self, installed_version, declared_version, local_file,
+ installed_path):
+ self.inst_v = installed_version
+ self.decl_v = declared_version
+ self.lp = local_file
+ self.ip = installed_path
+
+ def __str__(self):
+ return _("The file to be installed at %(ip)s declares a "
+ "python version of %(decl_v)s. However, the path suggests "
+ "that the version should be %(inst_v)s. The text of the "
+ "file can be found at %(lp)s") % self.__dict__
+
+
+class PythonSubprocessError(base.DependencyAnalysisError):
+ """This exception is raised when the subprocess created to analyze the
+ module using a different version of python exits with an error code."""
+
+ def __init__(self, rc, cmd, err):
+ self.rc = rc
+ self.cmd = cmd
+ self.err = err
+
+ def __str__(self):
+ return _("The command %(cmd)s\nexited with return code %(rc)s "
+ "and this message:\n%(err)s") % self.__dict__
+
+
+class PythonSubprocessBadLine(base.DependencyAnalysisError):
+ """This exception is used when the output from the subprocess does not
+ follow the expected format."""
+
+ def __init__(self, cmd, lines):
+ self.lines = "\n".join(lines)
+ self.cmd = cmd
+
+ def __str__(self):
+ return _("The command %(cmd)s produced the following lines "
+ "which cannot be understood:\n%(lines)s") % self.__dict__
+
+class PythonUnspecifiedVersion(base.PublishingDependency):
+ """This exception is used when an executable file starts with
+ #!/usr/bin/python and is not installed into a location from which its
+ python version may be inferred."""
+
+ def __init__(self, local_file, installed_path):
+ self.lp = local_file
+ self.ip = installed_path
+
+ def __str__(self):
+ return _("The file to be installed in %(ip)s does not specify "
+ "a specific version of python either in its installed path "
+ "nor in its text. Such a file cannot be analyzed for "
+ "dependencies since the version of python it will be used "
+ "with is unknown. The text of the file is here: %(lp)s.") \
+ % self.__dict__
+
class PythonDependency(base.PublishingDependency):
"""Class representing the dependency created by importing a module
in python."""
@@ -57,26 +125,156 @@
self.base_names, self.run_paths, self.pkg_vars)
-def process_python_dependencies(proto_dir, action, pkg_vars):
- """Given the path to a python file, the proto area containing that file,
- the action that produced the dependency, and the variants against which
- the action's package was published, produce a list of PythonDependency
- objects."""
+py_bin_re = re.compile(r"^\#\!/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):
+ """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
+ the action's package was published.
+
+ The 'script_path' parameter is None of the file is not executable, or
+ is the path for the binary which is used to execute the file.
+ """
- local_file = action.attrs[PD_LOCAL_PATH]
+ # There are three conditions which determine whether python dependency
+ # analysis is performed on a file with python in its #! line.
+ # 1) Is the file executable. (Represented in the table below by X)
+ # 2) Is the file installed into a directory which provides information
+ # about what version of python should be used for it.
+ # (Represented by D)
+ # 3) Does the first line of the file include a specific version of
+ # python. (Represented by F)
+ #
+ # Conditions || Perform Analysis
+ # X D F || Y, if F and D disagree, display a warning in the output
+ # || and use D to analyze the file.
+ # X D !F || Y
+ # X !D F || Y
+ # X !D !F || N, and display a warning in the output.
+ # !X D F || Y
+ # !X D !F || Y
+ # !X !D F || N
+ # !X !D !F || N
- mf = modulefinder.DepthLimitedModuleFinder(proto_dir)
- loaded_modules = mf.run_script(local_file)
+ local_file = action.attrs[PD_LOCAL_PATH]
deps = []
errs = []
+ path_version = None
- for names, dirs in set([
- (tuple(m.get_file_names()), tuple(m.dirs)) for m in loaded_modules
- ]):
- deps.append(PythonDependency(action, names, dirs, pkg_vars,
- proto_dir))
- missing, maybe = mf.any_missing_maybe()
- for name in missing:
- errs.append(PythonModuleMissingPath(name,
- action.attrs[PD_LOCAL_PATH]))
+ dir_major = None
+ dir_minor = None
+ file_major = None
+ file_minor = None
+ cur_major = None
+ cur_minor = None
+ executable = bool(script_path)
+
+ # Version of python to use to do the analysis.
+ analysis_major = None
+ analysis_minor = None
+
+ cur_major, cur_minor = sys.version_info[0:2]
+ install_match = py_lib_re.match(action.attrs["path"])
+ if install_match:
+ dir_major = install_match.group("major")
+ dir_minor = install_match.group("minor")
+
+ script_match = None
+ if script_path:
+ script_match = py_bin_re.match(script_path)
+ if script_match:
+ file_major = script_match.group("major")
+ file_minor = script_match.group("minor")
+
+ if executable:
+ # Check whether the version of python declared in the #! line
+ # of the file and the version of python implied by the directory
+ # the file is delivered into match.
+ if install_match and script_match and \
+ (file_major != dir_major or file_minor != dir_minor):
+ errs.append(PythonMismatchedVersion(
+ "%s.%s" % (dir_major, dir_minor),
+ "%s.%s" % (file_major, file_minor),
+ local_file, action.attrs["path"]))
+ if install_match:
+ analysis_major = dir_major
+ analysis_minor = dir_minor
+ elif script_match:
+ analysis_major = file_major
+ analysis_minor = file_minor
+ else:
+ # An example of this case is an executable file in
+ # /usr/bin with #!/usr/bin/python as its first line.
+ errs.append(PythonUnspecifiedVersion(
+ local_file, action.attrs["path"]))
+ elif install_match:
+ analysis_major = dir_major
+ analysis_minor = dir_minor
+
+ if analysis_major is None or analysis_minor is None:
+ return deps, errs
+
+ analysis_major = int(analysis_major)
+ analysis_minor = int(analysis_minor)
+
+ # 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)
+ loaded_modules = mf.run_script(local_file)
+
+ for names, dirs in set([
+ (tuple(m.get_file_names()), tuple(m.dirs))
+ for m in loaded_modules
+ ]):
+ deps.append(PythonDependency(action, names, dirs,
+ pkg_vars, proto_dir))
+ missing, maybe = mf.any_missing_maybe()
+ for name in missing:
+ errs.append(PythonModuleMissingPath(name,
+ action.attrs[PD_LOCAL_PATH]))
+ return deps, errs
+
+ # If the version implied by the directory hierarchy does not match the
+ # version of python running, it's necessary to fork and run the
+ # appropriate version of python.
+ root_dir = os.path.dirname(__file__)
+ 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]
+ try:
+ sp = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ except Exception, e:
+ return [], [PythonSubprocessError(None, " ".join(cmd), str(e))]
+ out, err = sp.communicate()
+ if sp.returncode:
+ errs.append(PythonSubprocessError(sp.returncode, " ".join(cmd),
+ err))
+ bad_lines = []
+ for l in out.splitlines():
+ l = l.strip()
+ if l.startswith("DEP "):
+ try:
+ names, dirs = eval(l[4:])
+ except Exception:
+ bad_lines.append(l)
+ else:
+ deps.append(PythonDependency(action, names,
+ dirs, pkg_vars, proto_dir))
+ elif l.startswith("ERR "):
+ errs.append(PythonModuleMissingPath(l[4:],
+ action.attrs[PD_LOCAL_PATH]))
+ else:
+ bad_lines.append(l)
+ if bad_lines:
+ errs.append(PythonSubprocessBadLine(" ".join(cmd), bad_lines))
return deps, errs
--- a/src/modules/flavor/script.py Wed Jan 20 15:05:44 2010 +0000
+++ b/src/modules/flavor/script.py Wed Jan 20 16:09:18 2010 -0800
@@ -21,11 +21,12 @@
#
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
import os
+import stat
import pkg.flavor.base as base
import pkg.flavor.python as python
@@ -60,22 +61,29 @@
l = f.readline()
f.close()
+ deps = []
+ elist = []
+ script_path = None
# add #! dependency
if l.startswith("#!"):
- # usedlist omits leading /
- p = (l[2:].split()[0]) # first part of string is path (removes
- # options)
- # we don't handle dependencies through links, so fix up the
- # common one
- p = p.strip()
- if p.startswith("/bin"):
- p = os.path.join("/usr", p)
- deps = [ScriptDependency(action, p, pkg_vars, proto_dir)]
- elist = []
+ # Determine whether the file will be delivered executable.
+ ex_bit = int(action.attrs.get("mode", "0"), 8) & \
+ (stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
+ if ex_bit:
+ # usedlist omits leading /
+ p = (l[2:].split()[0])
+ # first part of string is path (removes options)
+ # we don't handle dependencies through links, so fix up
+ # the common one
+ p = p.strip()
+ if p.startswith("/bin"):
+ p = os.path.join("/usr", p)
+ deps.append(ScriptDependency(action, p, pkg_vars,
+ proto_dir))
+ script_path = l
if "python" in l:
ds, errs = python.process_python_dependencies(proto_dir,
- action, pkg_vars)
+ action, pkg_vars, script_path)
elist.extend(errs)
deps.extend(ds)
- return deps, elist
- return [], []
+ return deps, elist
--- a/src/modules/publish/dependencies.py Wed Jan 20 15:05:44 2010 +0000
+++ b/src/modules/publish/dependencies.py Wed Jan 20 16:09:18 2010 -0800
@@ -352,6 +352,8 @@
files = file_dep.attrs[files_prefix]
if isinstance(files, basestring):
files = [files]
+ if isinstance(rps, basestring):
+ rps = [rps]
return [os.path.join(rp, f) for rp in rps for f in files]
def find_package_using_delivered_files(delivered, file_dep, dep_vars,
@@ -432,12 +434,10 @@
return [a for a, v in res if a not in multiple_path_errs], dep_vars, \
errs
-def find_package(api_inst, delivered, installed, file_dep, pkg_vars):
+def find_package(delivered, installed, file_dep, pkg_vars):
"""Find the packages which resolve the dependency. It returns a list of
dependency actions with the fmri tag resolved.
- 'api_inst' is an ImageInterface which references the current image.
-
'delivered' is a dictionary mapping paths to a list of fmri, variants
pairs.
@@ -528,7 +528,7 @@
pkg_deps[mp] = None
continue
pkg_res = [
- (d, find_package(api_inst, delivered_files, installed_files,
+ (d, find_package(delivered_files, installed_files,
d, pkg_vars))
for d in mfst.gen_actions_by_type("depend")
if is_file_dependency(d)
--- a/src/pkgdefs/Makefile Wed Jan 20 15:05:44 2010 +0000
+++ b/src/pkgdefs/Makefile Wed Jan 20 16:09:18 2010 -0800
@@ -58,8 +58,11 @@
check: protoproto pkgproto
diff protoproto pkgproto | grep "^<" | nawk '{print $$3} END {exit NR != 0}'
+# Find and sort are in the pipline below because when pkgproto encounters two
+# files hardlinked together, it is not consistent about which is the file and
+# which is the hardlink in its output.
protoproto: FRC
- (cd $(ROOT) && pkgproto . | nawk '{print $$1, $$3}' | sort +1) > $@
+ (cd $(ROOT) && find . | sort | pkgproto | nawk '{print $$1, $$3}' | sort +1) > $@
PROTOS = $(SUBDIRS:%=%/prototype)
@@ -69,7 +72,7 @@
# file entries for the subsequent comparison to suceed.
#
pkgproto: $(PROTOS)
- nawk '$$1 ~ /[sdef]/ {print $$1, $$3}' $(PROTOS) | sed 's/^e/f/' | \
+ nawk '$$1 ~ /[lsdef]/ {print $$1, $$3}' $(PROTOS) | sed 's/^e/f/' | \
sort +1 -u > $@
FRC:
--- a/src/pkgdefs/SUNWipkg/prototype Wed Jan 20 15:05:44 2010 +0000
+++ b/src/pkgdefs/SUNWipkg/prototype Wed Jan 20 16:09:18 2010 -0800
@@ -151,6 +151,10 @@
f none usr/lib/python2.6/vendor-packages/pkg/flavor/base.pyc 444 root bin
f none usr/lib/python2.6/vendor-packages/pkg/flavor/depthlimitedmf.py 444 root bin
f none usr/lib/python2.6/vendor-packages/pkg/flavor/depthlimitedmf.pyc 444 root bin
+f none usr/lib/python2.6/vendor-packages/pkg/flavor/depthlimitedmf24.py 444 root bin
+f none usr/lib/python2.6/vendor-packages/pkg/flavor/depthlimitedmf24.pyc 444 root bin
+l none usr/lib/python2.6/vendor-packages/pkg/flavor/depthlimitedmf25.py=depthlimitedmf24.py
+l none usr/lib/python2.6/vendor-packages/pkg/flavor/depthlimitedmf25.pyc=depthlimitedmf24.pyc
f none usr/lib/python2.6/vendor-packages/pkg/flavor/elf.py 444 root bin
f none usr/lib/python2.6/vendor-packages/pkg/flavor/elf.pyc 444 root bin
f none usr/lib/python2.6/vendor-packages/pkg/flavor/hardlink.py 444 root bin
--- a/src/pkgdep.py Wed Jan 20 15:05:44 2010 +0000
+++ b/src/pkgdep.py Wed Jan 20 16:09:18 2010 -0800
@@ -105,7 +105,6 @@
kernel_paths = []
platform_paths = []
dyn_tok_conv = {}
- import sys
for opt, arg in opts:
if opt == "-D":
--- a/src/setup.py Wed Jan 20 15:05:44 2010 +0000
+++ b/src/setup.py Wed Jan 20 16:09:18 2010 -0800
@@ -172,6 +172,13 @@
execattrd_dir = 'etc/security/exec_attr.d'
authattrd_dir = 'etc/security/auth_attr.d'
+# A list of source, destination tuples of modules which should be hardlinked
+# together if the os supports it and otherwise copied.
+hardlink_modules = [
+ ("%s/pkg/flavor/depthlimitedmf24" % py_install_dir,
+ "%s/pkg/flavor/depthlimitedmf25" % py_install_dir)
+]
+
scripts_sunos = {
scripts_dir: [
['client.py', 'pkg'],
@@ -428,6 +435,21 @@
_install.run(self)
+ for o_src, o_dest in hardlink_modules:
+ for e in [".py", ".pyc"]:
+ src = util.change_root(self.root_dir, o_src + e)
+ dest = util.change_root(
+ self.root_dir, o_dest + e)
+ if ostype == "posix":
+ if os.path.exists(dest) and \
+ os.stat(src)[stat.ST_INO] != \
+ os.stat(dest)[stat.ST_INO]:
+ os.remove(dest)
+ file_util.copy_file(src, dest,
+ link="hard", update=1)
+ else:
+ file_util.copy_file(src, dest, update=1)
+
for d, files in scripts[osname].iteritems():
for (srcname, dstname) in files:
dst_dir = util.change_root(self.root_dir, d)
--- a/src/tests/api/t_dependencies.py Wed Jan 20 15:05:44 2010 +0000
+++ b/src/tests/api/t_dependencies.py Wed Jan 20 16:09:18 2010 -0800
@@ -41,7 +41,12 @@
import pkg5unittest
import pkg.catalog as catalog
+import pkg.flavor.base as base
+import pkg.flavor.depthlimitedmf as dlmf
import pkg.flavor.elf as elf
+import pkg.flavor.hardlink as hl
+import pkg.flavor.python as py
+import pkg.flavor.script as scr
import pkg.fmri as fmri
import pkg.portable as portable
import pkg.publish.dependencies as dependencies
@@ -719,3 +724,19 @@
self.int_hardlink_manf_test_symlink)
ds, es, ms = dependencies.list_implicit_deps(t_path,
self.proto_dir, {}, [])
+
+ def test_str_methods(self):
+ """Test the str methods of objects in the flavor space."""
+
+ str(base.MissingFile("fp"))
+ str(elf.BadElfFile("fp", "ex"))
+ str(elf.UnsupportedDynamicToken("/proto_path", "/install",
+ "run_path", "tok"))
+ str(py.PythonModuleMissingPath("foo", "bar"))
+ str(py.PythonMismatchedVersion("2.4", "2.6", "foo", "bar"))
+ str(py.PythonSubprocessError(2, "foo", "bar"))
+ str(py.PythonSubprocessBadLine("cmd", ["l1", "l2"]))
+ mi = dlmf.ModuleInfo("name", ["/d1", "/d2"])
+ str(mi)
+ mi.make_package()
+ str(mi)
--- a/src/tests/baseline.txt Wed Jan 20 15:05:44 2010 +0000
+++ b/src/tests/baseline.txt Wed Jan 20 16:09:18 2010 -0800
@@ -26,6 +26,7 @@
api.t_dependencies.py TestDependencyAnalyzer.test_int_elf|pass
api.t_dependencies.py TestDependencyAnalyzer.test_int_hardlink|pass
api.t_dependencies.py TestDependencyAnalyzer.test_int_script|pass
+api.t_dependencies.py TestDependencyAnalyzer.test_str_methods|pass
api.t_dependencies.py TestDependencyAnalyzer.test_symlinks|pass
api.t_dependencies.py TestDependencyAnalyzer.test_variants_1|pass
api.t_dependencies.py TestDependencyAnalyzer.test_variants_2|pass
@@ -573,12 +574,13 @@
cli.t_pkgdep.py TestPkgdepBasics.test_bug_11517|pass
cli.t_pkgdep.py TestPkgdepBasics.test_bug_11805|pass
cli.t_pkgdep.py TestPkgdepBasics.test_bug_11829|pass
-cli.t_pkgdep.py TestPkgdepBasics.test_bug_11989|fail
cli.t_pkgdep.py TestPkgdepBasics.test_bug_12697|pass
cli.t_pkgdep.py TestPkgdepBasics.test_bug_12816|pass
cli.t_pkgdep.py TestPkgdepBasics.test_bug_12896|pass
+cli.t_pkgdep.py TestPkgdepBasics.test_bug_13059|pass
cli.t_pkgdep.py TestPkgdepBasics.test_opts|pass
cli.t_pkgdep.py TestPkgdepBasics.test_output|pass
+cli.t_pkgdep.py TestPkgdepBasics.test_python_combinations|pass
cli.t_pkgdep.py TestPkgdepBasics.test_resolve_screen_out|pass
cli.t_pkgdep_resolve.py TestApiDependencies.test_bug_11518|pass
cli.t_pkgdep_resolve.py TestApiDependencies.test_bug_12697_and_12896|pass
--- a/src/tests/cli/t_pkgdep.py Wed Jan 20 15:05:44 2010 +0000
+++ b/src/tests/cli/t_pkgdep.py Wed Jan 20 16:09:18 2010 -0800
@@ -65,9 +65,9 @@
"""
payload_manf = """\
-hardlink path=usr/baz target=../foo/bar.py
+hardlink path=usr/baz target=lib/python2.6/foo/bar.py
file usr/lib/python2.6/vendor-packages/pkg/client/indexer.py \
-group=bin mode=0755 owner=root path=foo/bar.py
+group=bin mode=0755 owner=root path=usr/lib/python2.6/foo/bar.py
"""
elf_sub_manf = """\
@@ -189,18 +189,6 @@
variant.arch:foo
"""
- test_manf_1_resolved = """\
-depend fmri=%(py_pkg_name)s %(pfx)s.file=usr/bin/python %(pfx)s.reason=usr/lib/python2.6/vendor-packages/pkg/client/indexer.py %(pfx)s.type=script type=require
-depend fmri=%(ips_pkg_name)s %(pfx)s.file=usr/lib/python2.6/vendor-packages/pkg/__init__.py %(pfx)s.reason=usr/lib/python2.6/vendor-packages/pkg/client/indexer.py %(pfx)s.type=python type=require
-depend fmri=%(ips_pkg_name)s %(pfx)s.file=usr/lib/python2.6/vendor-packages/pkg/indexer.py %(pfx)s.reason=usr/lib/python2.6/vendor-packages/pkg/client/indexer.py %(pfx)s.type=python type=require
-depend fmri=%(ips_pkg_name)s %(pfx)s.file=usr/lib/python2.6/vendor-packages/pkg/misc.py %(pfx)s.reason=usr/lib/python2.6/vendor-packages/pkg/client/indexer.py %(pfx)s.type=python type=require
-depend fmri=%(ips_pkg_name)s %(pfx)s.file=usr/lib/python2.6/vendor-packages/pkg/search_storage.py %(pfx)s.reason=usr/lib/python2.6/vendor-packages/pkg/client/indexer.py %(pfx)s.type=python type=require
-depend fmri=%(resolve_name)s %(pfx)s.file=var/log/authlog %(pfx)s.reason=baz %(pfx)s.type=hardlink type=require
-depend fmri=%(csl_pkg_name)s %(pfx)s.file=libc.so.1 %(pfx)s.path=lib %(pfx)s.path=usr/lib %(pfx)s.reason=usr/xpg4/lib/libcurses.so.1 %(pfx)s.type=elf type=require
-"""
-
- test_manf_1_full_resolved = test_manf_1_resolved + test_manf_1
-
def make_full_res_manf_1_mod_proto(self, proto_area):
return self.make_full_res_manf_1(proto_area) + \
"""\
@@ -218,20 +206,20 @@
"%(pfx)s.file=misc/__init__.py " +
self.__make_paths("pkg",
[proto_area + "/usr/bin"] + self.new_path) +
- " %(pfx)s.reason=foo/bar.py "
+ " %(pfx)s.reason=usr/lib/python2.6/foo/bar.py "
"%(pfx)s.type=python type=require\n"
"depend fmri=%(dummy_fmri)s "
"%(pfx)s.file=pkg/__init__.py " +
self.__make_paths("",
[proto_area + "/usr/bin"] + self.new_path) +
- " %(pfx)s.reason=foo/bar.py "
+ " %(pfx)s.reason=usr/lib/python2.6/foo/bar.py "
"%(pfx)s.type=python type=require\n"
"depend fmri=%(dummy_fmri)s "
"%(pfx)s.file=python "
"%(pfx)s.path=usr/bin "
- "%(pfx)s.reason=foo/bar.py "
+ "%(pfx)s.reason=usr/lib/python2.6/foo/bar.py "
"%(pfx)s.type=script type=require\n"
"depend fmri=%(dummy_fmri)s "
"%(pfx)s.file=search_storage.py "
@@ -240,7 +228,7 @@
"%(pfx)s.file=search_storage/__init__.py " +
self.__make_paths("pkg",
[proto_area + "/usr/bin"] + self.new_path) +
- " %(pfx)s.reason=foo/bar.py "
+ " %(pfx)s.reason=usr/lib/python2.6/foo/bar.py "
"%(pfx)s.type=python type=require\n"
"depend fmri=%(dummy_fmri)s "
@@ -250,20 +238,13 @@
"%(pfx)s.file=indexer/__init__.py " +
self.__make_paths("pkg",
[proto_area + "/usr/bin"] + self.new_path) +
- " %(pfx)s.reason=foo/bar.py "
+ " %(pfx)s.reason=usr/lib/python2.6/foo/bar.py "
"%(pfx)s.type=python type=require\n") % {
"pfx":
base.Dependency.DEPEND_DEBUG_PREFIX,
"dummy_fmri":base.Dependency.DUMMY_FMRI
}
- res_payload_1_tmp = """\
-depend fmri=__TBD pkg.debug.depend.file=misc.py pkg.debug.depend.file=misc.pyc pkg.debug.depend.file=misc.pyo pkg.debug.depend.file=misc/__init__.py pkg.debug.depend.path=export/home/bpytlik/IPS/dep_tests/proto/root_i386/usr/bin/pkg pkg.debug.depend.path=export/home/bpytlik/IPS/dep_tests/src/tests/pkg pkg.debug.depend.path=usr/lib/python2.6/lib-dynload/pkg pkg.debug.depend.path=usr/lib/python2.6/lib-old/pkg pkg.debug.depend.path=usr/lib/python2.6/lib-tk/pkg pkg.debug.depend.path=usr/lib/python2.6/pkg pkg.debug.depend.path=usr/lib/python2.6/plat-sunos5/pkg pkg.debug.depend.path=usr/lib/python2.6/site-packages/pkg pkg.debug.depend.path=usr/lib/python2.6/vendor-packages/gst-0.10/pkg pkg.debug.depend.path=usr/lib/python2.6/vendor-packages/gtk-2.0/pkg pkg.debug.depend.path=usr/lib/python2.6/vendor-packages/pkg pkg.debug.depend.path=usr/lib/python26.zip/pkg pkg.debug.depend.reason=foo/bar.py pkg.debug.depend.type=python type=require
-depend fmri=__TBD pkg.debug.depend.file=pkg/__init__.py pkg.debug.depend.path=export/home/bpytlik/IPS/dep_tests/proto/root_i386/usr/bin pkg.debug.depend.path=export/home/bpytlik/IPS/dep_tests/src/tests pkg.debug.depend.path=usr/lib/python2.6 pkg.debug.depend.path=usr/lib/python2.6/lib-dynload pkg.debug.depend.path=usr/lib/python2.6/lib-old pkg.debug.depend.path=usr/lib/python2.6/lib-tk pkg.debug.depend.path=usr/lib/python2.6/plat-sunos5 pkg.debug.depend.path=usr/lib/python2.6/site-packages pkg.debug.depend.path=usr/lib/python2.6/vendor-packages pkg.debug.depend.path=usr/lib/python2.6/vendor-packages/gst-0.10 pkg.debug.depend.path=usr/lib/python2.6/vendor-packages/gtk-2.0 pkg.debug.depend.path=usr/lib/python26.zip pkg.debug.depend.reason=foo/bar.py pkg.debug.depend.type=python type=require
-depend fmri=__TBD pkg.debug.depend.file=python pkg.debug.depend.path=usr/bin pkg.debug.depend.reason=foo/bar.py pkg.debug.depend.type=script type=require
-depend fmri=__TBD pkg.debug.depend.file=search_storage.py pkg.debug.depend.file=search_storage.pyc pkg.debug.depend.file=search_storage.pyo pkg.debug.depend.file=search_storage/__init__.py pkg.debug.depend.path=export/home/bpytlik/IPS/dep_tests/proto/root_i386/usr/bin/pkg pkg.debug.depend.path=export/home/bpytlik/IPS/dep_tests/src/tests/pkg pkg.debug.depend.path=usr/lib/python2.6/lib-dynload/pkg pkg.debug.depend.path=usr/lib/python2.6/lib-old/pkg pkg.debug.depend.path=usr/lib/python2.6/lib-tk/pkg pkg.debug.depend.path=usr/lib/python2.6/pkg pkg.debug.depend.path=usr/lib/python2.6/plat-sunos5/pkg pkg.debug.depend.path=usr/lib/python2.6/site-packages/pkg pkg.debug.depend.path=usr/lib/python2.6/vendor-packages/gst-0.10/pkg pkg.debug.depend.path=usr/lib/python2.6/vendor-packages/gtk-2.0/pkg pkg.debug.depend.path=usr/lib/python2.6/vendor-packages/pkg pkg.debug.depend.path=usr/lib/python26.zip/pkg pkg.debug.depend.reason=foo/bar.py pkg.debug.depend.type=python type=require
-depend fmri=__TBD pkg.debug.depend.file=indexer.py pkg.debug.depend.file=indexer.pyc pkg.debug.depend.file=indexer.pyo pkg.debug.depend.file=indexer/__init__.py pkg.debug.depend.path=export/home/bpytlik/IPS/dep_tests/proto/root_i386/usr/bin/pkg pkg.debug.depend.path=export/home/bpytlik/IPS/dep_tests/src/tests/pkg pkg.debug.depend.path=usr/lib/python2.6/lib-dynload/pkg pkg.debug.depend.path=usr/lib/python2.6/lib-old/pkg pkg.debug.depend.path=usr/lib/python2.6/lib-tk/pkg pkg.debug.depend.path=usr/lib/python2.6/pkg pkg.debug.depend.path=usr/lib/python2.6/plat-sunos5/pkg pkg.debug.depend.path=usr/lib/python2.6/site-packages/pkg pkg.debug.depend.path=usr/lib/python2.6/vendor-packages/gst-0.10/pkg pkg.debug.depend.path=usr/lib/python2.6/vendor-packages/gtk-2.0/pkg pkg.debug.depend.path=usr/lib/python2.6/vendor-packages/pkg pkg.debug.depend.path=usr/lib/python26.zip/pkg pkg.debug.depend.reason=foo/bar.py pkg.debug.depend.type=python type=require
-"""
two_variant_deps = """\
set name=variant.foo value=bar value=baz
set name=variant.num value=one value=two value=three
@@ -447,19 +428,96 @@
from pkg.misc import EmptyI
"""
- p24_test_manf_1 = """\
-file NOHASH group=bin mode=0755 owner=root path=usr/lib/python2.4/vendor-packages/pkg/client/indexer.py
+ py_in_usr_bin_manf = """\
+file NOHASH group=bin mode=0755 owner=root path=usr/bin/pkg \
+"""
+
+ py_in_usr_bin_manf_non_ex = """\
+file NOHASH group=bin mode=0644 owner=root path=usr/bin/pkg \
+"""
+
+ pyver_python_text = """\
+#!/usr/bin/python%s
+
+import pkg.indexer as indexer
+import pkg.search_storage as ss
+from pkg.misc import EmptyI
+"""
+
+ pyver_test_manf_1 = """\
+file NOHASH group=bin mode=0755 owner=root path=usr/lib/python%(py_ver)s/vendor-packages/pkg/client/indexer.py \
"""
- p24_res_full_manf_1 = """\
-file NOHASH group=bin mode=0755 owner=root path=usr/lib/python2.4/vendor-packages/pkg/client/indexer.py
-depend %(pfx)s.file=usr/bin/python fmri=%(dummy_fmri)s type=require %(pfx)s.reason=usr/lib/python2.4/vendor-packages/pkg/client/indexer.py %(pfx)s.type=script
-depend %(pfx)s.file=usr/lib/python2.4/vendor-packages/pkg/__init__.py fmri=%(dummy_fmri)s type=require %(pfx)s.reason=usr/lib/python2.4/vendor-packages/pkg/client/indexer.py %(pfx)s.type=python
-depend %(pfx)s.file=usr/lib/python2.4/vendor-packages/pkg/indexer.py fmri=%(dummy_fmri)s type=require %(pfx)s.reason=usr/lib/python2.4/vendor-packages/pkg/client/indexer.py %(pfx)s.type=python
-depend %(pfx)s.file=usr/lib/python2.4/vendor-packages/pkg/misc.py fmri=%(dummy_fmri)s type=require %(pfx)s.reason=usr/lib/python2.4/vendor-packages/pkg/client/indexer.py %(pfx)s.type=python
-depend %(pfx)s.file=usr/lib/python2.4/vendor-packages/pkg/search_storage.py fmri=%(dummy_fmri)s type=require %(pfx)s.reason=usr/lib/python2.4/vendor-packages/pkg/client/indexer.py %(pfx)s.type=python
+ pyver_test_manf_1_non_ex = """\
+file NOHASH group=bin mode=0644 owner=root path=usr/lib/python%(py_ver)s/vendor-packages/pkg/client/indexer.py \
+"""
+ pyver_24_python_res = """
+depend fmri=%(dummy_fmri)s %(pfx)s.file=indexer.py %(pfx)s.file=indexer.pyc %(pfx)s.file=indexer.pyo %(pfx)s.file=indexer/__init__.py %(pfx)s.path=%(cwd)s/pkg %(pfx)s.path=usr/lib/python2.4/lib-dynload/pkg %(pfx)s.path=usr/lib/python2.4/lib-tk/pkg %(pfx)s.path=usr/lib/python2.4/pkg %(pfx)s.path=usr/lib/python2.4/plat-sunos5/pkg %(pfx)s.path=usr/lib/python2.4/site-packages/pkg %(pfx)s.path=usr/lib/python2.4/vendor-packages/gst-0.10/pkg %(pfx)s.path=usr/lib/python2.4/vendor-packages/gtk-2.0/pkg %(pfx)s.path=usr/lib/python2.4/vendor-packages/pkg %(pfx)s.path=usr/lib/python24.zip/pkg %(pfx)s.reason=%(reason)s %(pfx)s.type=python type=require
+depend fmri=%(dummy_fmri)s %(pfx)s.file=misc.py %(pfx)s.file=misc.pyc %(pfx)s.file=misc.pyo %(pfx)s.file=misc/__init__.py %(pfx)s.path=%(cwd)s/pkg %(pfx)s.path=usr/lib/python2.4/lib-dynload/pkg %(pfx)s.path=usr/lib/python2.4/lib-tk/pkg %(pfx)s.path=usr/lib/python2.4/pkg %(pfx)s.path=usr/lib/python2.4/plat-sunos5/pkg %(pfx)s.path=usr/lib/python2.4/site-packages/pkg %(pfx)s.path=usr/lib/python2.4/vendor-packages/gst-0.10/pkg %(pfx)s.path=usr/lib/python2.4/vendor-packages/gtk-2.0/pkg %(pfx)s.path=usr/lib/python2.4/vendor-packages/pkg %(pfx)s.path=usr/lib/python24.zip/pkg %(pfx)s.reason=%(reason)s %(pfx)s.type=python type=require
+depend fmri=%(dummy_fmri)s %(pfx)s.file=pkg/__init__.py %(pfx)s.path=%(cwd)s %(pfx)s.path=usr/lib/python2.4 %(pfx)s.path=usr/lib/python2.4/lib-dynload %(pfx)s.path=usr/lib/python2.4/lib-tk %(pfx)s.path=usr/lib/python2.4/plat-sunos5 %(pfx)s.path=usr/lib/python2.4/site-packages %(pfx)s.path=usr/lib/python2.4/vendor-packages %(pfx)s.path=usr/lib/python2.4/vendor-packages/gst-0.10 %(pfx)s.path=usr/lib/python2.4/vendor-packages/gtk-2.0 %(pfx)s.path=usr/lib/python24.zip %(pfx)s.reason=%(reason)s %(pfx)s.type=python type=require
+depend fmri=%(dummy_fmri)s %(pfx)s.file=search_storage.py %(pfx)s.file=search_storage.pyc %(pfx)s.file=search_storage.pyo %(pfx)s.file=search_storage/__init__.py %(pfx)s.path=%(cwd)s/pkg %(pfx)s.path=usr/lib/python2.4/lib-dynload/pkg %(pfx)s.path=usr/lib/python2.4/lib-tk/pkg %(pfx)s.path=usr/lib/python2.4/pkg %(pfx)s.path=usr/lib/python2.4/plat-sunos5/pkg %(pfx)s.path=usr/lib/python2.4/site-packages/pkg %(pfx)s.path=usr/lib/python2.4/vendor-packages/gst-0.10/pkg %(pfx)s.path=usr/lib/python2.4/vendor-packages/gtk-2.0/pkg %(pfx)s.path=usr/lib/python2.4/vendor-packages/pkg %(pfx)s.path=usr/lib/python24.zip/pkg %(pfx)s.reason=%(reason)s %(pfx)s.type=python type=require
+""" % {
+ "pfx": base.Dependency.DEPEND_DEBUG_PREFIX,
+ "dummy_fmri": base.Dependency.DUMMY_FMRI,
+ "cwd": os.getcwd().lstrip("/"),
+ "reason": "%(reason)s"
+}
+
+ pyver_24_script_full_manf_1 = """
+file NOHASH group=bin mode=0755 owner=root path=%(reason)s
+depend fmri=%(dummy_fmri)s %(pfx)s.file=python%(bin_ver)s %(pfx)s.path=usr/bin %(pfx)s.reason=%(reason)s %(pfx)s.type=script type=require\
+""" % {
+ "pfx": base.Dependency.DEPEND_DEBUG_PREFIX,
+ "dummy_fmri": base.Dependency.DUMMY_FMRI,
+ "cwd": os.getcwd().lstrip("/"),
+ "reason": "%(reason)s",
+ "bin_ver": "%(bin_ver)s"
+}
+
+ pyver_res_full_manf_1 = {}
+ pyver_res_full_manf_1["2.4"] = pyver_24_script_full_manf_1 + \
+ pyver_24_python_res
+
+ # 2.5 needs a separate entry from 2.4 because the default module search
+ # paths changed between the versions.
+ pyver_res_full_manf_1["2.5"] = """
+file NOHASH group=bin mode=0755 owner=root path=usr/lib/python2.5/vendor-packages/pkg/client/indexer.py
+depend fmri=%(dummy_fmri)s %(pfx)s.file=indexer.py %(pfx)s.file=indexer.pyc %(pfx)s.file=indexer.pyo %(pfx)s.file=indexer/__init__.py %(pfx)s.path=%(cwd)s/pkg %(pfx)s.path=usr/lib/python2.5/lib-dynload/pkg %(pfx)s.path=usr/lib/python2.5/lib-tk/pkg %(pfx)s.path=usr/lib/python2.5/pkg %(pfx)s.path=usr/lib/python2.5/plat-sunos5/pkg %(pfx)s.path=usr/lib/python2.5/site-packages/pkg %(pfx)s.path=usr/lib/python2.5/vendor-packages/pkg %(pfx)s.path=usr/lib/python25.zip/pkg %(pfx)s.reason=usr/lib/python2.5/vendor-packages/pkg/client/indexer.py %(pfx)s.type=python type=require
+depend fmri=%(dummy_fmri)s %(pfx)s.file=misc.py %(pfx)s.file=misc.pyc %(pfx)s.file=misc.pyo %(pfx)s.file=misc/__init__.py %(pfx)s.path=%(cwd)s/pkg %(pfx)s.path=usr/lib/python2.5/lib-dynload/pkg %(pfx)s.path=usr/lib/python2.5/lib-tk/pkg %(pfx)s.path=usr/lib/python2.5/pkg %(pfx)s.path=usr/lib/python2.5/plat-sunos5/pkg %(pfx)s.path=usr/lib/python2.5/site-packages/pkg %(pfx)s.path=usr/lib/python2.5/vendor-packages/pkg %(pfx)s.path=usr/lib/python25.zip/pkg %(pfx)s.reason=usr/lib/python2.5/vendor-packages/pkg/client/indexer.py %(pfx)s.type=python type=require
+depend fmri=%(dummy_fmri)s %(pfx)s.file=pkg/__init__.py %(pfx)s.path=%(cwd)s %(pfx)s.path=usr/lib/python2.5 %(pfx)s.path=usr/lib/python2.5/lib-dynload %(pfx)s.path=usr/lib/python2.5/lib-tk %(pfx)s.path=usr/lib/python2.5/plat-sunos5 %(pfx)s.path=usr/lib/python2.5/site-packages %(pfx)s.path=usr/lib/python2.5/vendor-packages %(pfx)s.path=usr/lib/python25.zip %(pfx)s.reason=usr/lib/python2.5/vendor-packages/pkg/client/indexer.py %(pfx)s.type=python type=require
+depend fmri=%(dummy_fmri)s %(pfx)s.file=python %(pfx)s.path=usr/bin %(pfx)s.reason=usr/lib/python2.5/vendor-packages/pkg/client/indexer.py %(pfx)s.type=script type=require
+depend fmri=%(dummy_fmri)s %(pfx)s.file=search_storage.py %(pfx)s.file=search_storage.pyc %(pfx)s.file=search_storage.pyo %(pfx)s.file=search_storage/__init__.py %(pfx)s.path=%(cwd)s/pkg %(pfx)s.path=usr/lib/python2.5/lib-dynload/pkg %(pfx)s.path=usr/lib/python2.5/lib-tk/pkg %(pfx)s.path=usr/lib/python2.5/pkg %(pfx)s.path=usr/lib/python2.5/plat-sunos5/pkg %(pfx)s.path=usr/lib/python2.5/site-packages/pkg %(pfx)s.path=usr/lib/python2.5/vendor-packages/pkg %(pfx)s.path=usr/lib/python25.zip/pkg %(pfx)s.reason=usr/lib/python2.5/vendor-packages/pkg/client/indexer.py %(pfx)s.type=python type=require
+""" % {"pfx":base.Dependency.DEPEND_DEBUG_PREFIX, "dummy_fmri":base.Dependency.DUMMY_FMRI, "cwd":os.getcwd().lstrip("/")}
+
+ # pyver_resolve_dep_manf = {}
+ pyver_resolve_dep_manf = """
+file NOHASH group=bin mode=0444 owner=root path=usr/lib/python%(py_ver)s/vendor-packages/pkg/indexer.py
+file NOHASH group=bin mode=0444 owner=root path=usr/lib/python%(py_ver)s/vendor-packages/pkg/__init__.py
+file NOHASH group=bin mode=0444 owner=root path=usr/lib/python%(py_ver)s/lib-tk/pkg/search_storage.py
+file NOHASH group=bin mode=0444 owner=root path=usr/lib/python%(py_ver)s/vendor-packages/pkg/misc.py
+file NOHASH group=bin mode=0755 owner=root path=usr/bin/python
+"""
+
+ pyver_resolve_results = """
+depend fmri=%(res_manf)s %(pfx)s.file=usr/lib/python%(py_ver)s/vendor-packages/pkg/indexer.py %(pfx)s.reason=usr/lib/python%(py_ver)s/vendor-packages/pkg/client/indexer.py %(pfx)s.type=python type=require
+depend fmri=%(res_manf)s %(pfx)s.file=usr/lib/python%(py_ver)s/vendor-packages/pkg/misc.py %(pfx)s.reason=usr/lib/python%(py_ver)s/vendor-packages/pkg/client/indexer.py %(pfx)s.type=python type=require
+depend fmri=%(res_manf)s %(pfx)s.file=usr/lib/python%(py_ver)s/vendor-packages/pkg/__init__.py %(pfx)s.reason=usr/lib/python%(py_ver)s/vendor-packages/pkg/client/indexer.py %(pfx)s.type=python type=require
+depend fmri=%(res_manf)s %(pfx)s.file=usr/bin/python %(pfx)s.reason=usr/lib/python%(py_ver)s/vendor-packages/pkg/client/indexer.py %(pfx)s.type=script type=require
+depend fmri=%(res_manf)s %(pfx)s.file=usr/lib/python%(py_ver)s/lib-tk/pkg/search_storage.py %(pfx)s.reason=usr/lib/python%(py_ver)s/vendor-packages/pkg/client/indexer.py %(pfx)s.type=python type=require
+"""
+
+ pyver_mismatch_results = """
+depend fmri=%(dummy_fmri)s %(pfx)s.file=python2.6 %(pfx)s.path=usr/bin %(pfx)s.reason=usr/lib/python2.4/vendor-packages/pkg/client/indexer.py %(pfx)s.type=script type=require \
""" % {"pfx":base.Dependency.DEPEND_DEBUG_PREFIX, "dummy_fmri":base.Dependency.DUMMY_FMRI}
+ pyver_mismatch_errs = """
+The file to be installed at usr/lib/python2.4/vendor-packages/pkg/client/indexer.py declares a python version of 2.6. However, the path suggests that the version should be 2.4. The text of the file can be found at %s/usr/lib/python2.4/vendor-packages/pkg/client/indexer.py
+"""
+
+ pyver_unspecified_ver_err = """
+The file to be installed in usr/bin/pkg does not specify a specific version of python either in its installed path nor in its text. Such a file cannot be analyzed for dependencies since the version of python it will be used with is unknown. The text of the file is here: %s/usr/bin/pkg.
+"""
+
def setUp(self):
testutils.SingleDepotTestCase.setUp(self)
self.image_create(self.dc.get_depot_url())
@@ -623,107 +681,171 @@
portable.remove(tp)
- def test_bug_11989(self):
- """These tests fail because they're resolved using a 2.6 based
- interpreter, instead of a 2.4 one."""
+ def test_python_combinations(self):
+ """Test that each line in the following table is accounted for
+ by a test case.
- tp = self.make_manifest(self.p24_test_manf_1)
- self.make_text_file("usr/lib/python2.4/vendor-packages/pkg/"
- "client/indexer.py", self.python_text)
- self.make_elf([], "usr/xpg4/lib/libcurses.so.1")
+ There are three conditions which determine whether python
+ dependency analysis is performed on a file with python in its
+ #! line.
+ 1) Is the file executable.
+ (Represented in the table below by X)
+ 2) Is the file installed into a directory which provides
+ information about what version of python should be used
+ for it.
+ (Represented by D)
+ 3) Does the first line of the file include a specific version
+ of python.
+ (Represented by F)
+ Conditions || Perform Analysis
+ X D F || Y, if F and D disagree, display a warning in the
+ || output and use D to analyze the file.
+ X D !F || Y
+ X !D F || Y
+ X !D !F || N, and display a warning in the output.
+ !X D F || Y
+ !X D !F || Y
+ !X !D F || N
+ !X !D !F || N
+ """
+
+ # The test for line 1 with matching versions is done by
+ # test_bug_13059.
+
+ # Test line 1 (X D F) with mismatched versions.
+ tp = self.make_manifest(self.pyver_test_manf_1 %
+ {"py_ver":"2.4"})
+ fp = "usr/lib/python2.4/vendor-packages/pkg/client/indexer.py"
+ self.make_text_file(fp, self.pyver_python_text % "2.6")
+ self.pkgdepend("generate %s" % tp, proto=self.proto_dir, exit=1)
+ self.check_res(self.pyver_mismatch_results + \
+ self.pyver_24_python_res % {"reason": fp, "bin_ver": "2.6"},
+ self.output)
+ self.check_res(self.pyver_mismatch_errs % self.proto_dir,
+ self.errout)
+
+ # Test line 2 (X D !F)
+ tp = self.make_manifest(self.pyver_test_manf_1 %
+ {"py_ver":"2.4"})
+ fp = "usr/lib/python2.4/vendor-packages/pkg/client/indexer.py"
+ self.make_text_file(fp, self.pyver_python_text % "")
self.pkgdepend("generate -m %s" % tp, proto=self.proto_dir)
- self.check_res(self.p24_res_full_manf_1, self.output)
- self.check_res("ensure failure", self.errout)
-
- dependency_mp = self.make_manifest(self.output)
- provider_mp = self.make_manifest(self.resolve_dep_manf)
-
- self.pkgdepend("resolve %s %s" % (dependency_mp, provider_mp),
- use_proto=False)
- self.check_res("", self.output)
+ self.check_res(
+ self.pyver_res_full_manf_1["2.4"] %
+ {"reason": fp, "bin_ver": ""},
+ self.output)
self.check_res("", self.errout)
- dependency_res_p = dependency_mp + ".res"
- provider_res_p = provider_mp + ".res"
- lines = self.__read_file(dependency_res_p)
- self.check_res(self.test_manf_1_resolved % {
- "resolve_name": os.path.basename(provider_mp),
- "pfx":
- base.Dependency.DEPEND_DEBUG_PREFIX,
- "dummy_fmri": base.Dependency.DUMMY_FMRI
- }, lines)
- lines = self.__read_file(provider_res_p)
- self.check_res("", lines)
+
+ # Test line 3 (X !D F)
+ tp = self.make_manifest(self.py_in_usr_bin_manf)
+ fp = "usr/bin/pkg"
+ self.make_text_file(fp, self.pyver_python_text % "2.4")
+ self.pkgdepend("generate -m %s" % tp, proto=self.proto_dir)
+ self.check_res(
+ self.pyver_res_full_manf_1["2.4"] %
+ {"reason": fp, "bin_ver": "2.4"},
+ self.output)
+ self.check_res("", self.errout)
+
+ # Test line 4 (X !D !F)
+ tp = self.make_manifest(self.py_in_usr_bin_manf)
+ fp = "usr/bin/pkg"
+ self.make_text_file(fp, self.pyver_python_text % "")
+ self.pkgdepend("generate -m %s" % tp, proto=self.proto_dir,
+ 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.proto_dir,
+ self.errout)
- portable.remove(dependency_res_p)
- portable.remove(provider_res_p)
+ # 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_text_file(fp, self.pyver_python_text % "2.6")
+ self.pkgdepend("generate %s" % tp, proto=self.proto_dir)
+ self.check_res(self.pyver_24_python_res % {"reason": fp},
+ self.output)
+ self.check_res("", self.errout)
- tmp_d = tempfile.mkdtemp()
-
- self.pkgdepend("resolve -m -d %s %s %s" %
- (tmp_d, dependency_mp, provider_mp), use_proto=False)
+ # Test line 6 (!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_text_file(fp, self.pyver_python_text % "")
+ self.pkgdepend("generate %s" % tp, proto=self.proto_dir)
+ self.check_res(self.pyver_24_python_res % {"reason": fp},
+ self.output)
+ self.check_res("", self.errout)
+
+ # Test line 7 (!X !D F)
+ tp = self.make_manifest(self.py_in_usr_bin_manf_non_ex)
+ fp = "usr/bin/pkg"
+ self.make_text_file(fp, self.pyver_python_text % "2.4")
+ self.pkgdepend("generate %s" % tp, proto=self.proto_dir)
self.check_res("", self.output)
self.check_res("", self.errout)
- dependency_res_p = os.path.join(tmp_d,
- os.path.basename(dependency_mp))
- provider_res_p = os.path.join(tmp_d,
- os.path.basename(provider_mp))
- lines = self.__read_file(dependency_res_p)
- self.check_res(self.test_manf_1_full_resolved % {
- "resolve_name": os.path.basename(provider_mp),
- "pfx":
- base.Dependency.DEPEND_DEBUG_PREFIX,
- "dummy_fmri":base.Dependency.DUMMY_FMRI
- }, lines)
- lines = self.__read_file(provider_res_p)
- self.check_res(self.resolve_dep_manf, lines)
- portable.remove(dependency_res_p)
- portable.remove(provider_res_p)
-
- self.pkgdepend("resolve -s foo -d %s %s %s" %
- (tmp_d, dependency_mp, provider_mp), use_proto=False)
+ # Test line 8 (!X !D !F)
+ tp = self.make_manifest(self.py_in_usr_bin_manf_non_ex)
+ fp = "usr/bin/pkg"
+ self.make_text_file(fp, self.pyver_python_text % "")
+ self.pkgdepend("generate %s" % tp, proto=self.proto_dir)
self.check_res("", self.output)
self.check_res("", self.errout)
- dependency_res_p = os.path.join(tmp_d,
- os.path.basename(dependency_mp)) + ".foo"
- provider_res_p = os.path.join(tmp_d,
- os.path.basename(provider_mp)) + ".foo"
- lines = self.__read_file(dependency_res_p)
- self.check_res(self.test_manf_1_resolved % {
- "resolve_name": os.path.basename(provider_mp),
- "pfx":
- base.Dependency.DEPEND_DEBUG_PREFIX,
- "dummy_fmri":base.Dependency.DUMMY_FMRI
- }, lines)
- lines = self.__read_file(provider_res_p)
- self.check_res("", lines)
+
+ def test_bug_13059(self):
+ """Test that python modules written for a version of python
+ other than the current system version are analyzed correctly."""
+
+ for py_ver in ["2.4", "2.5"]:
- portable.remove(dependency_res_p)
- portable.remove(provider_res_p)
+ # Set up the files for generate.
+ tp = self.make_manifest(
+ self.pyver_test_manf_1 % {"py_ver":py_ver})
+ fp = "usr/lib/python%s/vendor-packages/pkg/" \
+ "client/indexer.py" % py_ver
+ self.make_text_file(fp, self.python_text)
+
+ # Run generate and check the output.
+ self.pkgdepend("generate -m %s" % tp,
+ proto=self.proto_dir)
+ self.check_res(self.pyver_res_full_manf_1[py_ver] %
+ {"bin_ver": "", "reason":fp},
+ self.output)
+ self.check_res("", self.errout)
- self.pkgdepend("resolve -s .foo %s %s" %
- (dependency_mp, provider_mp), use_proto=False)
- self.check_res("", self.output)
- self.check_res("", self.errout)
- dependency_res_p = dependency_mp + ".foo"
- provider_res_p = provider_mp + ".foo"
- lines = self.__read_file(dependency_res_p)
- self.check_res(self.test_manf_1_resolved % {
- "resolve_name": os.path.basename(provider_mp),
- "pfx":
- base.Dependency.DEPEND_DEBUG_PREFIX,
- "dummy_fmri":base.Dependency.DUMMY_FMRI
- }, lines)
- lines = self.__read_file(provider_res_p)
- self.check_res("", lines)
+ # Take the output from the run and make it a file
+ # for the resolver to use.
+ dependency_mp = self.make_manifest(self.output)
+ provider_mp = self.make_manifest(
+ self.pyver_resolve_dep_manf % {"py_ver":py_ver})
- portable.remove(dependency_res_p)
- portable.remove(provider_res_p)
-
- os.rmdir(tmp_d)
- portable.remove(dependency_mp)
- portable.remove(provider_mp)
+ # Run resolver and check the output.
+ self.pkgdepend(
+ "resolve %s %s" % (dependency_mp, provider_mp),
+ use_proto=False)
+ self.check_res("", self.output)
+ self.check_res("", self.errout)
+ dependency_res_p = dependency_mp + ".res"
+ provider_res_p = provider_mp + ".res"
+ lines = self.__read_file(dependency_res_p)
+ self.check_res(self.pyver_resolve_results % {
+ "res_manf": os.path.basename(provider_mp),
+ "pfx":
+ base.Dependency.DEPEND_DEBUG_PREFIX,
+ "py_ver": py_ver,
+ "reason": fp
+ }, lines)
+ lines = self.__read_file(provider_res_p)
+ self.check_res("", lines)
+
+ # Clean up
+ portable.remove(dependency_res_p)
+ portable.remove(provider_res_p)
def test_resolve_screen_out(self):
"""Check that the results printed to screen are what is