Hello community, here is the log from the commit of package zeroinstall-injector for openSUSE:Factory checked in at 2013-02-14 21:19:23 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 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-01-17 13:18:13.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.zeroinstall-injector.new/zeroinstall-injector.changes 2013-02-14 21:19:36.000000000 +0100 @@ -1,0 +2,6 @@ +Wed Feb 13 10:39:33 UTC 2013 - tal...@gmail.com + +- Updated to 1.15. For a list of changes, see: + http://thread.gmane.org/gmane.comp.file-systems.zero-install.devel/6686 + +------------------------------------------------------------------- Old: ---- 0install-1.14.tar.bz2 New: ---- 0install-1.15.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ zeroinstall-injector.spec ++++++ --- /var/tmp/diff_new_pack.Q9kvEY/_old 2013-02-14 21:19:37.000000000 +0100 +++ /var/tmp/diff_new_pack.Q9kvEY/_new 2013-02-14 21:19:37.000000000 +0100 @@ -26,9 +26,9 @@ %endif Name: zeroinstall-injector -Version: 1.14 +Version: 1.15 Release: 0 -%define source_version 1.14 +%define source_version 1.15 Summary: Decentralised cross-distribution software installation License: LGPL-2.1+ Group: System/Management ++++++ 0install-1.14.tar.bz2 -> 0install-1.15.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/0install.1 new/0install-1.15/0install.1 --- old/0install-1.14/0install.1 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/0install.1 2013-02-12 16:35:03.000000000 +0100 @@ -1,4 +1,4 @@ -.TH 0INSTALL 1 "2012" "Thomas Leonard" "" +.TH 0INSTALL 1 "2013" "Thomas Leonard" "" .SH NAME 0install \(em a decentralised software installation system @@ -240,7 +240,7 @@ to create shortcuts to run your programs. .PP -All options for `select' and `download' can also be used for `run'. In +All options for `select' can also be used for `run' except for \fB\-\-xml\fP. In addition, these options are available: .TP @@ -374,7 +374,7 @@ is displayed. .SS 0install --version -This can be used (without any command) the get version of 0install itself: +This can be used (without any command) the get version of 0install itself. .SH APPLICATIONS @@ -460,10 +460,9 @@ .B $ 0install run \-\-wrapper="strace \-e open" http://myprog \-\-help -If your program is interpreted (e.g. a Python program), and you wish to debug -the interpreter running it, you can do it like this: +To run the application under the gdb debugger: -.B $ 0install run \-\-wrapper="gdb \-\-args python" http://myprog \-\-help +.B $ 0install run \-\-wrapper="gdb \-\-args" http://myprog \-\-help .SH FILES @@ -510,7 +509,7 @@ .SH LICENSE .PP -Copyright (C) 2012 Thomas Leonard. +Copyright (C) 2013 Thomas Leonard. .PP You may redistribute copies of this program under the terms of the GNU Lesser General Public License. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/ZeroInstall.xml new/0install-1.15/ZeroInstall.xml --- old/0install-1.14/ZeroInstall.xml 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/ZeroInstall.xml 2013-02-12 16:35:03.000000000 +0100 @@ -46,11 +46,13 @@ <restricts interface="http://repo.roscidus.com/python/python" version="2.6..!3 | 3.2.2.."/> + <requires interface="http://repo.roscidus.com/python/python-gobject" os="POSIX"/> + <requires interface="http://0install.net/2012/interfaces/0install-runenv-cli.xml" os="Windows"> <environment insert="runenv.cli.template" mode="replace" name="ZEROINSTALL_CLI_TEMPLATE"/> <version not-before="1.12.1"/> </requires> - <implementation id="." released="2013-01-14" version="1.14"/> + <implementation id="." released="2013-02-12" version="1.15"/> </group> </interface> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/setup.py new/0install-1.15/setup.py --- old/0install-1.14/setup.py 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/setup.py 2013-02-12 16:35:03.000000000 +0100 @@ -103,6 +103,9 @@ install.finalize_options(self) # super.finalize_options() if self.home: self.__config_dir = os.path.join(self.home, '.config') + elif self.user: + from site import USER_BASE + self.__config_dir = os.path.join(USER_BASE, 'etc/xdg') elif self.prefix == '/usr': self.__config_dir = os.path.join(self.root or '/', 'etc/xdg') else: @@ -118,6 +121,13 @@ if self.home: self.run_command('adjust_scripts_for_home') +if '--home' in sys.argv: + zsh_functions_dir = '.zsh' +elif '--install-layout=deb' in sys.argv: + zsh_functions_dir = 'share/zsh/vendor-completions' +else: + zsh_functions_dir = 'share/zsh/site-functions' + setup(name="zeroinstall-injector", version=zeroinstall.version, description="The Zero Install Injector (0launch)", @@ -128,7 +138,7 @@ data_files = [('man/man1', ['0launch.1', '0alias.1', '0store-secure-add.1', '0store.1', '0desktop.1', '0install.1']), ('share/applications', ['share/applications/zeroinstall-add.desktop', 'share/applications/zeroinstall-manage.desktop']), ('share/bash-completion/completions', ['share/bash-completion/completions/0install']), - ('share/zsh/site-functions', ['share/zsh/site-functions/_0install']), + (zsh_functions_dir, ['share/zsh/site-functions/_0install']), ('share/desktop-directories', ['share/desktop-directories/zeroinstall.directory']), ('share/icons/hicolor/24x24/apps', ['share/icons/24x24/zeroinstall.png']), ('share/icons/hicolor/48x48/apps', ['share/icons/48x48/zeroinstall.png']), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/tests/runnable/ArgList.xml new/0install-1.15/tests/runnable/ArgList.xml --- old/0install-1.14/tests/runnable/ArgList.xml 1970-01-01 01:00:00.000000000 +0100 +++ new/0install-1.15/tests/runnable/ArgList.xml 2013-02-12 16:35:03.000000000 +0100 @@ -0,0 +1,31 @@ +<?xml version="1.0" ?> +<interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface"> + <name>Runnable</name> + <summary>test script that needs a runner</summary> + + <implementation id="test" local-path="." version="1"> + <command name="run" path="script"> + <runner interface='./Runner.xml' command='runme'> + <arg>arg-for-runner</arg> + <for-each item-from="RUNNER_ARGS"> + <arg>-X</arg> + <arg>${item}</arg> + </for-each> + </runner> + <arg>command-arg</arg> + <for-each item-from="COMMAND_ARGS" separator=","> + <arg>${item}</arg> + </for-each> + <for-each item-from="__NOT_SET__" separator=","> + <arg>${foo}</arg> + </for-each> + <arg>--</arg> + </command> + + <environment name='COMMAND_ARGS' value='ca1' separator=',' mode='append'/> + <environment name='COMMAND_ARGS' value='ca2' separator=',' mode='append'/> + + <environment name='RUNNER_ARGS' value='ra1' mode='append'/> + <environment name='RUNNER_ARGS' value='ra2' mode='append'/> + </implementation> +</interface> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/tests/testdownload.py new/0install-1.15/tests/testdownload.py --- old/0install-1.14/tests/testdownload.py 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/tests/testdownload.py 2013-02-12 16:35:03.000000000 +0100 @@ -15,7 +15,7 @@ from zeroinstall.injector import model, gpg, download, trust, background, arch, selections, qdom, run from zeroinstall.injector.requirements import Requirements from zeroinstall.injector.driver import Driver -from zeroinstall.zerostore import Store, NotStored +from zeroinstall.zerostore import NotStored from zeroinstall.support import basedir, tasks, ro_rmtree from zeroinstall.injector import fetch import data diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/tests/testescaping.py new/0install-1.15/tests/testescaping.py --- old/0install-1.14/tests/testescaping.py 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/tests/testescaping.py 2013-02-12 16:35:03.000000000 +0100 @@ -1,9 +1,8 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import unicode_literals -import basetest from basetest import BaseTest -import sys, os, re +import sys, re import unittest sys.path.insert(0, '..') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/tests/testinstall.py new/0install-1.15/tests/testinstall.py --- old/0install-1.14/tests/testinstall.py 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/tests/testinstall.py 2013-02-12 16:35:03.000000000 +0100 @@ -5,7 +5,7 @@ sys.path.insert(0, '..') from zeroinstall import cmd, logger, apps, alias -from zeroinstall.injector import model, selections, qdom, handler, gpg, config, background +from zeroinstall.injector import model, selections, qdom, handler, gpg, config mydir = os.path.dirname(__file__) @@ -515,6 +515,18 @@ assert "--- 2012-01-01" in out, out assert not err, err + # select detects changes + new_local = old_local.replace('0.1', '0.1-pre2') + with open(os.path.join(app.path, "selections.xml"), 'w') as stream: + stream.write(new_local) + out, err = self.run_0install(['show', 'local-app']) + assert "Version: 0.1-pre2" in out, out + assert not err, err + out, err = self.run_0install(['select', 'local-app']) + assert "Local.xml: 0.1-pre2 -> 0.1" in out, out + assert "(note: use '0install update' instead to save the changes)" in out, out + assert not err, err + assert 'local-app' in self.complete(['man'], 2) assert 'local-app' in self.complete(['destroy'], 2) self.assertEqual('', self.complete(['destroy', ''], 3)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/tests/testlaunch.py new/0install-1.15/tests/testlaunch.py --- old/0install-1.14/tests/testlaunch.py 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/tests/testlaunch.py 2013-02-12 16:35:03.000000000 +0100 @@ -13,7 +13,6 @@ from zeroinstall import SafeException from zeroinstall.support import tasks from zeroinstall.injector import run, cli, namespaces, qdom, selections -from zeroinstall.zerostore import Store from zeroinstall.injector.requirements import Requirements from zeroinstall.injector.driver import Driver diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/tests/testmodel.py new/0install-1.15/tests/testmodel.py --- old/0install-1.14/tests/testmodel.py 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/tests/testmodel.py 2013-02-12 16:35:03.000000000 +0100 @@ -13,6 +13,11 @@ mydir = os.path.dirname(os.path.abspath(__file__)) +class DummyImpl: + def __init__(self, version, distro): + self.version = model.parse_version(version) + self.distro_name = distro + class TestModel(BaseTest): def testLevels(self): assert model.network_offline in model.network_levels @@ -252,6 +257,7 @@ assert False except model.SafeException as ex: assert "Bad interface name 'CommandMissing.xml'" in str(ex), ex + assert "/tests/CommandMissing.xml' either" in str(ex), ex # file:absolute model.canonical_iface_uri('file://{path}/Command.xml'.format(path = mydir)) @@ -356,5 +362,19 @@ fail('.2', "Invalid version format in '.2': invalid literal for int() with base 10: ''") fail('0.2-hi', "Invalid version modifier in '0.2-hi': 'hi'") + def testRestrictions(self): + v6 = DummyImpl("6", "RPM") + v7 = DummyImpl("7", "Gentoo") + + r = model.VersionExpressionRestriction('!7') + self.assertEqual('<restriction: version !7>', repr(r)) + assert r.meets_restriction(v6) + assert not r.meets_restriction(v7) + + r = model.DistributionRestriction('RPM Debian') + self.assertEqual('<restriction: distro RPM|Debian>', repr(r)) + assert r.meets_restriction(v6) + assert not r.meets_restriction(v7) + if __name__ == '__main__': unittest.main() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/tests/testpackagekit.py new/0install-1.15/tests/testpackagekit.py --- old/0install-1.14/tests/testpackagekit.py 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/tests/testpackagekit.py 2013-02-12 16:35:03.000000000 +0100 @@ -139,6 +139,8 @@ return FakePackageKit() class TestPackageKit(BaseTest): + name = 'TestPackageKit' + def setUp(self): BaseTest.setUp(self) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/tests/testrun.py new/0install-1.15/tests/testrun.py --- old/0install-1.14/tests/testrun.py 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/tests/testrun.py 2013-02-12 16:35:03.000000000 +0100 @@ -17,6 +17,7 @@ mydir = os.path.abspath(os.path.dirname(__file__)) local_0launch = os.path.join(os.path.dirname(mydir), '0launch') +arglist = os.path.join(mydir, 'runnable', 'ArgList.xml') runnable = os.path.join(mydir, 'runnable', 'Runnable.xml') runexec = os.path.join(mydir, 'runnable', 'RunExec.xml') recursive_runner = os.path.join(mydir, 'runnable', 'RecursiveRunner.xml') @@ -95,6 +96,19 @@ sys.stdout = old_stdout assert 'runner-arg' in out, out + def testArgList(self): + d = Driver(requirements = Requirements(arglist), config = self.config) + self.config.handler.wait_for_blocker(d.solve_with_downloads()) + old_stdout = sys.stdout + try: + sys.stdout = StringIO() + run.execute_selections(d.solver.selections, [], dry_run = True, stores = self.config.stores) + out = sys.stdout.getvalue() + finally: + sys.stdout = old_stdout + assert 'arg-for-runner -X ra1 -X ra2' in out, out + assert 'command-arg ca1 ca2' in out, out + def testWrapper(self): p = Driver(requirements = Requirements(runnable), config = self.config) self.config.handler.wait_for_blocker(p.solve_with_downloads()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/tests/testsolver.py new/0install-1.15/tests/testsolver.py --- old/0install-1.14/tests/testsolver.py 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/tests/testsolver.py 2013-02-12 16:35:03.000000000 +0100 @@ -1,4 +1,6 @@ #!/usr/bin/env python +from __future__ import print_function + from basetest import BaseTest, BytesIO import sys, os, locale import unittest @@ -285,15 +287,20 @@ s.solve_for(r) assert not s.ready, s.selections.selections + if expected_error != str(s.get_failure_reason()): + print(s.get_failure_reason()) + self.assertEqual(expected_error, str(s.get_failure_reason())) return s + # No implementations s = test("", "", "Can't find all required implementations:\n" + "- http://localhost/top.xml -> (problem)\n" + " No known implementations at all") + # No retrieval method s = test("<implementation version='1' id='1'><requires interface='{diag}'/></implementation>".format(diag = diag_uri), "", "Can't find all required implementations:\n" + @@ -301,6 +308,7 @@ " No usable implementations:\n" + " 1: No retrieval methods") + # No run command s = test("""<implementation version='1' id='1'> <archive href='http://localhost:3000/foo.tgz' size='100'/> <requires interface='{diag}'> @@ -313,6 +321,22 @@ " Rejected candidates:\n" + " 1: No run command") + # Failing distribution requirement + s = test("""<implementation version='1' id='1' main='foo'> + <archive href='http://localhost:3000/foo.tgz' size='100'/> + <requires interface='{diag}' distribution='foo'/> + </implementation>""".format(diag = diag_uri), + """<implementation version='5' id='diag-5'> + <archive href='http://localhost:3000/diag.tgz' size='100'/> + </implementation> + """, + "Can't find all required implementations:\n" + "- http://localhost/diagnostics.xml -> (problem)\n" + " http://localhost/top.xml 1 requires distro foo\n" + " No usable implementations satisfy the restrictions\n" + "- http://localhost/top.xml -> 1 (1)") + + # Failing version requirement on library s = test("""<implementation version='1' id='1' main='foo'> <archive href='http://localhost:3000/foo.tgz' size='100'/> <requires interface='{diag}' version='100..!200'/> @@ -327,6 +351,23 @@ " No usable implementations satisfy the restrictions\n" "- http://localhost/top.xml -> 1 (1)") + # Failing version requires on root + s = test("""<implementation version='1' id='1' main='foo'> + <archive href='http://localhost:3000/foo.tgz' size='100'/> + <requires interface='{diag}'/> + </implementation>""".format(diag = diag_uri), + """<implementation version='5' id='diag-5'> + <archive href='http://localhost:3000/diag.tgz' size='100'/> + <restricts interface='{top_uri}' version='100..!200'/> + </implementation> + """.format(top_uri = top_uri), + "Can't find all required implementations:\n" + "- http://localhost/diagnostics.xml -> (problem)\n" + " Rejected candidates:\n" + " diag-5: requires http://localhost/top.xml version 100..!200\n" + "- http://localhost/top.xml -> 1 (1)") + + # Parse error in version restriction logger.setLevel(logging.ERROR) s = test("""<implementation version='1' id='1' main='foo'> <archive href='http://localhost:3000/foo.tgz' size='100'/> @@ -343,6 +384,7 @@ "- http://localhost/top.xml -> 1 (1)") logger.setLevel(logging.WARNING) + # Old-style version restriction s = test("""<implementation version='1' id='1' main='foo'> <archive href='http://localhost:3000/foo.tgz' size='100'/> <requires interface='{diag}'> @@ -359,6 +401,7 @@ " No usable implementations satisfy the restrictions\n" "- http://localhost/top.xml -> 1 (1)") + # Mismatched machine types s = test("""<group> <requires interface='{diag}'/> <implementation version='1' id='1' main='foo' arch='Windows-i486'> @@ -377,6 +420,7 @@ " diag-5: Can't use x86_64 with selection of Top-level (i486)\n" "- http://localhost/top.xml -> 1 (1)") + # Only show the first five unusable reasons s = test("""<group> <requires interface='{diag}'/> <implementation version='1' id='1' main='foo'> @@ -403,6 +447,7 @@ " ...\n" "- http://localhost/top.xml -> 1 (1)") + # Only show the first five rejection reasons s = test("""<group> <requires interface='{diag}'> <version before='6'/> @@ -436,6 +481,7 @@ " ...\n" "- http://localhost/top.xml -> 1 (1)") + # Justify why a particular version can't be used iface = self.config.iface_cache.get_interface(diag_uri) impl = self.config.iface_cache.get_feed(diag_uri).implementations['diag-5'] r = Requirements(top_uri) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/zeroinstall/0launch-gui/gui.py new/0install-1.15/zeroinstall/0launch-gui/gui.py --- old/0install-1.14/zeroinstall/0launch-gui/gui.py 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/zeroinstall/0launch-gui/gui.py 2013-02-12 16:35:03.000000000 +0100 @@ -5,7 +5,7 @@ from zeroinstall.support import tasks from zeroinstall.injector import handler, download -version = '1.14' +version = '1.15' class GUIHandler(handler.Handler): dl_callbacks = None # Download -> [ callback ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/zeroinstall/__init__.py new/0install-1.15/zeroinstall/__init__.py --- old/0install-1.14/zeroinstall/__init__.py 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/zeroinstall/__init__.py 2013-02-12 16:35:03.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.14' +version = '1.15' import sys, logging if sys.version_info[0] > 2: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/zeroinstall/apps.py new/0install-1.15/zeroinstall/apps.py --- old/0install-1.14/zeroinstall/apps.py 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/zeroinstall/apps.py 2013-02-12 16:35:03.000000000 +0100 @@ -6,7 +6,7 @@ # Copyright (C) 2012, Thomas Leonard # See the README file for details, or visit http://0install.net. -from zeroinstall import _, SafeException, logger, DryRun +from zeroinstall import _, SafeException, logger from zeroinstall.support import basedir, portable_rename from zeroinstall.injector import namespaces, selections, qdom, model import re, os, time, tempfile diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/zeroinstall/cmd/select.py new/0install-1.15/zeroinstall/cmd/select.py --- old/0install-1.14/zeroinstall/cmd/select.py 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/zeroinstall/cmd/select.py 2013-02-12 16:35:03.000000000 +0100 @@ -11,7 +11,8 @@ from zeroinstall import _, logger from zeroinstall.cmd import UsageError -from zeroinstall.injector import model, selections, requirements +from zeroinstall.injector import model, selections +from zeroinstall.injector.requirements import Requirements from zeroinstall.injector.driver import Driver from zeroinstall.support import tasks @@ -37,13 +38,15 @@ add_generic_select_options(parser) parser.add_option("", "--xml", help=_("write selected versions as XML"), action='store_true') -def get_selections(config, options, iface_uri, select_only, download_only, test_callback): +def get_selections(config, options, iface_uri, select_only, download_only, test_callback, requirements = None): """Get selections for iface_uri, according to the options passed. Will switch to GUI mode if necessary. @param options: options from OptionParser @param iface_uri: canonical URI of the interface @param select_only: return immediately even if the selected versions aren't cached @param download_only: wait for stale feeds, and display GUI button as Download, not Run + @param requirements: requirements to use; if None, requirements come from options (since 1.15) + @type requirements: Requirements @return: the selected versions, or None if the user cancels @rtype: L{selections.Selections} | None """ @@ -63,10 +66,11 @@ tasks.wait_for_blocker(blocker) return maybe_selections - r = requirements.Requirements(iface_uri) - r.parse_options(options) + if requirements is None: + requirements = Requirements(iface_uri) + requirements.parse_options(options) - return get_selections_for(r, config, options, select_only, download_only, test_callback) + return get_selections_for(requirements, config, options, select_only, download_only, test_callback) def get_selections_for(requirements, config, options, select_only, download_only, test_callback): """Get selections for given requirements. @@ -158,33 +162,36 @@ app = config.app_mgr.lookup_app(args[0], missing_ok = True) if app is not None: - sels = app.get_selections() + old_sels = app.get_selections() - r = app.get_requirements() - do_select = r.parse_update_options(options) - iface_uri = sels.interface + requirements = app.get_requirements() + changes = requirements.parse_update_options(options) + iface_uri = old_sels.interface - if not do_select and r.extra_restrictions and not options.xml: + if requirements.extra_restrictions and not options.xml: print("User-provided restrictions in force:") - for uri, expr in r.extra_restrictions.items(): + for uri, expr in requirements.extra_restrictions.items(): print(" {uri}: {expr}".format(uri = uri, expr = expr)) print() else: iface_uri = model.canonical_iface_uri(args[0]) - do_select = True + requirements = None + changes = False - if do_select or options.gui: - sels = get_selections(config, options, iface_uri, - select_only = True, download_only = False, test_callback = None) - if not sels: - sys.exit(1) # Aborted by user + sels = get_selections(config, options, iface_uri, + select_only = True, download_only = False, test_callback = None, requirements = requirements) + if not sels: + sys.exit(1) # Aborted by user if options.xml: show_xml(sels) else: show_human(sels, config.stores) - if app is not None and do_select: - print(_("(use '0install update' to save the new parameters)")) + if app is not None: + from zeroinstall.cmd import whatchanged + changes = whatchanged.show_changes(old_sels.selections, sels.selections) or changes + if changes: + print(_("(note: use '0install update' instead to save the changes)")) def show_xml(sels): doc = sels.toDOM() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/zeroinstall/gtkui/gtkutils.py new/0install-1.15/zeroinstall/gtkui/gtkutils.py --- old/0install-1.14/zeroinstall/gtkui/gtkutils.py 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/zeroinstall/gtkui/gtkutils.py 2013-02-12 16:35:03.000000000 +0100 @@ -85,7 +85,7 @@ def __init__(self, dialog): tasks.Blocker.__init__(self, dialog.get_title()) a = None - def response(d, resp): + def response(d, resp, self = self): # (PyGTK GC bug) self.response = resp d.disconnect(a) self.trigger() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/zeroinstall/injector/distro.py new/0install-1.15/zeroinstall/injector/distro.py --- old/0install-1.14/zeroinstall/injector/distro.py 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/zeroinstall/injector/distro.py 2013-02-12 16:35:03.000000000 +0100 @@ -17,8 +17,10 @@ _zeroinstall_regexp = '(?:%s)(?:-(?:pre|rc|post|)(?:%s))*' % (_dotted_ints, _dotted_ints) # This matches the interesting bits of distribution version numbers -# (first matching group is for Java-style 6b17 syntax, or "major") -_version_regexp = '(?:[a-z])?({ints}b)?({zero})(-r{ints})?'.format(zero = _zeroinstall_regexp, ints = _dotted_ints) +# (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) + +_PYTHON_URI = 'http://repo.roscidus.com/python/python' # We try to do updates atomically without locking, but we don't worry too much about # duplicate entries or being a little out of sync with the on-disk copy. @@ -135,7 +137,10 @@ Sub-classes should specialise this to integrate with the package managers of particular distributions. This base class ignores the native package manager. @since: 0.28 + @ivar name: the default value for Implementation.distro_name for our implementations + @type name: str """ + _packagekit = None def get_package_info(self, package, factory): @@ -214,19 +219,35 @@ if impl.installed: self.installed_fixup(impl) - if master_feed.url == 'http://repo.roscidus.com/python/python' and os.name != "nt" and all(not impl.installed for impl in feed.implementations.values()): + if master_feed.url == _PYTHON_URI and os.name != "nt": # Hack: we can support Python on platforms with unsupported package managers # by adding the implementation of Python running us now to the list. python_version = '.'.join([str(v) for v in sys.version_info if isinstance(v, int)]) impl_id = 'package:host:python:' + python_version assert impl_id not in feed.implementations - impl = model.DistributionImplementation(feed, impl_id, self) + 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.upstream_stability = model.packaged impl.machine = host_machine # (hopefully) feed.implementations[impl_id] = impl + elif master_feed.url == 'http://repo.roscidus.com/python/python-gobject' and os.name != "nt": + # Likewise, we know that there is a native python-gobject available for our Python + from zeroinstall import gobject + impl_id = 'package:host:python-gobject:' + '.'.join(str(x) for x in gobject.pygobject_version) + assert impl_id not in feed.implementations + impl = model.DistributionImplementation(feed, impl_id, self, distro_name = 'host') + impl.installed = True + impl.version = [list(gobject.pygobject_version)] + impl.upstream_stability = model.packaged + impl.machine = host_machine # (hopefully) + + # Requires our version of Python too + restriction_element = qdom.Element(namespaces.XMLNS_IFACE, 'restricts', {'interface': _PYTHON_URI, 'distribution': 'host'}) + impl.requires.append(model.process_depends(restriction_element, None)) + + feed.implementations[impl_id] = impl return feed @@ -263,7 +284,12 @@ @since: 1.11""" pass + def get_score(self, distro_name): + return int(distro_name == self.name) + class WindowsDistribution(Distribution): + name = 'Windows' + def get_package_info(self, package, factory): def _is_64bit_windows(): p = sys.platform @@ -304,8 +330,7 @@ reg_path = r"SOFTWARE\JavaSoft\{part}\{win_version}".format(part = part, win_version = win_version) (java32_home, java64_home) = _read_hklm_reg(reg_path, "JavaHome") - for (home, arch) in [(java32_home, 'i486'), - (java64_home, 'x86_64')]: + for (home, arch) in [(java32_home, 'i486'), (java64_home, 'x86_64')]: if os.path.isfile(home + r"\bin\java.exe"): impl = factory('package:windows:%s:%s:%s' % (package, zero_version, arch)) impl.machine = arch @@ -313,6 +338,31 @@ impl.upstream_stability = model.packaged impl.main = home + r"\bin\java.exe" + def find_netfx(win_version, zero_version): + reg_path = r"SOFTWARE\Microsoft\NET Framework Setup\NDP\{win_version}".format(win_version = win_version) + (netfx32_install, netfx64_install) = _read_hklm_reg(reg_path, "Install") + + for (install, arch) in [(netfx32_install, 'i486'), (netfx64_install, 'x86_64')]: + impl = factory('package:windows:%s:%s:%s' % (package, zero_version, arch)) + impl.installed = (install == 1) + impl.machine = arch + impl.version = model.parse_version(zero_version) + impl.upstream_stability = model.packaged + impl.main = "" # .NET executables do not need a runner on Windows but they need one elsewhere + + def find_netfx_release(win_version, release_version, zero_version): + reg_path = r"SOFTWARE\Microsoft\NET Framework Setup\NDP\{win_version}".format(win_version = win_version) + (netfx32_install, netfx64_install) = _read_hklm_reg(reg_path, "Install") + (netfx32_release, netfx64_release) = _read_hklm_reg(reg_path, "Release") + + for (install, release, arch) in [(netfx32_install, netfx32_release, 'i486'), (netfx64_install, netfx64_release, 'x86_64')]: + impl = factory('package:windows:%s:%s:%s' % (package, zero_version, arch)) + impl.installed = (install == 1 and release != '' and release >= release_version) + impl.machine = arch + impl.version = model.parse_version(zero_version) + impl.upstream_stability = model.packaged + impl.main = "" # .NET executables do not need a runner on Windows but they need one elsewhere + if package == 'openjdk-6-jre': find_java("Java Runtime Environment", "1.6", '6') elif package == 'openjdk-6-jdk': @@ -321,12 +371,22 @@ find_java("Java Runtime Environment", "1.7", '7') elif package == 'openjdk-7-jdk': find_java("Java Development Kit", "1.7", '7') - - def get_score(self, disto_name): - return int(disto_name == 'Windows') + elif package == 'netfx': + find_netfx("v2.0.50727", '2.0') + find_netfx("v3.0", '3.0') + find_netfx("v3.5", '3.5') + find_netfx("v4\\Full", '4.0') + find_netfx_release("v4\\Full", 378389, '4.5') + find_netfx("v5", '5.0') + elif package == 'netfx-client': + find_netfx("v4\\Client", '4.0') + find_netfx_release("v4\\Client", 378389, '4.5') class DarwinDistribution(Distribution): """@since: 1.11""" + + name = 'Darwin' + def get_package_info(self, package, factory): def java_home(version, arch): null = os.open(os.devnull, os.O_WRONLY) @@ -366,7 +426,7 @@ def find_program(file): if os.path.isfile(file) and os.access(file, os.X_OK): - program_version = get_version(file) + program_version = try_cleanup_distro_version(get_version(file)) impl = factory('package:darwin:%s:%s' % (package, program_version), True) if impl: impl.installed = True @@ -380,9 +440,6 @@ elif package == 'gnupg2': find_program("/usr/local/bin/gpg2") - def get_score(self, disto_name): - return int(disto_name == 'Darwin') - class CachedDistribution(Distribution): """For distributions where querying the package database is slow (e.g. requires running an external command), we cache the results. @@ -488,6 +545,8 @@ class DebianDistribution(Distribution): """A dpkg-based distribution.""" + name = 'Debian' + cache_leaf = 'dpkg-status.cache' def __init__(self, dpkg_status): @@ -585,9 +644,6 @@ impl.commands["run"] = model.Command(qdom.Element(namespaces.XMLNS_IFACE, 'command', {'path': java_bin, 'name': 'run'}), None) - def get_score(self, disto_name): - return int(disto_name == 'Debian') - def _get_dpkg_info(self, package): installed_cached_info = self.dpkg_cache.get(package) if installed_cached_info == None: @@ -635,6 +691,8 @@ class RPMDistribution(CachedDistribution): """An RPM-based distribution.""" + name = 'RPM' + cache_leaf = 'rpm-status.cache' def generate_cache(self): @@ -709,12 +767,11 @@ # OpenSUSE uses 1.6 to mean 6 del impl.version[0][0] - def get_score(self, disto_name): - return int(disto_name == 'RPM') - class SlackDistribution(Distribution): """A Slack-based distribution.""" + name = 'Slack' + def __init__(self, packages_dir): self._packages_dir = packages_dir @@ -738,12 +795,11 @@ # Add any uninstalled candidates found by PackageKit self.packagekit.get_candidates(package, factory, 'package:slack') - def get_score(self, disto_name): - return int(disto_name == 'Slack') - class ArchDistribution(Distribution): """An Arch Linux distribution.""" + name = 'Arch' + def __init__(self, packages_dir): self._packages_dir = os.path.join(packages_dir, "local") @@ -776,10 +832,8 @@ # Add any uninstalled candidates found by PackageKit self.packagekit.get_candidates(package, factory, 'package:arch') - def get_score(self, disto_name): - return int(disto_name == 'Arch') - class GentooDistribution(Distribution): + name = 'Gentoo' def __init__(self, pkgdir): self._pkgdir = pkgdir @@ -823,10 +877,8 @@ # Add any uninstalled candidates found by PackageKit self.packagekit.get_candidates(package, factory, 'package:gentoo') - def get_score(self, disto_name): - return int(disto_name == 'Gentoo') - class PortsDistribution(Distribution): + name = 'Ports' def __init__(self, pkgdir): self._pkgdir = pkgdir @@ -858,10 +910,9 @@ impl.version = model.parse_version(version) impl.machine = machine - def get_score(self, disto_name): - return int(disto_name == 'Ports') - class MacPortsDistribution(CachedDistribution): + name = 'MacPorts' + def __init__(self, db_status_file): super(MacPortsDistribution, self).__init__(db_status_file) self.darwin = DarwinDistribution() @@ -914,16 +965,18 @@ if machine != '*': impl.machine = machine - def get_score(self, disto_name): + def get_score(self, distro_name): # We support both sources of packages. # In theory, we should route 'Darwin' package names to DarwinDistribution, and # Mac Ports names to MacPortsDistribution. But since we only use Darwin for Java, # having one object handle both is OK. - return int(disto_name in ('Darwin', 'MacPorts')) + return int(distro_name in ('Darwin', 'MacPorts')) class CygwinDistribution(CachedDistribution): """A Cygwin-based distribution.""" + name = 'Cygwin' + cache_leaf = 'cygcheck-status.cache' def generate_cache(self): @@ -956,9 +1009,6 @@ if machine != '*': impl.machine = machine - def get_score(self, disto_name): - return int(disto_name == 'Cygwin') - _host_distribution = None def get_host_distribution(): @@ -986,9 +1036,8 @@ _host_distribution = GentooDistribution(_pkg_db) elif sys.platform.startswith("freebsd"): _host_distribution = PortsDistribution(_pkg_db) - elif os.path.isfile(_macports_db) \ - and sys.prefix.startswith("/opt/local"): - _host_distribution = MacPortsDistribution(_macports_db) + elif os.path.isfile(_macports_db): + _host_distribution = MacPortsDistribution(_macports_db) elif os.path.isfile(_cygwin_log) and sys.platform == "cygwin": _host_distribution = CygwinDistribution(_cygwin_log) elif os.access(dpkg_db_status, os.R_OK) \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/zeroinstall/injector/driver.py new/0install-1.15/zeroinstall/injector/driver.py --- old/0install-1.14/zeroinstall/injector/driver.py 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/zeroinstall/injector/driver.py 2013-02-12 16:35:03.000000000 +0100 @@ -11,7 +11,7 @@ from zeroinstall import _, logger import os -from zeroinstall.injector import arch, model +from zeroinstall.injector import arch from zeroinstall.injector.model import network_offline from zeroinstall.support import tasks diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/zeroinstall/injector/fetch.py new/0install-1.15/zeroinstall/injector/fetch.py --- old/0install-1.14/zeroinstall/injector/fetch.py 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/zeroinstall/injector/fetch.py 2013-02-12 16:35:03.000000000 +0100 @@ -5,7 +5,7 @@ # Copyright (C) 2009, Thomas Leonard # See the README file for details, or visit http://0install.net. -from zeroinstall import _, NeedDownload, logger +from zeroinstall import _, logger import os, sys from zeroinstall import support diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/zeroinstall/injector/handler.py new/0install-1.15/zeroinstall/injector/handler.py --- old/0install-1.14/zeroinstall/injector/handler.py 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/zeroinstall/injector/handler.py 2013-02-12 16:35:03.000000000 +0100 @@ -184,9 +184,9 @@ @type exception: L{SafeException} @param tb: optional traceback @since: 0.25""" - logger.warn("%s", str(exception) or type(exception)) - #import traceback - #traceback.print_exception(exception, None, tb) + import logging + logger.warn("%s", str(exception) or type(exception), + exc_info = (exception, None, tb) if logger.isEnabledFor(logging.INFO) else None) class ConsoleHandler(Handler): """A Handler that displays progress on stdout (a tty). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/zeroinstall/injector/model.py new/0install-1.15/zeroinstall/injector/model.py --- old/0install-1.14/zeroinstall/injector/model.py 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/zeroinstall/injector/model.py 2013-02-12 16:35:03.000000000 +0100 @@ -191,6 +191,10 @@ r = ImpossibleRestriction(msg) dependency.restrictions.append(r) + distro = item.getAttribute('distribution') + if distro: + dependency.restrictions.append(DistributionRestriction(distro)) + for e in item.childNodes: if e.uri != XMLNS_IFACE: continue if e.name in binding_names: @@ -226,6 +230,9 @@ """ raise NotImplementedError(_("Abstract")) + def __str__(self): + return "missing __str__ on %s" % type(self) + def __repr__(self): return "<restriction: %s>" % self @@ -237,6 +244,7 @@ """@param version: the required version number @see: L{parse_version}; use this to pre-process the version number """ + assert not isinstance(version, str), "Not parsed: " + version self.version = version def meets_restriction(self, impl): @@ -308,6 +316,23 @@ def __str__(self): return "<impossible: %s>" % self.reason +class DistributionRestriction(Restriction): + """A restriction that can only be satisfied by an implementation + from the given distribution. + For example, a MacPorts Python library requires us to select the MacPorts + version of Python too. + @since: 1.15""" + distros = None + + def __init__(self, distros): + self.distros = frozenset(distros.split(' ')) + + def meets_restriction(self, impl): + return impl.distro_name in self.distros + + def __str__(self): + return "distro " + '|'.join(self.distros) + class Binding(object): """Information about how the choice of a Dependency is made known to the application being run.""" @@ -801,14 +826,15 @@ @ivar package_implementation: the <package-implementation> element that generated this impl (since 1.7) @type package_implementation: L{qdom.Element} @since: 0.28""" - __slots__ = ['distro', 'installed', 'package_implementation'] + __slots__ = ['distro', 'installed', 'package_implementation', 'distro_name'] - def __init__(self, feed, id, distro, package_implementation = None): + def __init__(self, feed, id, distro, package_implementation = None, distro_name = None): assert id.startswith('package:') Implementation.__init__(self, feed, id) self.distro = distro self.installed = False self.package_implementation = package_implementation + self.distro_name = distro_name or distro.name if package_implementation: for child in package_implementation.childNodes: @@ -833,6 +859,8 @@ @since: 0.28""" __slots__ = ['os', 'size', 'digests', 'local_path'] + distro_name = '0install' + def __init__(self, feed, id, local_path): """id can be a local path (string starting with /) or a manifest hash (eg "sha1=XXX")""" assert not id.startswith('package:'), id @@ -1449,11 +1477,11 @@ return path if '/' not in uri: - path = support.find_in_path(uri) - if path is not None: + alias_path = support.find_in_path(uri) + if alias_path is not None: from zeroinstall import alias try: - alias.parse_script(path) + alias.parse_script(alias_path) except alias.NotAnAliasScript: pass else: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/zeroinstall/injector/run.py new/0install-1.15/zeroinstall/injector/run.py --- old/0install-1.14/zeroinstall/injector/run.py 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/zeroinstall/injector/run.py 2013-02-12 16:35:03.000000000 +0100 @@ -68,11 +68,22 @@ return results -def _process_args(args, element): - """Append each <arg> under <element> to args, performing $-expansion.""" +def _process_args(args, element, env = os.environ): + """Append each <arg> under <element> to args, performing $-expansion. Also, process <for-each> loops.""" for child in element.childNodes: - if child.uri == namespaces.XMLNS_IFACE and child.name == 'arg': - args.append(Template(child.content).substitute(os.environ)) + if child.uri != namespaces.XMLNS_IFACE: continue + + if child.name == 'arg': + args.append(Template(child.content).substitute(env)) + elif child.name == 'for-each': + array_var = child.attrs['item-from'] + separator = child.attrs.get('separator', os.pathsep) + env_copy = env.copy() + seq = env.get(array_var, None) + if seq: + for item in seq.split(separator): + env_copy['item'] = item + _process_args(args, child, env_copy) class Setup(object): """@since: 1.2""" @@ -307,7 +318,7 @@ user_command_element = qdom.Element(namespaces.XMLNS_IFACE, 'command', {'path': main}) if commands: for child in commands[0].qdom.childNodes: - if child.uri == namespaces.XMLNS_IFACE and child.name == 'arg': + if child.uri == namespaces.XMLNS_IFACE and child.name in ('arg', 'for-each'): continue user_command_element.childNodes.append(child) user_command = Command(user_command_element, None) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/zeroinstall/injector/solver.py new/0install-1.15/zeroinstall/injector/solver.py --- old/0install-1.14/zeroinstall/injector/solver.py 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/zeroinstall/injector/solver.py 2013-02-12 16:35:03.000000000 +0100 @@ -491,9 +491,13 @@ logger.warn(_("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 Exception as 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}) #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}, + exc_info = True if logger.isEnabledFor(logging.INFO) else None) impls.sort(key = lambda impl: self.get_rating(iface, impl, arch), reverse = True) @@ -933,6 +937,20 @@ this_arch = i.machine, other_name = example_machine_impl.feed.get_name(), other_arch = example_machine_impl.machine) + + if reason is None: + # Check if our requirements conflict with an existing selection + for dep in i.requires: + if not isinstance(dep, model.InterfaceRestriction): continue + dep_selection = sels.get(dep.interface) + if dep_selection is not None: + for r in dep.restrictions: + if not r.meets_restriction(dep_selection.impl): + reason = _("requires {iface} {reqs}").format( + iface = dep.interface, + reqs = ', '.join(str(r) for r in dep.restrictions)) + break + if reason is None: var = self._iface_to_vars[iface].get(i, None) if var is None: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/zeroinstall/support/escaping.py new/0install-1.15/zeroinstall/support/escaping.py --- old/0install-1.14/zeroinstall/support/escaping.py 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/zeroinstall/support/escaping.py 2013-02-12 16:35:03.000000000 +0100 @@ -11,7 +11,7 @@ @since: 1.13 """ -import os, sys, re +import re # Copyright (C) 2012, Thomas Leonard # See the README file for details, or visit http://0install.net. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/0install-1.14/zeroinstall/zerostore/optimise.py new/0install-1.15/zeroinstall/zerostore/optimise.py --- old/0install-1.14/zeroinstall/zerostore/optimise.py 2013-01-14 12:33:10.000000000 +0100 +++ new/0install-1.15/zeroinstall/zerostore/optimise.py 2013-02-12 16:35:03.000000000 +0100 @@ -86,7 +86,9 @@ logger.warn(_("Failed to read manifest file '%(manifest_path)s': %(exception)s"), {'manifest': manifest_path, 'exception': str(ex)}) continue - if alg == 'sha1': continue + if alg == 'sha1': + ms.close() + continue man_size += os.path.getsize(manifest_path) -- To unsubscribe, e-mail: opensuse-commit+unsubscr...@opensuse.org For additional commands, e-mail: opensuse-commit+h...@opensuse.org