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)
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)
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
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''')
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'))
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'))
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'))
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'))
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()
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()
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/
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))]
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))
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()
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))
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) self.maxDiff = 1000 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:\n" " sha1=999 (5): incompatible with restrictions\n" " sha1=345 (1.0): incompatible with restrictions\n" " sha1=678 (0.1): incompatible with 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''' )
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)
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"] apache_user = pwd.getpwnam(site_config_settings["apache_user"])
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'))
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)