Exemplo n.º 1
0
    def testNoNeedDl(self):
        policy = Policy(foo_iface_uri, config=self.config)
        policy.freshness = 0
        assert policy.need_download()

        policy = Policy(os.path.abspath('Foo.xml'), config=self.config)
        assert not policy.need_download()
        assert policy.ready
Exemplo n.º 2
0
	def testNoNeedDl(self):
		policy = Policy(foo_iface_uri, config = self.config)
		policy.freshness = 0
		assert policy.need_download()

		policy = Policy(os.path.abspath('Foo.xml'), config = self.config)
		assert not policy.need_download()
		assert policy.ready
Exemplo n.º 3
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')
			self.child = server.handle_requests('Native.xml', '6FCF121BE2390E0B.gpg', '/key-info/key/DE937DD411906ACF7C263B396FCF121BE2390E0B')
			policy = Policy(native_url, config = self.config)
			assert policy.need_download()

			solve = policy.solve_with_downloads()
			self.config.handler.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
Exemplo n.º 4
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')
            self.child = server.handle_requests(
                'Native.xml', '6FCF121BE2390E0B.gpg',
                '/key-info/key/DE937DD411906ACF7C263B396FCF121BE2390E0B')
            policy = Policy(native_url, config=self.config)
            assert policy.need_download()

            solve = policy.solve_with_downloads()
            self.config.handler.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
Exemplo n.º 5
0
	def testAcceptKey(self):
		with output_suppressed():
			self.child = server.handle_requests('Hello', '6FCF121BE2390E0B.gpg', '/key-info/key/DE937DD411906ACF7C263B396FCF121BE2390E0B', 'HelloWorld.tgz')
			policy = Policy('http://localhost:8000/Hello', config = self.config)
			assert policy.need_download()
			sys.stdin = Reply("Y\n")
			try:
				download_and_execute(policy, ['Hello'], main = 'Missing')
				assert 0
			except model.SafeException as ex:
				if "HelloWorld/Missing" not in str(ex):
					raise
Exemplo n.º 6
0
def _check_for_updates(old_policy, verbose):
    from zeroinstall.injector.policy import Policy
    from zeroinstall.injector.config import load_config

    iface_cache = old_policy.config.iface_cache
    root_iface = iface_cache.get_interface(old_policy.root).get_name()

    background_config = load_config(
        BackgroundHandler(root_iface, old_policy.root))
    policy = Policy(config=background_config,
                    requirements=old_policy.requirements)

    info(_("Checking for updates to '%s' in a background process"), root_iface)
    if verbose:
        policy.handler.notify("Zero Install",
                              _("Checking for updates to '%s'...") %
                              root_iface,
                              timeout=1)

    network_state = policy.handler.get_network_state()
    if network_state != _NetworkState.NM_STATE_CONNECTED:
        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!"))

    policy.freshness = 0  # Don't bother trying to refresh when getting the interface
    refresh = policy.refresh_all()  # (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 policy.need_download():
        if verbose:
            policy.handler.notify("Zero Install",
                                  _("No updates to download."),
                                  timeout=1)
        sys.exit(0)

    policy.handler.notify("Zero Install",
                          _("Updates ready to download for '%s'.") %
                          root_iface,
                          timeout=1)
    _exec_gui(policy.root, '--refresh', '--systray')
    sys.exit(1)
Exemplo n.º 7
0
	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)
		policy = Policy(foo_iface_uri, config = self.config)
		policy.network_use = model.network_full
		policy.freshness = 0

		assert policy.need_download()

		feed = self.config.iface_cache.get_feed(foo_iface_uri)
		feed.feeds = [model.Feed('/BadFeed', None, False)]

		logger.setLevel(logging.ERROR)
		assert policy.need_download()	# Triggers warning
		logger.setLevel(logging.WARN)
Exemplo n.º 8
0
    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)
        policy = Policy(foo_iface_uri, config=self.config)
        policy.network_use = model.network_full
        policy.freshness = 0

        assert policy.need_download()

        feed = self.config.iface_cache.get_feed(foo_iface_uri)
        feed.feeds = [model.Feed('/BadFeed', None, False)]

        logger.setLevel(logging.ERROR)
        assert policy.need_download()  # Triggers warning
        logger.setLevel(logging.WARN)
Exemplo n.º 9
0
 def testAcceptKey(self):
     with output_suppressed():
         self.child = server.handle_requests(
             'Hello', '6FCF121BE2390E0B.gpg',
             '/key-info/key/DE937DD411906ACF7C263B396FCF121BE2390E0B',
             'HelloWorld.tgz')
         policy = Policy('http://localhost:8000/Hello', config=self.config)
         assert policy.need_download()
         sys.stdin = Reply("Y\n")
         try:
             download_and_execute(policy, ['Hello'], main='Missing')
             assert 0
         except model.SafeException as ex:
             if "HelloWorld/Missing" not in str(ex):
                 raise
Exemplo n.º 10
0
	def testRejectKey(self):
		with output_suppressed():
			self.child = server.handle_requests('Hello', '6FCF121BE2390E0B.gpg', '/key-info/key/DE937DD411906ACF7C263B396FCF121BE2390E0B')
			policy = Policy('http://localhost:8000/Hello', config = self.config)
			assert policy.need_download()
			sys.stdin = Reply("N\n")
			try:
				download_and_execute(policy, ['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(policy.handler.ex):
					raise ex
				self.config.handler.ex = None
Exemplo n.º 11
0
 def testWrongSize(self):
     with output_suppressed():
         self.child = server.handle_requests(
             "Hello-wrong-size",
             "6FCF121BE2390E0B.gpg",
             "/key-info/key/DE937DD411906ACF7C263B396FCF121BE2390E0B",
             "HelloWorld.tgz",
         )
         policy = Policy("http://localhost:8000/Hello-wrong-size", config=self.config)
         assert policy.need_download()
         sys.stdin = Reply("Y\n")
         try:
             download_and_execute(policy, ["Hello"], main="Missing")
             assert 0
         except model.SafeException, ex:
             if "Downloaded archive has incorrect size" not in str(ex):
                 raise ex
Exemplo n.º 12
0
 def testRejectKeyXML(self):
     with output_suppressed():
         self.child = server.handle_requests(
             "Hello.xml", "6FCF121BE2390E0B.gpg", "/key-info/key/DE937DD411906ACF7C263B396FCF121BE2390E0B"
         )
         policy = Policy("http://example.com:8000/Hello.xml", config=self.config)
         assert policy.need_download()
         sys.stdin = Reply("N\n")
         try:
             download_and_execute(policy, ["Hello"])
             assert 0
         except model.SafeException, ex:
             if "has no usable implementations" not in str(ex):
                 raise ex
             if "Not signed with a trusted key" not in str(policy.handler.ex):
                 raise
             self.config.handler.ex = None
Exemplo n.º 13
0
 def testRejectKey(self):
     with output_suppressed():
         self.child = server.handle_requests(
             'Hello', '6FCF121BE2390E0B.gpg',
             '/key-info/key/DE937DD411906ACF7C263B396FCF121BE2390E0B')
         policy = Policy('http://localhost:8000/Hello', config=self.config)
         assert policy.need_download()
         sys.stdin = Reply("N\n")
         try:
             download_and_execute(policy, ['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(
                     policy.handler.ex):
                 raise ex
             self.config.handler.ex = None
Exemplo n.º 14
0
def _check_for_updates(old_policy, verbose):
	from zeroinstall.injector.policy import Policy
	from zeroinstall.injector.config import load_config

	iface_cache = old_policy.config.iface_cache
	root_iface = iface_cache.get_interface(old_policy.root).get_name()

	background_config = load_config(BackgroundHandler(root_iface, old_policy.root))
	policy = Policy(config = background_config, requirements = old_policy.requirements)

	info(_("Checking for updates to '%s' in a background process"), root_iface)
	if verbose:
		policy.handler.notify("Zero Install", _("Checking for updates to '%s'...") % root_iface, timeout = 1)

	network_state = policy.handler.get_network_state()
	if network_state != _NetworkState.NM_STATE_CONNECTED:
		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!"))

	policy.freshness = 0			# Don't bother trying to refresh when getting the interface
	refresh = policy.refresh_all()		# (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 policy.need_download():
		if verbose:
			policy.handler.notify("Zero Install", _("No updates to download."), timeout = 1)
		sys.exit(0)

	policy.handler.notify("Zero Install",
			      _("Updates ready to download for '%s'.") % root_iface,
			      timeout = 1)
	_exec_gui(policy.root, '--refresh', '--systray')
	sys.exit(1)
Exemplo n.º 15
0
    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)
        policy = Policy(foo_iface_uri, config=self.config)
        policy.freshness = 0
        policy.network_use = model.network_full
        recalculate(policy)
        assert policy.need_download()
        assert policy.ready
Exemplo n.º 16
0
	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)
		policy = Policy(foo_iface_uri, config = self.config)
		policy.freshness = 0
		policy.network_use = model.network_full
		recalculate(policy)
		assert policy.need_download()
		assert policy.ready
Exemplo n.º 17
0
	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)
		policy = Policy(foo_iface_uri, config = self.config)
		policy.freshness = 0
		try:
			assert policy.need_download()
			download_and_execute(policy, [])
		except model.SafeException as ex:
			assert 'Unknown digest algorithm' in str(ex)
Exemplo n.º 18
0
    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)
        policy = Policy(foo_iface_uri, config=self.config)
        policy.freshness = 0
        try:
            assert policy.need_download()
            download_and_execute(policy, [])
        except model.SafeException as ex:
            assert 'Unknown digest algorithm' in str(ex)
Exemplo n.º 19
0
def _check_for_updates(old_policy, verbose):
	from zeroinstall.injector.policy import load_config, Policy

	iface_cache = old_policy.config.iface_cache
	root_iface = iface_cache.get_interface(old_policy.root).get_name()

	background_config = load_config(BackgroundHandler(root_iface, old_policy.root))
	policy = Policy(config = background_config, requirements = old_policy.requirements)

	info(_("Checking for updates to '%s' in a background process"), root_iface)
	if verbose:
		policy.handler.notify("Zero Install", _("Checking for updates to '%s'...") % root_iface, timeout = 1)

	network_state = policy.handler.get_network_state()
	if network_state != _NetworkState.NM_STATE_CONNECTED:
		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!"))

	policy.freshness = 0			# Don't bother trying to refresh when getting the interface
	refresh = policy.refresh_all()		# (causes confusing log messages)
	policy.handler.wait_for_blocker(refresh)

	# We could even download the archives here, but for now just
	# update the interfaces.

	if not policy.need_download():
		if verbose:
			policy.handler.notify("Zero Install", _("No updates to download."), timeout = 1)
		sys.exit(0)

	if not policy.handler.have_actions_support():
		# Can't ask the user to choose, so just notify them
		# In particular, Ubuntu/Jaunty doesn't support actions
		policy.handler.notify("Zero Install",
				      _("Updates ready to download for '%s'.") % root_iface,
				      timeout = 1)
		_exec_gui(policy.root, '--refresh', '--systray')
		sys.exit(1)

	notification_closed = tasks.Blocker("wait for notification response")

	def _NotificationClosed(nid, *unused):
		if nid != our_question: return
		notification_closed.trigger()

	def _ActionInvoked(nid, action):
		if nid != our_question: return
		if action == 'download':
			_exec_gui(policy.root)
		notification_closed.trigger()

	policy.handler.notification_service.connect_to_signal('NotificationClosed', _NotificationClosed)
	policy.handler.notification_service.connect_to_signal('ActionInvoked', _ActionInvoked)

	our_question = policy.handler.notify("Zero Install", _("Updates ready to download for '%s'.") % root_iface,
				actions = ['download', 'Download'])

	policy.handler.wait_for_blocker(notification_closed)
Exemplo n.º 20
0
class _SolveLink(_Link):
    name = 'Solve'

    def __init__(self, feed, seed=None):
        _Link.__init__(self)

        self.force = False

        iface_uri = model.canonical_iface_uri(feed)
        self.policy = Policy(iface_uri)
        self.policy.solver.record_details = True

        if seed is not None:
            self.policy.network_use = seed.policy.network_use
            self.policy.handler = seed.policy.handler
            self.force = seed.force

    def attach(self):
        if self.force or not self.policy.ready:
            msg = _('Download feed for service %s:') % \
                    self.get_name()
            self.emit('verbose', msg)
        else:
            msg = _('Download requirements for service %s:') % \
                    self.get_name()
            self.emit('verbose', msg)

        return self.policy.solve_with_downloads(force=self.force)

    def detach(self, blocker):
        if self.policy.solver.ready:
            for iface, __ in self.policy.implementation.items():
                msg = _('* %s done;') % _name(iface.uri)
                self.emit('verbose', msg)
            if self.policy.need_download():
                return [_DownloadLink(self)]
            else:
                return []

        zcompile = _SolveLink(www.IFACE_COMPILE, self)

        # at the end, we should restart current link
        next_links = [_SolveLink(self.policy.root, self)]
        failed = False
        need_build = False

        for iface, impl in self.policy.implementation.items():
            if impl is not None:
                msg = _('* %s done;') % _name(iface.uri)
                self.emit('verbose', msg)
                continue

            if self._has_source(iface):
                msg = _('* %s needs to be built from sources;') % \
                        _name(iface.uri)
                self.emit('verbose', msg)
                next_links.append(_BuildLink(iface.uri, zcompile))
                next_links.append(_SolveSourceLink(iface.uri, self))
                need_build = True
            else:
                reason = self.policy.solver.details.get(iface) or _('Unknown')
                msg = _('* %s failed to resolve due to "%s";') % \
                        (_name(iface.uri), reason)
                self.emit('verbose', msg)
                failed = True

        if failed and not need_build:
            return None

        # check for 0compile at first
        next_links.append(zcompile)
        msg = _('* add %s;') % zcompile.get_name()
        self.emit('verbose', msg)

        return next_links

    def _has_source(self, iface):
        for feed in iface.feeds:
            if feed.machine == 'src':
                return True

        for impl in iface.implementations.values():
            if impl.machine == 'src':
                return True

        return False
Exemplo n.º 21
0
def get_selections(config, options, iface_uri, select_only, download_only, test_callback):
	"""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
	@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:
				logging.info(_("Waiting for selected implementations to be downloaded..."))
				tasks.wait_for_blocker(blocker)
		return maybe_selections

	r = requirements.Requirements(iface_uri)
	r.parse_options(options)

	policy = Policy(config = config, requirements = r)

	# 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
			policy.need_download()
			can_run_immediately = policy.ready
		else:
			can_run_immediately = not policy.need_download()

		stale_feeds = [feed for feed in policy.solver.feeds_used if
				not os.path.isabs(feed) and			# Ignore local feeds (note: file might be missing too)
				not feed.startswith('distribution:') and	# Ignore (memory-only) PackageKit feeds
				iface_cache.is_stale(iface_cache.get_feed(feed), config.freshness)]

		if download_only and stale_feeds:
			can_run_immediately = False

	if can_run_immediately:
		if stale_feeds:
			if policy.network_use == model.network_offline:
				logging.debug(_("No doing background update because we are in off-line mode."))
			else:
				# There are feeds we should update, but we can run without them.
				# Do the update in the background while the program is running.
				from zeroinstall.injector import background
				background.spawn_background_update(policy, options.verbose > 0)
		return policy.solver.selections

	# If the user didn't say whether to use the GUI, choose for them.
	if options.gui is None and os.environ.get('DISPLAY', None):
		options.gui = True
		# If we need to download anything, we might as well
		# refresh all the feeds first.
		options.refresh = True
		logging.info(_("Switching to GUI mode... (use --console to disable)"))

	if options.gui:
		gui_args = policy.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(iface_uri, gui_args, test_callback)

		if not sels:
			return None		# Aborted
	else:
		# Note: --download-only also makes us stop and download stale feeds first.
		downloaded = policy.solve_and_download_impls(refresh = options.refresh or download_only or False,
							     select_only = select_only)
		if downloaded:
			tasks.wait_for_blocker(downloaded)
		sels = selections.Selections(policy)

	return sels
Exemplo n.º 22
0
def get_selections(config, options, iface_uri, select_only, download_only, test_callback):
	"""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
	@return: the selected versions, or None if the user cancels
	@rtype: L{selections.Selections} | None
	"""
	if options.offline:
		config.network_use = model.network_offline

	# 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 = config.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:
				logging.info(_("Waiting for selected implementations to be downloaded..."))
				config.handler.wait_for_blocker(blocker)
		return maybe_selections

	r = requirements.Requirements(iface_uri)
	r.parse_options(options)

	policy = Policy(config = config, requirements = r)

	# 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
			policy.need_download()
			can_run_immediately = policy.ready
		else:
			can_run_immediately = not policy.need_download()

		stale_feeds = [feed for feed in policy.solver.feeds_used if
				not feed.startswith('distribution:') and	# Ignore (memory-only) PackageKit feeds
				policy.is_stale(config.iface_cache.get_feed(feed))]

		if download_only and stale_feeds:
			can_run_immediately = False

	if can_run_immediately:
		if stale_feeds:
			if policy.network_use == model.network_offline:
				logging.debug(_("No doing background update because we are in off-line mode."))
			else:
				# There are feeds we should update, but we can run without them.
				# Do the update in the background while the program is running.
				from zeroinstall.injector import background
				background.spawn_background_update(policy, options.verbose > 0)
		return policy.solver.selections

	# If the user didn't say whether to use the GUI, choose for them.
	if options.gui is None and os.environ.get('DISPLAY', None):
		options.gui = True
		# If we need to download anything, we might as well
		# refresh all the feeds first.
		options.refresh = True
		logging.info(_("Switching to GUI mode... (use --console to disable)"))

	if options.gui:
		gui_args = policy.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(iface_uri, gui_args, test_callback)

		if not sels:
			return None		# Aborted
	else:
		# Note: --download-only also makes us stop and download stale feeds first.
		downloaded = policy.solve_and_download_impls(refresh = options.refresh or download_only or False,
							     select_only = select_only)
		if downloaded:
			config.handler.wait_for_blocker(downloaded)
		sels = selections.Selections(policy)

	return sels