# HG changeset patch # User Shawn Walker # Date 1259813226 21600 # Node ID 78ac66abc1862cf045292ec1c286d0a40824bd37 # Parent 00a5b4d54eb87625d5e97d4521a7e229f2c74776 12130 install/update operations should always refresh publisher metadata (when allowed) 4419 misleading error message when pkg not found because refresh failed 10976 operations should report when refresh failed if appropriate diff -r 00a5b4d54eb8 -r 78ac66abc186 doc/client_api_versions.txt --- a/doc/client_api_versions.txt Wed Dec 02 19:21:44 2009 -0600 +++ b/doc/client_api_versions.txt Wed Dec 02 22:07:06 2009 -0600 @@ -1,3 +1,9 @@ +Version 26: +Compatible with clients using version 25. + The client API has changed such that an immediate refresh is always + performed when the 'refresh_catalogs' parameter is True for install, + update, and change variant operations. + Version 25: Incompatible with clients using versions 0-24: Changes: diff -r 00a5b4d54eb8 -r 78ac66abc186 src/client.py --- a/src/client.py Wed Dec 02 19:21:44 2009 -0600 +++ b/src/client.py Wed Dec 02 22:07:06 2009 -0600 @@ -80,7 +80,7 @@ RESULT_FAILED_OUTOFMEMORY) from pkg.misc import EmptyI, msg, PipeError -CLIENT_API_VERSION = 25 +CLIENT_API_VERSION = 26 PKG_CLIENT_NAME = "pkg" JUST_UNKNOWN = 0 @@ -300,8 +300,21 @@ # changing (such as an origin uri, etc.). try: api_inst.refresh() - except KeyboardInterrupt: - raise + except api_errors.PermissionsException: + # Ignore permission exceptions with the + # assumption that an unprivileged user is + # executing this command and that the + # refresh doesn't matter. + pass + except api_errors.CatalogRefreshException, e: + succeeded = display_catalog_failures(e, + ignore_perms_failure=True) + if succeeded != e.total: + # If total number of publishers does + # not match 'successful' number + # refreshed, abort. + return EXIT_OOPS + except: # Ignore the above error and just use what # already exists. @@ -607,10 +620,10 @@ error(_("%s cannot be done on live image") % operation) return EXIT_NOTLIVE except api_errors.RebootNeededOnLiveImageException: - error(_("Requested \"%s\" operation would affect files that cannot be " - "modified in live image.\n" - "Please retry this operation on an alternate boot environment.") % - operation) + error(_("Requested \"%s\" operation would affect files that " + "cannot be modified in live image.\n" + "Please retry this operation on an alternate boot " + "environment.") % operation) return EXIT_NOTLIVE except api_errors.CorruptedIndexException, e: error(INCONSISTENT_INDEX_ERROR_MESSAGE) @@ -638,7 +651,7 @@ raise except api_errors.ActionExecutionError, e: if not raise_ActionExecutionError: - return 1 + return EXIT_OOPS error(_("An unexpected error happened during " \ "%s: %s") % (operation, e)) raise @@ -685,16 +698,13 @@ return False if e_type == api_errors.CatalogRefreshException: if display_catalog_failures(e) != 0: - raise RuntimeError("Catalog refresh failed during %s." % - op) + return False if noexecute: return True return False - if issubclass(e_type, api_errors.BEException): error(_(e)) return False - if e_type in (api_errors.CertificateError, api_errors.PlanCreationException, api_errors.PermissionsException): @@ -755,7 +765,7 @@ api_inst = __api_alloc(img, quiet) if api_inst == None: - return 1 + return EXIT_OOPS try: stuff_to_do = api_inst.plan_change_varcets(variants, facets=None, @@ -849,7 +859,7 @@ be_name=be_name) except: if not __api_plan_exception(op, noexecute=noexecute): - return 1 + return EXIT_OOPS if not stuff_to_do: msg(_("Facet change has no effect on image")) @@ -929,7 +939,7 @@ return EXIT_OK if not __api_prepare(op, api_inst, verbose=verbose): - return 1 + return EXIT_OOPS ret_code = __api_execute_plan(op, api_inst) @@ -1211,7 +1221,7 @@ if not misc.valid_pub_url(arg): error(_("%s is not a valid " "server URL.") % orig_arg) - return 1 + return EXIT_OOPS remote = True servers.append({"origin": arg}) elif opt == "-I": @@ -1667,9 +1677,9 @@ try: int(v) return JUST_RIGHT - # attribute is non-numeric or is something like - # a list. except (ValueError, TypeError): + # attribute is non-numeric or is something like + # a list. return JUST_LEFT def create_output_format(display_headers, widths, justs, line): @@ -1951,7 +1961,7 @@ img.cleanup_downloads() return err -def display_catalog_failures(cre): +def display_catalog_failures(cre, ignore_perms_failure=False): total = cre.total succeeded = cre.succeeded @@ -1964,6 +1974,19 @@ msg(txt) for pub, err in cre.failed: + if ignore_perms_failure and \ + not isinstance(err, api_errors.PermissionsException): + # If any errors other than a permissions exception are + # found, then don't ignore them. + ignore_perms_failure = False + break + + if cre.failed and ignore_perms_failure: + # Consider those that failed to have succeeded and add them + # to the actual successful total. + return succeeded + len(cre.failed) + + for pub, err in cre.failed: if isinstance(err, urllib2.HTTPError): logger.error(" %s: %s - %s" % \ (err.filename, err.code, err.msg)) @@ -2012,7 +2035,7 @@ error(e) error(_("'pkg publisher' will show a list of publishers.")) return EXIT_OOPS - except (api_errors.PermissionsException), e: + except api_errors.PermissionsException, e: # Prepend a newline because otherwise the exception will # be printed on the same line as the spinner. error("\n" + str(e)) @@ -2154,7 +2177,7 @@ ssl_key = uri.ssl_key break - origin = repo.reset_origins() + repo.reset_origins() repo.add_origin(origin_url) # XXX once image configuration supports storing this @@ -2756,11 +2779,9 @@ { "image_dir": image_dir, "reason": e.args[1] }, cmd="image-create") return EXIT_OOPS - except api_errors.PublisherError, e: error(e, cmd="image-create") return EXIT_OOPS - except api_errors.PermissionsException, e: # Ensure messages are displayed after the spinner. img.cleanup_downloads() diff -r 00a5b4d54eb8 -r 78ac66abc186 src/gui/modules/misc_non_gui.py --- a/src/gui/modules/misc_non_gui.py Wed Dec 02 19:21:44 2009 -0600 +++ b/src/gui/modules/misc_non_gui.py Wed Dec 02 22:07:06 2009 -0600 @@ -31,7 +31,7 @@ # The current version of the Client API the PM, UM and # WebInstall GUIs have been tested against and are known to work with. -CLIENT_API_VERSION = 25 +CLIENT_API_VERSION = 26 def get_cache_dir(api_object): img = api_object.img diff -r 00a5b4d54eb8 -r 78ac66abc186 src/modules/client/api.py --- a/src/modules/client/api.py Wed Dec 02 19:21:44 2009 -0600 +++ b/src/modules/client/api.py Wed Dec 02 22:07:06 2009 -0600 @@ -50,7 +50,7 @@ from pkg.client.imageplan import EXECUTED_OK from pkg.client import global_settings -CURRENT_API_VERSION = 25 +CURRENT_API_VERSION = 26 CURRENT_P5I_VERSION = 1 logger = global_settings.logger @@ -95,7 +95,7 @@ canceled changes. It can raise VersionException and ImageNotFoundException.""" - compatible_versions = set([CURRENT_API_VERSION]) + compatible_versions = set([25, CURRENT_API_VERSION]) if version_id not in compatible_versions: raise api_errors.VersionException(CURRENT_API_VERSION, @@ -186,19 +186,8 @@ # attempting network operations. # self.__cert_verify() - - try: - self.__img.refresh_publishers( - progtrack=self.__progresstracker) - except KeyboardInterrupt: - raise - except api_errors.InvalidDepotResponseException: - raise - except: - # Since this is not a refresh - # that was explicitly requested, - # it doesn't matter if it fails. - pass + self.__img.refresh_publishers(immediate=True, + progtrack=self.__progresstracker) def __plan_common_start(self, operation): """Start planning an operation. Aquire locks and log diff -r 00a5b4d54eb8 -r 78ac66abc186 src/modules/client/image.py --- a/src/modules/client/image.py Wed Dec 02 19:21:44 2009 -0600 +++ b/src/modules/client/image.py Wed Dec 02 22:07:06 2009 -0600 @@ -1508,6 +1508,11 @@ if pub.refresh(full_refresh=full_refresh, immediate=immediate): updated += 1 + except api_errors.PermissionsException, e: + failed.append((pub, e)) + # No point in continuing since no data can + # be written. + break except api_errors.ApiException, e: failed.append((pub, e)) continue diff -r 00a5b4d54eb8 -r 78ac66abc186 src/pkgdep.py --- a/src/pkgdep.py Wed Dec 02 19:21:44 2009 -0600 +++ b/src/pkgdep.py Wed Dec 02 22:07:06 2009 -0600 @@ -42,7 +42,7 @@ import pkg.publish.dependencies as dependencies from pkg.misc import msg, emsg, PipeError -CLIENT_API_VERSION = 25 +CLIENT_API_VERSION = 26 PKG_CLIENT_NAME = "pkgdep" DEFAULT_SUFFIX = ".res" diff -r 00a5b4d54eb8 -r 78ac66abc186 src/tests/cli/t_api.py --- a/src/tests/cli/t_api.py Wed Dec 02 19:21:44 2009 -0600 +++ b/src/tests/cli/t_api.py Wed Dec 02 22:07:06 2009 -0600 @@ -40,7 +40,7 @@ import time import unittest -API_VERSION = 25 +API_VERSION = 26 PKG_CLIENT_NAME = "pkg" class TestPkgApi(testutils.SingleDepotTestCase): diff -r 00a5b4d54eb8 -r 78ac66abc186 src/tests/cli/t_api_info.py --- a/src/tests/cli/t_api_info.py Wed Dec 02 19:21:44 2009 -0600 +++ b/src/tests/cli/t_api_info.py Wed Dec 02 22:07:06 2009 -0600 @@ -40,7 +40,7 @@ import pkg.client.api_errors as api_errors import pkg.client.progress as progress -API_VERSION = 25 +API_VERSION = 26 PKG_CLIENT_NAME = "pkg" class TestApiInfo(testutils.SingleDepotTestCase): diff -r 00a5b4d54eb8 -r 78ac66abc186 src/tests/cli/t_api_list.py --- a/src/tests/cli/t_api_list.py Wed Dec 02 19:21:44 2009 -0600 +++ b/src/tests/cli/t_api_list.py Wed Dec 02 22:07:06 2009 -0600 @@ -46,7 +46,7 @@ import pkg.misc as misc import pkg.version as version -API_VERSION = 25 +API_VERSION = 26 PKG_CLIENT_NAME = "pkg" class TestApiList(testutils.ManyDepotTestCase): diff -r 00a5b4d54eb8 -r 78ac66abc186 src/tests/cli/t_api_search.py --- a/src/tests/cli/t_api_search.py Wed Dec 02 19:21:44 2009 -0600 +++ b/src/tests/cli/t_api_search.py Wed Dec 02 22:07:06 2009 -0600 @@ -47,7 +47,7 @@ import pkg.portable as portable import pkg.search_storage as ss -API_VERSION = 25 +API_VERSION = 26 PKG_CLIENT_NAME = "pkg" class TestApiSearchBasics(testutils.SingleDepotTestCase): diff -r 00a5b4d54eb8 -r 78ac66abc186 src/tests/cli/t_pkg_api_install.py --- a/src/tests/cli/t_pkg_api_install.py Wed Dec 02 19:21:44 2009 -0600 +++ b/src/tests/cli/t_pkg_api_install.py Wed Dec 02 22:07:06 2009 -0600 @@ -38,7 +38,7 @@ import pkg.client.api_errors as api_errors import pkg.client.progress as progress -API_VERSION = 25 +API_VERSION = 26 PKG_CLIENT_NAME = "pkg" class TestPkgApiInstall(testutils.SingleDepotTestCase): diff -r 00a5b4d54eb8 -r 78ac66abc186 src/tests/cli/t_pkg_install.py --- a/src/tests/cli/t_pkg_install.py Wed Dec 02 19:21:44 2009 -0600 +++ b/src/tests/cli/t_pkg_install.py Wed Dec 02 22:07:06 2009 -0600 @@ -2458,7 +2458,8 @@ def test_08_install_repository_access(self): """Verify that packages can still be installed from a repository - even when any of the other repositories are not reachable.""" + even when any of the other repositories are not reachable and + --no-refresh is used.""" # Change the second publisher to point to an unreachable URI. self.pkg("set-publisher --no-refresh -O http://test.invalid7 test2") @@ -2466,9 +2467,15 @@ # Verify that no packages are installed. self.pkg("list", exit=1) - # Verify moo can be installed (as only depot1 has it) even though + # Verify moo can not be installed (as only depot1 has it) since # test2 cannot be reached (and needs a refresh). - self.pkg("install moo") + self.pkg("install moo", exit=1) + + # Verify moo can be installed (as only depot1 has it) even though + # test2 cannot be reached (and needs a refresh) if --no-refresh + # is used. + self.pkg("install --no-refresh moo") + self.pkg("uninstall moo") # Reset the test2 publisher. @@ -2487,9 +2494,14 @@ durl4 = self.dcs[4].get_depot_url() self.pkg("set-publisher -O %s test2" % durl4) + # Verify image-update does not work since test1 is unreachable + # even though upgrade-np@1.1 is available from test2. + self.pkg("image-update", exit=1) + # Verify image-update works even though test1 is unreachable - # since upgrade-np@1.1 is available from test2. - self.pkg("image-update") + # since upgrade-np@1.1 is available from test2 if --no-refresh + # is used. + self.pkg("image-update --no-refresh") # Now reset everything for the next test. self.pkg("uninstall upgrade-np") diff -r 00a5b4d54eb8 -r 78ac66abc186 src/tests/cli/t_pkg_intent.py --- a/src/tests/cli/t_pkg_intent.py Wed Dec 02 19:21:44 2009 -0600 +++ b/src/tests/cli/t_pkg_intent.py Wed Dec 02 22:07:06 2009 -0600 @@ -39,7 +39,7 @@ import pkg.client.api_errors as api_errors import pkg.client.progress as progress -API_VERSION = 25 +API_VERSION = 26 PKG_CLIENT_NAME = "pkg" class TestPkgIntent(testutils.SingleDepotTestCase): diff -r 00a5b4d54eb8 -r 78ac66abc186 src/tests/cli/t_pkg_list.py --- a/src/tests/cli/t_pkg_list.py Wed Dec 02 19:21:44 2009 -0600 +++ b/src/tests/cli/t_pkg_list.py Wed Dec 02 22:07:06 2009 -0600 @@ -378,15 +378,19 @@ def test_list_10_all_known_failed_refresh(self): """Verify that a failed implicit refresh will not prevent pkg - list from working properly.""" + list from working properly when appropriate.""" # Set test2's origin to an unreachable URI. - self.pkg("set-publisher --no-refresh -O http://test.invalid2 test2") + self.pkg("set-publisher --no-refresh -O http://test.invalid2 " + "test2") - # Verify pkg list -a works as expected for both an unprivileged - # user and a privileged one when a publisher needs a refresh. + # Verify pkg list -a works as expected for an unprivileged user + # when a permissions failure is encountered. self.pkg("list -a", su_wrap=True) - self.pkg("list -a") + + # Verify pkg list -a fails for a privileged user when a + # publisher's repository is unreachable. + self.pkg("list -a", exit=1) # Reset test2's origin. durl2 = self.dcs[2].get_depot_url() diff -r 00a5b4d54eb8 -r 78ac66abc186 src/tests/cli/t_pkgdep_resolve.py --- a/src/tests/cli/t_pkgdep_resolve.py Wed Dec 02 19:21:44 2009 -0600 +++ b/src/tests/cli/t_pkgdep_resolve.py Wed Dec 02 22:07:06 2009 -0600 @@ -40,7 +40,7 @@ import pkg.portable as portable import pkg.publish.dependencies as dependencies -API_VERSION = 25 +API_VERSION = 26 PKG_CLIENT_NAME = "pkg" class TestApiDependencies(testutils.SingleDepotTestCase):