Hello community,

here is the log from the commit of package zeroinstall-injector for 
openSUSE:Factory checked in at 2013-02-25 20:47:53
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/zeroinstall-injector (Old)
 and      /work/SRC/openSUSE:Factory/.zeroinstall-injector.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "zeroinstall-injector", Maintainer is ""

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/zeroinstall-injector/zeroinstall-injector.changes    
    2013-02-14 21:19:36.000000000 +0100
+++ 
/work/SRC/openSUSE:Factory/.zeroinstall-injector.new/zeroinstall-injector.changes
   2013-02-25 20:47:55.000000000 +0100
@@ -1,0 +2,6 @@
+Mon Feb 25 12:23:28 UTC 2013 - [email protected]
+
+- Updated to 1.16. For a list of changes, see:
+  http://thread.gmane.org/gmane.comp.file-systems.zero-install.devel/6730
+
+-------------------------------------------------------------------

Old:
----
  0install-1.15.tar.bz2

New:
----
  0install-1.16.tar.bz2

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ zeroinstall-injector.spec ++++++
--- /var/tmp/diff_new_pack.Fd1ukn/_old  2013-02-25 20:47:57.000000000 +0100
+++ /var/tmp/diff_new_pack.Fd1ukn/_new  2013-02-25 20:47:57.000000000 +0100
@@ -26,9 +26,9 @@
 %endif
 
 Name:           zeroinstall-injector
-Version:        1.15
+Version:        1.16
 Release:        0
-%define source_version 1.15
+%define source_version 1.16
 Summary:        Decentralised cross-distribution software installation
 License:        LGPL-2.1+
 Group:          System/Management
@@ -50,6 +50,7 @@
 Requires:       gnupg
 Requires:       sudo
 Requires:       xdg-utils
+AutoReqProv:    no
 
 %if 0%{?suse_version}
 BuildRequires:  python-xml

++++++ 0install-1.15.tar.bz2 -> 0install-1.16.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/Makefile new/0install-1.16/Makefile
--- old/0install-1.15/Makefile  2013-02-12 16:35:03.000000000 +0100
+++ new/0install-1.16/Makefile  2013-02-24 15:29:35.000000000 +0100
@@ -1,6 +1,4 @@
-
-
-PYTHON=$(shell which python3 || echo python)
+PYTHON=$(shell which python3 || which python2 || echo python)
 
 MO = $(shell find share/locale -name '*.po' | sort | sed -e 's/\.po/\.mo/')
 PY = $(shell find zeroinstall -name '*.py' | sort)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/ZeroInstall.xml 
new/0install-1.16/ZeroInstall.xml
--- old/0install-1.15/ZeroInstall.xml   2013-02-12 16:35:03.000000000 +0100
+++ new/0install-1.16/ZeroInstall.xml   2013-02-24 15:29:35.000000000 +0100
@@ -53,6 +53,6 @@
       <version not-before="1.12.1"/>
     </requires>
 
-    <implementation id="." released="2013-02-12" version="1.15"/>
+    <implementation id="." released="2013-02-24" version="1.16"/>
   </group>
 </interface>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/tests/server.py 
new/0install-1.16/tests/server.py
--- old/0install-1.15/tests/server.py   2013-02-12 16:35:03.000000000 +0100
+++ new/0install-1.16/tests/server.py   2013-02-24 15:29:35.000000000 +0100
@@ -40,7 +40,8 @@
                print(parsed)
                if parsed.path.startswith('/redirect/'):
                        self.send_response(302)
-                       self.wfile.write(('Location: /' + 
parsed.path[1:].split('/', 1)[1]).encode('utf-8'))
+                       self.send_header('Location', '/' + 
parsed.path[1:].split('/', 1)[1])
+                       self.end_headers()
                        return
 
                leaf = os.path.basename(parsed.path)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/tests/testdownload.py 
new/0install-1.16/tests/testdownload.py
--- old/0install-1.15/tests/testdownload.py     2013-02-12 16:35:03.000000000 
+0100
+++ new/0install-1.16/tests/testdownload.py     2013-02-24 15:29:35.000000000 
+0100
@@ -628,7 +628,7 @@
                                        os.unlink(last_check_attempt)
 
                        # Download the implementation
-                       sels = app.get_selections(may_update = True)
+                       sels = app.get_selections(may_update = False)
                        run_server('HelloWorld.tgz')
                        tasks.wait_for_blocker(app.download_selections(sels))
                        kill_server_process()
@@ -726,6 +726,79 @@
                        assert dl == None
                        assert not ran_gui
 
+       def testBackgroundUnsolvable(self):
+               my_dbus.system_services = {"org.freedesktop.NetworkManager": 
{"/org/freedesktop/NetworkManager": NetworkManager()}}
+
+               
trust.trust_db.trust_key('DE937DD411906ACF7C263B396FCF121BE2390E0B', 
'example.com:8000')
+
+               global ran_gui
+
+               # Select a version of Hello
+               run_server('Hello.xml', '6FCF121BE2390E0B.gpg', 
'HelloWorld.tgz')
+               r = Requirements('http://example.com:8000/Hello.xml')
+               driver = Driver(requirements = r, config = self.config)
+               tasks.wait_for_blocker(driver.solve_with_downloads())
+               assert driver.solver.ready
+               kill_server_process()
+
+               # Save it as an app
+               app = self.config.app_mgr.create_app('test-app', r)
+
+               # Replace the selection with a bogus and unusable 
<package-implementation>
+               sels = driver.solver.selections
+               sel, = sels.selections.values()
+               sel.attrs['id'] = "package:dummy:badpackage"
+               sel.attrs['package'] = "badpackage"
+               sel.get_command('run').qdom.attrs['path'] = '/i/dont/exist'
+
+               app.set_selections(driver.solver.selections)
+
+               # Not time for a background update yet, but the missing binary 
should trigger
+               # an update anyway.
+               self.config.freshness = 0
+
+               # Check we try to launch the GUI...
+               os.environ['DISPLAY'] = 'dummy'
+               try:
+                       app.get_selections(may_update = True)
+                       assert 0
+               except model.SafeException as ex:
+                       assert 'Aborted by user' in str(ex)
+               assert ran_gui
+               ran_gui = False
+
+               # Check we can also work without the GUI...
+               del os.environ['DISPLAY']
+
+               run_server('Hello.xml', 'HelloWorld.tgz')
+               sels = app.get_selections(may_update = True)
+               kill_server_process()
+
+               dl = app.download_selections(sels)
+               assert dl == None
+
+               assert not ran_gui
+
+               # Now trigger a background update which discovers that no 
solution is possible
+               timestamp = os.path.join(app.path, 'last-checked')
+               last_check_attempt = os.path.join(app.path, 
'last-check-attempt')
+               selections_path = os.path.join(app.path, 'selections.xml')
+               def reset_timestamps():
+                       global ran_gui
+                       ran_gui = False
+                       os.utime(timestamp, (1, 1))             # 1970
+                       os.utime(selections_path, (1, 1))
+                       if os.path.exists(last_check_attempt):
+                               os.unlink(last_check_attempt)
+               reset_timestamps()
+
+               r.source = True
+               app.set_requirements(r)
+               run_server('Hello.xml')
+               with trapped_exit(1):
+                       sels = app.get_selections(may_update = True)
+               kill_server_process()
+
        def testAbort(self):
                dl = download.Download("http://localhost/test.tgz";, auto_delete 
= True)
                dl.abort()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/tests/testinstall.py 
new/0install-1.16/tests/testinstall.py
--- old/0install-1.15/tests/testinstall.py      2013-02-12 16:35:03.000000000 
+0100
+++ new/0install-1.16/tests/testinstall.py      2013-02-24 15:29:35.000000000 
+0100
@@ -450,6 +450,12 @@
                assert "No updates found. Continuing with version 0.1." in out, 
out
                assert not err, err
 
+               # Run
+               out, err = self.run_0install(['run', '--dry-run', 'local-app'])
+               assert '[dry-run] would execute:' in out, out
+               assert '/test-echo' in out, out
+               assert not err, err
+
                # restrictions
                path = os.path.dirname(model.canonical_iface_uri(local_feed))
                out, err = self.run_0install(['update', 'local-app', 
'--version=10..'])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/tests/testmodel.py 
new/0install-1.16/tests/testmodel.py
--- old/0install-1.15/tests/testmodel.py        2013-02-12 16:35:03.000000000 
+0100
+++ new/0install-1.16/tests/testmodel.py        2013-02-24 15:29:35.000000000 
+0100
@@ -372,7 +372,7 @@
                assert not r.meets_restriction(v7)
 
                r = model.DistributionRestriction('RPM Debian')
-               self.assertEqual('<restriction: distro RPM|Debian>', repr(r))
+               self.assertEqual('<restriction: distro Debian|RPM>', repr(r))
                assert r.meets_restriction(v6)
                assert not r.meets_restriction(v7)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/tests/testpackagekit.py 
new/0install-1.16/tests/testpackagekit.py
--- old/0install-1.15/tests/testpackagekit.py   2013-02-12 16:35:03.000000000 
+0100
+++ new/0install-1.16/tests/testpackagekit.py   2013-02-24 15:29:35.000000000 
+0100
@@ -138,6 +138,8 @@
                                later()
        return FakePackageKit()
 
+old_meta_path = sys.meta_path
+
 class TestPackageKit(BaseTest):
        name = 'TestPackageKit'
 
@@ -145,7 +147,7 @@
                BaseTest.setUp(self)
 
        def tearDown(self):
-               sys.meta_path = []
+               sys.meta_path = old_meta_path
                BaseTest.tearDown(self)
 
        def find_module(self, fullname, path=None):
@@ -158,7 +160,7 @@
                import dbus
                old_dbus = dbus
                try:
-                       sys.meta_path = [self]
+                       sys.meta_path.insert(0, self)
                        del sys.modules['dbus']
 
                        imp.reload(packagekit)
@@ -169,7 +171,6 @@
                        factory = Exception("not called")
                        pk.get_candidates('gimp', factory, 'package:null')
                finally:
-                       self.meta_path = []
                        sys.modules['dbus'] = old_dbus
 
        def testNoPackageKit(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/tests/testselections.py 
new/0install-1.16/tests/testselections.py
--- old/0install-1.15/tests/testselections.py   2013-02-12 16:35:03.000000000 
+0100
+++ new/0install-1.16/tests/testselections.py   2013-02-24 15:29:35.000000000 
+0100
@@ -73,7 +73,7 @@
                        self.assertEqual('BINDIR', dep.bindings[2].name)
                        self.assertEqual('replace', dep.bindings[2].mode)
 
-                       self.assertEqual(["sha1=345", 'sha256new_345'], 
sels[0].digests)
+                       self.assertEqual(["sha1=345", 'sha256new_345'], 
sorted(sels[0].digests))
 
                assert driver.solver.ready, driver.solver.get_failure_reason()
                s1 = driver.solver.selections
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/tests/testunpack.py 
new/0install-1.16/tests/testunpack.py
--- old/0install-1.15/tests/testunpack.py       2013-02-12 16:35:03.000000000 
+0100
+++ new/0install-1.16/tests/testunpack.py       2013-02-24 15:29:35.000000000 
+0100
@@ -118,6 +118,7 @@
                        unpack.unpack_archive('ftp://foo/file.tar', stream, 
self.tmpdir)
                
self.assert_manifest('sha1new=290eb133e146635fe37713fd58174324a16d595f')
        
+       @skipIf(not find_in_path('rpm2cpio'), "not running; no rpm2cpio")
        def testRPM(self):
                with open('dummy-1-1.noarch.rpm', 'rb') as stream:
                        unpack.unpack_archive('ftp://foo/file.rpm', stream, 
self.tmpdir)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/0launch-gui/gui.py 
new/0install-1.16/zeroinstall/0launch-gui/gui.py
--- old/0install-1.15/zeroinstall/0launch-gui/gui.py    2013-02-12 
16:35:03.000000000 +0100
+++ new/0install-1.16/zeroinstall/0launch-gui/gui.py    2013-02-24 
15:29:35.000000000 +0100
@@ -5,7 +5,7 @@
 from zeroinstall.support import tasks
 from zeroinstall.injector import handler, download
 
-version = '1.15'
+version = '1.16'
 
 class GUIHandler(handler.Handler):
        dl_callbacks = None             # Download -> [ callback ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/__init__.py 
new/0install-1.16/zeroinstall/__init__.py
--- old/0install-1.15/zeroinstall/__init__.py   2013-02-12 16:35:03.000000000 
+0100
+++ new/0install-1.16/zeroinstall/__init__.py   2013-02-24 15:29:35.000000000 
+0100
@@ -13,7 +13,7 @@
 @var _: a function for translating strings using the zero-install domain (for 
use internally by Zero Install)
 """
 
-version = '1.15'
+version = '1.16'
 
 import sys, logging
 if sys.version_info[0] > 2:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/apps.py 
new/0install-1.16/zeroinstall/apps.py
--- old/0install-1.15/zeroinstall/apps.py       2013-02-12 16:35:03.000000000 
+0100
+++ new/0install-1.16/zeroinstall/apps.py       2013-02-24 15:29:35.000000000 
+0100
@@ -47,7 +47,7 @@
                        break
        else:
                path = os.path.expanduser('~/bin/')
-               logger.warn('%s is not in $PATH. Add it with:\n%s' % (path, 
_export('PATH', path + ':$PATH')))
+               logger.warning('%s is not in $PATH. Add it with:\n%s' % (path, 
_export('PATH', path + ':$PATH')))
 
                if not os.path.isdir(path):
                        os.makedirs(path)
@@ -125,15 +125,19 @@
                if set_last_checked:
                        self.set_last_checked()
 
-       def get_selections(self, snapshot_date = None, may_update = False):
+       def get_selections(self, snapshot_date = None, may_update = False, 
use_gui = None):
                """Load the selections.
+               If may_update is True then the returned selections will be 
cached and available.
                @param may_update: whether to check for updates
                @type may_update: bool
                @param snapshot_date: get a historical snapshot
                @type snapshot_date: (as returned by L{get_history}) | None
+               @param use_gui: whether to use the GUI for foreground updates
+               @type use_gui: bool | None (never/always/if possible)
                @return: the selections
                @rtype: L{selections.Selections}"""
                if snapshot_date:
+                       assert may_update is False, "Can't update a snapshot!"
                        sels_file = os.path.join(self.path, 'selections-' + 
snapshot_date + '.xml')
                else:
                        sels_file = os.path.join(self.path, 'selections.xml')
@@ -141,7 +145,7 @@
                        sels = selections.Selections(qdom.parse(stream))
 
                if may_update:
-                       sels = self._check_for_updates(sels)
+                       sels = self._check_for_updates(sels, use_gui)
 
                return sels
 
@@ -163,13 +167,14 @@
                @rtype: L{tasks.Blocker} | None"""
                return sels.download_missing(self.config)       # TODO: package 
impls
 
-       def _check_for_updates(self, sels):
+       def _check_for_updates(self, sels, use_gui):
                """Check whether the selections need to be updated.
                If any input feeds have changed, we re-run the solver. If the
                new selections require a download, we schedule one in the
                background and return the old selections. Otherwise, we return 
the
                new selections. If we can select better versions without 
downloading,
                we update the app's selections and return the new selections.
+               If we can't use the current selections, we update in the 
foreground.
                We also schedule a background update from time-to-time anyway.
                @return: the selections to use
                @rtype: L{selections.Selections}"""
@@ -216,7 +221,13 @@
                                        path, mtime = item
                                else:
                                        path = item
-                                       mtime = os.stat(path).st_mtime
+                                       try:
+                                               mtime = os.stat(path).st_mtime
+                                       except OSError as ex:
+                                               logger.info("Triggering update 
to {app} due to error: {ex}".format(
+                                                       app = self, path = 
path, ex = ex))
+                                               need_solve = True
+                                               break
 
                                if mtime and mtime > last_solve:
                                        logger.info("Triggering update to %s 
because %s has changed", self, path)
@@ -235,12 +246,23 @@
                        if freshness_threshold > 0 and staleness >= 
freshness_threshold:
                                need_update = True
 
+               # If any of the saved selections aren't available then we need
+               # to download right now, not later in the background.
+               unavailable_selections = sels.get_unavailable_selections(config 
= self.config, include_packages = True)
+               if unavailable_selections:
+                       logger.info("Saved selections are unusable (missing 
%s)",
+                                   ', '.join(str(s) for s in 
unavailable_selections))
+                       need_solve = True
+
                if need_solve:
                        from zeroinstall.injector.driver import Driver
                        driver = Driver(config = self.config, requirements = 
self.get_requirements())
                        if driver.need_download():
-                               # Continue with the current (hopefully cached) 
selections while we download
-                               need_update = True
+                               if unavailable_selections:
+                                       return self._foreground_update(driver, 
use_gui)
+                               else:
+                                       # Continue with the current (cached) 
selections while we download
+                                       need_update = True
                        else:
                                old_sels = sels
                                sels = driver.solver.selections
@@ -264,6 +286,27 @@
 
                return sels
 
+       def _foreground_update(self, driver, use_gui):
+               """We can't run with saved selections or solved selections 
without downloading.
+               Try to open the GUI for a blocking download. If we can't do 
that, download without the GUI."""
+               from zeroinstall import helpers
+               from zeroinstall.support import tasks
+
+               gui_args = driver.requirements.get_as_options() + 
['--download-only', '--refresh']
+               sels = 
helpers.get_selections_gui(driver.requirements.interface_uri, gui_args,
+                                                 test_callback = None, use_gui 
= use_gui)
+               if sels is None:
+                       raise SafeException("Aborted by user")
+               if sels is helpers.DontUseGUI:
+                       downloaded = driver.solve_and_download_impls(refresh = 
True)
+                       if downloaded:
+                               tasks.wait_for_blocker(downloaded)
+                       sels = driver.solver.selections
+
+               self.set_selections(sels, set_last_checked = True)
+
+               return sels
+
        def set_requirements(self, requirements):
                reqs_file = os.path.join(self.path, 'requirements.json')
                if self.config.handler.dry_run:
@@ -324,7 +367,7 @@
                        return os.stat(timestamp_path).st_mtime
                except Exception as ex:
                        if warn_if_missing:
-                               logger.warn("Failed to get time-stamp of %s: 
%s", timestamp_path, ex)
+                               logger.warning("Failed to get time-stamp of %s: 
%s", timestamp_path, ex)
                        return 0
 
        def get_last_checked(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/cmd/__init__.py 
new/0install-1.16/zeroinstall/cmd/__init__.py
--- old/0install-1.15/zeroinstall/cmd/__init__.py       2013-02-12 
16:35:03.000000000 +0100
+++ new/0install-1.16/zeroinstall/cmd/__init__.py       2013-02-24 
15:29:35.000000000 +0100
@@ -121,9 +121,9 @@
                args = []
                consume_args = 0
                complete_option_arg = None      # (option, args, arg pos)
-               #logger.warn("%s at %d", self.command_args, self.cword)
+               #logger.warning("%s at %d", self.command_args, self.cword)
                for i, a in enumerate(self.command_args):
-                       #logger.warn("%d %s (%d)", i, a, options_possible)
+                       #logger.warning("%d %s (%d)", i, a, options_possible)
                        if consume_args > 0:
                                #print("consume " + a, file=sys.stderr)
                                consume_args -= 1
@@ -167,7 +167,7 @@
                                cmd.complete(self, args[1:], arg_word)
                else:
                        metavar = complete_option_arg[0].metavar
-                       #logger.warn("complete option arg %s %s as %s", 
args[1:], complete_option_arg, metavar)
+                       #logger.warning("complete option arg %s %s as %s", 
args[1:], complete_option_arg, metavar)
                        if metavar == 'DIR':
                                self.expand_files()
                        elif metavar == 'OS':
@@ -196,7 +196,7 @@
                                from zeroinstall.zerostore import manifest
                                for alg in sorted(manifest.algorithms):
                                        self.add("filter", alg)
-                       #else: logger.warn("%r", metavar)
+                       #else: logger.warning("%r", metavar)
 
        def _complete_option(self, parser):
                if len(self.current) < 2 or self.current.startswith('--'):
@@ -230,7 +230,7 @@
                        prefix = ''
 
                for v in sorted(versions):
-                       #logger.warn(prefix + v)
+                       #logger.warning(prefix + v)
                        self.add("filter", prefix + v)
 
        def expand_apps(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/cmd/man.py 
new/0install-1.16/zeroinstall/cmd/man.py
--- old/0install-1.15/zeroinstall/cmd/man.py    2013-02-12 16:35:03.000000000 
+0100
+++ new/0install-1.16/zeroinstall/cmd/man.py    2013-02-24 15:29:35.000000000 
+0100
@@ -28,21 +28,26 @@
        if not path:
                return None
 
-       with open(path, 'rt') as stream:
-               app_info = apps.parse_script_header(stream)
-               if app_info:
-                       app = config.app_mgr.lookup_app(app_info.name)
-                       sels = app.get_selections()
-                       main = None
-               else:
-                       alias_info = alias.parse_script_header(stream)
-                       if alias_info is None:
-                               return None
-                       sels = helpers.ensure_cached(alias_info.uri, 
alias_info.command, config = config)
-                       if not sels:
-                               # Cancelled by user
-                               sys.exit(1)
-                       main = alias_info.main
+       try:
+               with open(path, 'rt') as stream:
+                       app_info = apps.parse_script_header(stream)
+                       if app_info:
+                               app = config.app_mgr.lookup_app(app_info.name)
+                               sels = app.get_selections()
+                               main = None
+                       else:
+                               alias_info = alias.parse_script_header(stream)
+                               if alias_info is None:
+                                       return None
+                               sels = helpers.ensure_cached(alias_info.uri, 
alias_info.command, config = config)
+                               if not sels:
+                                       # Cancelled by user
+                                       sys.exit(1)
+                               main = alias_info.main
+       except IOError as e:
+               logger.info("Error reading %s, falling back to `man %s`", path, 
command)
+               os.execlp('man', 'man', command)
+               sys.exit(1)
 
        helpers.exec_man(config.stores, sels, main, fallback_name = command)
        assert 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/cmd/run.py 
new/0install-1.16/zeroinstall/cmd/run.py
--- old/0install-1.15/zeroinstall/cmd/run.py    2013-02-12 16:35:03.000000000 
+0100
+++ new/0install-1.16/zeroinstall/cmd/run.py    2013-02-24 15:29:35.000000000 
+0100
@@ -34,7 +34,7 @@
 
        app = config.app_mgr.lookup_app(args[0], missing_ok = True)
        if app is not None:
-               sels = app.get_selections(may_update = True)
+               sels = app.get_selections(may_update = True, use_gui = 
options.gui)
                r = app.get_requirements()
                do_select = r.parse_update_options(options)
                iface_uri = sels.interface
@@ -48,11 +48,6 @@
                                        test_callback = test_callback)
                if not sels:
                        sys.exit(1)     # Aborted by user
-       else:
-               dl = app.download_selections(sels)
-               if dl:
-                       tasks.wait_for_blocker(dl)
-                       tasks.check(dl)
 
        from zeroinstall.injector import run
        run.execute_selections(sels, prog_args, dry_run = options.dry_run, main 
= options.main, wrapper = options.wrapper, stores = config.stores)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/cmd/show.py 
new/0install-1.16/zeroinstall/cmd/show.py
--- old/0install-1.15/zeroinstall/cmd/show.py   2013-02-12 16:35:03.000000000 
+0100
+++ new/0install-1.16/zeroinstall/cmd/show.py   2013-02-24 15:29:35.000000000 
+0100
@@ -7,7 +7,9 @@
 
 from __future__ import print_function
 
-from zeroinstall import _
+import os
+
+from zeroinstall import _, SafeException
 from zeroinstall.cmd import select, UsageError
 from zeroinstall.injector import qdom, selections
 
@@ -32,9 +34,11 @@
                        for uri, expr in r.extra_restrictions.items():
                                print("  {uri}: {expr}".format(uri = uri, expr 
= expr))
                        print()
-       else:
+       elif os.path.exists(args[0]):
                with open(args[0], 'rb') as stream:
                        sels = selections.Selections(qdom.parse(stream))
+       else:
+               raise SafeException(_("Neither an app nor a file: '%s'") % 
args[0])
 
        if options.root_uri:
                print(sels.interface)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/gtkui/icon.py 
new/0install-1.16/zeroinstall/gtkui/icon.py
--- old/0install-1.15/zeroinstall/gtkui/icon.py 2013-02-12 16:35:03.000000000 
+0100
+++ new/0install-1.16/zeroinstall/gtkui/icon.py 2013-02-24 15:29:35.000000000 
+0100
@@ -44,5 +44,5 @@
                        loader.close()
                return loader.get_pixbuf()
        except Exception as ex:
-               logger.warn(_("Failed to load cached PNG icon: %s") % ex)
+               logger.warning(_("Failed to load cached PNG icon: %s") % ex)
                return None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/gtkui/xdgutils.py 
new/0install-1.16/zeroinstall/gtkui/xdgutils.py
--- old/0install-1.15/zeroinstall/gtkui/xdgutils.py     2013-02-12 
16:35:03.000000000 +0100
+++ new/0install-1.16/zeroinstall/gtkui/xdgutils.py     2013-02-24 
15:29:35.000000000 +0100
@@ -74,5 +74,5 @@
                                                else:
                                                        logger.info(_("Failed 
to find Exec line in %s"), full)
                                except Exception as ex:
-                                       logger.warn(_("Failed to load .desktop 
file %(filename)s: %(exceptions"), {'filename': full, 'exception': ex})
+                                       logger.warning(_("Failed to load 
.desktop file %(filename)s: %(exceptions"), {'filename': full, 'exception': ex})
        return already_installed
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/injector/background.py 
new/0install-1.16/zeroinstall/injector/background.py
--- old/0install-1.15/zeroinstall/injector/background.py        2013-02-12 
16:35:03.000000000 +0100
+++ new/0install-1.16/zeroinstall/injector/background.py        2013-02-24 
15:29:35.000000000 +0100
@@ -99,7 +99,7 @@
                                return state
 
                        except Exception as ex:
-                               logger.warn(_("Error getting network state: 
%s"), ex)
+                               logger.warning(_("Error getting network state: 
%s"), ex)
                return _NetworkState.NM_STATE_UNKNOWN
 
        def confirm_import_feed(self, pending, valid_sigs):
@@ -219,7 +219,7 @@
        refresh = driver.solve_with_downloads(force = True)     # (causes 
confusing log messages)
        tasks.wait_for_blocker(refresh)
 
-       if background_handler.need_gui or driver.get_uncached_implementations():
+       if background_handler.need_gui or not driver.solver.ready or 
driver.get_uncached_implementations():
                if verbose:
                        background_handler.notify("Zero Install",
                                              _("Updates ready to download for 
'%s'.") % root_iface,
@@ -232,6 +232,10 @@
                if new_sels is None:
                        sys.exit(0)     # Cancelled by user
                elif new_sels is helpers.DontUseGUI:
+                       if not driver.solver.ready:
+                               background_handler.notify("Zero Install", 
_("Can't update '%s'") % root_iface)
+                               sys.exit(1)
+
                        
tasks.wait_for_blocker(driver.download_uncached_implementations())
                        new_sels = driver.solver.selections
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/injector/config.py 
new/0install-1.16/zeroinstall/injector/config.py
--- old/0install-1.15/zeroinstall/injector/config.py    2013-02-12 
16:35:03.000000000 +0100
+++ new/0install-1.16/zeroinstall/injector/config.py    2013-02-24 
15:29:35.000000000 +0100
@@ -132,7 +132,7 @@
                try:
                        parser.read(path)
                except Exception as ex:
-                       logger.warn(_("Error loading config: %s"), str(ex) or 
repr(ex))
+                       logger.warning(_("Error loading config: %s"), str(ex) 
or repr(ex))
 
        config.help_with_testing = parser.getboolean('global', 
'help_with_testing')
        config.network_use = parser.get('global', 'network_use')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/injector/distro.py 
new/0install-1.16/zeroinstall/injector/distro.py
--- old/0install-1.15/zeroinstall/injector/distro.py    2013-02-12 
16:35:03.000000000 +0100
+++ new/0install-1.16/zeroinstall/injector/distro.py    2013-02-24 
15:29:35.000000000 +0100
@@ -18,7 +18,7 @@
 
 # This matches the interesting bits of distribution version numbers
 # (first matching group is for Java-style 6b17 or 7u9 syntax, or "major")
-_version_regexp = '(?:[a-z])?({ints}[bu])?({zero})(-r{ints})?'.format(zero = 
_zeroinstall_regexp, ints = _dotted_ints)
+_version_regexp = '(?:[a-z])?({ints}\.?[bu])?({zero})(-r{ints})?'.format(zero 
= _zeroinstall_regexp, ints = _dotted_ints)
 
 _PYTHON_URI = 'http://repo.roscidus.com/python/python'
 
@@ -48,7 +48,7 @@
                        mtime = int(info.st_mtime)
                        size = info.st_size
                except Exception as ex:
-                       logger.warn("Failed to stat %s: %s", self.source, ex)
+                       logger.warning("Failed to stat %s: %s", self.source, ex)
                        mtime = size = 0
                self.cache = {}
                import tempfile
@@ -105,7 +105,7 @@
                        with open(cache_path, 'a') as stream:
                                stream.write('%s=%s\n' % (key, value))
                except Exception as ex:
-                       logger.warn("Failed to write to cache %s: %s=%s: %s", 
cache_path, key, value, ex)
+                       logger.warning("Failed to write to cache %s: %s=%s: 
%s", cache_path, key, value, ex)
 
 def try_cleanup_distro_version(version):
        """Try to turn a distribution version string into one readable by Zero 
Install.
@@ -126,7 +126,7 @@
        if match:
                major, version, revision = match.groups()
                if major is not None:
-                       version = major[:-1] + '.' + version
+                       version = major[:-1].rstrip('.') + '.' + version
                if revision is not None:
                        version = '%s-%s' % (version, revision[2:])
                return version + suffix
@@ -141,6 +141,8 @@
        @type name: str
        """
 
+       name = "fallback"
+
        _packagekit = None
 
        def get_package_info(self, package, factory):
@@ -191,7 +193,7 @@
                                if id in feed.implementations:
                                        if only_if_missing:
                                                return None
-                                       logger.warn(_("Duplicate ID '%s' for 
DistributionImplementation"), id)
+                                       logger.warning(_("Duplicate ID '%s' for 
DistributionImplementation"), id)
                                impl = model.DistributionImplementation(feed, 
id, self, item)
                                feed.implementations[id] = impl
                                new_impls.append(impl)
@@ -228,7 +230,7 @@
                        impl = model.DistributionImplementation(feed, impl_id, 
self, distro_name = 'host')
                        impl.installed = True
                        impl.version = model.parse_version(python_version)
-                       impl.main = sys.executable
+                       impl.main = sys.executable or '/usr/bin/python'
                        impl.upstream_stability = model.packaged
                        impl.machine = host_machine     # (hopefully)
                        feed.implementations[impl_id] = impl
@@ -463,7 +465,7 @@
                                self.generate_cache()
                                self._load_cache()
                        except Exception as ex:
-                               logger.warn(_("Failed to regenerate 
distribution database cache: %s"), ex)
+                               logger.warning(_("Failed to regenerate 
distribution database cache: %s"), ex)
 
        def _load_cache(self):
                """Load {cache_leaf} cache file into self.versions if it is 
available and up-to-date.
@@ -571,7 +573,7 @@
                        if clean_version:
                                return '%s\t%s' % (clean_version, 
canonical_machine(debarch.strip()))
                        else:
-                               logger.warn(_("Can't parse distribution version 
'%(version)s' for package '%(package)s'"), {'version': version, 'package': 
package})
+                               logger.warning(_("Can't parse distribution 
version '%(version)s' for package '%(package)s'"), {'version': version, 
'package': package})
 
                return '-'
 
@@ -683,7 +685,7 @@
                                child.stdout.close()
                                child.wait()
                        except Exception as ex:
-                               logger.warn("'apt-cache show %s' failed: %s", 
package, ex)
+                               logger.warning("'apt-cache show %s' failed: 
%s", package, ex)
                                cached = None
                        # (multi-arch support? can there be multiple 
candidates?)
                        self.apt_cache[package] = cached
@@ -709,7 +711,7 @@
                        if clean_version:
                                cache.append('%s\t%s\t%s' % (package, 
clean_version, zi_arch))
                        else:
-                               logger.warn(_("Can't parse distribution version 
'%(version)s' for package '%(package)s'"), {'version': version, 'package': 
package})
+                               logger.warning(_("Can't parse distribution 
version '%(version)s' for package '%(package)s'"), {'version': version, 
'package': package})
 
                self._write_cache(cache)
                child.stdout.close()
@@ -783,7 +785,7 @@
                                zi_arch = canonical_machine(arch)
                                clean_version = 
try_cleanup_distro_version("%s-%s" % (version, build))
                                if not clean_version:
-                                       logger.warn(_("Can't parse distribution 
version '%(version)s' for package '%(package)s'"), {'version': version, 
'package': name})
+                                       logger.warning(_("Can't parse 
distribution version '%(version)s' for package '%(package)s'"), {'version': 
version, 'package': name})
                                        continue
        
                                impl = factory('package:slack:%s:%s:%s' % \
@@ -820,7 +822,7 @@
                                zi_arch = canonical_machine(arch)
                                clean_version = 
try_cleanup_distro_version("%s-%s" % (version, build))
                                if not clean_version:
-                                       logger.warn(_("Can't parse distribution 
version '%(version)s' for package '%(package)s'"), {'version': version, 
'package': name})
+                                       logger.warning(_("Can't parse 
distribution version '%(version)s' for package '%(package)s'"), {'version': 
version, 'package': name})
                                        continue
        
                                impl = factory('package:arch:%s:%s:%s' % \
@@ -857,7 +859,7 @@
 
                                match = re.search(_version_start_reqexp, name)
                                if match is None:
-                                       logger.warn(_('Cannot parse version 
from Gentoo package named "%(name)s"'), {'name': name})
+                                       logger.warning(_('Cannot parse version 
from Gentoo package named "%(name)s"'), {'name': name})
                                        continue
                                else:
                                        version = 
try_cleanup_distro_version(name[match.start() + 1:])
@@ -895,7 +897,7 @@
 
                        match = nameversion.search(pkgname)
                        if match is None:
-                               logger.warn(_('Cannot parse version from Ports 
package named "%(pkgname)s"'), {'pkgname': pkgname})
+                               logger.warning(_('Cannot parse version from 
Ports package named "%(pkgname)s"'), {'pkgname': pkgname})
                                continue
                        else:
                                name = match.group(1)
@@ -948,7 +950,7 @@
                                else:
                                        cache.append('%s\t%s\t%s' % (package, 
clean_version, zi_arch))
                        else:
-                               logger.warn(_("Can't parse distribution version 
'%(version)s' for package '%(package)s'"), {'version': version, 'package': 
package})
+                               logger.warning(_("Can't parse distribution 
version '%(version)s' for package '%(package)s'"), {'version': version, 
'package': package})
                self._write_cache(cache)
                child.stdout.close()
                child.wait()
@@ -995,7 +997,7 @@
                        if clean_version:
                                cache.append('%s\t%s\t%s' % (package, 
clean_version, zi_arch))
                        else:
-                               logger.warn(_("Can't parse distribution version 
'%(version)s' for package '%(package)s'"), {'version': version, 'package': 
package})
+                               logger.warning(_("Can't parse distribution 
version '%(version)s' for package '%(package)s'"), {'version': version, 
'package': package})
 
                self._write_cache(cache)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/injector/fetch.py 
new/0install-1.16/zeroinstall/injector/fetch.py
--- old/0install-1.15/zeroinstall/injector/fetch.py     2013-02-12 
16:35:03.000000000 +0100
+++ new/0install-1.16/zeroinstall/injector/fetch.py     2013-02-24 
15:29:35.000000000 +0100
@@ -252,7 +252,7 @@
                                # Primary failed
                                primary = None
                                primary_ex = ex
-                               logger.warn(_("Feed download from %(url)s 
failed: %(exception)s"), {'url': feed_url, 'exception': ex})
+                               logger.warning(_("Feed download from %(url)s 
failed: %(exception)s"), {'url': feed_url, 'exception': ex})
 
                        # Start downloading from mirror...
                        mirror = self._download_and_import_feed(feed_url, 
use_mirror = True)
@@ -430,6 +430,11 @@
                                                                        None, 
None, type = 'application/x-bzip-compressed-tar')
                                                continue                # Retry
                                        raise
+                               except SafeException as ex:
+                                       raise SafeException("Error fetching 
{url} {version}: {ex}".format(
+                                               url = impl.feed.url,
+                                               version = impl.get_version(),
+                                               ex = ex))
                                break
 
                        self.handler.impl_added_to_store(impl)
@@ -526,7 +531,7 @@
                        source = icon.getAttribute('href')
                        if source:
                                break
-                       logger.warn(_('Missing "href" attribute on <icon> in 
%s'), interface)
+                       logger.warning(_('Missing "href" attribute on <icon> in 
%s'), interface)
                else:
                        logger.info(_('No PNG icons found in %s'), interface)
                        return
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/injector/gpg.py 
new/0install-1.16/zeroinstall/injector/gpg.py
--- old/0install-1.15/zeroinstall/injector/gpg.py       2013-02-12 
16:35:03.000000000 +0100
+++ new/0install-1.16/zeroinstall/injector/gpg.py       2013-02-24 
15:29:35.000000000 +0100
@@ -163,7 +163,7 @@
                                        try:
                                                keys[current_fpr].name = 
codecs.decode(current_uid, 'utf-8')
                                        except:
-                                               logger.warn("Not UTF-8: %s", 
current_uid)
+                                               logger.warning("Not UTF-8: %s", 
current_uid)
                                                keys[current_fpr].name = 
current_uid
                        if line.startswith('uid:'):
                                assert current_fpr is not None
@@ -177,7 +177,7 @@
                child.stdout.close()
 
                if child.wait():
-                       logger.warn(_("gpg --list-keys failed with exit code 
%d") % child.returncode)
+                       logger.warning(_("gpg --list-keys failed with exit code 
%d") % child.returncode)
 
        return keys
 
@@ -205,7 +205,7 @@
                else:
                        raise SafeException(_("Non-zero exit code %d from 'gpg 
--import'") % status)
        elif error_messages:
-               logger.warn(_("Warnings from 'gpg --import':\n%s") % 
error_messages)
+               logger.warning(_("Warnings from 'gpg --import':\n%s") % 
error_messages)
 
 def _check_xml_stream(stream):
        xml_comment_start = b'<!-- Base64 Signature'
@@ -308,7 +308,7 @@
                if not line.startswith('[GNUPG:] '):
                        # The docs says every line starts with this, but if 
auto-key-retrieve
                        # is on then they might not. See bug #3420548
-                       logger.warn("Invalid output from GnuPG: %r", line)
+                       logger.warning("Invalid output from GnuPG: %r", line)
                        continue
 
                line = line[9:-1]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/injector/handler.py 
new/0install-1.16/zeroinstall/injector/handler.py
--- old/0install-1.15/zeroinstall/injector/handler.py   2013-02-12 
16:35:03.000000000 +0100
+++ new/0install-1.16/zeroinstall/injector/handler.py   2013-02-24 
15:29:35.000000000 +0100
@@ -139,7 +139,7 @@
                                        try:
                                                tasks.check(b)
                                        except Exception as ex:
-                                               logger.warn(_("Failed to get 
key info: %s"), ex)
+                                               logger.warning(_("Failed to get 
key info: %s"), ex)
                                if stdin.happened:
                                        print(_("Skipping remaining key lookups 
due to input from user"), file=sys.stderr)
                                        break
@@ -185,7 +185,7 @@
                @param tb: optional traceback
                @since: 0.25"""
                import logging
-               logger.warn("%s", str(exception) or type(exception),
+               logger.warning("%s", str(exception) or type(exception),
                                exc_info = (exception, None, tb) if 
logger.isEnabledFor(logging.INFO) else None)
        
 class ConsoleHandler(Handler):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/injector/iface_cache.py 
new/0install-1.16/zeroinstall/injector/iface_cache.py
--- old/0install-1.15/zeroinstall/injector/iface_cache.py       2013-02-12 
16:35:03.000000000 +0100
+++ new/0install-1.16/zeroinstall/injector/iface_cache.py       2013-02-24 
15:29:35.000000000 +0100
@@ -124,7 +124,7 @@
                                                blockers.append(b)
                                except Exception:
                                        _type, exception, tb = sys.exc_info()
-                                       logger.warn(_("Failed to import key for 
'%(url)s': %(exception)s"), {'url': self.url, 'exception': str(exception)})
+                                       logger.warning(_("Failed to import key 
for '%(url)s': %(exception)s"), {'url': self.url, 'exception': str(exception)})
                                        stream.close()
 
                if exception and not any_success:
@@ -493,7 +493,7 @@
                        try:
                                results[imp.uri] = self.get_feed(imp.uri)
                        except SafeException as ex:
-                               logger.warn("Failed to load feed '%s: %s", 
imp.uri, ex)
+                               logger.warning("Failed to load feed '%s: %s", 
imp.uri, ex)
                if main_feed:
                        for imp in main_feed.feeds:
                                results[imp.uri] = self.get_feed(imp.uri)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/injector/model.py 
new/0install-1.16/zeroinstall/injector/model.py
--- old/0install-1.15/zeroinstall/injector/model.py     2013-02-12 
16:35:03.000000000 +0100
+++ new/0install-1.16/zeroinstall/injector/model.py     2013-02-24 
15:29:35.000000000 +0100
@@ -187,7 +187,7 @@
                        r = VersionExpressionRestriction(version)
                except SafeException as ex:
                        msg = "Can't parse version restriction '{version}': 
{error}".format(version = version, error = ex)
-                       logger.warn(msg)
+                       logger.warning(msg)
                        r = ImpossibleRestriction(msg)
                dependency.restrictions.append(r)
 
@@ -286,7 +286,7 @@
 
 class VersionExpressionRestriction(Restriction):
        """Only versions for which the expression is true are acceptable.
-       @since 1.13"""
+       @since: 1.13"""
        __slots__ = ['expr', '_test_fn']
 
        def __init__(self, expr):
@@ -331,7 +331,7 @@
                return impl.distro_name in self.distros
 
        def __str__(self):
-               return "distro " + '|'.join(self.distros)
+               return "distro " + '|'.join(sorted(self.distros))
 
 class Binding(object):
        """Information about how the choice of a Dependency is made known
@@ -1174,7 +1174,7 @@
                                        # In older feeds, the ID was the 
(single) digest
                                        impl.digests.append(id)
                        if id in self.implementations:
-                               logger.warn(_("Duplicate ID '%(id)s' in feed 
'%(feed)s'"), {'id': id, 'feed': self})
+                               logger.warning(_("Duplicate ID '%(id)s' in feed 
'%(feed)s'"), {'id': id, 'feed': self})
                        self.implementations[id] = impl
 
                        impl.metadata = item_attrs
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/injector/qdom.py 
new/0install-1.16/zeroinstall/injector/qdom.py
--- old/0install-1.15/zeroinstall/injector/qdom.py      2013-02-12 
16:35:03.000000000 +0100
+++ new/0install-1.16/zeroinstall/injector/qdom.py      2013-02-24 
15:29:35.000000000 +0100
@@ -68,14 +68,14 @@
 
 class QSAXhandler:
        """SAXHandler that builds a tree of L{Element}s"""
-       filter_range = lambda x: True
-
        def __init__(self, filter_for_version = False):
                """@param filter_for_version: skip elements if their
                if-0install-version attribute doesn't match 
L{zeroinstall.version} (since 1.13)."""
                self.stack = []
                if filter_for_version:
                        self.filter_range = lambda expr: 
versions.parse_version_expression(expr)(_parsed_version)
+               else:
+                       self.filter_range = lambda x: True
        
        def startElementNS(self, fullname, attrs):
                split = fullname.split(' ', 1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/injector/reader.py 
new/0install-1.16/zeroinstall/injector/reader.py
--- old/0install-1.15/zeroinstall/injector/reader.py    2013-02-12 
16:35:03.000000000 +0100
+++ new/0install-1.16/zeroinstall/injector/reader.py    2013-02-24 
15:29:35.000000000 +0100
@@ -24,7 +24,7 @@
                if impl.startswith('.'): continue
                feed = os.path.join(site_packages, impl, '0install', 'feed.xml')
                if not os.path.exists(feed):
-                       logger.warn(_("Site-local feed {path} not 
found").format(path = feed))
+                       logger.warning(_("Site-local feed {path} not 
found").format(path = feed))
                logger.debug("Adding site-local feed '%s'", feed)
 
                # (we treat these as user overrides in order to let old 
versions of 0install
@@ -62,7 +62,7 @@
                try:
                        _add_site_packages(interface, path, known_site_feeds)
                except Exception as ex:
-                       logger.warn("Error loading site packages from {path}: 
{ex}".format(path = path, ex = ex))
+                       logger.warning("Error loading site packages from 
{path}: {ex}".format(path = path, ex = ex))
 
        update_user_overrides(interface, known_site_feeds)
 
@@ -109,7 +109,7 @@
                with open(user, 'rb') as stream:
                        root = qdom.parse(stream)
        except Exception as ex:
-               logger.warn(_("Error reading '%(user)s': %(exception)s"), 
{'user': user, 'exception': ex})
+               logger.warning(_("Error reading '%(user)s': %(exception)s"), 
{'user': user, 'exception': ex})
                raise
 
        last_checked = root.getAttribute('last-checked')
@@ -150,7 +150,7 @@
                with open(user, 'rb') as stream:
                        root = qdom.parse(stream)
        except Exception as ex:
-               logger.warn(_("Error reading '%(user)s': %(exception)s"), 
{'user': user, 'exception': ex})
+               logger.warning(_("Error reading '%(user)s': %(exception)s"), 
{'user': user, 'exception': ex})
                raise
 
        stability_policy = root.getAttribute('stability-policy')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/injector/scheduler.py 
new/0install-1.16/zeroinstall/injector/scheduler.py
--- old/0install-1.15/zeroinstall/injector/scheduler.py 2013-02-12 
16:35:03.000000000 +0100
+++ new/0install-1.16/zeroinstall/injector/scheduler.py 2013-02-24 
15:29:35.000000000 +0100
@@ -68,7 +68,7 @@
                                if original_exception is None:
                                        original_exception = ex
                                else:
-                                       logger.warn("%s (while trying mirror)", 
ex)
+                                       logger.warning("%s (while trying 
mirror)", ex)
                                mirror_url = step.dl.get_next_mirror_url()
                                if mirror_url is None:
                                        raise original_exception
@@ -78,7 +78,7 @@
                                # looks to see if we have an exact copy of same 
file somewhere else. If this
                                # fails, Fetcher will also look for a different 
archive that would generate
                                # the required implementation.
-                               logger.warn("%s: trying archive mirror at %s", 
ex, mirror_url)
+                               logger.warning("%s: trying archive mirror at 
%s", ex, mirror_url)
                                step.redirect = mirror_url
                                redirections_remaining = 10
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/injector/selections.py 
new/0install-1.16/zeroinstall/injector/selections.py
--- old/0install-1.15/zeroinstall/injector/selections.py        2013-02-12 
16:35:03.000000000 +0100
+++ new/0install-1.16/zeroinstall/injector/selections.py        2013-02-24 
15:29:35.000000000 +0100
@@ -169,7 +169,8 @@
                @param root: a saved set of selections."""
                self.interface = root.getAttribute('interface')
                self.command = root.getAttribute('command')
-               assert self.interface
+               if self.interface is None:
+                       raise model.SafeException(_("Not a selections document 
(no 'interface' attribute on root)"))
                old_commands = []
 
                for selection in root.childNodes:
@@ -324,18 +325,14 @@
        def __repr__(self):
                return "Selections for " + self.interface
 
-       def download_missing(self, config, _old = None, include_packages = 
False):
-               """Check all selected implementations are available.
-               Download any that are not present. Since native distribution 
packages are usually
-               only available in a single version, which is unlikely to be the 
one in the
-               selections document, we ignore them by default.
-               Note: package implementations (distribution packages) are 
ignored.
-               @param config: used to get iface_cache, stores and fetcher
-               @param include_packages: also try to install native packages 
(since 1.5)
-               @return: a L{tasks.Blocker} or None"""
-               if _old:
-                       config = get_deprecated_singleton_config()
-
+       def get_unavailable_selections(self, config, include_packages):
+               """Find those selections which are not present.
+               Local implementations are available if their directory exists.
+               Other 0install implementations are available if they are in the 
cache.
+               Package implementations are available if the Distribution says 
so.
+               @param include_packages: whether to include 
<package-implementation>s
+               @rtype: [Selection]
+               @since: 1.16"""
                iface_cache = config.iface_cache
                stores = config.stores
 
@@ -352,7 +349,24 @@
                        else:
                                return sel.get_path(stores, missing_ok = True) 
is None
 
-               needed_downloads = list(filter(needs_download, 
self.selections.values()))
+               return [sel for sel in self.selections.values() if 
needs_download(sel)]
+
+       def download_missing(self, config, _old = None, include_packages = 
False):
+               """Check all selected implementations are available.
+               Download any that are not present. Since native distribution 
packages are usually
+               only available in a single version, which is unlikely to be the 
one in the
+               selections document, we ignore them by default.
+               Note: package implementations (distribution packages) are 
ignored.
+               @param config: used to get iface_cache, stores and fetcher
+               @param include_packages: also try to install native packages 
(since 1.5)
+               @return: a L{tasks.Blocker} or None"""
+               if _old:
+                       config = get_deprecated_singleton_config()
+
+               iface_cache = config.iface_cache
+               stores = config.stores
+
+               needed_downloads = self.get_unavailable_selections(config, 
include_packages)
                if not needed_downloads:
                        return
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/injector/solver.py 
new/0install-1.16/zeroinstall/injector/solver.py
--- old/0install-1.15/zeroinstall/injector/solver.py    2013-02-12 
16:35:03.000000000 +0100
+++ new/0install-1.16/zeroinstall/injector/solver.py    2013-02-24 
15:29:35.000000000 +0100
@@ -488,15 +488,15 @@
                                                if distro_feed.implementations:
                                                        
impls.extend(distro_feed.implementations.values())
                                except MissingLocalFeed as ex:
-                                       logger.warn(_("Missing local feed; if 
it's no longer required, remove it with:") +
+                                       logger.warning(_("Missing local feed; 
if it's no longer required, remove it with:") +
                                                        '\n0install remove-feed 
' + iface.uri + ' ' + f,
                                                {'feed': f, 'interface': iface, 
'exception': ex})
                                except model.SafeException as ex:
-                                       logger.warn(_("Failed to load feed 
%(feed)s for %(interface)s: %(exception)s"), {'feed': f, 'interface': iface, 
'exception': ex})
+                                       logger.warning(_("Failed to load feed 
%(feed)s for %(interface)s: %(exception)s"), {'feed': f, 'interface': iface, 
'exception': ex})
                                        #raise
                                except Exception as ex:
                                        import logging
-                                       logger.warn(_("Failed to load feed 
%(feed)s for %(interface)s: %(exception)s"), {'feed': f, 'interface': iface, 
'exception': ex},
+                                       logger.warning(_("Failed to load feed 
%(feed)s for %(interface)s: %(exception)s"), {'feed': f, 'interface': iface, 
'exception': ex},
                                                        exc_info = True if 
logger.isEnabledFor(logging.INFO) else None)
 
                        impls.sort(key = lambda impl: self.get_rating(iface, 
impl, arch), reverse = True)
@@ -641,7 +641,7 @@
                # Can't select an implementation of an interface and of its 
replacement
                for original, replacement in replacement_for.items():
                        if original == replacement:
-                               logger.warn("Interface %s replaced-by itself!", 
original)
+                               logger.warning("Interface %s replaced-by 
itself!", original)
                                continue
                        rep_impls = iface_to_vars.get(replacement, None)
                        if rep_impls is None:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/injector/versions.py 
new/0install-1.16/zeroinstall/injector/versions.py
--- old/0install-1.15/zeroinstall/injector/versions.py  2013-02-12 
16:35:03.000000000 +0100
+++ new/0install-1.16/zeroinstall/injector/versions.py  2013-02-24 
15:29:35.000000000 +0100
@@ -57,7 +57,7 @@
 
 def format_version(version):
        """Format a parsed version for display. Undoes the effect of 
L{parse_version}.
-       @see: L{Implementation.get_version}
+       @see: L{model.Implementation.get_version}
        @rtype: str
        @since: 0.24"""
        version = version[:]
@@ -75,7 +75,7 @@
        @param r: the range expression
        @type r: str
        @return: a function which returns whether a parsed version is in the 
range
-       @type: parsed_version -> bool
+       @rtype: parsed_version -> bool
        @since: 1.13"""
        parts = r.split('..', 1)
        if len(parts) == 1:
@@ -110,7 +110,7 @@
        @param expr: the expression to parse
        @type expr: str
        @return: a function which tests whether a parsed version is in the range
-       @type: parsed_version -> bool
+       @rtype: parsed_version -> bool
        @since: 1.13"""
        tests = [parse_version_range(r.strip()) for r in expr.split('|')]
        return lambda v: any(test(v) for test in tests)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/support/tasks.py 
new/0install-1.16/zeroinstall/support/tasks.py
--- old/0install-1.15/zeroinstall/support/tasks.py      2013-02-12 
16:35:03.000000000 +0100
+++ new/0install-1.16/zeroinstall/support/tasks.py      2013-02-24 
15:29:35.000000000 +0100
@@ -56,12 +56,12 @@
                                try:
                                        reporter(*b.exception)
                                except:
-                                       logger.warn("Failure reporting error! 
Error was: %s", repr(b.exception[0]))
+                                       logger.warning("Failure reporting 
error! Error was: %s", repr(b.exception[0]))
                                        raise
                        elif ex is None:
                                ex = b.exception
                        else:
-                               logger.warn(_("Multiple exceptions waiting; 
skipping %s"), b.exception[0])
+                               logger.warning(_("Multiple exceptions waiting; 
skipping %s"), b.exception[0])
        if ex:
                support.raise_with_traceback(ex[0], ex[1])
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/zerostore/__init__.py 
new/0install-1.16/zeroinstall/zerostore/__init__.py
--- old/0install-1.15/zeroinstall/zerostore/__init__.py 2013-02-12 
16:35:03.000000000 +0100
+++ new/0install-1.16/zeroinstall/zerostore/__init__.py 2013-02-24 
15:29:35.000000000 +0100
@@ -157,8 +157,8 @@
                        _copytree2(path, tmp)
                        self.check_manifest_and_rename(required_digest, tmp, 
try_helper = try_helper, dry_run = dry_run)
                except:
-                       logger.warn(_("Error importing directory."))
-                       logger.warn(_("Deleting %s"), tmp)
+                       logger.warning(_("Error importing directory."))
+                       logger.warning(_("Deleting %s"), tmp)
                        support.ro_rmtree(tmp)
                        raise
 
@@ -200,7 +200,7 @@
                        os.close(dev_null)
 
                if exit_code:
-                       logger.warn(_("0store-secure-add-helper failed."))
+                       logger.warning(_("0store-secure-add-helper failed."))
                        return False
 
                logger.info(_("Added succcessfully."))
@@ -244,7 +244,7 @@
 
                final_name = os.path.join(self.dir, required_digest)
                if os.path.isdir(final_name):
-                       logger.warn(_("Item %s already stored.") % final_name) 
# not really an error
+                       logger.warning(_("Item %s already stored.") % 
final_name) # not really an error
                        return
 
                if dry_run:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/zerostore/manifest.py 
new/0install-1.16/zeroinstall/zerostore/manifest.py
--- old/0install-1.15/zeroinstall/zerostore/manifest.py 2013-02-12 
16:35:03.000000000 +0100
+++ new/0install-1.16/zeroinstall/zerostore/manifest.py 2013-02-24 
15:29:35.000000000 +0100
@@ -378,7 +378,7 @@
                try:
                        required_details = wanted.pop(path)
                except KeyError:
-                       logger.warn(_("Skipping file not in manifest: '%s'"), 
path)
+                       logger.warning(_("Skipping file not in manifest: 
'%s'"), path)
                        continue
                if required_details[0] != type:
                        raise BadDigest(_("Item '%s' has wrong type!") % path)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/zerostore/optimise.py 
new/0install-1.16/zeroinstall/zerostore/optimise.py
--- old/0install-1.15/zeroinstall/zerostore/optimise.py 2013-02-12 
16:35:03.000000000 +0100
+++ new/0install-1.16/zeroinstall/zerostore/optimise.py 2013-02-24 
15:29:35.000000000 +0100
@@ -27,7 +27,7 @@
 def _link(a, b, tmpfile):
        """Keep 'a', delete 'b' and hard-link to 'a'"""
        if not _byte_identical(a, b):
-               logger.warn(_("Files should be identical, but they're 
not!\n%(file_a)s\n%(file_b)s"), {'file_a': a, 'file_b': b})
+               logger.warning(_("Files should be identical, but they're 
not!\n%(file_a)s\n%(file_b)s"), {'file_a': a, 'file_b': b})
 
        b_dir = os.path.dirname(b)
        old_mode = os.lstat(b_dir).st_mode
@@ -77,13 +77,13 @@
                try:
                        alg, manifest_digest = parse_algorithm_digest_pair(impl)
                except BadDigest:
-                       logger.warn(_("Skipping non-implementation '%s'"), impl)
+                       logger.warning(_("Skipping non-implementation '%s'"), 
impl)
                        continue
                manifest_path = os.path.join(impl_dir, impl, '.manifest')
                try:
                        ms = open(manifest_path, 'rt')
                except OSError as ex:
-                       logger.warn(_("Failed to read manifest file 
'%(manifest_path)s': %(exception)s"), {'manifest': manifest_path, 'exception': 
str(ex)})
+                       logger.warning(_("Failed to read manifest file 
'%(manifest_path)s': %(exception)s"), {'manifest': manifest_path, 'exception': 
str(ex)})
                        continue
 
                if alg == 'sha1':
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/0install-1.15/zeroinstall/zerostore/unpack.py 
new/0install-1.16/zeroinstall/zerostore/unpack.py
--- old/0install-1.15/zeroinstall/zerostore/unpack.py   2013-02-12 
16:35:03.000000000 +0100
+++ new/0install-1.16/zeroinstall/zerostore/unpack.py   2013-02-24 
15:29:35.000000000 +0100
@@ -59,7 +59,7 @@
                        version = list(map(int, version.group(1).split('.')))
                        recent_gnu_tar = version > [1, 13, 92]
                else:
-                       logger.warn(_("Failed to extract GNU tar version 
number"))
+                       logger.warning(_("Failed to extract GNU tar version 
number"))
        logger.debug(_("Recent GNU tar = %s"), recent_gnu_tar)
        return recent_gnu_tar
 

-- 
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to