18856 resolve errors need readability help for file dependencies
authorBrock Pytlik <brock.pytlik@oracle.com>
Thu, 01 Sep 2011 13:48:16 -0700
changeset 2528 d8f40e4e0ed6
parent 2527 19bead0d2dfa
child 2529 de3a83014795
18856 resolve errors need readability help for file dependencies
src/modules/actions/depend.py
src/modules/publish/dependencies.py
src/tests/cli/t_pkgdep.py
--- a/src/modules/actions/depend.py	Fri Aug 26 15:52:18 2011 -0700
+++ b/src/modules/actions/depend.py	Thu Sep 01 13:48:16 2011 -0700
@@ -323,6 +323,113 @@
                                 inds.append(("depend", ctype, stem, None))
                 return inds
 
+        def pretty_print(self):
+                """Write a dependency action across multiple lines.  This is
+                designed to be used in exceptions for cleaner printing of
+                unsatisfied dependencies."""
+
+                base_indent = "    "
+                act = self
+                out = base_indent + act.name
+
+                if hasattr(act, "hash") and act.hash != "NOHASH":
+                        out += " " + act.hash
+
+                # high order bits in sorting
+                def kvord(a):
+                        # Variants should always be last attribute.
+                        if a[0].startswith("variant."):
+                                return 7
+                        # Facets should always be before variants.
+                        if a[0].startswith("facet."):
+                                return 6
+                        # List attributes should be before facets and variants.
+                        if isinstance(a[1], list):
+                                return 5
+
+                        # For depend actions, type should always come
+                        # first even though it's not the key attribute,
+                        # and fmri should always come after type.
+                        if a[0] == "fmri":
+                                return 1
+                        elif a[0] == "type":
+                                return 0
+                        # Any other attributes should come just before list,
+                        # facet, and variant attributes.
+                        if a[0] != act.key_attr:
+                                return 4
+
+                        # No special order for all other cases.
+                        return 0
+
+                # actual cmp function
+                def cmpkv(a, b):
+                        c = cmp(kvord(a), kvord(b))
+                        if c:
+                                return c
+
+                        return cmp(a[0], b[0])
+
+                JOIN_TOK = " \\\n    " + base_indent
+                def grow(a, b, rem_values, force_nl=False):
+                        if not force_nl:
+                                lastnl = a.rfind("\n")
+                                if lastnl == -1:
+                                        lastnl = 0
+
+                                if rem_values == 1:
+                                        # If outputting the last attribute
+                                        # value, then use full line length.
+                                        max_len = 80
+                                else:
+                                        # If V1 format, or there are more
+                                        # attributes to output, then account for
+                                        # line-continuation marker.
+                                        max_len = 78
+
+                                # Note this length comparison doesn't include
+                                # the space used to append the second part of
+                                # the string.
+                                if (len(a) - lastnl + len(b) < max_len):
+                                        return a + " " + b
+                        return a + JOIN_TOK + b
+
+                def astr(aout):
+                        # Number of attribute values for first line and
+                        # remaining.
+                        first_line = True
+
+                        # Total number of remaining attribute values to output.
+                        rem_count = sum(len(act.attrlist(k)) for k in act.attrs)
+
+                        # Now build the action output string an attribute at a
+                        # time.
+                        for k, v in sorted(act.attrs.iteritems(), cmp=cmpkv):
+                                # Newline breaks are only forced when there is
+                                # more than one value for an attribute.
+                                if not (isinstance(v, list) or
+                                    isinstance(v, set)):
+                                        nv = [v]
+                                        use_force_nl = False
+                                else:
+                                        nv = v
+                                        use_force_nl = True
+
+                                for lmt in sorted(nv):
+                                        force_nl = use_force_nl and \
+                                            k.startswith("pkg.debug")
+                                        aout = grow(aout,
+                                            "=".join((k,
+                                                generic.quote_attr_value(lmt))),
+                                            rem_count,
+                                            force_nl=force_nl)
+                                        # Must be done for each value.
+                                        if first_line and JOIN_TOK in aout:
+                                                first_line = False
+                                        rem_count -= 1
+                        return aout
+                return astr(out)
+
         def validate(self, fmri=None):
                 """Performs additional validation of action attributes that
                 for performance or other reasons cannot or should not be done
--- a/src/modules/publish/dependencies.py	Fri Aug 26 15:52:18 2011 -0700
+++ b/src/modules/publish/dependencies.py	Thu Sep 01 13:48:16 2011 -0700
@@ -143,10 +143,11 @@
                 self.source = source
 
         def __str__(self):
+                s_str = "\n" + self.source.pretty_print() + "\n"
                 return _("The file dependency %(src)s depends on a path "
                     "delivered by multiple packages. Those packages "
                     "are:%(pkgs)s") % {
-                        "src":self.source,
+                        "src":s_str,
                         "pkgs":" ".join([str(p) for p in self.pkgs])
                     }
 
@@ -160,13 +161,14 @@
                 self.pvars = pvars
 
         def __str__(self):
+                dep_str = "\n" + self.file_dep.pretty_print()
                 if self.pvars.not_sat_set:
                         return _("%(pth)s has unresolved dependency '%(dep)s' "
                             "under the following combinations of "
                             "variants:\n%(combo)s") % \
                             {
                                 "pth":self.path,
-                                "dep":self.file_dep,
+                                "dep":dep_str + "\n",
                                 "combo":"\n".join([
                                     " ".join([
                                         ("%s:%s" % (name, val))
@@ -177,7 +179,7 @@
                 else:
                         return _("%(pth)s has unresolved dependency "
                             "'%(dep)s'.") % \
-                            { "pth":self.path, "dep":self.file_dep }
+                            { "pth":self.path, "dep":dep_str }
 
 
 class MissingPackageVariantError(DependencyError):
--- a/src/tests/cli/t_pkgdep.py	Fri Aug 26 15:52:18 2011 -0700
+++ b/src/tests/cli/t_pkgdep.py	Thu Sep 01 13:48:16 2011 -0700
@@ -191,7 +191,13 @@
         res_manf_2_missing = "ascii text"
 
         resolve_error = """\
-%(manf_path)s has unresolved dependency 'depend fmri=%(dummy_fmri)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' under the following combinations of variants:
+%(manf_path)s has unresolved dependency '
+    depend type=require fmri=%(dummy_fmri)s %(pfx)s.file=libc.so.1 \\
+        %(pfx)s.reason=usr/xpg4/lib/libcurses.so.1 \\
+        %(pfx)s.type=elf \\
+        %(pfx)s.path=lib \\
+        %(pfx)s.path=usr/lib
+' under the following combinations of variants:
 variant.arch:foo
 """
 
@@ -417,7 +423,10 @@
 }
 
         two_v_deps_resolve_error = """\
-%(manf_path)s has unresolved dependency 'depend fmri=%(dummy_fmri)s %(pfx)s.file=var/log/authlog %(pfx)s.reason=baz %(pfx)s.type=hardlink type=require' under the following combinations of variants:
+%(manf_path)s has unresolved dependency '
+    depend type=require fmri=%(dummy_fmri)s %(pfx)s.file=var/log/authlog \\
+        %(pfx)s.reason=baz %(pfx)s.type=hardlink
+' under the following combinations of variants:
 variant.foo:baz variant.num:three
 """
         usage_msg = """\
@@ -460,7 +469,13 @@
 The actions are:
 	depend fmri=pkg:/sat_bar_libc %(pfx)s.file=platform/bar/baz/no_such_named_file %(pfx)s.reason=foo/bar %(pfx)s.type=elf type=require
 	depend fmri=pkg:/sat_foo_libc %(pfx)s.file=platform/foo/baz/no_such_named_file %(pfx)s.reason=foo/bar %(pfx)s.type=elf type=require
-%(unresolved_path)s has unresolved dependency 'depend fmri=__TBD %(pfx)s.file=no_such_named_file %(pfx)s.path=platform/foo/baz %(pfx)s.path=platform/bar/baz %(pfx)s.path=lib %(pfx)s.path=usr/lib %(pfx)s.reason=foo/bar %(pfx)s.type=elf type=require'.
+%(unresolved_path)s has unresolved dependency '
+    depend type=require fmri=__TBD %(pfx)s.file=no_such_named_file \\
+        %(pfx)s.reason=foo/bar %(pfx)s.type=elf \\
+        %(pfx)s.path=lib \\
+        %(pfx)s.path=platform/bar/baz \\
+        %(pfx)s.path=platform/foo/baz \\
+        %(pfx)s.path=usr/lib'.
 """ % {
     "pfx":base.Dependency.DEPEND_DEBUG_PREFIX,
     "dummy_fmri":base.Dependency.DUMMY_FMRI,
@@ -468,8 +483,21 @@
 }
 
         amb_path_errors = """\
-The file dependency depend fmri=%(dummy_fmri)s %(pfx)s.file=no_such_named_file %(pfx)s.path=platform/foo/baz %(pfx)s.path=platform/bar/baz %(pfx)s.path=lib %(pfx)s.path=usr/lib %(pfx)s.reason=foo/bar %(pfx)s.type=elf type=require depends on a path delivered by multiple packages. Those packages are:pkg:/sat_bar_libc2 pkg:/sat_bar_libc
-%(unresolved_path)s has unresolved dependency 'depend fmri=%(dummy_fmri)s %(pfx)s.file=no_such_named_file %(pfx)s.path=platform/foo/baz %(pfx)s.path=platform/bar/baz %(pfx)s.path=lib %(pfx)s.path=usr/lib %(pfx)s.reason=foo/bar %(pfx)s.type=elf type=require'.
+The file dependency
+    depend type=require fmri=%(dummy_fmri)s %(pfx)s.file=no_such_named_file \\
+        %(pfx)s.reason=foo/bar %(pfx)s.type=elf \\
+        %(pfx)s.path=platform/foo/baz \\
+        %(pfx)s.path=platform/bar/baz \\
+        %(pfx)s.path=lib \\
+        %(pfx)s.path=usr/lib
+depends on a path delivered by multiple packages. Those packages are:pkg:/sat_bar_libc2 pkg:/sat_bar_libc
+%(unresolved_path)s has unresolved dependency '
+    depend type=require fmri=%(dummy_fmri)s %(pfx)s.file=no_such_named_file \\
+        %(pfx)s.reason=foo/bar %(pfx)s.type=elf \\
+        %(pfx)s.path=lib \\
+        %(pfx)s.path=platform/foo/baz \\
+        %(pfx)s.path=platform/bar/baz \\
+        %(pfx)s.path=usr/lib'.
 """ % {
     "pfx":base.Dependency.DEPEND_DEBUG_PREFIX,
     "dummy_fmri":base.Dependency.DUMMY_FMRI,
@@ -552,11 +580,18 @@
 """
 
         unsatisfied_error_1 = """\
-%s has unresolved dependency 'depend fmri=__TBD pkg.debug.depend.file=unsatisfied pkg.debug.depend.path=usr/bin pkg.debug.depend.reason=foo/bar pkg.debug.depend.type=elf type=require'.
+%s has unresolved dependency '
+    depend type=require fmri=__TBD pkg.debug.depend.file=unsatisfied \\
+        pkg.debug.depend.path=usr/bin pkg.debug.depend.reason=foo/bar \\
+        pkg.debug.depend.type=elf'.
 """
 
         unsatisfied_error_2 = """\
-%s has unresolved dependency 'depend fmri=__TBD pkg.debug.depend.file=unsatisfied pkg.debug.depend.path=usr/bin pkg.debug.depend.reason=foo/bar pkg.debug.depend.type=elf type=require' under the following combinations of variants:
+%s has unresolved dependency '
+    depend  type=require fmri=__TBD pkg.debug.depend.file=unsatisfied \\
+        pkg.debug.depend.path=usr/bin pkg.debug.depend.reason=foo/bar \\
+        pkg.debug.depend.type=elf
+' under the following combinations of variants:
 variant.foo:bar
 """