16950 imageconfig set property silently converts single values to lists breaking consumers
16951 test needed for flush-content-cache-on-success
16952 property API errors need minor formatting fixes
16953 client_api_versions.txt missing entry for version 43
16954 pkg.client.api compatible_versions needs update
--- a/doc/client_api_versions.txt Thu Aug 26 10:44:20 2010 -0700
+++ b/doc/client_api_versions.txt Mon Aug 30 16:11:30 2010 -0500
@@ -1,3 +1,29 @@
+Version 43:
+Incompatible with clients using versions 0-42.
+
+ pkg.client.api.ImageInterface has changed as follows:
+
+ * A new boot environment will now only be created if required
+ for image-modifying operations (except for plan_update_all
+ which continues to always create one by default).
+
+ * The verbose parameter has been removed from the plan_*
+ functions.
+
+ * All plan_* functions now accept an additional boolean named
+ 'new_be' that indicates whether a new boot environment should
+ be created for the operation. This overrides the deafult
+ behaviour that only creates one if needed.
+
+ pkg.client.api.PlanDescription has changed as follows:
+
+ * get_services(), get_varcets(), and get_actions() were added
+ to allow clients more access to plan information.
+
+ * A boolean property named new_be was added that indicates
+ whether the planned operation will requires a new boot
+ environment.
+
Version 42:
Incompatible with clients using versions 0-41.
--- a/src/modules/client/api.py Thu Aug 26 10:44:20 2010 -0700
+++ b/src/modules/client/api.py Mon Aug 30 16:11:30 2010 -0500
@@ -125,7 +125,7 @@
This function can raise VersionException and
ImageNotFoundException."""
- compatible_versions = set([40, CURRENT_API_VERSION])
+ compatible_versions = set([CURRENT_API_VERSION])
if version_id not in compatible_versions:
raise apx.VersionException(CURRENT_API_VERSION,
--- a/src/modules/client/image.py Thu Aug 26 10:44:20 2010 -0700
+++ b/src/modules/client/image.py Mon Aug 30 16:11:30 2010 -0500
@@ -909,9 +909,9 @@
if not isinstance(t, list):
raise api_errors.InvalidPropertyValue(_(
"Cannot add a value to a single valued "
- "property. The property name is:%(name)s "
- "and the current value is:%(value)s") %
- {"name":prop_name, "value":t})
+ "property. The property name is: %(name)s "
+ "and the current value is: %(value)s") %
+ { "name": prop_name, "value": t })
self.cfg_cache.properties[prop_name].append(prop_value)
self.save_config()
@@ -922,10 +922,10 @@
if not isinstance(t, list):
raise api_errors.InvalidPropertyValue(_(
"Cannot remove a value from a single "
- "valued property, unset must be used. The "
- "property name is:%(name)s and the current "
- "value is:%(value)s") %
- {"name":prop_name, "value":t})
+ "valued property, unset must be used. "
+ "The property name is: %(name)s and the "
+ "current value is: %(value)s") %
+ { "name": prop_name, "value": t })
try:
self.cfg_cache.properties[prop_name].remove(
prop_value)
@@ -934,7 +934,7 @@
"Cannot remove the value %(value)s from "
"the property %(name)s because the value "
"is not in the property's list.") %
- {"value":prop_value, "name":prop_name})
+ { "value": prop_value, "name": prop_name })
self.save_config()
def destroy(self):
--- a/src/modules/client/imageconfig.py Thu Aug 26 10:44:20 2010 -0700
+++ b/src/modules/client/imageconfig.py Mon Aug 30 16:11:30 2010 -0500
@@ -282,11 +282,11 @@
pass
try:
- self.properties["ca-path"] = str(
- self.properties["ca-path"])
+ self.properties[CA_PATH] = str(
+ self.properties[CA_PATH])
except KeyError:
- self.properties["ca-path"] = \
- self.default_properties["ca-path"]
+ self.properties[CA_PATH] = \
+ default_properties[CA_PATH]
# read disabled publisher file
# XXX when compatility with the old code is no longer needed,
@@ -775,7 +775,7 @@
if policy_name not in sigpolicy.Policy.policies():
raise api_errors.InvalidPropertyValue(_(
"%(val)s is not a valid value for this "
- "property:%(prop)s") % {"val": policy_name,
+ "property: %(prop)s") % {"val": policy_name,
"prop": SIGNATURE_POLICY})
self.__properties[SIGNATURE_POLICY] = policy_name
if policy_name == "require-names":
@@ -808,12 +808,32 @@
if len(values) > 1:
raise api_errors.InvalidPropertyValue(
_("%(name)s is not a multivalued "
- "property. Values are:%(value)r") %
- {"name":name, "value":values})
+ "property. Values are: %(value)r") %
+ { "name": name, "value": values })
values = values[0]
self.__properties[name] = values
+ elif name == "publisher-search-order":
+ self.__properties[name] = values
else:
- self.__properties[name] = values
+ # No other properties are expected to be a list, so
+ # forcibly convert to a single value.
+ if values:
+ if isinstance(values, basestring) and \
+ values[0] == "[" and values[-1] == "]":
+ values = self.read_list(values)
+ if isinstance(values, list):
+ if len(values) > 1:
+ raise api_errors.InvalidPropertyValue(
+ _("%(name)s is not a "
+ "multivalued property. "
+ "Values are: %(value)r") %
+ { "name": name,
+ "value": values })
+ self.__properties[name] = values[0]
+ else:
+ self.__properties[name] = values
+ else:
+ self.__properties[name] = ""
if not self.__delay_validation:
self.__validate_properties()
--- a/src/modules/lint/engine.py Thu Aug 26 10:44:20 2010 -0700
+++ b/src/modules/lint/engine.py Mon Aug 30 16:11:30 2010 -0500
@@ -43,7 +43,7 @@
import sys
PKG_CLIENT_NAME = "pkglint"
-CLIENT_API_VERSION = 40
+CLIENT_API_VERSION = 43
pkg.client.global_settings.client_name = PKG_CLIENT_NAME
class LintEngineException(Exception):
--- a/src/tests/cli/t_pkg_install.py Thu Aug 26 10:44:20 2010 -0700
+++ b/src/tests/cli/t_pkg_install.py Mon Aug 30 16:11:30 2010 -0500
@@ -221,8 +221,19 @@
refresh_index=True)
self.image_create(self.rurl)
+ # Set content cache to be flushed on success.
+ self.pkg("set-property flush-content-cache-on-success True")
+
self.pkg("list -a")
self.pkg("install foo")
+
+ # Verify that content cache is empty after successful install.
+ api_inst = self.get_img_api_obj()
+ img_inst = api_inst.img
+ cache_dirs = os.listdir(img_inst.cached_download_dir())
+ self.assertEqual(cache_dirs, [])
+ self.pkg("set-property flush-content-cache-on-success False")
+
self.pkg("verify")
self.pkg("list")
@@ -253,11 +264,24 @@
self.pkgsend_bulk(self.rurl, (self.foo10, self.foo11))
self.image_create(self.rurl)
+ # Verify that content cache is empty before install.
+ api_inst = self.get_img_api_obj()
+ img_inst = api_inst.img
+ cache_dirs = os.listdir(img_inst.cached_download_dir())
+ self.assertEqual(cache_dirs, [])
+
self.pkg("install [email protected]")
self.pkg("list [email protected]")
self.pkg("list [email protected]", exit=1)
self.pkg("install [email protected]")
+
+ # Verify that content cache is not empty after successful
+ # install (since flush-content-cache-on-success is False
+ # by default) for packages that have content.
+ cache_dirs = os.listdir(img_inst.cached_download_dir())
+ self.assertNotEqual(cache_dirs, [])
+
self.pkg("list [email protected]")
self.pkg("list [email protected]", exit=1)
self.pkg("list foo@1")
@@ -274,8 +298,24 @@
self.bar10))
self.image_create(self.rurl)
+ # Set content cache to not be flushed on success.
+ self.pkg("set-property flush-content-cache-on-success False")
+
+ # Verify that content cache is empty before install.
+ api_inst = self.get_img_api_obj()
+ img_inst = api_inst.img
+ cache_dirs = os.listdir(img_inst.cached_download_dir())
+ self.assertEqual(cache_dirs, [])
+
self.pkg("list -a")
self.pkg("install [email protected]")
+
+ # Verify that content cache is not empty after successful
+ # install (since flush-content-cache-on-success is False)
+ # for packages that have content.
+ cache_dirs = os.listdir(img_inst.cached_download_dir())
+ self.assertNotEqual(cache_dirs, [])
+
self.pkg("list")
self.pkg("verify")
self.pkg("uninstall -v bar foo")
--- a/src/tests/cli/t_pkg_property.py Thu Aug 26 10:44:20 2010 -0700
+++ b/src/tests/cli/t_pkg_property.py Mon Aug 30 16:11:30 2010 -0500
@@ -33,7 +33,7 @@
import unittest
-class TestPkgInfoBasics(pkg5unittest.SingleDepotTestCase):
+class TestPkgPropertyBasics(pkg5unittest.SingleDepotTestCase):
# Only start/stop the depot once (instead of for every test)
persistent_setup = True
@@ -83,6 +83,12 @@
self.pkg("set-property trust-anchor-directory %s %s" %
(self.test_root, self.test_root), exit=1)
+ # Verify that properties with single values can be set and
+ # retrieved as expected.
+ self.pkg("set-property flush-content-cache-on-success False")
+ self.pkg("property -H flush-content-cache-on-success |"
+ "grep -i flush-content-cache-on-success.*false$")
+
def test_missing_permssions(self):
"""Bug 2393"""
--- a/src/tests/cli/t_pkgdep_resolve.py Thu Aug 26 10:44:20 2010 -0700
+++ b/src/tests/cli/t_pkgdep_resolve.py Mon Aug 30 16:11:30 2010 -0500
@@ -38,9 +38,6 @@
import pkg.publish.dependencies as dependencies
from pkg.fmri import PkgFmri
-API_VERSION = 42
-PKG_CLIENT_NAME = "pkg"
-
class TestApiDependencies(pkg5unittest.SingleDepotTestCase):
# Only start/stop the depot once (instead of for every test)