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
def testDLfeed(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> <feed src='http://example.com'/> </interface>""" % foo_iface_uri, ) driver = Driver(requirements=Requirements(foo_iface_uri), config=self.config) self.config.network_use = model.network_full assert driver.need_download() feed = self.config.iface_cache.get_feed(foo_iface_uri) feed.feeds = [model.Feed("/BadFeed", None, False)] logger.setLevel(logging.ERROR) assert driver.need_download() # Triggers warning logger.setLevel(logging.WARN)
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'))
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'))
def testLocalPath(self): # 0launch --get-selections Local.xml iface = os.path.join(mydir, "Local.xml") driver = Driver(requirements = Requirements(iface), config = self.config) driver.need_download() assert driver.solver.ready s1 = driver.solver.selections xml = s1.toDOM().toxml("utf-8") # Reload selections and check they're the same root = qdom.parse(BytesIO(xml)) s2 = selections.Selections(root) local_path = s2.selections[iface].local_path assert os.path.isdir(local_path), local_path assert not s2.selections[iface].digests, s2.selections[iface].digests # Add a newer implementation and try again feed = self.config.iface_cache.get_feed(iface) impl = model.ZeroInstallImplementation(feed, "foo bar=123", local_path = None) impl.version = model.parse_version('1.0') impl.commands["run"] = model.Command(qdom.Element(namespaces.XMLNS_IFACE, 'command', {'path': 'dummy', 'name': 'run'}), None) impl.add_download_source('http://localhost/bar.tgz', 1000, None) feed.implementations = {impl.id: impl} assert driver.need_download() assert driver.solver.ready, driver.solver.get_failure_reason() s1 = driver.solver.selections xml = s1.toDOM().toxml("utf-8") root = qdom.parse(BytesIO(xml)) s2 = selections.Selections(root) xml = s2.toDOM().toxml("utf-8") qdom.parse(BytesIO(xml)) assert s2.selections[iface].local_path is None assert not s2.selections[iface].digests, s2.selections[iface].digests assert s2.selections[iface].id == 'foo bar=123'
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
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)
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 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
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
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
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)
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 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
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
def testArgList(self): d = Driver(requirements = Requirements(arglist), config = self.config) self.config.handler.wait_for_blocker(d.solve_with_downloads()) old_stdout = sys.stdout try: sys.stdout = StringIO() run.execute_selections(d.solver.selections, [], dry_run = True, stores = self.config.stores) out = sys.stdout.getvalue() finally: sys.stdout = old_stdout assert 'arg-for-runner -X ra1 -X ra2' in out, out assert 'command-arg ca1 ca2' in out, out
def 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
def testArgList(self): d = Driver(requirements=Requirements(arglist), config=self.config) self.config.handler.wait_for_blocker(d.solve_with_downloads()) old_stdout = sys.stdout try: sys.stdout = StringIO() run.execute_selections(d.solver.selections, [], dry_run=True, stores=self.config.stores) out = sys.stdout.getvalue() finally: sys.stdout = old_stdout assert 'arg-for-runner -X ra1 -X ra2' in out, out assert 'command-arg ca1 ca2' in out, out
def testCommandBindings(self): if 'SELF_COMMAND' in os.environ: del os.environ['SELF_COMMAND'] p = Driver(requirements = Requirements(command_feed), config = self.config) tasks.wait_for_blocker(p.solve_with_downloads()) old_stdout = sys.stdout try: sys.stdout = StringIO() run.execute_selections(p.solver.selections, [], main = 'runnable/go.sh', dry_run = True, stores = self.config.stores) finally: sys.stdout = old_stdout assert 'local' in os.environ['LOCAL'], os.environ['LOCAL'] assert 'SELF_COMMAND' in os.environ
def testDryRun(self): with output_suppressed(): run_server('Hello', '6FCF121BE2390E0B.gpg', '/key-info/key/DE937DD411906ACF7C263B396FCF121BE2390E0B', 'HelloWorld.tgz') self.config.handler.dry_run = True driver = Driver(requirements = Requirements('http://localhost:8000/Hello'), config = self.config) assert driver.need_download() sys.stdin = Reply("Y\n") sys.stdout = StringIO() download_and_execute(driver, ['Hello'], main = 'Missing', dry_run = True) out = sys.stdout.getvalue() assert '[dry-run] would trust key DE937DD411906ACF7C263B396FCF121BE2390E0B for localhost:8000' in out, out assert '[dry-run] would cache feed http://localhost:8000/Hello as ' in out, out assert '[dry-run] would store implementation as ' in out, out assert '[dry-run] would execute:' in out, out
def testMirrors(self): old_out = sys.stdout try: sys.stdout = StringIO() getLogger().setLevel(ERROR) trust.trust_db.trust_key('DE937DD411906ACF7C263B396FCF121BE2390E0B', 'example.com:8000') run_server(server.Give404('/Hello.xml'), 'latest.xml', '/0mirror/keys/6FCF121BE2390E0B.gpg') driver = Driver(requirements = Requirements('http://example.com:8000/Hello.xml'), config = self.config) self.config.feed_mirror = 'http://example.com:8000/0mirror' refreshed = driver.solve_with_downloads() tasks.wait_for_blocker(refreshed) assert driver.solver.ready finally: sys.stdout = old_out
def testRejectKeyXML(self): with output_suppressed(): run_server('Hello.xml', '6FCF121BE2390E0B.gpg', '/key-info/key/DE937DD411906ACF7C263B396FCF121BE2390E0B') driver = Driver(requirements = Requirements('http://example.com:8000/Hello.xml'), config = self.config) assert driver.need_download() sys.stdin = Reply("N\n") try: download_and_execute(driver, ['Hello']) assert 0 except model.SafeException as ex: if "has no usable implementations" not in str(ex): raise ex if "Not signed with a trusted key" not in str(self.config.handler.ex): raise self.config.handler.ex = None
def testRejectKeyXML(self): with output_suppressed(): run_server('Hello.xml', '6FCF121BE2390E0B.gpg', '/key-info/key/DE937DD411906ACF7C263B396FCF121BE2390E0B') driver = Driver(requirements = Requirements('http://example.com:8000/Hello.xml'), config = self.config) assert driver.need_download() sys.stdin = Reply("N\n") try: download_and_execute(driver, ['Hello']) assert 0 except model.SafeException as ex: if "No known implementations at all" not in str(ex): raise ex if "Not signed with a trusted key" not in str(self.config.handler.ex): raise self.config.handler.ex = None
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)
def testCommandBindings(self): if 'SELF_COMMAND' in os.environ: del os.environ['SELF_COMMAND'] p = Driver(requirements=Requirements(command_feed), config=self.config) tasks.wait_for_blocker(p.solve_with_downloads()) old_stdout = sys.stdout try: sys.stdout = StringIO() run.execute_selections(p.solver.selections, [], main='runnable/go.sh', dry_run=True, stores=self.config.stores) finally: sys.stdout = old_stdout assert 'local' in os.environ['LOCAL'], os.environ['LOCAL'] assert 'SELF_COMMAND' in os.environ
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 testLocalFeedMirror(self): with resourcewarnings_suppressed(): # This is like testImplMirror, except we have a local feed. run_server(server.Give404('/HelloWorld.tgz'), '/0mirror/archive/http%3A%23%23example.com%3A8000%23HelloWorld.tgz') iface_uri = model.canonical_iface_uri('Hello.xml') driver = Driver(requirements = Requirements(iface_uri), 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[iface_uri].digests) assert os.path.exists(os.path.join(path, 'HelloWorld', 'main'))
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 testNeedDL(self): self.cache_iface(foo_iface_uri, """<?xml version="1.0" ?> <interface last-modified="0" uri="%s" main='ThisBetterNotExist' xmlns="http://zero-install.sourceforge.net/2004/injector/interface"> <name>Foo</name> <summary>Foo</summary> <description>Foo</description> <implementation version='1.0' id='sha1=123'> <archive href='http://foo/foo.tgz' size='100'/> </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.need_download() assert driver.solver.ready
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 _check_for_updates(requirements, verbose): from zeroinstall.injector.driver import Driver from zeroinstall.injector.config import load_config background_handler = BackgroundHandler(requirements.interface_uri, requirements.interface_uri) background_config = load_config(background_handler) root_iface = background_config.iface_cache.get_interface(requirements.interface_uri).get_name() background_handler.title = root_iface driver = Driver(config = background_config, requirements = requirements) info(_("Checking for updates to '%s' in a background process"), root_iface) if verbose: background_handler.notify("Zero Install", _("Checking for updates to '%s'...") % root_iface, timeout = 1) network_state = background_handler.get_network_state() if network_state not in (_NetworkState.NM_STATE_CONNECTED_SITE, _NetworkState.NM_STATE_CONNECTED_GLOBAL): info(_("Not yet connected to network (status = %d). Sleeping for a bit..."), network_state) import time time.sleep(120) if network_state in (_NetworkState.NM_STATE_DISCONNECTED, _NetworkState.NM_STATE_ASLEEP): info(_("Still not connected to network. Giving up.")) sys.exit(1) else: info(_("NetworkManager says we're on-line. Good!")) background_config.freshness = 0 # Don't bother trying to refresh when getting the interface refresh = driver.solve_with_downloads(force = True) # (causes confusing log messages) tasks.wait_for_blocker(refresh) # We could even download the archives here, but for now just # update the interfaces. if not driver.need_download(): if verbose: background_handler.notify("Zero Install", _("No updates to download."), timeout = 1) sys.exit(0) background_handler.notify("Zero Install", _("Updates ready to download for '%s'.") % root_iface, timeout = 1) _exec_gui(requirements.interface_uri, '--refresh', '--systray') sys.exit(1)
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)
def testUnknownAlg(self): self.cache_iface(foo_iface_uri, """<?xml version="1.0" ?> <interface uri="%s" xmlns="http://zero-install.sourceforge.net/2004/injector/interface"> <name>Foo</name> <summary>Foo</summary> <description>Foo</description> <implementation main='.' id='unknown=123' version='1.0'> <archive href='http://foo/foo.tgz' size='100'/> </implementation> </interface>""" % foo_iface_uri) self.config.fetcher = fetch.Fetcher(self.config) driver = Driver(requirements = Requirements(foo_iface_uri), config = self.config) try: assert driver.need_download() download_and_execute(driver, []) except model.SafeException as ex: assert "Use '_' not '=' for new algorithms, in unknown=123" in str(ex), ex
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 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 testCommands(self): iface = os.path.join(mydir, "Command.xml") driver = Driver(requirements = Requirements(iface), config = self.config) driver.need_download() assert driver.solver.ready impl = driver.solver.selections[self.config.iface_cache.get_interface(iface)] assert impl.id == 'c' assert impl.main == 'test-gui' dep_impl_uri = impl.commands['run'].requires[0].interface dep_impl = driver.solver.selections[self.config.iface_cache.get_interface(dep_impl_uri)] assert dep_impl.id == 'sha1=256' s1 = driver.solver.selections assert s1.commands[0].path == 'test-gui' xml = s1.toDOM().toxml("utf-8") root = qdom.parse(BytesIO(xml)) s2 = selections.Selections(root) assert s2.commands[0].path == 'test-gui' impl = s2.selections[iface] assert impl.id == 'c' assert s2.commands[0].qdom.attrs['http://custom attr'] == 'namespaced' custom_element = s2.commands[0].qdom.childNodes[0] assert custom_element.name == 'child' dep_impl = s2.selections[dep_impl_uri] assert dep_impl.id == 'sha1=256' d = Driver(self.config, requirements.Requirements(runexec)) need_download = d.need_download() assert need_download == False xml = d.solver.selections.toDOM().toxml("utf-8") root = qdom.parse(BytesIO(xml)) s3 = selections.Selections(root) runnable_impl = s3.selections[runnable] assert 'foo' in runnable_impl.commands assert 'run' in runnable_impl.commands
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)
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'))
def testLocalPath(self): # 0launch --get-selections Local.xml iface = os.path.join(mydir, "Local.xml") driver = Driver(requirements=Requirements(iface), config=self.config) driver.need_download() assert driver.solver.ready s1 = driver.solver.selections xml = s1.toDOM().toxml("utf-8") # Reload selections and check they're the same root = qdom.parse(BytesIO(xml)) s2 = selections.Selections(root) local_path = s2.selections[iface].local_path assert os.path.isdir(local_path), local_path assert not s2.selections[iface].digests, s2.selections[iface].digests # Add a newer implementation and try again feed = self.config.iface_cache.get_feed(iface) impl = model.ZeroInstallImplementation(feed, "foo bar=123", local_path=None) impl.version = model.parse_version('1.0') impl.commands["run"] = model.Command( qdom.Element(namespaces.XMLNS_IFACE, 'command', { 'path': 'dummy', 'name': 'run' }), None) impl.add_download_source('http://localhost/bar.tgz', 1000, None) feed.implementations = {impl.id: impl} assert driver.need_download() assert driver.solver.ready, driver.solver.get_failure_reason() s1 = driver.solver.selections xml = s1.toDOM().toxml("utf-8") root = qdom.parse(BytesIO(xml)) s2 = selections.Selections(root) xml = s2.toDOM().toxml("utf-8") qdom.parse(BytesIO(xml)) assert s2.selections[iface].local_path is None assert not s2.selections[iface].digests, s2.selections[iface].digests assert s2.selections[iface].id == 'foo bar=123'
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'))
def testDLfeed(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> <feed src='http://example.com'/> </interface>""" % foo_iface_uri) driver = Driver(requirements = Requirements(foo_iface_uri), config = self.config) self.config.network_use = model.network_full assert driver.need_download() feed = self.config.iface_cache.get_feed(foo_iface_uri) feed.feeds = [model.Feed('/BadFeed', None, False)] logger.setLevel(logging.ERROR) assert driver.need_download() # Triggers warning logger.setLevel(logging.WARN)
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[foo].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[foo].id == 'sha1=234' # The source assert driver.solver.selections[compiler].id == 'sha1=345' # A binary needed to compile it
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
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 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
def testBackgroundUnsolvable(self): my_dbus.system_services = {"org.freedesktop.NetworkManager": {"/org/freedesktop/NetworkManager": NetworkManager()}} trust.trust_db.trust_key('DE937DD411906ACF7C263B396FCF121BE2390E0B', 'example.com:8000') global ran_gui # Select a version of Hello run_server('Hello.xml', '6FCF121BE2390E0B.gpg', 'HelloWorld.tgz') r = Requirements('http://example.com:8000/Hello.xml') driver = Driver(requirements = r, config = self.config) tasks.wait_for_blocker(driver.solve_with_downloads()) assert driver.solver.ready kill_server_process() # Save it as an app app = self.config.app_mgr.create_app('test-app', r) # Replace the selection with a bogus and unusable <package-implementation> sels = driver.solver.selections sel, = sels.selections.values() sel.attrs['id'] = "package:dummy:badpackage" sel.attrs['package'] = "badpackage" sel.get_command('run').qdom.attrs['path'] = '/i/dont/exist' app.set_selections(driver.solver.selections) # Not time for a background update yet, but the missing binary should trigger # an update anyway. self.config.freshness = 0 # Check we try to launch the GUI... os.environ['DISPLAY'] = 'dummy' try: app.get_selections(may_update = True) assert 0 except model.SafeException as ex: assert 'Aborted by user' in str(ex) assert ran_gui ran_gui = False # Check we can also work without the GUI... del os.environ['DISPLAY'] run_server('Hello.xml', 'HelloWorld.tgz') sels = app.get_selections(may_update = True) kill_server_process() dl = app.download_selections(sels) assert dl == None assert not ran_gui # Now trigger a background update which discovers that no solution is possible timestamp = os.path.join(app.path, 'last-checked') last_check_attempt = os.path.join(app.path, 'last-check-attempt') selections_path = os.path.join(app.path, 'selections.xml') def reset_timestamps(): global ran_gui ran_gui = False os.utime(timestamp, (1, 1)) # 1970 os.utime(selections_path, (1, 1)) if os.path.exists(last_check_attempt): os.unlink(last_check_attempt) reset_timestamps() r.source = True app.set_requirements(r) run_server('Hello.xml') with trapped_exit(1): sels = app.get_selections(may_update = True) kill_server_process()
def 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)
def _check_for_updates(self, sels, use_gui): """Check whether the selections need to be updated. If any input feeds have changed, we re-run the solver. If the new selections require a download, we schedule one in the background and return the old selections. Otherwise, we return the new selections. If we can select better versions without downloading, we update the app's selections and return the new selections. If we can't use the current selections, we update in the foreground. We also schedule a background update from time-to-time anyway. @type sels: L{zeroinstall.injector.selections.Selections} @type use_gui: bool @return: the selections to use @rtype: L{selections.Selections}""" need_solve = False # Rerun solver (cached feeds have changed) need_update = False # Update over the network if sels: utime = self._get_mtime('last-checked', warn_if_missing = True) last_solve = max(self._get_mtime('last-solve', warn_if_missing = False), utime) # Ideally, this would return all the files which were inputs into the solver's # decision. Currently, we approximate with: # - the previously selected feed files (local or cached) # - configuration files for the selected interfaces # - the global configuration # We currently ignore feeds and interfaces which were # considered but not selected. # Can yield None (ignored), paths or (path, mtime) tuples. # If this throws an exception, we will log it and resolve anyway. def get_inputs(): for sel in sels.selections.values(): logger.info("Checking %s", sel.feed) if sel.feed.startswith('distribution:'): # If the package has changed version, we'll detect that below # with get_unavailable_selections. pass elif os.path.isabs(sel.feed): # Local feed yield sel.feed else: # Cached feed cached = basedir.load_first_cache(namespaces.config_site, 'interfaces', model.escape(sel.feed)) if cached: yield cached else: raise IOError("Input %s missing; update" % sel.feed) # Per-feed configuration yield basedir.load_first_config(namespaces.config_site, namespaces.config_prog, 'interfaces', model._pretty_escape(sel.interface)) # Global configuration yield basedir.load_first_config(namespaces.config_site, namespaces.config_prog, 'global') # If any of the feeds we used have been updated since the last check, do a quick re-solve try: for item in get_inputs(): if not item: continue if isinstance(item, tuple): path, mtime = item else: path = item try: mtime = os.stat(path).st_mtime except OSError as ex: logger.info("Triggering update to {app} due to error: {ex}".format( app = self, path = path, ex = ex)) need_solve = True break if mtime and mtime > last_solve: logger.info("Triggering update to %s because %s has changed", self, path) need_solve = True break except Exception as ex: logger.info("Error checking modification times: %s", ex) need_solve = True need_update = True # Is it time for a background update anyway? if not need_update: staleness = time.time() - utime logger.info("Staleness of app %s is %d hours", self, staleness / (60 * 60)) freshness_threshold = self.config.freshness if freshness_threshold > 0 and staleness >= freshness_threshold: need_update = True # If any of the saved selections aren't available then we need # to download right now, not later in the background. unavailable_selections = sels.get_unavailable_selections(config = self.config, include_packages = True) if unavailable_selections: logger.info("Saved selections are unusable (missing %s)", ', '.join(str(s) for s in unavailable_selections)) need_solve = True else: # No current selections need_solve = True unavailable_selections = True if need_solve: from zeroinstall.injector.driver import Driver driver = Driver(config = self.config, requirements = self.get_requirements()) if driver.need_download(): if unavailable_selections: return self._foreground_update(driver, use_gui) else: # Continue with the current (cached) selections while we download need_update = True else: old_sels = sels sels = driver.solver.selections from zeroinstall.support import xmltools if old_sels is None or not xmltools.nodes_equal(sels.toDOM(), old_sels.toDOM()): self.set_selections(sels, set_last_checked = False) try: self._touch('last-solve') except OSError as ex: logger.warning("Error checking for updates: %s", ex) # If we tried to check within the last hour, don't try again. if need_update: last_check_attempt = self._get_mtime('last-check-attempt', warn_if_missing = False) if last_check_attempt and last_check_attempt + 60 * 60 > time.time(): logger.info("Tried to check within last hour; not trying again now") need_update = False if need_update: try: self.set_last_check_attempt() except OSError as ex: logger.warning("Error checking for updates: %s", ex) else: from zeroinstall.injector import background r = self.get_requirements() background.spawn_background_update2(r, False, self) return sels
def get_selections_for(requirements, config, options, select_only, download_only, test_callback): """Get selections for given requirements. @since: 1.9""" if options.offline: config.network_use = model.network_offline iface_cache = config.iface_cache driver = Driver(config = config, requirements = requirements) # 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: if select_only: # --select-only: we only care that we've made a selection, not that we've cached the implementations driver.need_download() can_run_immediately = driver.solver.ready else: can_run_immediately = not driver.need_download() stale_feeds = [feed for feed in driver.solver.feeds_used if not feed.startswith('distribution:') and # Ignore (memory-only) PackageKit feeds iface_cache.is_stale(feed, config.freshness)] if download_only and stale_feeds: can_run_immediately = False if can_run_immediately: if stale_feeds: if config.network_use == model.network_offline: logger.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. from zeroinstall.injector import background background.spawn_background_update(driver, options.verbose) return driver.solver.selections # If we need to download anything, we might as well # refresh all the feeds first. options.refresh = True if options.gui != False: # If the user didn't say whether to use the GUI, choose for them. gui_args = driver.requirements.get_as_options() if download_only: # Just changes the button's label gui_args.append('--download-only') if options.refresh: gui_args.append('--refresh') if options.verbose: gui_args.insert(0, '--verbose') if options.verbose > 1: gui_args.insert(0, '--verbose') if options.with_store: for x in options.with_store: gui_args += ['--with-store', x] if select_only: gui_args.append('--select-only') from zeroinstall import helpers sels = helpers.get_selections_gui(requirements.interface_uri, gui_args, test_callback, use_gui = options.gui) if not sels: return None # Aborted elif sels is helpers.DontUseGUI: sels = None else: sels = None if sels is None: # Note: --download-only also makes us stop and download stale feeds first. downloaded = driver.solve_and_download_impls(refresh = options.refresh or download_only or False, select_only = select_only) if downloaded: tasks.wait_for_blocker(downloaded) sels = driver.solver.selections return sels
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 testBackgroundApp(self): my_dbus.system_services = {"org.freedesktop.NetworkManager": {"/org/freedesktop/NetworkManager": NetworkManager()}} trust.trust_db.trust_key('DE937DD411906ACF7C263B396FCF121BE2390E0B', 'example.com:8000') global ran_gui with output_suppressed(): # 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) app.set_selections(driver.solver.selections) 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) # Download the implementation sels = app.get_selections(may_update = True) run_server('HelloWorld.tgz') tasks.wait_for_blocker(app.download_selections(sels)) kill_server_process() # Not time for a background update yet self.config.freshness = 100 dl = app.download_selections(app.get_selections(may_update = True)) assert dl == None assert not ran_gui # Trigger a background update - no updates found reset_timestamps() run_server('Hello.xml') with trapped_exit(1): dl = app.download_selections(app.get_selections(may_update = True)) assert dl == None assert not ran_gui self.assertNotEqual(1, os.stat(timestamp).st_mtime) self.assertEqual(1, os.stat(selections_path).st_mtime) kill_server_process() # Change the selections sels_path = os.path.join(app.path, 'selections.xml') with open(sels_path) as stream: old = stream.read() with open(sels_path, 'w') as stream: stream.write(old.replace('Hello', 'Goodbye')) # Trigger another background update - metadata changes found reset_timestamps() run_server('Hello.xml') with trapped_exit(1): dl = app.download_selections(app.get_selections(may_update = True)) assert dl == None assert not ran_gui self.assertNotEqual(1, os.stat(timestamp).st_mtime) self.assertNotEqual(1, os.stat(selections_path).st_mtime) kill_server_process() # Trigger another background update - GUI needed now # Delete cached implementation so we need to download it again stored = sels.selections['http://example.com:8000/Hello.xml'].get_path(self.config.stores) assert os.path.basename(stored).startswith('sha1') ro_rmtree(stored) # Replace with a valid local feed so we don't have to download immediately with open(sels_path, 'w') as stream: stream.write(local_hello) os.environ['DISPLAY'] = 'dummy' reset_timestamps() run_server('Hello.xml') with trapped_exit(1): dl = app.download_selections(app.get_selections(may_update = True)) assert dl == None assert ran_gui # (so doesn't actually update) kill_server_process() # Now again with no DISPLAY reset_timestamps() del os.environ['DISPLAY'] run_server('Hello.xml', 'HelloWorld.tgz') with trapped_exit(1): dl = app.download_selections(app.get_selections(may_update = True)) assert dl == None assert not ran_gui # (so doesn't actually update) self.assertNotEqual(1, os.stat(timestamp).st_mtime) self.assertNotEqual(1, os.stat(selections_path).st_mtime) kill_server_process() sels = app.get_selections() sel, = sels.selections.values() self.assertEqual("sha1=3ce644dc725f1d21cfcf02562c76f375944b266a", sel.id) # Untrust the key trust.trust_db.untrust_key('DE937DD411906ACF7C263B396FCF121BE2390E0B', 'example.com:8000') os.environ['DISPLAY'] = 'dummy' reset_timestamps() run_server('Hello.xml') with trapped_exit(1): #import logging; logging.getLogger().setLevel(logging.INFO) dl = app.download_selections(app.get_selections(may_update = True)) assert dl == None assert ran_gui kill_server_process() # Update not triggered because of last-check-attempt ran_gui = False os.utime(timestamp, (1, 1)) # 1970 os.utime(selections_path, (1, 1)) dl = app.download_selections(app.get_selections(may_update = True)) assert dl == None assert not ran_gui