Example #1
0
	def testNoNeedDl(self):
		driver = Driver(requirements = Requirements(foo_iface_uri), config = self.config)
		assert driver.need_download()

		driver = Driver(requirements = Requirements(os.path.abspath('Foo.xml')), config = self.config)
		assert not driver.need_download()
		assert driver.solver.ready
Example #2
0
def ensure_cached(uri, command = 'run', config = None):
	"""Ensure that an implementation of uri is cached.
	If not, it downloads one. It uses the GUI if a display is
	available, or the console otherwise.
	@param uri: the required interface
	@type uri: str
	@return: the selected implementations, or None if the user cancelled
	@rtype: L{zeroinstall.injector.selections.Selections}
	"""
	from zeroinstall.injector.driver import Driver

	if config is None:
		from zeroinstall.injector.config import load_config
		config = load_config()

	from zeroinstall.injector.requirements import Requirements
	requirements = Requirements(uri)
	requirements.command = command

	d = Driver(config, requirements)

	if d.need_download() or not d.solver.ready:
		sels = get_selections_gui(uri, ['--command', command], use_gui = None)
		if sels != DontUseGUI:
			return sels
		done = d.solve_and_download_impls()
		tasks.wait_for_blocker(done)

	return d.solver.selections
Example #3
0
    def testReplacedConflicts(self):
        self.import_feed('http://localhost:8000/Hello', 'Hello')
        s = solver.DefaultSolver(self.config)
        replaced_path = model.canonical_iface_uri(
            os.path.join(mydir, 'Replaced.xml'))
        replaced_conflicts_path = model.canonical_iface_uri(
            os.path.join(mydir, 'ReplacedConflicts.xml'))
        r = Requirements(replaced_conflicts_path)
        s.solve_for(r)
        assert s.ready, s.get_failure_reason()
        assert s.selections
        self.assertEqual("b",
                         s.selections.selections[replaced_conflicts_path].id)
        self.assertEqual(
            "2", s.selections.selections[replaced_conflicts_path].version)
        self.assertEqual(
            "sha1=3ce644dc725f1d21cfcf02562c76f375944b266a",
            s.selections.selections["http://localhost:8000/Hello"].id)
        self.assertEqual(2, len(s.selections.selections))

        r.extra_restrictions[r.interface_uri] = '..!2'
        s.extra_restrictions = r.get_extra_restrictions(
            self.config.iface_cache)

        s.solve_for(r)
        assert s.ready, s.get_failure_reason()
        assert s.selections
        self.assertEqual(
            "1", s.selections.selections[replaced_conflicts_path].version)
        self.assertEqual("0", s.selections.selections[replaced_path].version)
        self.assertEqual(2, len(s.selections.selections))
Example #4
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{config.Config}
		Note: all other arguments are deprecated (since 0launch 0.52)
		"""
        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
        else:
            assert root == src == None
            assert command == -1

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

        self.driver = driver.Driver(config=config, requirements=requirements)
Example #5
0
def ensure_cached(uri, command = 'run', config = None):
	"""Ensure that an implementation of uri is cached.
	If not, it downloads one. It uses the GUI if a display is
	available, or the console otherwise.
	@param uri: the required interface
	@type uri: str
	@return: the selected implementations, or None if the user cancelled
	@rtype: L{zeroinstall.injector.selections.Selections}
	"""
	from zeroinstall.injector.driver import Driver

	if config is None:
		from zeroinstall.injector.config import load_config
		config = load_config()

	from zeroinstall.injector.requirements import Requirements
	requirements = Requirements(uri)
	requirements.command = command

	d = Driver(config, requirements)

	if d.need_download() or not d.solver.ready:
		sels = get_selections_gui(uri, ['--command', command], use_gui = None)
		if sels != DontUseGUI:
			return sels
		done = d.solve_and_download_impls()
		tasks.wait_for_blocker(done)

	return d.solver.selections
Example #6
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{config.Config}
		Note: all other arguments are deprecated (since 0launch 0.52)
		"""
		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
		else:
			assert root == src == None
			assert command == -1

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

		self.driver = driver.Driver(config = config, requirements = requirements)
Example #7
0
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
	"""
	if options.offline:
		config.network_use = model.network_offline

	iface_cache = config.iface_cache

	# Try to load it as a feed. If it is a feed, it'll get cached. If not, it's a
	# selections document and we return immediately.
	maybe_selections = iface_cache.get_feed(iface_uri, selections_ok = True)
	if isinstance(maybe_selections, selections.Selections):
		if not select_only:
			blocker = maybe_selections.download_missing(config)
			if blocker:
				logger.info(_("Waiting for selected implementations to be downloaded..."))
				tasks.wait_for_blocker(blocker)
		return maybe_selections

	if requirements is None:
		requirements = Requirements(iface_uri)
		requirements.parse_options(options)

	return get_selections_for(requirements, config, options, select_only, download_only, test_callback)
Example #8
0
	def testDetails(self):
		iface_cache = self.config.iface_cache
		s = solver.DefaultSolver(self.config)

		foo_binary_uri = 'http://foo/Binary.xml'
		foo = iface_cache.get_interface(foo_binary_uri)
		self.import_feed(foo_binary_uri, 'Binary.xml')
		foo_src = iface_cache.get_interface('http://foo/Source.xml')
		self.import_feed(foo_src.uri, 'Source.xml')
		compiler = iface_cache.get_interface('http://foo/Compiler.xml')
		self.import_feed(compiler.uri, 'Compiler.xml')

		r = Requirements('http://foo/Binary.xml')
		r.source = True
		r.command = 'compile'

		s.record_details = True
		s.solve_for(r)
		assert s.ready, s.get_failure_reason()

		foo_bin_impls = iface_cache.get_feed(foo_binary_uri).implementations
		foo_src_impls = iface_cache.get_feed(foo_src.uri).implementations
		foo_impls = iface_cache.get_feed(foo.uri).implementations
		compiler_impls = iface_cache.get_feed(compiler.uri).implementations

		assert len(s.details) == 2
		self.assertEqual([
				(foo_src_impls['impossible'], None),
				(foo_src_impls['sha1=234'], None),
				(foo_impls['sha1=123'], 'Not source code'),
				(foo_src_impls['old'], None),
			], sorted(s.details[foo]))
		self.assertEqual([
				(compiler_impls['sha1=999'], None),
				(compiler_impls['sha1=345'], None),
				(compiler_impls['sha1=678'], None),
			], s.details[compiler])

		def justify(uri, impl, expected):
			iface = iface_cache.get_interface(uri)
			e = s.justify_decision(r, iface, impl)
			self.assertEqual(expected, e)

		justify(foo_binary_uri, foo_bin_impls["sha1=123"],
				'Binary 1.0 cannot be used (regardless of other components): Not source code')
		justify(foo_binary_uri, foo_src_impls["sha1=234"],
				'Binary 1.0 was selected as the preferred version.')
		justify(foo_binary_uri, foo_src_impls["old"],
				'Binary 0.1 is ranked lower than 1.0: newer versions are preferred')
		justify(foo_binary_uri, foo_src_impls["impossible"],
				"There is no possible selection using Binary 3.\n"
				"Can't find all required implementations:\n"
				"- http://foo/Binary.xml -> 3 (impossible)\n"
				"    User requested implementation 3 (impossible)\n"
				"- http://foo/Compiler.xml -> (problem)\n"
				"    http://foo/Binary.xml 3 requires version < 1.0, 1.0 <= version\n"
				"    No usable implementations satisfy the restrictions")
		justify(compiler.uri, compiler_impls["sha1=999"],
				'''Compiler 5 is selectable, but using it would produce a less optimal solution overall.\n\nThe changes would be:\n\nhttp://foo/Binary.xml: 1.0 to 0.1''')
Example #9
0
    def testLocalArchive(self):
        local_iface = os.path.join(mydir, 'LocalArchive.xml')
        with open(local_iface, 'rb') as stream:
            root = qdom.parse(stream)

        # Not local => error
        feed = model.ZeroInstallFeed(root)
        impl = feed.implementations['impl1']
        blocker = self.config.fetcher.download_impls([impl],
                                                     self.config.stores)
        try:
            tasks.wait_for_blocker(blocker)
            assert 0
        except model.SafeException as ex:
            assert "Relative URL 'HelloWorld.tgz' in non-local feed" in str(
                ex), ex

        feed = model.ZeroInstallFeed(root, local_path=local_iface)

        # Missing file
        impl2 = feed.implementations['impl2']
        blocker = self.config.fetcher.download_impls([impl2],
                                                     self.config.stores)
        try:
            tasks.wait_for_blocker(blocker)
            assert 0
        except model.SafeException as ex:
            assert 'tests/IDONTEXIST.tgz' in str(ex), ex

        # Wrong size
        impl3 = feed.implementations['impl3']
        blocker = self.config.fetcher.download_impls([impl3],
                                                     self.config.stores)
        try:
            tasks.wait_for_blocker(blocker)
            assert 0
        except model.SafeException as ex:
            assert 'feed says 177, but actually 176 bytes' in str(ex), ex

        self.config.network_use = model.network_offline
        r = Requirements(local_iface)
        r.command = None
        driver = Driver(requirements=r, config=self.config)
        driver.need_download()
        assert driver.solver.ready, driver.solver.get_failure_reason()

        # Local => OK
        impl = feed.implementations['impl1']

        path = self.config.stores.lookup_maybe(impl.digests)
        assert not path

        blocker = self.config.fetcher.download_impls([impl],
                                                     self.config.stores)
        tasks.wait_for_blocker(blocker)

        path = self.config.stores.lookup_any(impl.digests)
        assert os.path.exists(os.path.join(path, 'HelloWorld'))
Example #10
0
	def testExtractToNewSubdirectory(self):
		with output_suppressed():
			run_server(('HelloWorld.tar.bz2',))
			requirements = Requirements(os.path.abspath('HelloExtractToNewDest.xml'))
			requirements.command = None
			driver = Driver(requirements = requirements, config = self.config)
			driver_download(driver)
			digests = driver.solver.selections.selections[requirements.interface_uri].digests
			path = self.config.stores.lookup_any(digests)
			assert os.path.exists(os.path.join(path, 'src', 'HelloWorld', 'main'))
Example #11
0
	def testRecipeRemoveDir(self):
		with output_suppressed():
			run_server(('HelloWorld.tar.bz2',))
			requirements = Requirements(os.path.abspath('RecipeRemoveDir.xml'))
			requirements.command = None
			driver = Driver(requirements = requirements, config = self.config)
			driver_download(driver)
			digests = driver.solver.selections.selections[requirements.interface_uri].digests
			path = self.config.stores.lookup_any(digests)
			assert not os.path.exists(os.path.join(path, 'HelloWorld'))
Example #12
0
	def testDownloadFile(self):
		with output_suppressed():
			run_server(('HelloWorldMain',))
			requirements = Requirements(os.path.abspath('HelloSingleFile.xml'))
			requirements.command = None
			driver = Driver(requirements = requirements, config = self.config)
			driver_download(driver)
			digests = driver.solver.selections[requirements.interface_uri].digests
			path = self.config.stores.lookup_any(digests)
			assert os.path.exists(os.path.join(path, 'main'))
Example #13
0
	def testDownloadFile(self):
		with output_suppressed():
			run_server(('HelloWorldMain',))
			requirements = Requirements(os.path.abspath('HelloSingleFile.xml'))
			requirements.command = None
			driver = Driver(requirements = requirements, config = self.config)
			driver_download(driver)
			digests = driver.solver.selections.selections[requirements.interface_uri].digests
			path = self.config.stores.lookup_any(digests)
			with open(os.path.join(path, 'main'), 'rt') as stream:
				assert 'Hello World' in stream.read()
Example #14
0
	def testRecipeSingleFile(self):
		with output_suppressed():
			run_server(('HelloWorldMain',))
			requirements = Requirements(os.path.abspath('RecipeSingleFile.xml'))
			requirements.command = None
			driver = Driver(requirements = requirements, config = self.config)
			driver_download(driver)
			digests = driver.solver.selections.selections[requirements.interface_uri].digests
			path = self.config.stores.lookup_any(digests)
			with open(os.path.join(path, 'bin','main'), 'rt') as stream:
				assert 'Hello World' in stream.read()
Example #15
0
	def testRecipeExtractToExistingSubdirectory(self):
		with output_suppressed():
			run_server(('HelloWorld.tar.bz2','HelloWorld.tar.bz2'))
			requirements = Requirements(os.path.abspath('RecipeExtractToExistingDest.xml'))
			requirements.command = None
			driver = Driver(requirements = requirements, config = self.config)
			driver_download(driver)
			digests = driver.solver.selections.selections[requirements.interface_uri].digests
			path = self.config.stores.lookup_any(digests)
			assert os.path.exists(os.path.join(path, 'HelloWorld', 'main')) # first archive's main
			assert os.path.exists(os.path.join(path, 'HelloWorld', 'HelloWorld', 'main')) # second archive, extracted to HelloWorld/
Example #16
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))]
Example #17
0
    def testSource(self):
        iface_cache = self.config.iface_cache

        foo = iface_cache.get_interface('http://foo/Binary.xml')
        self.import_feed(foo.uri, 'Binary.xml')
        foo_src = iface_cache.get_interface('http://foo/Source.xml')
        self.import_feed(foo_src.uri, 'Source.xml')
        compiler = iface_cache.get_interface('http://foo/Compiler.xml')
        self.import_feed(compiler.uri, 'Compiler.xml')

        self.config.freshness = 0
        self.config.network_use = model.network_full
        driver = Driver(requirements=Requirements('http://foo/Binary.xml'),
                        config=self.config)
        tasks.wait_for_blocker(driver.solve_with_downloads())
        assert driver.solver.selections.selections[foo.uri].id == 'sha1=123'

        # Now ask for source instead
        driver.requirements.source = True
        driver.requirements.command = 'compile'
        tasks.wait_for_blocker(driver.solve_with_downloads())
        assert driver.solver.ready, driver.solver.get_failure_reason()
        assert driver.solver.selections.selections[
            foo.uri].id == 'sha1=234'  # The source
        assert driver.solver.selections.selections[
            compiler.uri].id == 'sha1=345'  # A binary needed to compile it
Example #18
0
    def testDistro(self):
        with output_suppressed():
            native_url = 'http://example.com:8000/Native.xml'

            # Initially, we don't have the feed at all...
            master_feed = self.config.iface_cache.get_feed(native_url)
            assert master_feed is None, master_feed

            trust.trust_db.trust_key(
                'DE937DD411906ACF7C263B396FCF121BE2390E0B', 'example.com:8000')
            run_server(
                'Native.xml', '6FCF121BE2390E0B.gpg',
                '/key-info/key/DE937DD411906ACF7C263B396FCF121BE2390E0B')
            driver = Driver(requirements=Requirements(native_url),
                            config=self.config)
            assert driver.need_download()

            solve = driver.solve_with_downloads()
            tasks.wait_for_blocker(solve)
            tasks.check(solve)

            master_feed = self.config.iface_cache.get_feed(native_url)
            assert master_feed is not None
            assert master_feed.implementations == {}

            distro_feed_url = master_feed.get_distro_feed()
            assert distro_feed_url is not None
            distro_feed = self.config.iface_cache.get_feed(distro_feed_url)
            assert distro_feed is not None
            assert len(
                distro_feed.implementations) == 2, distro_feed.implementations
Example #19
0
    def testAbsMain(self):
        with tempfile.NamedTemporaryFile(prefix='test-', delete=False) as tmp:
            tmp.write(("""<?xml version="1.0" ?>
<interface last-modified="1110752708"
 uri="%s"
 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
  <name>Foo</name>
  <summary>Foo</summary>
  <description>Foo</description>
  <group main='/bin/sh'>
   <implementation id='.' version='1'/>
  </group>
</interface>""" % foo_iface_uri).encode('utf-8'))

        driver = Driver(requirements=Requirements(tmp.name),
                        config=self.config)
        try:
            downloaded = driver.solve_and_download_impls()
            if downloaded:
                tasks.wait_for_blocker(downloaded)
            run.execute_selections(driver.solver.selections, [],
                                   stores=self.config.stores)
            assert False
        except SafeException as ex:
            assert 'Command path must be relative' in str(ex), ex
Example #20
0
    def testImplMirror(self):
        with resourcewarnings_suppressed():
            # This is like testMirror, except we have a different archive (that generates the same content),
            # rather than an exact copy of the unavailable archive.
            trust.trust_db.trust_key(
                'DE937DD411906ACF7C263B396FCF121BE2390E0B', 'example.com:8000')
            run_server(
                '/Hello.xml', '/6FCF121BE2390E0B.gpg',
                server.Give404('/HelloWorld.tgz'),
                server.Give404(
                    '/0mirror/archive/http%3A%2F%2Flocalhost%3A8000%2FHelloWorld.tgz'
                ),
                '/0mirror/feeds/http/example.com:8000/Hello.xml/impl/sha1=3ce644dc725f1d21cfcf02562c76f375944b266a'
            )
            driver = Driver(
                requirements=Requirements('http://example.com:8000/Hello.xml'),
                config=self.config)
            self.config.mirror = 'http://example.com:8000/0mirror'

            refreshed = driver.solve_with_downloads()
            tasks.wait_for_blocker(refreshed)
            assert driver.solver.ready

            getLogger().setLevel(logging.ERROR)
            downloaded = driver.download_uncached_implementations()
            tasks.wait_for_blocker(downloaded)
            path = self.config.stores.lookup_any(
                driver.solver.selections.
                selections['http://example.com:8000/Hello.xml'].digests)
            assert os.path.exists(os.path.join(path, 'HelloWorld', 'main'))
Example #21
0
    def testRestricts(self):
        iface_cache = self.config.iface_cache
        s = solver.DefaultSolver(self.config)
        uri = os.path.join(os.path.abspath(os.path.dirname(__file__)),
                           'Conflicts.xml')
        versions = os.path.join(os.path.abspath(os.path.dirname(__file__)),
                                'Versions.xml')
        iface = iface_cache.get_interface(uri)

        r = Requirements(uri)

        # Selects 0.2 as the highest version, applying the restriction to versions < 4.
        s.solve_for(r)
        assert s.ready
        self.assertEqual("0.2", s.selections.selections[uri].version)
        self.assertEqual("3", s.selections.selections[versions].version)

        s.extra_restrictions[iface] = [
            model.VersionRestriction(model.parse_version('0.1'))
        ]
        s.solve_for(r)
        assert s.ready
        self.assertEqual("0.1", s.selections.selections[uri].version)
        self.assertEqual(None, s.selections.selections.get(versions, None))

        s.extra_restrictions[iface] = [
            model.VersionRestriction(model.parse_version('0.3'))
        ]
        s.solve_for(r)
        assert not s.ready
Example #22
0
	def testImplMirrorFails(self):
		with resourcewarnings_suppressed():
			trust.trust_db.trust_key('DE937DD411906ACF7C263B396FCF121BE2390E0B', 'example.com:8000')
			run_server('/Hello.xml',
					'/6FCF121BE2390E0B.gpg',
					server.Give404('/HelloWorld.tgz'),
					server.Give404('/0mirror/archive/http%3A%23%23example.com%3A8000%23HelloWorld.tgz'),
					server.Give404('/0mirror/feeds/http/example.com:8000/Hello.xml/impl/sha1=3ce644dc725f1d21cfcf02562c76f375944b266a'))
			driver = Driver(requirements = Requirements('http://example.com:8000/Hello.xml'), config = self.config)
			self.config.mirror = 'http://example.com:8000/0mirror'

			refreshed = driver.solve_with_downloads()
			tasks.wait_for_blocker(refreshed)
			assert driver.solver.ready

			getLogger().setLevel(logging.ERROR)
			try:
				downloaded = driver.download_uncached_implementations()
				tasks.wait_for_blocker(downloaded)
				assert 0
			except download.DownloadError as ex:
				assert 'Missing: HelloWorld.tgz' in str(ex), ex

			self.assertEqual([
				'http://example.com:8000/Hello.xml',
				'http://example.com:8000/6FCF121BE2390E0B.gpg',
				# The original archive:
				'http://example.com:8000/HelloWorld.tgz',
				# Mirror of original archive:
				'http://example.com:8000/0mirror/archive/http%3A%23%23example.com%3A8000%23HelloWorld.tgz',
				# Mirror of implementation:
				'http://example.com:8000/0mirror/feeds/http/example.com:8000/Hello.xml/impl/sha1=3ce644dc725f1d21cfcf02562c76f375944b266a'
				], traced_downloads)
Example #23
0
	def testFeeds(self):
		self.cache_iface(foo_iface_uri,
"""<?xml version="1.0" ?>
<interface last-modified="0"
 uri="%s"
 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
  <name>Foo</name>
  <summary>Foo</summary>
  <description>Foo</description>
  <feed src='http://bar'/>
</interface>""" % foo_iface_uri)
		self.cache_iface('http://bar',
"""<?xml version="1.0" ?>
<interface last-modified="0"
 uri="http://bar"
 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
  <feed-for interface='%s'/>
  <name>Bar</name>
  <summary>Bar</summary>
  <description>Bar</description>
  <implementation version='1.0' id='sha1=123' main='dummy'>
    <archive href='foo' size='10'/>
  </implementation>
</interface>""" % foo_iface_uri)
		driver = Driver(requirements = Requirements(foo_iface_uri), config = self.config)
		self.config.network_use = model.network_full
		recalculate(driver)
		assert driver.solver.ready
		foo_iface = self.config.iface_cache.get_interface(foo_iface_uri)
		self.assertEqual('sha1=123', driver.solver.selections[foo_iface].id)
Example #24
0
    def testMirrors(self):
        with resourcewarnings_suppressed():
            getLogger().setLevel(logging.ERROR)
            trust.trust_db.trust_key(
                'DE937DD411906ACF7C263B396FCF121BE2390E0B', 'example.com:8000')
            run_server(
                server.Give404('/Hello.xml'),
                '/0mirror/feeds/http/example.com:8000/Hello.xml/latest.xml',
                '/0mirror/keys/6FCF121BE2390E0B.gpg',
                server.Give404('/HelloWorld.tgz'),
                '/0mirror/archive/http%3A%23%23example.com%3A8000%23HelloWorld.tgz'
            )
            driver = Driver(
                requirements=Requirements('http://example.com:8000/Hello.xml'),
                config=self.config)
            self.config.mirror = 'http://example.com:8000/0mirror'

            refreshed = driver.solve_with_downloads()
            tasks.wait_for_blocker(refreshed)
            assert driver.solver.ready

            #getLogger().setLevel(logging.WARN)
            downloaded = driver.download_uncached_implementations()
            tasks.wait_for_blocker(downloaded)
            path = self.config.stores.lookup_any(
                driver.solver.selections.
                selections['http://example.com:8000/Hello.xml'].digests)
            assert os.path.exists(os.path.join(path, 'HelloWorld', 'main'))
Example #25
0
    def testAbsMain(self):
        p = Driver(requirements=Requirements(command_feed), config=self.config)
        self.config.handler.wait_for_blocker(p.solve_with_downloads())

        old_stdout = sys.stdout
        try:
            sys.stdout = StringIO()
            run.execute_selections(p.solver.selections, [],
                                   main='/runnable/runner',
                                   dry_run=True,
                                   stores=self.config.stores)
        finally:
            sys.stdout = old_stdout

        try:
            old_stdout = sys.stdout
            try:
                sys.stdout = StringIO()
                run.execute_selections(p.solver.selections, [],
                                       main='/runnable/not-there',
                                       dry_run=True,
                                       stores=self.config.stores)
            finally:
                sys.stdout = old_stdout
        except SafeException as ex:
            assert 'not-there' in unicode(ex)
Example #26
0
        def test(top_xml, diag_xml, expected_error):
            root = qdom.parse(
                BytesIO("""<?xml version="1.0" ?>
			<interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface" uri="{top}">
			  <name>Top-level</name>
			  <summary>Top-level</summary>
			  <group>
			    {top_xml}
			  </group>
			</interface>""".format(top=top_uri, top_xml=top_xml).encode("utf-8")))
            self.import_feed(top_uri, root)

            root = qdom.parse(
                BytesIO("""<?xml version="1.0" ?>
			<interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface" uri="{diag}">
			  <name>Diagnostics</name>
			  <summary>Diagnostics</summary>
			  <group>
			    {impls}
			  </group>
			</interface>""".format(diag=diag_uri, impls=diag_xml).encode("utf-8")))
            self.import_feed(diag_uri, root)

            root = qdom.parse(
                BytesIO("""<?xml version="1.0" ?>
			<interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface" uri="{old}">
			  <name>Old</name>
			  <summary>Old</summary>
			  <feed src='{diag}'/>
			  <replaced-by interface='{diag}'/>
			</interface>""".format(diag=diag_uri, old=old_uri).encode("utf-8")))
            self.import_feed(old_uri, root)

            r = Requirements(top_uri)
            r.os = "Windows"
            r.cpu = "x86_64"
            s = solver.DefaultSolver(self.config)
            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
def solve(mountpoint, context):
    global _mountpoints, _client

    _mountpoints = [mountpoint]
    if mountpoint != '~':
        _mountpoints.append('~')
    if mountpoint != '/':
        _mountpoints.append('/')

    _client = IPCClient()
    try:
        requirement = Requirements(context)
        # TODO
        requirement.command = 'activity'
        return _solve(requirement)
    finally:
        _client.close()
Example #28
0
	def testBadMain(self):
		r = Requirements(command_feed)
		r.command = None
		d = Driver(requirements = r, config = self.config)
		self.config.handler.wait_for_blocker(d.solve_with_downloads())

		try:
			run.execute_selections(d.solver.selections, [], dry_run = True, stores = self.config.stores)
			assert 0
		except SafeException as ex:
			self.assertEqual("Can't run: no command specified!", unicode(ex))

		try:
			run.execute_selections(d.solver.selections, [], main = 'relpath', dry_run = True, stores = self.config.stores)
			assert 0
		except SafeException as ex:
			self.assertEqual("Can't use a relative replacement main when there is no original one!", unicode(ex))
Example #29
0
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.
	@type config: L{zeroinstall.injector.config.Config}
	@param options: options from OptionParser
	@param iface_uri: canonical URI of the interface
	@type iface_uri: str
	@param select_only: return immediately even if the selected versions aren't cached
	@type select_only: bool
	@param download_only: wait for stale feeds, and display GUI button as Download, not Run
	@type download_only: bool
	@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"""
    if options.offline:
        config.network_use = model.network_offline

    iface_cache = config.iface_cache

    # Try to load it as a feed. If it is a feed, it'll get cached. If not, it's a
    # selections document and we return immediately.
    maybe_selections = iface_cache.get_feed(iface_uri, selections_ok=True)
    if isinstance(maybe_selections, selections.Selections):
        if not select_only:
            blocker = maybe_selections.download_missing(config)
            if blocker:
                logger.info(
                    _("Waiting for selected implementations to be downloaded..."
                      ))
                tasks.wait_for_blocker(blocker)
        return maybe_selections

    if requirements is None:
        requirements = Requirements(iface_uri)
        requirements.parse_options(options)

    return get_selections_for(requirements, config, options, select_only,
                              download_only, test_callback)
Example #30
0
    def testConstraints(self):
        self.cache_iface(
            'http://bar', """<?xml version="1.0" ?>
<interface last-modified="1110752708"
 uri="http://bar"
 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
  <name>Bar</name>
  <summary>Bar</summary>
  <description>Bar</description>
  <implementation id='sha1=100' version='1.0'>
    <archive href='foo' size='10'/>
  </implementation>
  <implementation id='sha1=150' stability='developer' version='1.5'>
    <archive href='foo' size='10'/>
  </implementation>
  <implementation id='sha1=200' version='2.0'>
    <archive href='foo' size='10'/>
  </implementation>
</interface>""")
        self.cache_iface(
            foo_iface_uri, """<?xml version="1.0" ?>
<interface last-modified="1110752708"
 uri="%s"
 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
  <name>Foo</name>
  <summary>Foo</summary>
  <description>Foo</description>
  <group main='dummy'>
   <requires interface='http://bar'>
    <version/>
   </requires>
   <implementation id='sha1=123' version='1.0'>
    <archive href='foo' size='10'/>
   </implementation>
  </group>
</interface>""" % foo_iface_uri)
        driver = Driver(requirements=Requirements(foo_iface_uri),
                        config=self.config)
        self.config.network_use = model.network_full
        #logger.setLevel(logging.DEBUG)
        recalculate(driver)
        #logger.setLevel(logging.WARN)
        foo_iface = self.config.iface_cache.get_interface(foo_iface_uri)
        bar_iface = self.config.iface_cache.get_interface('http://bar')
        assert driver.solver.selections[bar_iface].id == 'sha1=200'

        dep = driver.solver.selections[foo_iface].dependencies['http://bar']
        assert len(dep.restrictions) == 1
        restriction = dep.restrictions[0]

        restriction.before = model.parse_version('2.0')
        recalculate(driver)
        assert driver.solver.selections[bar_iface].id == 'sha1=100'

        restriction.not_before = model.parse_version('1.5')
        recalculate(driver)
        assert driver.solver.selections[bar_iface].id == 'sha1=150'
		def test(top_xml, diag_xml, expected_error):
			root = qdom.parse(BytesIO("""<?xml version="1.0" ?>
			<interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface" uri="{top}">
			  <name>Top-level</name>
			  <summary>Top-level</summary>
			  <group>
			    {top_xml}
			  </group>
			</interface>""".format(top = top_uri, top_xml = top_xml).encode("utf-8")))
			self.import_feed(top_uri, root)

			root = qdom.parse(BytesIO("""<?xml version="1.0" ?>
			<interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface" uri="{diag}">
			  <name>Diagnostics</name>
			  <summary>Diagnostics</summary>
			  <group>
			    {impls}
			  </group>
			</interface>""".format(diag = diag_uri, impls = diag_xml).encode("utf-8")))
			self.import_feed(diag_uri, root)

			root = qdom.parse(BytesIO("""<?xml version="1.0" ?>
			<interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface" uri="{old}">
			  <name>Old</name>
			  <summary>Old</summary>
			  <feed src='{diag}'/>
			  <replaced-by interface='{diag}'/>
			</interface>""".format(diag = diag_uri, old = old_uri).encode("utf-8")))
			self.import_feed(old_uri, root)

			r = Requirements(top_uri)
			r.os = "Windows"
			r.cpu = "x86_64"
			s = solver.DefaultSolver(self.config)
			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
Example #32
0
    def testArchFor(self):
        s = solver.DefaultSolver(self.config)
        r = Requirements('http://foo/Binary.xml')

        r.cpu = 'i386'
        bin_arch = s.get_arch_for(r)
        self.assertEqual({'i386': 0, None: 1}, bin_arch.machine_ranks)

        r.source = True
        src_arch = s.get_arch_for(r)
        self.assertEqual({'src': 1}, src_arch.machine_ranks)

        child = self.config.iface_cache.get_interface('http://foo/Dep.xml')
        arch = s.get_arch_for(r, child)
        self.assertEqual(arch.machine_ranks, bin_arch.machine_ranks)

        child = self.config.iface_cache.get_interface(r.interface_uri)
        arch = s.get_arch_for(r, child)
        self.assertEqual(arch.machine_ranks, src_arch.machine_ranks)
Example #33
0
	def testArchFor(self):
		s = solver.DefaultSolver(self.config)
		r = Requirements('http://foo/Binary.xml')

		r.cpu = 'i386'
		bin_arch = s.get_arch_for(r)
		self.assertEqual({'i386': 0, None: 1}, bin_arch.machine_ranks)

		r.source = True
		src_arch = s.get_arch_for(r)
		self.assertEqual({'src': 1}, src_arch.machine_ranks)

		child = self.config.iface_cache.get_interface('http://foo/Dep.xml')
		arch = s.get_arch_for(r, child)
		self.assertEqual(arch.machine_ranks, bin_arch.machine_ranks)

		child = self.config.iface_cache.get_interface(r.interface_uri)
		arch = s.get_arch_for(r, child)
		self.assertEqual(arch.machine_ranks, src_arch.machine_ranks)
Example #34
0
	def testBadConfig(self):
		path = basedir.save_config_path(namespaces.config_site,
						namespaces.config_prog)
		glob = os.path.join(path, 'global')
		assert not os.path.exists(glob)
		stream = open(glob, 'w')
		stream.write('hello!')
		stream.close()

		logger.setLevel(logging.ERROR)
		Driver(requirements = Requirements(foo_iface_uri), config = self.config)
		logger.setLevel(logging.WARN)
Example #35
0
	def testAcceptKey(self):
		with output_suppressed():
			run_server('Hello', '6FCF121BE2390E0B.gpg', '/key-info/key/DE937DD411906ACF7C263B396FCF121BE2390E0B', 'HelloWorld.tgz')
			driver = Driver(requirements = Requirements('http://localhost:8000/Hello'), config = self.config)
			assert driver.need_download()
			sys.stdin = Reply("Y\n")
			try:
				download_and_execute(driver, ['Hello'], main = 'Missing')
				assert 0
			except model.SafeException as ex:
				if "HelloWorld/Missing" not in str(ex):
					raise
Example #36
0
 def testArgs(self):
     p = Driver(requirements=Requirements(runnable), config=self.config)
     self.config.handler.wait_for_blocker(p.solve_with_downloads())
     old_stdout = sys.stdout
     try:
         sys.stdout = StringIO()
         run.execute_selections(p.solver.selections, [],
                                dry_run=True,
                                stores=self.config.stores)
         out = sys.stdout.getvalue()
     finally:
         sys.stdout = old_stdout
     assert 'runner-arg' in out, out
Example #37
0
	def testReplacedConflicts(self):
		self.import_feed('http://localhost:8000/Hello', 'Hello')
		s = solver.DefaultSolver(self.config)
		replaced_path = model.canonical_iface_uri(os.path.join(mydir, 'Replaced.xml'))
		replaced_conflicts_path = model.canonical_iface_uri(os.path.join(mydir, 'ReplacedConflicts.xml'))
		r = Requirements(replaced_conflicts_path)
		s.solve_for(r)
		assert s.ready, s.get_failure_reason()
		assert s.selections
		self.assertEqual("b", s.selections.selections[replaced_conflicts_path].id)
		self.assertEqual("2", s.selections.selections[replaced_conflicts_path].version)
		self.assertEqual("sha1=3ce644dc725f1d21cfcf02562c76f375944b266a", s.selections.selections["http://localhost:8000/Hello"].id)
		self.assertEqual(2, len(s.selections.selections))

		r.extra_restrictions[r.interface_uri] = '..!2'
		s.extra_restrictions = r.get_extra_restrictions(self.config.iface_cache)

		s.solve_for(r)
		assert s.ready, s.get_failure_reason()
		assert s.selections
		self.assertEqual("1", s.selections.selections[replaced_conflicts_path].version)
		self.assertEqual("0", s.selections.selections[replaced_path].version)
		self.assertEqual(2, len(s.selections.selections))
Example #38
0
 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
Example #39
0
	def testNoArchives(self):
		self.cache_iface(foo_iface_uri,
"""<?xml version="1.0" ?>
<interface last-modified="1110752708"
 uri="%s"
 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
  <name>Foo</name>
  <summary>Foo</summary>
  <description>Foo</description>
  <implementation id='sha1=123' version='1.0' main='dummy'/>
</interface>""" % foo_iface_uri)
		driver = Driver(requirements = Requirements(foo_iface_uri), config = self.config)
		recalculate(driver)
		assert not driver.solver.ready
Example #40
0
	def testAutopackage(self):
		old_out = sys.stdout
		try:
			sys.stdout = StringIO()
			run_server('HelloWorld.autopackage')
			driver = Driver(requirements = Requirements(os.path.abspath('Autopackage.xml')), config = self.config)
			try:
				download_and_execute(driver, [])
				assert False
			except model.SafeException as ex:
				if "HelloWorld/Missing" not in str(ex):
					raise
		finally:
			sys.stdout = old_out
Example #41
0
	def testRecipeFailure(self):
		with resourcewarnings_suppressed():
			old_out = sys.stdout
			try:
				run_server('*')
				driver = Driver(requirements = Requirements(os.path.abspath('Recipe.xml')), config = self.config)
				try:
					download_and_execute(driver, [])
					assert False
				except download.DownloadError as ex:
					if "Connection" not in str(ex):
						raise
			finally:
				sys.stdout = old_out
	def testSelections(self):
		requirements = Requirements('http://foo/Source.xml')
		requirements.source = True
		requirements.command = 'compile'
		driver = Driver(requirements = requirements, config = self.config)
		source = self.config.iface_cache.get_interface('http://foo/Source.xml')
		compiler = self.config.iface_cache.get_interface('http://foo/Compiler.xml')
		self.import_feed(source.uri, 'Source.xml')
		self.import_feed(compiler.uri, 'Compiler.xml')

		self.config.network_use = model.network_full
		#import logging
		#logging.getLogger().setLevel(logging.DEBUG)
		assert driver.need_download()

		def assertSel(s):
			self.assertEqual('http://foo/Source.xml', s.interface)
			self.assertEqual(2, len(s.selections))

			sels = [(sel.interface, sel) for sel in s.selections.values()]
			sels.sort()
			sels = [sel for uri,sel in sels]
			
			self.assertEqual('http://foo/Compiler.xml', sels[0].interface)
			self.assertEqual('http://foo/Source.xml', sels[1].interface)

			self.assertEqual("sha1=345", sels[0].id)
			self.assertEqual("1.0", sels[0].version)

			self.assertEqual('sha1=234', sels[1].id)
			self.assertEqual("1.0", sels[1].version)
			self.assertEqual("bar", sels[1].attrs['http://namespace foo'])
			self.assertEqual("1.0", sels[1].attrs['version'])
			assert 'version-modifier' not in sels[1].attrs

			self.assertEqual(0, len(sels[0].bindings))
			self.assertEqual(0, len(sels[0].dependencies))

			self.assertEqual(3, len(sels[1].bindings))
			self.assertEqual('.', sels[1].bindings[0].insert)
			self.assertEqual('/', sels[1].bindings[1].mount_point)
			self.assertEqual('source', sels[1].bindings[2].qdom.attrs['foo'])

			self.assertEqual(1, len(sels[1].dependencies))
			dep = sels[1].dependencies[0]
			self.assertEqual('http://foo/Compiler.xml', dep.interface)
			self.assertEqual(4, len(dep.bindings))
			self.assertEqual('bin', dep.bindings[0].insert)
			self.assertEqual('PATH', dep.bindings[0].name)
			self.assertEqual('prepend', dep.bindings[0].mode)
			assert dep.bindings[0].separator in ';:'

			self.assertEqual('bin', dep.bindings[1].value)
			self.assertEqual('NO_PATH', dep.bindings[1].name)
			self.assertEqual(',', dep.bindings[1].separator)

			self.assertEqual('bin', dep.bindings[2].insert)
			self.assertEqual('BINDIR', dep.bindings[2].name)
			self.assertEqual('replace', dep.bindings[2].mode)

			foo_binding = dep.bindings[3]
			self.assertEqual('compiler', foo_binding.qdom.attrs['foo'])
			self.assertEqual('child', foo_binding.qdom.childNodes[0].name)
			self.assertEqual('run', foo_binding.command)

			self.assertEqual(["sha1=345", 'sha256new_345'], sorted(sels[0].digests))

		assert driver.solver.ready, driver.solver.get_failure_reason()
		s1 = driver.solver.selections
		s1.selections['http://foo/Source.xml'].attrs['http://namespace foo'] = 'bar'
		assertSel(s1)

		xml = s1.toDOM().toxml("utf-8")
		root = qdom.parse(BytesIO(xml))
		self.assertEqual(namespaces.XMLNS_IFACE, root.uri)

		s2 = selections.Selections(root)
		assertSel(s2)
Example #43
0
	def testLocalArchive(self):
		local_iface = os.path.join(mydir, 'LocalArchive.xml')
		with open(local_iface, 'rb') as stream:
			root = qdom.parse(stream)

		# Not local => error
		feed = model.ZeroInstallFeed(root)
		impl = feed.implementations['impl1']
		blocker = self.config.fetcher.download_impls([impl], self.config.stores)
		try:
			tasks.wait_for_blocker(blocker)
			assert 0
		except model.SafeException as ex:
			assert "Relative URL 'HelloWorld.tgz' in non-local feed" in str(ex), ex

		feed = model.ZeroInstallFeed(root, local_path = local_iface)

		# Missing file
		impl2 = feed.implementations['impl2']
		blocker = self.config.fetcher.download_impls([impl2], self.config.stores)
		try:
			tasks.wait_for_blocker(blocker)
			assert 0
		except model.SafeException as ex:
			assert 'tests/IDONTEXIST.tgz' in str(ex), ex

		# Wrong size
		impl3 = feed.implementations['impl3']
		blocker = self.config.fetcher.download_impls([impl3], self.config.stores)
		try:
			tasks.wait_for_blocker(blocker)
			assert 0
		except model.SafeException as ex:
			assert 'feed says 177, but actually 176 bytes' in str(ex), ex

		self.config.network_use = model.network_offline
		r = Requirements(local_iface)
		r.command = None
		driver = Driver(requirements = r, config = self.config)
		driver.need_download()
		assert driver.solver.ready, driver.solver.get_failure_reason()

		# Local => OK
		impl = feed.implementations['impl1']

		path = self.config.stores.lookup_maybe(impl.digests)
		assert not path

		blocker = self.config.fetcher.download_impls([impl], self.config.stores)
		tasks.wait_for_blocker(blocker)

		path = self.config.stores.lookup_any(impl.digests)
		assert os.path.exists(os.path.join(path, 'HelloWorld'))

		# Local <file> => OK
		impl = feed.implementations['impl4']

		path = self.config.stores.lookup_maybe(impl.digests)
		assert not path

		blocker = self.config.fetcher.download_impls([impl], self.config.stores)
		tasks.wait_for_blocker(blocker)

		path = self.config.stores.lookup_any(impl.digests)
		assert os.path.exists(os.path.join(path, 'archive.tgz'))
refresh = True

mydir = os.path.dirname(os.path.abspath(__file__))
site_config = os.path.join(mydir, 'site-config.xml')
if not os.path.exists(site_config):
	print "Copy site-config.xml.template as site-config.xml and edit..."
	sys.exit(1)

drupal = "http://repo.roscidus.com/drupal/core"

config = load_config()

import local_config
local_config.apply_local_config(config)

requirements = Requirements(site_config)
requirements.command = None
driver = Driver(config, requirements)
tasks.wait_for_blocker(driver.solve_and_download_impls(refresh = refresh))
selections = driver.solver.selections.selections

drupal_impl = selections[drupal]
drupal_root = drupal_impl.local_path or config.stores.lookup_any(drupal_impl.digests)

config_impl = selections[site_config]

site_config_settings = {}
for binding in config_impl.bindings:
	site_config_settings[binding.name] = binding.value

doc_root = site_config_settings["doc_root"]
Example #45
0
	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()
Example #46
0
	def testDiagnostics(self):
		top_uri = 'http://localhost/top.xml'
		old_uri = 'http://localhost/diagnostics-old.xml'
		diag_uri = 'http://localhost/diagnostics.xml'

		def test(top_xml, diag_xml, expected_error):
			root = qdom.parse(BytesIO("""<?xml version="1.0" ?>
			<interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface" uri="{top}">
			  <name>Top-level</name>
			  <summary>Top-level</summary>
			  <group>
			    {top_xml}
			  </group>
			</interface>""".format(top = top_uri, top_xml = top_xml).encode("utf-8")))
			self.import_feed(top_uri, root)

			root = qdom.parse(BytesIO("""<?xml version="1.0" ?>
			<interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface" uri="{diag}">
			  <name>Diagnostics</name>
			  <summary>Diagnostics</summary>
			  <group>
			    {impls}
			  </group>
			</interface>""".format(diag = diag_uri, impls = diag_xml).encode("utf-8")))
			self.import_feed(diag_uri, root)

			root = qdom.parse(BytesIO("""<?xml version="1.0" ?>
			<interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface" uri="{old}">
			  <name>Old</name>
			  <summary>Old</summary>
			  <feed src='{diag}'/>
			  <replaced-by interface='{diag}'/>
			</interface>""".format(diag = diag_uri, old = old_uri).encode("utf-8")))
			self.import_feed(old_uri, root)

			r = Requirements(top_uri)
			r.os = "Windows"
			r.cpu = "x86_64"
			s = solver.DefaultSolver(self.config)
			s.solve_for(r)
			assert not s.ready, s.selections.selections

			self.assertEqual(expected_error, str(s.get_failure_reason()))

			return s

		s = test("", "",
			"Can't find all required implementations:\n" +
			"- http://localhost/top.xml -> (problem)\n" +
			"    No known implementations at all")

		s = test("<implementation version='1' id='1'><requires interface='{diag}'/></implementation>".format(diag = diag_uri),
			 "",
			 "Can't find all required implementations:\n" +
			 "- http://localhost/top.xml -> (problem)\n" +
			 "    No usable implementations:\n" +
			 "      1: No retrieval methods")

		s = test("""<implementation version='1' id='1'>
				<archive href='http://localhost:3000/foo.tgz' size='100'/>
				<requires interface='{diag}'>
				  <version not-before='100'/>
				</requires>
			     </implementation>""".format(diag = diag_uri),
			 "",
			 "Can't find all required implementations:\n" +
			 "- http://localhost/top.xml -> (problem)\n" +
			 "    Rejected candidates:\n" +
			 "      1: No run command")

		s = test("""<implementation version='1' id='1' main='foo'>
				<archive href='http://localhost:3000/foo.tgz' size='100'/>
				<requires interface='{diag}' version='100..!200'/>
			     </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 version 100..!200\n"
			 "    No usable implementations satisfy the restrictions\n"
			 "- http://localhost/top.xml -> 1 (1)")

		logger.setLevel(logging.ERROR)
		s = test("""<implementation version='1' id='1' main='foo'>
				<archive href='http://localhost:3000/foo.tgz' size='100'/>
				<requires interface='{diag}' version='100..200'/>
			     </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 <impossible: Can't parse version restriction '100..200': End of range must be exclusive (use '..!200', not '..200')>\n"
			 "    No usable implementations satisfy the restrictions\n"
			 "- http://localhost/top.xml -> 1 (1)")
		logger.setLevel(logging.WARNING)

		s = test("""<implementation version='1' id='1' main='foo'>
				<archive href='http://localhost:3000/foo.tgz' size='100'/>
				<requires interface='{diag}'>
				  <version not-before='100'/>
				</requires>
			     </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 100 <= version\n"
			 "    No usable implementations satisfy the restrictions\n"
			 "- http://localhost/top.xml -> 1 (1)")

		s = test("""<group>
			      <requires interface='{diag}'/>
			      <implementation version='1' id='1' main='foo' arch='Windows-i486'>
				<archive href='http://localhost:3000/foo.tgz' size='100'/>
			     </implementation>
			   </group>""".format(diag = diag_uri),
			 """<group>
			      <implementation version='5' id='diag-5' arch='Windows-x86_64'>
				<archive href='http://localhost:3000/diag.tgz' size='100'/>
			     </implementation>
			   </group>
			 """,
			 "Can't find all required implementations:\n"
			 "- http://localhost/diagnostics.xml -> (problem)\n"
			 "    Rejected candidates:\n"
			 "      diag-5: Can't use x86_64 with selection of Top-level (i486)\n"
			 "- http://localhost/top.xml -> 1 (1)")

		s = test("""<group>
			      <requires interface='{diag}'/>
			      <implementation version='1' id='1' main='foo'>
				<archive href='http://localhost:3000/foo.tgz' size='100'/>
			     </implementation>
			   </group>""".format(diag = diag_uri),
			 """<group>
			      <implementation version='1' id='diag-1'/>
			      <implementation version='2' id='diag-2'/>
			      <implementation version='3' id='diag-3'/>
			      <implementation version='4' id='diag-4'/>
			      <implementation version='5' id='diag-5'/>
			      <implementation version='6' id='diag-6'/>
			   </group>
			 """,
			 "Can't find all required implementations:\n"
			 "- http://localhost/diagnostics.xml -> (problem)\n"
			 "    No usable implementations:\n"
			 "      diag-6: No retrieval methods\n"
			 "      diag-5: No retrieval methods\n"
			 "      diag-4: No retrieval methods\n"
			 "      diag-3: No retrieval methods\n"
			 "      diag-2: No retrieval methods\n"
			 "      ...\n"
			 "- http://localhost/top.xml -> 1 (1)")

		s = test("""<group>
			      <requires interface='{diag}'>
			        <version before='6'/>
			      </requires>
			      <implementation version='1' id='1' main='foo' arch='Windows-i486'>
				<archive href='http://localhost:3000/foo.tgz' size='100'/>
			     </implementation>
			   </group>""".format(diag = diag_uri),
			 """<group>
			      <implementation version='5' id='diag-5' arch='Windows-x86_64'>
				<archive href='http://localhost:3000/diag.tgz' size='100'/>
			     </implementation>
			     <implementation version='6' id='diag-6' arch='Windows-i486'>
				<archive href='http://localhost:3000/diag.tgz' size='100'/>
			     </implementation>
			     {others}
			   </group>
			 """.format(others = "\n".join(
			  """<implementation version='{i}' id='diag-{i}' arch='Windows-x86_64'>
				<archive href='http://localhost:3000/diag.tgz' size='100'/>
			     </implementation>""".format(i = i) for i in range(0, 5))),
			 "Can't find all required implementations:\n"
			 "- http://localhost/diagnostics.xml -> (problem)\n"
			 "    http://localhost/top.xml 1 requires version < 6\n"
			 "    Rejected candidates:\n"
			 "      diag-5: Can't use x86_64 with selection of Top-level (i486)\n"
			 "      diag-4: Can't use x86_64 with selection of Top-level (i486)\n"
			 "      diag-3: Can't use x86_64 with selection of Top-level (i486)\n"
			 "      diag-2: Can't use x86_64 with selection of Top-level (i486)\n"
			 "      diag-1: Can't use x86_64 with selection of Top-level (i486)\n"
			 "      ...\n"
			 "- http://localhost/top.xml -> 1 (1)")

		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)
		r.os = 'Windows'
		self.assertEqual("There is no possible selection using Diagnostics 5.\n"
				 "Can't find all required implementations:\n"
				 "- http://localhost/diagnostics.xml -> (problem)\n"
				 "    http://localhost/top.xml 1 requires version < 6\n"
				 "    User requested implementation 5 (diag-5)\n"
				 "    Rejected candidates:\n"
				 "      diag-5: Can't use x86_64 with selection of Top-level (i486)\n"
				 "- http://localhost/top.xml -> 1 (1)",
				s.justify_decision(r, iface, impl))

		# Can't select old and diag because they conflict
		test("""<group>
			  <requires interface='{diag}'/>
			  <requires interface='{old}'/>
			  <implementation version='1' id='1' main='foo'>
			    <archive href='http://localhost:3000/foo.tgz' size='100'/>
			  </implementation>
		        </group>""".format(diag = diag_uri, old = old_uri),
		    """<group>
			 <implementation version='5' id='diag-5'>
			   <archive href='http://localhost:3000/diag.tgz' size='100'/>
			 </implementation>
		       </group>
		    """,
		    "Can't find all required implementations:\n"
		    "- http://localhost/diagnostics-old.xml -> (problem)\n"
		    "    Replaced by (and therefore conflicts with) http://localhost/diagnostics.xml\n"
		    "    No usable implementations satisfy the restrictions\n"
		    "- http://localhost/diagnostics.xml -> 5 (diag-5)\n"
		    "    Replaces (and therefore conflicts with) http://localhost/diagnostics-old.xml\n"
		    "- http://localhost/top.xml -> 1 (1)")