Beispiel #1
0
	def testMultiArch(self):
		iface_cache = self.config.iface_cache
		s = solver.DefaultSolver(self.config)

		foo = iface_cache.get_interface('http://foo/MultiArch.xml')
		self.import_feed(foo.uri, 'MultiArch.xml')
		lib = iface_cache.get_interface('http://foo/MultiArchLib.xml')
		self.import_feed(lib.uri, 'MultiArchLib.xml')

		# On an i686 system we can only use the i486 implementation

		binary_arch = arch.get_architecture('Linux', 'i686')
		s.solve('http://foo/MultiArch.xml', binary_arch)
		assert s.ready
		assert s.selections[foo].machine == 'i486'
		assert s.selections[lib].machine == 'i486'

		# On an 64 bit system we could use either, but we prefer the 64
		# bit implementation. The i486 version of the library is newer,
		# but we must pick one that is compatible with the main binary.

		binary_arch = arch.get_architecture('Linux', 'x86_64')
		s.solve('http://foo/MultiArch.xml', binary_arch)
		assert s.ready
		assert s.selections[foo].machine == 'x86_64'
		assert s.selections[lib].machine == 'x86_64'
Beispiel #2
0
    def testMultiArch(self):
        iface_cache = self.config.iface_cache
        s = solver.DefaultSolver(self.config)

        foo = iface_cache.get_interface('http://foo/MultiArch.xml')
        self.import_feed(foo.uri, 'MultiArch.xml')
        lib = iface_cache.get_interface('http://foo/MultiArchLib.xml')
        self.import_feed(lib.uri, 'MultiArchLib.xml')

        # On an i686 system we can only use the i486 implementation

        binary_arch = arch.get_architecture('Linux', 'i686')
        s.solve('http://foo/MultiArch.xml', binary_arch)
        assert s.ready
        assert s.selections[foo].machine == 'i486'
        assert s.selections[lib].machine == 'i486'

        # On an 64 bit system we could use either, but we prefer the 64
        # bit implementation. The i486 version of the library is newer,
        # but we must pick one that is compatible with the main binary.

        binary_arch = arch.get_architecture('Linux', 'x86_64')
        s.solve('http://foo/MultiArch.xml', binary_arch)
        assert s.ready
        assert s.selections[foo].machine == 'x86_64'
        assert s.selections[lib].machine == 'x86_64'
Beispiel #3
0
	def testLangs(self):
		iface_cache = self.config.iface_cache
		try:
			locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')

			s = solver.DefaultSolver(self.config)
			iface = iface_cache.get_interface('http://foo/Langs.xml')
			self.import_feed(iface.uri, 'Langs.xml')

			# 1 is the oldest, but the only one in our language
			binary_arch = arch.get_architecture(None, 'arch_1')
			s.solve('http://foo/Langs.xml', binary_arch)
			assert s.ready
			self.assertEquals('sha1=1', s.selections[iface].id)

			# 6 is the newest, and close enough, even though not
			# quite the right locale
			binary_arch = arch.get_architecture(None, 'arch_2')
			s.solve('http://foo/Langs.xml', binary_arch)
			assert s.ready
			self.assertEquals('sha1=6', s.selections[iface].id)

			# 9 is the newest, although 7 is a closer match
			binary_arch = arch.get_architecture(None, 'arch_3')
			s.solve('http://foo/Langs.xml', binary_arch)
			assert s.ready
			self.assertEquals('sha1=9', s.selections[iface].id)

			# 11 is the newest we understand
			binary_arch = arch.get_architecture(None, 'arch_4')
			s.solve('http://foo/Langs.xml', binary_arch)
			assert s.ready
			self.assertEquals('sha1=11', s.selections[iface].id)

			# 13 is the newest we understand
			binary_arch = arch.get_architecture(None, 'arch_5')
			s.solve('http://foo/Langs.xml', binary_arch)
			assert s.ready
			self.assertEquals('sha1=13', s.selections[iface].id)

			def check(target_arch, langs, expected):
				s.langs = langs
				binary_arch = arch.get_architecture(None, target_arch)
				s.solve('http://foo/Langs.xml', binary_arch)
				assert s.ready
				self.assertEquals(expected, s.selections[iface].id)

			# We don't understand any, so pick the newest
			check('arch_2', ['es_ES'], 'sha1=6')

			# These two have the same version number. Choose the
			# one most appropriate to our country
			check('arch_6', ['zh_CN'], 'sha1=15')
			check('arch_6', ['zh_TW'], 'sha1=16')

			# Same, but one doesn't have a country code
			check('arch_7', ['bn'], 'sha1=17')
			check('arch_7', ['bn_IN'], 'sha1=18')
		finally:
			locale.setlocale(locale.LC_ALL, '')
Beispiel #4
0
    def testLangs(self):
        iface_cache = self.config.iface_cache
        try:
            locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')

            s = solver.DefaultSolver(self.config)
            iface = iface_cache.get_interface('http://foo/Langs.xml')
            self.import_feed(iface.uri, 'Langs.xml')

            # 1 is the oldest, but the only one in our language
            binary_arch = arch.get_architecture(None, 'arch_1')
            s.solve('http://foo/Langs.xml', binary_arch)
            assert s.ready
            self.assertEqual('sha1=1', s.selections[iface].id)

            # 6 is the newest, and close enough, even though not
            # quite the right locale
            binary_arch = arch.get_architecture(None, 'arch_2')
            s.solve('http://foo/Langs.xml', binary_arch)
            assert s.ready
            self.assertEqual('sha1=6', s.selections[iface].id)

            # 9 is the newest, although 7 is a closer match
            binary_arch = arch.get_architecture(None, 'arch_3')
            s.solve('http://foo/Langs.xml', binary_arch)
            assert s.ready
            self.assertEqual('sha1=9', s.selections[iface].id)

            # 11 is the newest we understand
            binary_arch = arch.get_architecture(None, 'arch_4')
            s.solve('http://foo/Langs.xml', binary_arch)
            assert s.ready
            self.assertEqual('sha1=11', s.selections[iface].id)

            # 13 is the newest we understand
            binary_arch = arch.get_architecture(None, 'arch_5')
            s.solve('http://foo/Langs.xml', binary_arch)
            assert s.ready
            self.assertEqual('sha1=13', s.selections[iface].id)

            def check(target_arch, langs, expected):
                s.langs = langs
                binary_arch = arch.get_architecture(None, target_arch)
                s.solve('http://foo/Langs.xml', binary_arch)
                assert s.ready
                self.assertEqual(expected, s.selections[iface].id)

            # We don't understand any, so pick the newest
            check('arch_2', ['es_ES'], 'sha1=6')

            # These two have the same version number. Choose the
            # one most appropriate to our country
            check('arch_6', ['zh_CN'], 'sha1=15')
            check('arch_6', ['zh_TW'], 'sha1=16')

            # Same, but one doesn't have a country code
            check('arch_7', ['bn'], 'sha1=17')
            check('arch_7', ['bn_IN'], 'sha1=18')
        finally:
            locale.setlocale(locale.LC_ALL, '')
Beispiel #5
0
	def testArch(self):
		host_arch = arch.get_host_architecture()
		host_arch2 = arch.get_architecture(None, None)
		self.assertEquals(host_arch.os_ranks, host_arch2.os_ranks)
		self.assertEquals(host_arch.machine_ranks, host_arch2.machine_ranks)

		other = arch.get_architecture('FooBar', 'i486')
		self.assertEquals(2, len(other.os_ranks))

		assert 'FooBar' in other.os_ranks
		assert None in other.os_ranks
		assert 'i486' in other.machine_ranks
		assert 'ppc' not in other.machine_ranks
    def testArch(self):
        host_arch = arch.get_host_architecture()
        host_arch2 = arch.get_architecture(None, None)
        self.assertEquals(host_arch.os_ranks, host_arch2.os_ranks)
        self.assertEquals(host_arch.machine_ranks, host_arch2.machine_ranks)

        other = arch.get_architecture('FooBar', 'i486')
        self.assertEquals(2, len(other.os_ranks))

        assert 'FooBar' in other.os_ranks
        assert None in other.os_ranks
        assert 'i486' in other.machine_ranks
        assert 'ppc' not in other.machine_ranks
Beispiel #7
0
    def __init__(self, config, requirements):
        """
		@param config: The configuration settings to use
		@type config: L{config.Config}
		@param requirements: Details about the program we want to run
		@type requirements: L{requirements.Requirements}
		@since: 0.53
		"""
        self.watchers = []

        assert config
        self.config = config

        assert requirements
        self.requirements = requirements

        self.target_arch = arch.get_architecture(requirements.os, requirements.cpu)

        from zeroinstall.injector.solver import DefaultSolver

        self.solver = DefaultSolver(self.config)

        logger.debug(_("Supported systems: '%s'"), arch.os_ranks)
        logger.debug(_("Supported processors: '%s'"), arch.machine_ranks)

        if requirements.before or requirements.not_before:
            self.solver.extra_restrictions[config.iface_cache.get_interface(requirements.interface_uri)] = [
                model.VersionRangeRestriction(
                    model.parse_version(requirements.before), model.parse_version(requirements.not_before)
                )
            ]
Beispiel #8
0
    def get_arch_for(self, requirements, interface=None):
        """Return the Architecture we would use when solving for this interface.
		Normally, this architecture is constructed from the OS and CPU type in the requirements,
		using the host platform's settings if these are not given.
		If interface is the root, then we wrap this in a SourceArchitecture if looking
		for source code and (for backwards compatibility) we enable use="testing" dependencies
		if the command is "test".
		@param requirements: the overall requirements for the solve
		@type requirements: L{requirements.Requirements}
		@param interface: the interface of interest
		@type interface: L{model.Interface}
		@return: the architecture that would be used
		@rtype: L{architecture.Architecture}
		@since: 1.9"""
        root_arch = arch.get_architecture(requirements.os, requirements.cpu)
        if interface is None or interface.uri == requirements.interface_uri:
            if requirements.source:
                root_arch = arch.SourceArchitecture(root_arch)
            if requirements.command == 'test':
                # This is for old feeds that have use='testing' instead of the newer
                # 'test' command for giving test-only dependencies.
                root_arch = arch.Architecture(root_arch.os_ranks,
                                              root_arch.machine_ranks)
                root_arch.use = frozenset([None, "testing"])
            return root_arch
        # Assume we use the same arch for all descendants
        return root_arch.child_arch
Beispiel #9
0
 def check(target_arch, langs, expected):
     s.langs = langs
     binary_arch = arch.get_architecture(None, target_arch)
     s.solve('http://foo/Langs.xml', binary_arch)
     assert s.ready
     self.assertEqual(expected,
                      s.selections.selections[iface.uri].id)
Beispiel #10
0
	def get_arch_for(self, requirements, interface = None):
		"""Return the Architecture we would use when solving for this interface.
		Normally, this architecture is constructed from the OS and CPU type in the requirements,
		using the host platform's settings if these are not given.
		If interface is the root, then we wrap this in a SourceArchitecture if looking
		for source code and (for backwards compatibility) we enable use="testing" dependencies
		if the command is "test".
		@param requirements: the overall requirements for the solve
		@type requirements: L{requirements.Requirements}
		@param interface: the interface of interest
		@type interface: L{model.Interface}
		@return: the architecture that would be used
		@rtype: L{architecture.Architecture}
		@since: 1.9"""
		root_arch = arch.get_architecture(requirements.os, requirements.cpu)
		if interface is None or interface.uri == requirements.interface_uri:
			if requirements.source:
				root_arch = arch.SourceArchitecture(root_arch)
			if requirements.command == 'test':
				# This is for old feeds that have use='testing' instead of the newer
				# 'test' command for giving test-only dependencies.
				root_arch = arch.Architecture(root_arch.os_ranks, root_arch.machine_ranks)
				root_arch.use = frozenset([None, "testing"])
			return root_arch
		# Assume we use the same arch for all descendants
		return root_arch.child_arch
Beispiel #11
0
    def testRanking(self):
        iface_cache = self.config.iface_cache
        s = solver.DefaultSolver(self.config)
        ranking = os.path.join(os.path.abspath(os.path.dirname(__file__)),
                               'Ranking.xml')
        iface = iface_cache.get_interface(ranking)

        binary_arch = arch.get_architecture('Linux', 'x86_64')
        selected = []
        while True:
            s.solve(ranking, binary_arch)
            if not s.ready:
                break
            impl = s.selections[iface]
            selected.append(impl.get_version() + ' ' + impl.arch)
            impl.arch = 'Foo-odd'  # prevent reselection
        self.assertEqual(
            [
                '0.2 Linux-i386',  # poor arch, but newest version
                '0.1 Linux-x86_64',  # 64-bit is best match for host arch
                '0.1 Linux-i686',
                '0.1 Linux-i586',
                '0.1 Linux-i486'
            ],  # ordering of x86 versions
            selected)
Beispiel #12
0
    def __init__(self, config, requirements):
        """@param config: The configuration settings to use
		@type config: L{config.Config}
		@param requirements: Details about the program we want to run
		@type requirements: L{requirements.Requirements}
		@since: 0.53"""
        self.watchers = []

        assert config
        self.config = config

        assert requirements
        self.requirements = requirements

        self.target_arch = arch.get_architecture(requirements.os,
                                                 requirements.cpu)

        from zeroinstall.injector.solver import DefaultSolver
        self.solver = DefaultSolver(self.config)

        logger.debug(_("Supported systems: '%s'"), arch.os_ranks)
        logger.debug(_("Supported processors: '%s'"), arch.machine_ranks)

        self.solver.extra_restrictions = requirements.get_extra_restrictions(
            self.config.iface_cache)
	def __init__(self, config, requirements):
		"""
		@param config: The configuration settings to use
		@type config: L{config.Config}
		@param requirements: Details about the program we want to run
		@type requirements: L{requirements.Requirements}
		@since: 0.53
		"""
		self.watchers = []

		assert config
		self.config = config

		assert requirements
		self.requirements = requirements

		self.target_arch = arch.get_architecture(requirements.os, requirements.cpu)

		from zeroinstall.injector.solver import DefaultSolver
		self.solver = DefaultSolver(self.config)

		debug(_("Supported systems: '%s'"), arch.os_ranks)
		debug(_("Supported processors: '%s'"), arch.machine_ranks)

		if requirements.before or requirements.not_before:
			self.solver.extra_restrictions[config.iface_cache.get_interface(requirements.interface_uri)] = [
					model.VersionRangeRestriction(model.parse_version(requirements.before),
								      model.parse_version(requirements.not_before))]
Beispiel #14
0
 def testDecideBug(self):
     s = solver.DefaultSolver(self.config)
     watch_xml = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                              'watchdog.xml')
     s.solve(watch_xml,
             arch.get_architecture(None, None),
             command_name='test')
Beispiel #15
0
 def testRecommendBug(self):
     s = solver.DefaultSolver(self.config)
     optional_missing_xml = os.path.join(
         os.path.dirname(os.path.abspath(__file__)), 'OptionalMissing.xml')
     s.solve(optional_missing_xml,
             arch.get_architecture(None, None),
             command_name=None)
Beispiel #16
0
	def testFeedBug(self):
		self.import_feed('http://foo/Build.xml', 'Build.xml')
		self.import_feed('http://foo/Compiler.xml', 'Compiler.xml')
		self.import_feed('http://foo/Compiler-new.xml', 'Compiler-new.xml')
		s = solver.DefaultSolver(self.config)
		s.solve('http://foo/Build.xml', arch.get_architecture(None, None))
		assert s.ready, s.get_failure_reason()
		assert s.selections
Beispiel #17
0
 def testFeedBug(self):
     self.import_feed('http://foo/Build.xml', 'Build.xml')
     self.import_feed('http://foo/Compiler.xml', 'Compiler.xml')
     self.import_feed('http://foo/Compiler-new.xml', 'Compiler-new.xml')
     s = solver.DefaultSolver(self.config)
     s.solve('http://foo/Build.xml', arch.get_architecture(None, None))
     assert s.ready, s.get_failure_reason()
     assert s.selections
Beispiel #18
0
def assertSelection(expected, repo):
    cache = TestCache()

    expected = [tuple(e.strip().split('-')) for e in expected.split(",")]

    for line in repo.split('\n'):
        line = line.strip()
        if not line: continue
        if ':' in line:
            prog, versions = line.split(':')
            prog = prog.strip()
            if ' ' in prog:
                prog, prog_arch = prog.split()
            else:
                prog_arch = None
            for v in versions.split():
                cache.get_prog(prog).get_version(v).arch = prog_arch
        elif '=>' in line:
            prog, requires = line.split('=>')
            prog, version_range = prog.strip().split('[')
            lib, min_v, max_v = requires.split()
            assert version_range.endswith(']')
            version_range = version_range[:-1]
            if ',' in version_range:
                min_p, max_p = map(int, version_range.split(','))
                prog_versions = range(min_p, max_p + 1)
            else:
                prog_versions = [int(version_range)]
            for prog_version in prog_versions:
                cache.get_prog(prog).get_version(
                    str(prog_version)).add_requires(lib, min_v, max_v)

    root = uri_prefix + expected[0][0]

    class TestConfig:
        help_with_testing = False
        network_use = model.network_offline
        stores = stores
        iface_cache = cache

    s = Solver(TestConfig())
    s.solve(root, arch.get_architecture('Linux', 'x86_64'))

    if expected[0][1] == 'FAIL':
        assert not s.ready
    else:
        assert s.ready

        actual = []
        for iface_uri, impl in s.selections.selections.iteritems():
            actual.append(((iface_uri.rsplit('/', 1)[1]), impl.version))

        expected.sort()
        actual.sort()
        if expected != actual:
            raise Exception("Solve failed:\nExpected: %s\n  Actual: %s" %
                            (expected, actual))
    return s
Beispiel #19
0
def assertSelection(expected, repo):
	cache = TestCache()

	expected = [tuple(e.strip().split('-')) for e in expected.split(",")]

	for line in repo.split('\n'):
		line = line.strip()
		if not line: continue
		if ':' in line:
			prog, versions = line.split(':')
			prog = prog.strip()
			if ' ' in prog:
				prog, prog_arch = prog.split()
			else:
				prog_arch = None
			for v in versions.split():
				cache.get_prog(prog).get_version(v).arch = prog_arch
		elif '=>' in line:
			prog, requires = line.split('=>')
			prog, version_range = prog.strip().split('[')
			lib, min_v, max_v = requires.split()
			assert version_range.endswith(']')
			version_range = version_range[:-1]
			if ',' in version_range:
				min_p, max_p = map(int, version_range.split(','))
				prog_versions = range(min_p, max_p + 1)
			else:
				prog_versions = [int(version_range)]
			for prog_version in prog_versions:
				cache.get_prog(prog).get_version(str(prog_version)).add_requires(lib, min_v, max_v)

	root = uri_prefix + expected[0][0]

	class TestConfig:
		help_with_testing = False
		network_use = model.network_offline
		stores = stores
		iface_cache = cache

	s = Solver(TestConfig())
	s.solve(root, arch.get_architecture('Linux', 'x86_64'))

	if expected[0][1] == 'FAIL':
		assert not s.ready
	else:
		assert s.ready

		actual = []
		for iface_uri, impl in s.selections.selections.items():
			actual.append(((iface_uri.rsplit('/', 1)[1]), impl.version))

		expected.sort()
		actual.sort()
		if expected != actual:
			raise Exception("Solve failed:\nExpected: %s\n  Actual: %s" % (expected, actual))
	return s
Beispiel #20
0
	def solve_for(self, requirements):
		"""Solve for given requirements.
		@param requirements: the interface, architecture and command to solve for
		@type requirements: L{requirements.Requirements}
		@postcondition: self.ready, self.selections and self.feeds_used are updated
		@since: 1.8"""
		root_arch = arch.get_architecture(requirements.os, requirements.cpu)
		if requirements.source:
			root_arch = arch.SourceArchitecture(root_arch)
		return self.solve(requirements.interface_uri, root_arch, requirements.command)
Beispiel #21
0
	def __init__(self, root = None, handler = None, src = None, command = -1, config = None, requirements = None):
		"""
		@param requirements: Details about the program we want to run
		@type requirements: L{requirements.Requirements}
		@param config: The configuration settings to use, or None to load from disk.
		@type config: L{ConfigParser.ConfigParser}
		Note: all other arguments are deprecated (since 0launch 0.52)
		"""
		self.watchers = []
		if requirements is None:
			from zeroinstall.injector.requirements import Requirements
			requirements = Requirements(root)
			requirements.source = bool(src)				# Root impl must be a "src" machine type
			if command == -1:
				if src:
					command = 'compile'
				else:
					command = 'run'
			requirements.command = command
			self.target_arch = arch.get_host_architecture()
		else:
			assert root == src == None
			assert command == -1
			self.target_arch = arch.get_architecture(requirements.os, requirements.cpu)
		self.requirements = requirements

		self.stale_feeds = set()

		if config is None:
			self.config = load_config(handler or Handler())
		else:
			assert handler is None, "can't pass a handler and a config"
			self.config = config

		from zeroinstall.injector.solver import DefaultSolver
		self.solver = DefaultSolver(self.config)

		# If we need to download something but can't because we are offline,
		# warn the user. But only the first time.
		self._warned_offline = False

		debug(_("Supported systems: '%s'"), arch.os_ranks)
		debug(_("Supported processors: '%s'"), arch.machine_ranks)

		if requirements.before or requirements.not_before:
			self.solver.extra_restrictions[config.iface_cache.get_interface(requirements.interface_uri)] = [
					model.VersionRangeRestriction(model.parse_version(requirements.before),
								      model.parse_version(requirements.not_before))]
Beispiel #22
0
	def testRanking(self):
		iface_cache = self.config.iface_cache
		s = solver.DefaultSolver(self.config)
		ranking = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'Ranking.xml')

		binary_arch = arch.get_architecture('Linux', 'x86_64')
		selected = []
		while True:
			s.solve(ranking, binary_arch)
			if not s.ready:
				break
			impl = s.selections.selections[ranking]
			selected.append(impl.version + ' ' + impl.attrs['arch'])
			iface_cache.get_feed(ranking).implementations[impl.id].arch = 'Foo-odd'		# prevent reselection
		self.assertEqual([
			'0.2 Linux-i386',	# poor arch, but newest version
			'0.1 Linux-x86_64',	# 64-bit is best match for host arch
			'0.1 Linux-i686', '0.1 Linux-i586', '0.1 Linux-i486'],	# ordering of x86 versions
			selected)
Beispiel #23
0
    def justify_decision(self, requirements, iface, impl):
        """Run a solve with impl_id forced to be selected, and explain why it wasn't (or was)
		selected in the normal case."""
        assert isinstance(iface, model.Interface), iface

        restrictions = self.extra_restrictions.copy()
        restrictions[iface] = restrictions.get(iface, []) + [_ForceImpl(impl)]
        s = SATSolver(self.config, restrictions)
        s.record_details = True
        s.solve_for(requirements)

        wanted = "{iface} {version}".format(iface=iface.get_name(),
                                            version=impl.get_version())

        # Could a selection involving impl even be valid?
        if not s.ready or iface.uri not in s.selections.selections:
            reasons = s.details.get(iface, [])
            for (rid, rstr) in reasons:
                if rid.id == impl.id and rstr is not None:
                    return _(
                        "{wanted} cannot be used (regardless of other components): {reason}"
                    ).format(wanted=wanted, reason=rstr)

            if not s.ready:
                return _(
                    "There is no possible selection using {wanted}.\n{reason}"
                ).format(wanted=wanted, reason=s.get_failure_reason())

        actual_selection = self.selections.get(iface, None)
        if actual_selection is not None:
            # Was impl actually selected anyway?
            if actual_selection.id == impl.id:
                return _("{wanted} was selected as the preferred version."
                         ).format(wanted=wanted)

            # Was impl ranked below the selected version?
            iface_arch = arch.get_architecture(requirements.os,
                                               requirements.cpu)
            if requirements.source and iface.uri == requirements.interface_uri:
                iface_arch = arch.SourceArchitecture(iface_arch)
            wanted_rating = self.get_rating(iface, impl, arch)
            selected_rating = self.get_rating(iface, actual_selection, arch)

            if wanted_rating < selected_rating:
                _ranking_component_reason = [
                    _("natural languages we understand are preferred"),
                    _("preferred versions come first"),
                    _("locally-available versions are preferred when network use is limited"
                      ),
                    _("packages that don't require admin access to install are preferred"
                      ),
                    _("more stable versions preferred"),
                    _("newer versions are preferred"),
                    _("native packages are preferred"),
                    _("newer versions are preferred"),
                    _("better OS match"),
                    _("better CPU match"),
                    _("better locale match"),
                    _("is locally available"),
                    _("better ID (tie-breaker)"),
                ]

                actual = actual_selection.get_version()
                if impl.get_version() == actual:

                    def detail(i):
                        if len(i.id) < 18:
                            return " (" + i.id + ")"
                        else:
                            return " (" + i.id[:16] + "...)"

                    wanted += detail(impl)
                    actual += detail(actual_selection)

                for i in range(len(wanted_rating)):
                    if wanted_rating[i] < selected_rating[i]:
                        return _(
                            "{wanted} is ranked lower than {actual}: {why}"
                        ).format(wanted=wanted,
                                 actual=actual,
                                 why=_ranking_component_reason[i])

        used_impl = iface.uri in s.selections.selections

        # Impl is selectable and ranked higher than the selected version. Selecting it would cause
        # a problem elsewhere.
        changes = []
        for old_iface, old_sel in self.selections.selections.items():
            if old_iface == iface.uri and used_impl: continue
            new_sel = s.selections.selections.get(old_iface, None)
            if new_sel is None:
                changes.append(
                    _("{interface}: no longer used").format(
                        interface=old_iface))
            elif old_sel.version != new_sel.version:
                changes.append(
                    _("{interface}: {old} to {new}").format(
                        interface=old_iface,
                        old=old_sel.version,
                        new=new_sel.version))
            elif old_sel.id != new_sel.id:
                changes.append(
                    _("{interface}: {old} to {new}").format(
                        interface=old_iface, old=old_sel.id, new=new_sel.id))

        if changes:
            changes_text = '\n\n' + _(
                'The changes would be:') + '\n\n' + '\n'.join(changes)
        else:
            changes_text = ''

        if used_impl:
            return _(
                "{wanted} is selectable, but using it would produce a less optimal solution overall."
            ).format(wanted=wanted) + changes_text
        else:
            return _(
                "If {wanted} were the only option, the best available solution wouldn't use it."
            ).format(wanted=wanted) + changes_text
Beispiel #24
0
def _normal_mode(options, args):
	from zeroinstall.injector import handler

	if len(args) < 1:
		if options.gui:
			from zeroinstall import helpers
			return helpers.get_selections_gui(None, [])
		else:
			raise UsageError()

	iface_uri = model.canonical_iface_uri(args[0])
	root_iface = iface_cache.get_interface(iface_uri)

	if os.isatty(1):
		h = handler.ConsoleHandler()
	else:
		h = handler.Handler()
	h.dry_run = bool(options.dry_run)

	policy = autopolicy.AutoPolicy(iface_uri,
				handler = h,
				download_only = bool(options.download_only),
				src = options.source)

	if options.before or options.not_before:
		policy.solver.extra_restrictions[root_iface] = [model.VersionRangeRestriction(model.parse_version(options.before),
									      		      model.parse_version(options.not_before))]

	if options.os or options.cpu:
		from zeroinstall.injector import arch
		policy.target_arch = arch.get_architecture(options.os, options.cpu)

	if options.offline:
		policy.network_use = model.network_offline

	if options.get_selections:
		if len(args) > 1:
			raise SafeException(_("Can't use arguments with --get-selections"))
		if options.main:
			raise SafeException(_("Can't use --main with --get-selections"))

	# Note that need_download() triggers a solve
	if options.refresh or options.gui:
		# We could run immediately, but the user asked us not to
		can_run_immediately = False
	else:
		can_run_immediately = (not policy.need_download()) and policy.ready

		stale_feeds = [feed for feed in policy.solver.feeds_used if policy.is_stale(iface_cache.get_feed(feed))]

		if options.download_only and stale_feeds:
			can_run_immediately = False

	if can_run_immediately:
		if stale_feeds:
			if policy.network_use == model.network_offline:
				logging.debug(_("No doing background update because we are in off-line mode."))
			else:
				# There are feeds we should update, but we can run without them.
				# Do the update in the background while the program is running.
				import background
				background.spawn_background_update(policy, options.verbose > 0)
		if options.get_selections:
			_get_selections(policy)
		else:
			if not options.download_only:
				from zeroinstall.injector import run
				run.execute(policy, args[1:], dry_run = options.dry_run, main = options.main, wrapper = options.wrapper)
			else:
				logging.info(_("Downloads done (download-only mode)"))
			assert options.dry_run or options.download_only
		return

	# If the user didn't say whether to use the GUI, choose for them.
	if options.gui is None and os.environ.get('DISPLAY', None):
		options.gui = True
		# If we need to download anything, we might as well
		# refresh all the interfaces first. Also, this triggers
		# the 'checking for updates' box, which is non-interactive
		# when there are no changes to the selection.
		options.refresh = True
		logging.info(_("Switching to GUI mode... (use --console to disable)"))

	prog_args = args[1:]

	try:
		from zeroinstall.injector import run
		if options.gui:
			gui_args = []
			if options.download_only:
				# Just changes the button's label
				gui_args.append('--download-only')
			if options.refresh:
				gui_args.append('--refresh')
			if options.systray:
				gui_args.append('--systray')
			if options.not_before:
				gui_args.insert(0, options.not_before)
				gui_args.insert(0, '--not-before')
			if options.before:
				gui_args.insert(0, options.before)
				gui_args.insert(0, '--before')
			if options.source:
				gui_args.insert(0, '--source')
			if options.message:
				gui_args.insert(0, options.message)
				gui_args.insert(0, '--message')
			if options.verbose:
				gui_args.insert(0, '--verbose')
				if options.verbose > 1:
					gui_args.insert(0, '--verbose')
			if options.cpu:
				gui_args.insert(0, options.cpu)
				gui_args.insert(0, '--cpu')
			if options.os:
				gui_args.insert(0, options.os)
				gui_args.insert(0, '--os')
			if options.with_store:
				for x in options.with_store:
					gui_args += ['--with-store', x]
			sels = _fork_gui(iface_uri, gui_args, prog_args, options)
			if not sels:
				sys.exit(1)		# Aborted
		else:
			#program_log('download_and_execute ' + iface_uri)
			downloaded = policy.solve_and_download_impls(refresh = bool(options.refresh))
			if downloaded:
				policy.handler.wait_for_blocker(downloaded)
			sels = selections.Selections(policy)

		if options.get_selections:
			doc = sels.toDOM()
			doc.writexml(sys.stdout)
			sys.stdout.write('\n')
		elif not options.download_only:
			run.execute_selections(sels, prog_args, options.dry_run, options.main, options.wrapper)

	except NeedDownload, ex:
		# This only happens for dry runs
		print ex
Beispiel #25
0
	def testOs(self):
		arch = get_architecture('MacOSX', 'ppc')
		assert ('Darwin' in arch.os_ranks)
Beispiel #26
0
	def testDefault(self):
		arch = get_architecture(None, None)
		assert arch
Beispiel #27
0
	def testDecideBug(self):
		s = solver.DefaultSolver(self.config)
		watch_xml = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'watchdog.xml')
		s.solve(watch_xml, arch.get_architecture(None, None), command_name = 'test')
Beispiel #28
0
	def testMachine(self):
		arch = get_architecture('Linux', 'i686')
		assert ('i386' in arch.machine_ranks)
Beispiel #29
0
 def testOs(self):
     arch = get_architecture('MacOSX', 'ppc')
     assert ('Darwin' in arch.os_ranks)
Beispiel #30
0
 def testDefault(self):
     arch = get_architecture(None, None)
     assert arch
Beispiel #31
0
	def testRecommendBug(self):
		s = solver.DefaultSolver(self.config)
		optional_missing_xml = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'OptionalMissing.xml')
		s.solve(optional_missing_xml, arch.get_architecture(None, None), command_name = None)
Beispiel #32
0
 def testMachine(self):
     arch = get_architecture('Linux', 'i686')
     assert ('i386' in arch.machine_ranks)
Beispiel #33
0
def run_gui(args):
	parser = OptionParser(usage=_("usage: %prog [options] interface"))
	parser.add_option("", "--before", help=_("choose a version before this"), metavar='VERSION')
	parser.add_option("", "--cpu", help=_("target CPU type"), metavar='CPU')
	parser.add_option("-c", "--cache", help=_("show the cache"), action='store_true')
	parser.add_option("-d", "--download-only", help=_("fetch but don't run"), action='store_true')
	parser.add_option("", "--message", help=_("message to display when interacting with user"))
	parser.add_option("", "--not-before", help=_("minimum version to choose"), metavar='VERSION')
	parser.add_option("", "--os", help=_("target operation system type"), metavar='OS')
	parser.add_option("-r", "--refresh", help=_("check for updates of all interfaces"), action='store_true')
	parser.add_option("-s", "--source", help=_("select source code"), action='store_true')
	parser.add_option("", "--systray", help=_("download in the background"), action='store_true')
	parser.add_option("-v", "--verbose", help=_("more verbose output"), action='count')
	parser.add_option("-V", "--version", help=_("display version information"), action='store_true')
	parser.add_option("", "--with-store", help=_("add an implementation cache"), action='append', metavar='DIR')

	parser.disable_interspersed_args()

	(options, args) = parser.parse_args(args)

	if options.verbose:
		import logging
		logger = logging.getLogger()
		if options.verbose == 1:
			logger.setLevel(logging.INFO)
		else:
			logger.setLevel(logging.DEBUG)

	if options.cache:
		# Must fork before importing gtk, or ATK dies
		if os.fork():
			# We exit, so our parent can call waitpid and unblock.
			sys.exit(0)
		# The grandchild continues...

	if options.with_store:
		from zeroinstall import zerostore
		for x in options.with_store:
			iface_cache.stores.stores.append(zerostore.Store(os.path.abspath(x)))

	import gui

	if options.version:
		print "0launch-gui (zero-install) " + gui.version
		print "Copyright (C) 2009 Thomas Leonard"
		print _("This program comes with ABSOLUTELY NO WARRANTY,"
				"\nto the extent permitted by law."
				"\nYou may redistribute copies of this program"
				"\nunder the terms of the GNU Lesser General Public License."
				"\nFor more information about these matters, see the file named COPYING.")
		sys.exit(0)

	import gtk
	if gtk.gdk.get_display() is None:
		print >>sys.stderr, "Failed to connect to display. Aborting."
		sys.exit(1)

	if not hasattr(gtk, 'combo_box_new_text'):
		import combo_compat

	if options.cache:
		import cache
		cache_explorer = cache.CacheExplorer()
		cache_explorer.show()
		cache_explorer.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
		gtk.gdk.flush()
		cache_explorer.populate_model()
		cache_explorer.window.set_cursor(None)
		gtk.main()
		sys.exit(0)

	handler = gui.GUIHandler()

	if len(args) < 1:
		import preferences
		# Once we separate configuration from Policy, this hack can go away
		class DummyPolicy(Policy):
			def recalculate(fetch_stale_interfaces = True):
				pass
			def solve_with_downloads(force = False):
				pass
		box = preferences.show_preferences(DummyPolicy('http://localhost/dummy', handler))
		box.connect('destroy', gtk.main_quit)
		gtk.main()
		sys.exit(0)

	interface_uri = args[0]

	if len(args) > 1:
		parser.print_help()
		sys.exit(1)

	import mainwindow, dialog

	restrictions = []
	if options.before or options.not_before:
		restrictions.append(model.VersionRangeRestriction(model.parse_version(options.before),
								  model.parse_version(options.not_before)))

	widgets = dialog.Template('main')

	policy = Policy(interface_uri, handler, src = bool(options.source))
	policy.target_arch = arch.get_architecture(options.os, options.cpu)
	root_iface = iface_cache.get_interface(interface_uri)
	policy.solver.extra_restrictions[root_iface] = restrictions
	policy.solver.record_details = True

	window = mainwindow.MainWindow(policy, widgets, download_only = bool(options.download_only))
	handler.mainwindow = window

	if options.message:
		window.set_message(options.message)

	root = iface_cache.get_interface(policy.root)
	window.browser.set_root(root)

	window.window.connect('destroy', lambda w: handler.abort_all_downloads())

	if options.systray:
		window.use_systray_icon()

	@tasks.async
	def main():
		force_refresh = bool(options.refresh)
		while True:
			window.refresh_button.set_sensitive(False)
			window.browser.set_update_icons(force_refresh)

			solved = policy.solve_with_downloads(force = force_refresh)

			if not window.systray_icon:
				window.show()
			yield solved
			try:
				window.refresh_button.set_sensitive(True)
				tasks.check(solved)
			except Exception, ex:
				window.report_exception(ex)

			if window.systray_icon and window.systray_icon.get_visible() and \
			   window.systray_icon.is_embedded():
				if policy.ready:
					window.systray_icon.set_tooltip(_('Downloading updates for %s') % root_iface.get_name())
					window.run_button.set_active(True)
				else:
					# Should already be reporting an error, but
					# blink it again just in case
					window.systray_icon.set_blinking(True)

			yield dialog.ButtonClickedBlocker(window.refresh_button)
			force_refresh = True
Beispiel #34
0
	def justify_decision(self, requirements, iface, impl):
		"""Run a solve with impl_id forced to be selected, and explain why it wasn't (or was)
		selected in the normal case.
		@type requirements: L{zeroinstall.injector.requirements.Requirements}
		@type iface: L{zeroinstall.injector.model.Interface}
		@type impl: L{zeroinstall.injector.model.Implementation}
		@rtype: str"""
		assert isinstance(iface, model.Interface), iface

		restrictions = self.extra_restrictions.copy()
		restrictions[iface] = restrictions.get(iface, []) + [_ForceImpl(impl)]
		s = SATSolver(self.config, restrictions)
		s.record_details = True
		s.solve_for(requirements)

		wanted = "{iface} {version}".format(iface = iface.get_name(), version = impl.get_version())

		# Could a selection involving impl even be valid?
		if not s.ready or iface.uri not in s.selections.selections:
			reasons = s.details.get(iface, [])
			for (rid, rstr) in reasons:
				if rid.id == impl.id and rstr is not None:
					return _("{wanted} cannot be used (regardless of other components): {reason}").format(
							wanted = wanted,
							reason = rstr)

			if not s.ready:
				return _("There is no possible selection using {wanted}.\n{reason}").format(
					wanted = wanted,
					reason = s.get_failure_reason())

		actual_selection = self.selections.get(iface, None)
		if actual_selection is not None:
			# Was impl actually selected anyway?
			if actual_selection.id == impl.id:
				return _("{wanted} was selected as the preferred version.").format(wanted = wanted)

			# Was impl ranked below the selected version?
			iface_arch = arch.get_architecture(requirements.os, requirements.cpu)
			if requirements.source and iface.uri == requirements.interface_uri:
				iface_arch = arch.SourceArchitecture(iface_arch)
			wanted_rating = self.get_rating(iface, impl, arch)
			selected_rating = self.get_rating(iface, actual_selection, arch)

			if wanted_rating < selected_rating:
				_ranking_component_reason = [
					_("natural languages we understand are preferred"),
					_("preferred versions come first"),
					_("locally-available versions are preferred when network use is limited"),
					_("packages that don't require admin access to install are preferred"),
					_("more stable versions preferred"),
					_("newer versions are preferred"),
					_("native packages are preferred"),
					_("newer versions are preferred"),
					_("better OS match"),
					_("better CPU match"),
					_("better locale match"),
					_("is locally available"),
					_("better ID (tie-breaker)"),
				]

				actual = actual_selection.get_version()
				if impl.get_version() == actual:
					def detail(i):
						if len(i.id) < 18:
							return " (" + i.id + ")"
						else:
							return " (" + i.id[:16] + "...)"

					wanted += detail(impl)
					actual += detail(actual_selection)

				for i in range(len(wanted_rating)):
					if wanted_rating[i] < selected_rating[i]:
						return _("{wanted} is ranked lower than {actual}: {why}").format(
								wanted = wanted,
								actual = actual,
								why = _ranking_component_reason[i])

		used_impl = iface.uri in s.selections.selections

		# Impl is selectable and ranked higher than the selected version. Selecting it would cause
		# a problem elsewhere.
		changes = []
		for old_iface, old_sel in self.selections.selections.items():
			if old_iface == iface.uri and used_impl: continue
			new_sel = s.selections.selections.get(old_iface, None)
			if new_sel is None:
				changes.append(_("{interface}: no longer used").format(interface = old_iface))
			elif old_sel.version != new_sel.version:
				changes.append(_("{interface}: {old} to {new}").format(interface = old_iface, old = old_sel.version, new = new_sel.version))
			elif old_sel.id != new_sel.id:
				changes.append(_("{interface}: {old} to {new}").format(interface = old_iface, old = old_sel.id, new = new_sel.id))

		if changes:
			changes_text = '\n\n' + _('The changes would be:') + '\n\n' + '\n'.join(changes)
		else:
			changes_text = ''

		if used_impl:
			return _("{wanted} is selectable, but using it would produce a less optimal solution overall.").format(wanted = wanted) + changes_text
		else:
			return _("If {wanted} were the only option, the best available solution wouldn't use it.").format(wanted = wanted) + changes_text
Beispiel #35
0
			def check(target_arch, langs, expected):
				s.langs = langs
				binary_arch = arch.get_architecture(None, target_arch)
				s.solve('http://foo/Langs.xml', binary_arch)
				assert s.ready
				self.assertEquals(expected, s.selections[iface].id)