--- a/src/modules/manifest.py Mon Mar 11 15:15:21 2013 -0700
+++ b/src/modules/manifest.py Thu Feb 28 16:50:44 2013 -0800
@@ -41,6 +41,7 @@
from pkg.misc import EmptyDict, EmptyI, expanddirs, PKG_FILE_MODE, PKG_DIR_MODE
from pkg.actions.attribute import AttributeAction
+from pkg.actions.directory import DirectoryAction
class ManifestDifference(
namedtuple("ManifestDifference", "added changed removed")):
@@ -328,9 +329,8 @@
dirs = self._actions_to_dict(gen_references)
for d in dirs:
for v in dirs[d]:
- yield "dir path=%s %s\n" % \
- (d, " ".join("%s=%s" % t \
- for t in v.iteritems()))
+ a = DirectoryAction(path=d, **v)
+ yield str(a) + "\n"
def _gen_mediators_to_str(self):
"""Generate contents of mediatorcache file containing all
@@ -1148,28 +1148,39 @@
"""
mpath = self.__cache_path(name)
- if not os.path.exists(mpath):
- # no cached copy
- if not self.loaded:
- # need to load from disk
- self.__load()
- assert self.loaded
- return
+ if os.path.exists(mpath):
+ # we have cached copy on disk; use it
+ try:
+ with open(mpath, "rb") as f:
+ self._cache[name] = [
+ a for a in
+ (
+ actions.fromstr(s.rstrip())
+ for s in f
+ )
+ if not self.excludes or
+ a.include_this(self.excludes)
+ ]
+ return
+ except EnvironmentError, e:
+ raise apx._convert_error(e)
+ except actions.ActionError, e:
+ # Cache file is malformed; hopefully due to bugs
+ # that have been resolved (as opposed to actual
+ # corruption). Assume we should just ignore the
+ # cache and load action data.
+ try:
+ self.clear_cache(self.__cache_root)
+ except Exception, e:
+ # Ignore errors encountered during cache
+ # dump for this specific case.
+ pass
- # we have cached copy on disk; use it
- try:
- with open(mpath, "rb") as f:
- self._cache[name] = [
- a for a in
- (
- actions.fromstr(s.rstrip())
- for s in f
- )
- if not self.excludes or
- a.include_this(self.excludes)
- ]
- except EnvironmentError, e:
- raise apx._convert_error(e)
+ # no cached copy
+ if not self.loaded:
+ # need to load from disk
+ self.__load()
+ assert self.loaded
def get_directories(self, excludes):
""" return a list of directories implicitly or explicitly
--- a/src/tests/api/t_manifest.py Mon Mar 11 15:15:21 2013 -0700
+++ b/src/tests/api/t_manifest.py Thu Feb 28 16:50:44 2013 -0800
@@ -21,7 +21,7 @@
# CDDL HEADER END
#
-# Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
import unittest
import tempfile
@@ -79,7 +79,9 @@
set com.sun,test=false
depend type=require fmri=pkg:/library/libc
file fff555ff9 mode=0555 owner=sch group=staff path=/usr/bin/i386/sort isa=i386
-dir owner=root path=usr/bin group=bin mode=0755
+dir owner=root path=usr/bin group=bin mode=0755 variant.arch=i386 variant.arch=sparc
+dir owner=root path="opt/dir with spaces in value" group=bin mode=0755
+dir owner=root path="opt/dir with whitespaces in value" group=bin mode=0755
link path=usr/lib/amd64/libjpeg.so \
target=libjpeg.so.62.0.0
hardlink path=usr/bin/amd64/rksh93 target=ksh93 variant.opensolaris.zone=global
@@ -275,14 +277,14 @@
#
# Expect to see something -> None differences
#
- self.assertEqual(len(diffs), 7)
+ self.assertEqual(len(diffs), 9)
for d in diffs:
self.assertEqual(type(d[1]), types.NoneType)
#
# Expect to see None -> something differences
#
- self.assertEqual(len(diffs2), 7)
+ self.assertEqual(len(diffs2), 9)
for d in diffs2:
self.assertEqual(type(d[0]), types.NoneType)
self.assertNotEqual(type(d[1]), types.NoneType)
@@ -378,9 +380,18 @@
class TestFactoredManifest(pkg5unittest.Pkg5TestCase):
+ foo_content = """\
+set name=pkg.fmri value=pkg:/[email protected]
+dir owner=root path=usr/bin group=bin mode=0755 variant.arch=i386
+dir owner=root path="opt/dir with spaces in value" group=bin mode=0755
+dir owner=root path="opt/dir with whitespaces in value" group=bin mode=0755 variant.debug.osnet=true
+"""
+
def setUp(self):
pkg5unittest.Pkg5TestCase.setUp(self)
self.cache_dir = tempfile.mkdtemp()
+ self.foo_content_p5m = self.make_misc_files(
+ { "foo_content.p5m": self.foo_content })[0]
def test_cached_gen_actions_by_type(self):
"""Test that when a factored manifest generates actions by type
@@ -400,6 +411,77 @@
m1.exclude_content([v.allow_action, lambda x: True])
self.assertEqual(len(list(m1.gen_actions_by_type("dir"))), 1)
+ def test_get_directories(self):
+ """Verifies that get_directories() works as expected."""
+
+ v = variant.Variants({ "variant.arch": "sparc" })
+ excludes = [v.allow_action, lambda x: True]
+
+ m1 = manifest.FactoredManifest("[email protected]", self.cache_dir,
+ pathname=self.foo_content_p5m)
+
+ all_expected = [
+ "opt/dir with spaces in value",
+ "opt",
+ "usr/bin",
+ "opt/dir with whitespaces in value",
+ "usr"
+ ]
+
+ var_expected = [
+ "opt/dir with spaces in value",
+ "opt"
+ ]
+
+ def do_get_dirs():
+ actual = m1.get_directories([])
+ self.assertEqualDiff(all_expected, actual)
+
+ actual = m1.get_directories(excludes)
+ self.assertEqualDiff(var_expected, actual)
+
+ # Verify get_directories works for initial load.
+ do_get_dirs()
+
+ # Now repeat experiment using "cached" FactoredManifest.
+ cfile_path = os.path.join(self.cache_dir, "manifest.dircache")
+ self.assert_(os.path.isfile(cfile_path))
+ m1 = manifest.FactoredManifest("[email protected]", self.cache_dir,
+ pathname=self.foo_content_p5m)
+
+ do_get_dirs()
+
+ # Now rewrite the dircache so that it contains actions with
+ # paths that are not properly quoted to simulate older, broken
+ # behaviour and verify that the cache will be removed and that
+ # get_directories() still works as expected.
+ m1 = manifest.FactoredManifest("[email protected]", self.cache_dir,
+ pathname=self.foo_content_p5m)
+
+ with open(cfile_path, "wb") as f:
+ for a in m1.gen_actions_by_type("dir"):
+ f.write(
+ "dir path=%s %s\n" % (a.attrs["path"],
+ " ".join(
+ "%s=%s" % (attr, a.attrs[attr])
+ for attr in itertools.chain(
+ *a.get_varcet_keys())
+ )
+ ))
+
+ # Repeat tests again.
+ do_get_dirs()
+
+ # Verify cache file was removed (presumably because we
+ # detected it was malformed).
+ self.assert_(not os.path.exists(cfile_path))
+
+ # Repeat tests again, verifying cache file is recreated.
+ m1 = manifest.FactoredManifest("[email protected]", self.cache_dir,
+ pathname=self.foo_content_p5m)
+ do_get_dirs()
+ self.assert_(os.path.isfile(cfile_path))
+
if __name__ == "__main__":
unittest.main()
--- a/src/tests/cli/t_pkg_install.py Mon Mar 11 15:15:21 2013 -0700
+++ b/src/tests/cli/t_pkg_install.py Thu Feb 28 16:50:44 2013 -0800
@@ -181,6 +181,17 @@
add file tmp/cat mode=0555 owner=root group=bin path=/bin/cat
close """
+ fuzzy = """
+ open [email protected],5.11-0
+ add dir mode=0755 owner=root group=bin path="opt/dir with white\tspace"
+ add file tmp/cat mode=0644 owner=root group=bin path="opt/dir with white\tspace/cat in a hat"
+ close
+ open [email protected],5.11-0
+ add dir mode=0755 owner=root group=bin path="opt/dir with white\tspace"
+ add file tmp/cat mode=0644 owner=root group=bin path="opt/dir with white\tspace/cat in a hat"
+ add link path=etc/cat_link target="../opt/dir with white\tspace/cat in a hat"
+ close """
+
misc_files = [ "tmp/libc.so.1", "tmp/cat", "tmp/baz" ]
def setUp(self):
@@ -748,6 +759,29 @@
afobj.close()
self.pkg("install a16189", exit=1)
+ def test_install_fuzz(self):
+ """Verify that packages delivering files with whitespace in
+ their paths can be installed, updated, and uninstalled."""
+
+ self.pkgsend_bulk(self.rurl, self.fuzzy)
+ self.image_create(self.rurl)
+
+ self.pkg("install fuzzy@1")
+ self.pkg("verify -v")
+ self.pkg("update -vvv fuzzy@2")
+ self.pkg("verify -v")
+
+ for name in (
+ "opt/dir with white\tspace/cat in a hat",
+ "etc/cat_link",
+ ):
+ self.debug("fname: %s" % name)
+ self.assert_(os.path.exists(os.path.join(self.get_img_path(),
+ name)))
+
+ self.pkg("uninstall -vvv fuzzy")
+
+
class TestPkgInstallApache(pkg5unittest.ApacheDepotTestCase):
# Only start/stop the depot once (instead of for every test)