def __init__(self, config, requirements): """@param config: The configuration settings to use @type config: L{config.Config} @param requirements: Details about the program we want to run @type requirements: L{requirements.Requirements} @since: 0.53""" self.watchers = [] assert config self.config = config assert requirements self.requirements = requirements self.target_arch = arch.get_architecture(requirements.os, requirements.cpu) from zeroinstall.injector.solver import DefaultSolver self.solver = DefaultSolver(self.config) logger.debug(_("Supported systems: '%s'"), arch.os_ranks) logger.debug(_("Supported processors: '%s'"), arch.machine_ranks) self.solver.extra_restrictions = requirements.get_extra_restrictions( self.config.iface_cache)
def __init__(self, config, requirements): """ @param config: The configuration settings to use @type config: L{config.Config} @param requirements: Details about the program we want to run @type requirements: L{requirements.Requirements} @since: 0.53 """ self.watchers = [] assert config self.config = config assert requirements self.requirements = requirements self.target_arch = arch.get_architecture(requirements.os, requirements.cpu) from zeroinstall.injector.solver import DefaultSolver self.solver = DefaultSolver(self.config) debug(_("Supported systems: '%s'"), arch.os_ranks) debug(_("Supported processors: '%s'"), arch.machine_ranks) if requirements.before or requirements.not_before: self.solver.extra_restrictions[config.iface_cache.get_interface(requirements.interface_uri)] = [ model.VersionRangeRestriction(model.parse_version(requirements.before), model.parse_version(requirements.not_before))]
def __init__(self, config, requirements): """ @param config: The configuration settings to use @type config: L{config.Config} @param requirements: Details about the program we want to run @type requirements: L{requirements.Requirements} @since: 0.53 """ self.watchers = [] assert config self.config = config assert requirements self.requirements = requirements self.target_arch = arch.get_architecture(requirements.os, requirements.cpu) from zeroinstall.injector.solver import DefaultSolver self.solver = DefaultSolver(self.config) logger.debug(_("Supported systems: '%s'"), arch.os_ranks) logger.debug(_("Supported processors: '%s'"), arch.machine_ranks) if requirements.before or requirements.not_before: self.solver.extra_restrictions[config.iface_cache.get_interface(requirements.interface_uri)] = [ model.VersionRangeRestriction( model.parse_version(requirements.before), model.parse_version(requirements.not_before) ) ]
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 __init__(self, root, handler = None, src = False): """ @param root: The URI of the root interface (the program we want to run). @param handler: A handler for main-loop integration. @type handler: L{zeroinstall.injector.handler.Handler} @param src: Whether we are looking for source code. @type src: bool """ self.watchers = [] self.freshness = 60 * 60 * 24 * 30 self.src = src # Root impl must be a "src" machine type self.stale_feeds = set() from zeroinstall.injector.solver import DefaultSolver self.solver = DefaultSolver(network_full, iface_cache, iface_cache.stores) # 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 self._fetcher = None # (allow self for backwards compat) self.handler = handler or self debug(_("Supported systems: '%s'"), arch.os_ranks) debug(_("Supported processors: '%s'"), arch.machine_ranks) path = basedir.load_first_config(config_site, config_prog, 'global') if path: try: config = ConfigParser.ConfigParser() config.read(path) self.solver.help_with_testing = config.getboolean('global', 'help_with_testing') self.solver.network_use = config.get('global', 'network_use') self.freshness = int(config.get('global', 'freshness')) assert self.solver.network_use in network_levels, self.solver.network_use except Exception, ex: warn(_("Error loading config: %s"), str(ex) or repr(ex))
class Driver(object): """Chooses a set of implementations based on a policy. Typical use: 1. Create a Driver object, giving it the requirements about the program to be run. 2. Call L{solve_with_downloads}. If more information is needed, a L{fetch.Fetcher} will be used to download it. 3. When all downloads are complete, the L{solver} contains the chosen versions. 4. Use L{get_uncached_implementations} to find where to get these versions and download them using L{download_uncached_implementations}. @ivar target_arch: target architecture for binaries (deprecated) @type target_arch: L{arch.Architecture} @ivar solver: solver used to choose a set of implementations @type solver: L{solve.Solver} @ivar watchers: callbacks to invoke after solving """ __slots__ = ["watchers", "requirements", "config", "target_arch", "solver"] def __init__(self, config, requirements): """ @param config: The configuration settings to use @type config: L{config.Config} @param requirements: Details about the program we want to run @type requirements: L{requirements.Requirements} @since: 0.53 """ self.watchers = [] assert config self.config = config assert requirements self.requirements = requirements self.target_arch = arch.get_architecture(requirements.os, requirements.cpu) from zeroinstall.injector.solver import DefaultSolver self.solver = DefaultSolver(self.config) logger.debug(_("Supported systems: '%s'"), arch.os_ranks) logger.debug(_("Supported processors: '%s'"), arch.machine_ranks) if requirements.before or requirements.not_before: self.solver.extra_restrictions[config.iface_cache.get_interface(requirements.interface_uri)] = [ model.VersionRangeRestriction( model.parse_version(requirements.before), model.parse_version(requirements.not_before) ) ] def get_uncached_implementations(self): """List all chosen implementations which aren't yet available locally. @rtype: [(L{model.Interface}, L{model.Implementation})]""" iface_cache = self.config.iface_cache stores = self.config.stores uncached = [] for uri, selection in self.solver.selections.selections.items(): impl = selection.impl assert impl, self.solver.selections if not impl.is_available(stores): uncached.append((iface_cache.get_interface(uri), impl)) return uncached @tasks.async def solve_with_downloads(self, force=False, update_local=False): """Run the solver, then download any feeds that are missing or that need to be updated. Each time a new feed is imported into the cache, the solver is run again, possibly adding new downloads. @param force: whether to download even if we're already ready to run. @param update_local: fetch PackageKit feeds even if we're ready to run.""" downloads_finished = set() # Successful or otherwise downloads_in_progress = {} # URL -> Download # There are three cases: # 1. We want to run immediately if possible. If not, download all the information we can. # (force = False, update_local = False) # 2. We're in no hurry, but don't want to use the network unnecessarily. # We should still update local information (from PackageKit). # (force = False, update_local = True) # 3. The user explicitly asked us to refresh everything. # (force = True) try_quick_exit = not (force or update_local) while True: self.solver.solve_for(self.requirements) for w in self.watchers: w() if try_quick_exit and self.solver.ready: break try_quick_exit = False if not self.solver.ready: force = True for f in self.solver.feeds_used: if f in downloads_finished or f in downloads_in_progress: continue if os.path.isabs(f): if force: self.config.iface_cache.get_feed(f, force=True) downloads_in_progress[f] = tasks.IdleBlocker("Refresh local feed") continue elif f.startswith("distribution:"): if force or update_local: downloads_in_progress[f] = self.config.fetcher.download_and_import_feed( f, self.config.iface_cache ) elif force and self.config.network_use != network_offline: downloads_in_progress[f] = self.config.fetcher.download_and_import_feed(f, self.config.iface_cache) # Once we've starting downloading some things, # we might as well get them all. force = True if not downloads_in_progress: if self.config.network_use == network_offline: logger.info(_("Can't choose versions and in off-line mode, so aborting")) break # Wait for at least one download to finish blockers = downloads_in_progress.values() yield blockers tasks.check(blockers, self.config.handler.report_error) for f in list(downloads_in_progress.keys()): if f in downloads_in_progress and downloads_in_progress[f].happened: del downloads_in_progress[f] downloads_finished.add(f) # Need to refetch any "distribution" feed that # depends on this one distro_feed_url = "distribution:" + f if distro_feed_url in downloads_finished: downloads_finished.remove(distro_feed_url) if distro_feed_url in downloads_in_progress: del downloads_in_progress[distro_feed_url] @tasks.async def solve_and_download_impls(self, refresh=False, select_only=False): """Run L{solve_with_downloads} and then get the selected implementations too. @raise SafeException: if we couldn't select a set of implementations @since: 0.40""" refreshed = self.solve_with_downloads(refresh) if refreshed: yield refreshed tasks.check(refreshed) if not self.solver.ready: raise self.solver.get_failure_reason() if not select_only: downloaded = self.download_uncached_implementations() if downloaded: yield downloaded tasks.check(downloaded) def need_download(self): """Decide whether we need to download anything (but don't do it!) @return: true if we MUST download something (feeds or implementations) @rtype: bool""" self.solver.solve_for(self.requirements) for w in self.watchers: w() if not self.solver.ready: return True # Maybe a newer version will work? if self.get_uncached_implementations(): return True return False def download_uncached_implementations(self): """Download all implementations chosen by the solver that are missing from the cache.""" assert self.solver.ready, "Solver is not ready!\n%s" % self.solver.selections stores = self.config.stores return self.config.fetcher.download_impls( [impl for impl in self.solver.selections.values() if not impl.is_available(stores)], stores )
class Driver(object): """Chooses a set of implementations based on a policy. Typical use: 1. Create a Driver object, giving it the requirements about the program to be run. 2. Call L{solve_with_downloads}. If more information is needed, a L{fetch.Fetcher} will be used to download it. 3. When all downloads are complete, the L{solver} contains the chosen versions. 4. Use L{get_uncached_implementations} to find where to get these versions and download them using L{download_uncached_implementations}. @ivar target_arch: target architecture for binaries (deprecated) @type target_arch: L{arch.Architecture} @ivar solver: solver used to choose a set of implementations @type solver: L{solve.Solver} @ivar watchers: callbacks to invoke after solving """ __slots__ = ['watchers', 'requirements', 'config', 'target_arch', 'solver'] def __init__(self, config, requirements): """@param config: The configuration settings to use @type config: L{config.Config} @param requirements: Details about the program we want to run @type requirements: L{requirements.Requirements} @since: 0.53""" self.watchers = [] assert config self.config = config assert requirements self.requirements = requirements self.target_arch = arch.get_architecture(requirements.os, requirements.cpu) from zeroinstall.injector.solver import DefaultSolver self.solver = DefaultSolver(self.config) logger.debug(_("Supported systems: '%s'"), arch.os_ranks) logger.debug(_("Supported processors: '%s'"), arch.machine_ranks) self.solver.extra_restrictions = requirements.get_extra_restrictions( self.config.iface_cache) def get_uncached_implementations(self): """List all chosen implementations which aren't yet available locally. @rtype: [(L{model.Interface}, L{model.Implementation})]""" iface_cache = self.config.iface_cache stores = self.config.stores uncached = [] for uri, selection in self.solver.selections.selections.items(): impl = selection.impl assert impl, self.solver.selections if not impl.is_available(stores): uncached.append((iface_cache.get_interface(uri), impl)) return uncached @tasks. async def solve_with_downloads(self, force=False, update_local=False): """Run the solver, then download any feeds that are missing or that need to be updated. Each time a new feed is imported into the cache, the solver is run again, possibly adding new downloads. @param force: whether to download even if we're already ready to run. @type force: bool @param update_local: fetch PackageKit feeds even if we're ready to run. @type update_local: bool""" downloads_finished = set() # Successful or otherwise downloads_in_progress = {} # URL -> Download # There are three cases: # 1. We want to run immediately if possible. If not, download all the information we can. # (force = False, update_local = False) # 2. We're in no hurry, but don't want to use the network unnecessarily. # We should still update local information (from PackageKit). # (force = False, update_local = True) # 3. The user explicitly asked us to refresh everything. # (force = True) try_quick_exit = not (force or update_local) while True: self.solver.solve_for(self.requirements) for w in self.watchers: w() if try_quick_exit and self.solver.ready: break try_quick_exit = False if not self.solver.ready: force = True for f in self.solver.feeds_used: if f in downloads_finished or f in downloads_in_progress: continue if os.path.isabs(f): if force: try: self.config.iface_cache.get_feed(f, force=True) except reader.MissingLocalFeed as ex: logger.warning( "Reloading %s: %s", f, ex, exc_info=True if logger.isEnabledFor(logging.INFO) else None) downloads_in_progress[f] = tasks.IdleBlocker( 'Refresh local feed') continue elif f.startswith('distribution:'): if force or update_local: downloads_in_progress[ f] = self.config.fetcher.download_and_import_feed( f, self.config.iface_cache) elif force and self.config.network_use != network_offline: downloads_in_progress[ f] = self.config.fetcher.download_and_import_feed( f, self.config.iface_cache) # Once we've starting downloading some things, # we might as well get them all. force = True if not downloads_in_progress: if self.config.network_use == network_offline: logger.info( _("Can't choose versions and in off-line mode, so aborting" )) break # Wait for at least one download to finish blockers = downloads_in_progress.values() yield blockers tasks.check(blockers, self.config.handler.report_error) for f in list(downloads_in_progress.keys()): if f in downloads_in_progress and downloads_in_progress[ f].happened: del downloads_in_progress[f] downloads_finished.add(f) # Need to refetch any "distribution" feed that # depends on this one distro_feed_url = 'distribution:' + f if distro_feed_url in downloads_finished: downloads_finished.remove(distro_feed_url) if distro_feed_url in downloads_in_progress: del downloads_in_progress[distro_feed_url] @tasks. async def solve_and_download_impls(self, refresh=False, select_only=False): """Run L{solve_with_downloads} and then get the selected implementations too. @type refresh: bool @type select_only: bool @raise SafeException: if we couldn't select a set of implementations @since: 0.40""" refreshed = self.solve_with_downloads(refresh) if refreshed: yield refreshed tasks.check(refreshed) if not self.solver.ready: raise self.solver.get_failure_reason() if not select_only: downloaded = self.download_uncached_implementations() if downloaded: yield downloaded tasks.check(downloaded) def need_download(self): """Decide whether we need to download anything (but don't do it!) @return: true if we MUST download something (feeds or implementations) @rtype: bool""" self.solver.solve_for(self.requirements) for w in self.watchers: w() if not self.solver.ready: return True # Maybe a newer version will work? if self.get_uncached_implementations(): return True return False def download_uncached_implementations(self): """Download all implementations chosen by the solver that are missing from the cache. @rtype: L{zeroinstall.support.tasks.Blocker}""" assert self.solver.ready, "Solver is not ready!\n%s" % self.solver.selections return self.solver.selections.download_missing(self.config, include_packages=True)
class Policy(object): """Chooses a set of implementations based on a policy. Typical use: 1. Create a Policy object, giving it the URI of the program to be run and a handler. 2. Call L{solve_with_downloads}. If more information is needed, a L{fetch.Fetcher} will be used to download it. 3. When all downloads are complete, the L{solver} contains the chosen versions. 4. Use L{get_uncached_implementations} to find where to get these versions and download them using L{download_uncached_implementations}. @ivar target_arch: target architecture for binaries @type target_arch: L{arch.Architecture} @ivar root: URI of the root interface @ivar solver: solver used to choose a set of implementations @type solver: L{solve.Solver} @ivar watchers: callbacks to invoke after recalculating @ivar help_with_testing: default stability policy @type help_with_testing: bool @ivar network_use: one of the model.network_* values @ivar freshness: seconds allowed since last update @type freshness: int @ivar stale_feeds: set of feeds which are present but haven't been checked for a long time @type stale_feeds: set """ __slots__ = ['root', 'watchers', 'requirements', 'config', '_warned_offline', 'command', 'target_arch', 'stale_feeds', 'solver'] help_with_testing = property(lambda self: self.config.help_with_testing, lambda self, value: setattr(self.config, 'help_with_testing', bool(value))) network_use = property(lambda self: self.config.network_use, lambda self, value: setattr(self.config, 'network_use', value)) freshness = property(lambda self: self.config.freshness, lambda self, value: setattr(self.config, 'freshness', str(value))) implementation = property(lambda self: self.solver.selections) ready = property(lambda self: self.solver.ready) # (used by 0test) handler = property(lambda self: self.config.handler, lambda self, value: setattr(self.config, 'handler', value)) 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))] @property def fetcher(self): return self.config.fetcher def save_config(self): self.config.save_globals() def recalculate(self, fetch_stale_interfaces = True): """@deprecated: see L{solve_with_downloads} """ import warnings warnings.warn("Policy.recalculate is deprecated!", DeprecationWarning, stacklevel = 2) self.stale_feeds = set() host_arch = self.target_arch if self.requirements.source: host_arch = arch.SourceArchitecture(host_arch) self.solver.solve(self.root, host_arch, command_name = self.command) if self.network_use == network_offline: fetch_stale_interfaces = False blockers = [] for f in self.solver.feeds_used: if os.path.isabs(f): continue feed = self.config.iface_cache.get_feed(f) if feed is None or feed.last_modified is None: self.download_and_import_feed_if_online(f) # Will start a download elif self.is_stale(feed): debug(_("Adding %s to stale set"), f) self.stale_feeds.add(self.config.iface_cache.get_interface(f)) # Legacy API if fetch_stale_interfaces: self.download_and_import_feed_if_online(f) # Will start a download for w in self.watchers: w() return blockers def usable_feeds(self, iface): """Generator for C{iface.feeds} that are valid for our architecture. @rtype: generator @see: L{arch}""" if self.requirements.source and iface.uri == self.root: # Note: when feeds are recursive, we'll need a better test for root here machine_ranks = {'src': 1} else: machine_ranks = arch.machine_ranks for f in self.config.iface_cache.get_feed_imports(iface): if f.os in arch.os_ranks and f.machine in machine_ranks: yield f else: debug(_("Skipping '%(feed)s'; unsupported architecture %(os)s-%(machine)s"), {'feed': f, 'os': f.os, 'machine': f.machine}) def is_stale(self, feed): """Check whether feed needs updating, based on the configured L{freshness}. None is considered to be stale. @return: true if feed is stale or missing.""" if feed is None: return True if os.path.isabs(feed.url): return False # Local feeds are never stale if feed.last_modified is None: return True # Don't even have it yet now = time.time() staleness = now - (feed.last_checked or 0) debug(_("Staleness for %(feed)s is %(staleness).2f hours"), {'feed': feed, 'staleness': staleness / 3600.0}) if self.freshness <= 0 or staleness < self.freshness: return False # Fresh enough for us last_check_attempt = self.config.iface_cache.get_last_check_attempt(feed.url) if last_check_attempt and last_check_attempt > now - FAILED_CHECK_DELAY: debug(_("Stale, but tried to check recently (%s) so not rechecking now."), time.ctime(last_check_attempt)) return False return True def download_and_import_feed_if_online(self, feed_url): """If we're online, call L{fetch.Fetcher.download_and_import_feed}. Otherwise, log a suitable warning.""" if self.network_use != network_offline: debug(_("Feed %s not cached and not off-line. Downloading..."), feed_url) return self.fetcher.download_and_import_feed(feed_url, self.config.iface_cache) else: if self._warned_offline: debug(_("Not downloading feed '%s' because we are off-line."), feed_url) else: warn(_("Not downloading feed '%s' because we are in off-line mode."), feed_url) self._warned_offline = True def get_implementation_path(self, impl): """Return the local path of impl. @rtype: str @raise zeroinstall.zerostore.NotStored: if it needs to be added to the cache first.""" assert isinstance(impl, Implementation) return impl.local_path or self.config.stores.lookup_any(impl.digests) def get_implementation(self, interface): """Get the chosen implementation. @type interface: Interface @rtype: L{model.Implementation} @raise SafeException: if interface has not been fetched or no implementation could be chosen.""" assert isinstance(interface, Interface) try: return self.implementation[interface] except KeyError: raise SafeException(_("No usable implementation found for '%s'.") % interface.uri) def get_cached(self, impl): """Check whether an implementation is available locally. @type impl: model.Implementation @rtype: bool """ if isinstance(impl, DistributionImplementation): return impl.installed if impl.local_path: return os.path.exists(impl.local_path) else: try: path = self.get_implementation_path(impl) assert path return True except: pass # OK return False def get_uncached_implementations(self): """List all chosen implementations which aren't yet available locally. @rtype: [(L{model.Interface}, L{model.Implementation})]""" iface_cache = self.config.iface_cache uncached = [] for uri, selection in self.solver.selections.selections.iteritems(): impl = selection.impl assert impl, self.solver.selections if not self.get_cached(impl): uncached.append((iface_cache.get_interface(uri), impl)) return uncached def refresh_all(self, force = True): """Start downloading all feeds for all selected interfaces. @param force: Whether to restart existing downloads.""" return self.solve_with_downloads(force = True) def get_feed_targets(self, feed): """Return a list of Interfaces for which feed can be a feed. This is used by B{0install add-feed}. @param feed: the feed @type feed: L{model.ZeroInstallFeed} (or, deprecated, a URL) @rtype: [model.Interface] @raise SafeException: If there are no known feeds.""" if not isinstance(feed, model.ZeroInstallFeed): # (deprecated) feed = self.config.iface_cache.get_feed(feed) if feed is None: raise SafeException("Feed is not cached and using deprecated API") if not feed.feed_for: raise SafeException(_("Missing <feed-for> element in '%s'; " "it can't be used as a feed for any other interface.") % feed.url) feed_targets = feed.feed_for debug(_("Feed targets: %s"), feed_targets) return [self.config.iface_cache.get_interface(uri) for uri in feed_targets] @tasks.async def solve_with_downloads(self, force = False, update_local = False): """Run the solver, then download any feeds that are missing or that need to be updated. Each time a new feed is imported into the cache, the solver is run again, possibly adding new downloads. @param force: whether to download even if we're already ready to run. @param update_local: fetch PackageKit feeds even if we're ready to run.""" downloads_finished = set() # Successful or otherwise downloads_in_progress = {} # URL -> Download host_arch = self.target_arch if self.requirements.source: host_arch = arch.SourceArchitecture(host_arch) # There are three cases: # 1. We want to run immediately if possible. If not, download all the information we can. # (force = False, update_local = False) # 2. We're in no hurry, but don't want to use the network unnecessarily. # We should still update local information (from PackageKit). # (force = False, update_local = True) # 3. The user explicitly asked us to refresh everything. # (force = True) try_quick_exit = not (force or update_local) while True: self.solver.solve(self.root, host_arch, command_name = self.command) for w in self.watchers: w() if try_quick_exit and self.solver.ready: break try_quick_exit = False if not self.solver.ready: force = True for f in self.solver.feeds_used: if f in downloads_finished or f in downloads_in_progress: continue if os.path.isabs(f): if force: self.config.iface_cache.get_feed(f, force = True) downloads_in_progress[f] = tasks.IdleBlocker('Refresh local feed') continue elif f.startswith('distribution:'): if force or update_local: downloads_in_progress[f] = self.fetcher.download_and_import_feed(f, self.config.iface_cache) elif force and self.network_use != network_offline: downloads_in_progress[f] = self.fetcher.download_and_import_feed(f, self.config.iface_cache) # Once we've starting downloading some things, # we might as well get them all. force = True if not downloads_in_progress: if self.network_use == network_offline: info(_("Can't choose versions and in off-line mode, so aborting")) break # Wait for at least one download to finish blockers = downloads_in_progress.values() yield blockers tasks.check(blockers, self.handler.report_error) for f in downloads_in_progress.keys(): if f in downloads_in_progress and downloads_in_progress[f].happened: del downloads_in_progress[f] downloads_finished.add(f) # Need to refetch any "distribution" feed that # depends on this one distro_feed_url = 'distribution:' + f if distro_feed_url in downloads_finished: downloads_finished.remove(distro_feed_url) if distro_feed_url in downloads_in_progress: del downloads_in_progress[distro_feed_url] @tasks.async def solve_and_download_impls(self, refresh = False, select_only = False): """Run L{solve_with_downloads} and then get the selected implementations too. @raise SafeException: if we couldn't select a set of implementations @since: 0.40""" refreshed = self.solve_with_downloads(refresh) if refreshed: yield refreshed tasks.check(refreshed) if not self.solver.ready: raise self.solver.get_failure_reason() if not select_only: downloaded = self.download_uncached_implementations() if downloaded: yield downloaded tasks.check(downloaded) def need_download(self): """Decide whether we need to download anything (but don't do it!) @return: true if we MUST download something (feeds or implementations) @rtype: bool""" host_arch = self.target_arch if self.requirements.source: host_arch = arch.SourceArchitecture(host_arch) self.solver.solve(self.root, host_arch, command_name = self.command) for w in self.watchers: w() if not self.solver.ready: return True # Maybe a newer version will work? if self.get_uncached_implementations(): return True return False def download_uncached_implementations(self): """Download all implementations chosen by the solver that are missing from the cache.""" assert self.solver.ready, "Solver is not ready!\n%s" % self.solver.selections return self.fetcher.download_impls([impl for impl in self.solver.selections.values() if not self.get_cached(impl)], self.config.stores) def download_icon(self, interface, force = False): """Download an icon for this interface and add it to the icon cache. If the interface has no icon or we are offline, do nothing. @return: the task doing the import, or None @rtype: L{tasks.Task}""" if self.network_use == network_offline: info("Not downloading icon for %s as we are off-line", interface) return modification_time = None existing_icon = self.config.iface_cache.get_icon_path(interface) if existing_icon: file_mtime = os.stat(existing_icon).st_mtime from email.utils import formatdate modification_time = formatdate(timeval = file_mtime, localtime = False, usegmt = True) return self.fetcher.download_icon(interface, force, modification_time) def get_interface(self, uri): """@deprecated: use L{iface_cache.IfaceCache.get_interface} instead""" import warnings warnings.warn("Policy.get_interface is deprecated!", DeprecationWarning, stacklevel = 2) return self.config.iface_cache.get_interface(uri) @property def command(self): return self.requirements.command @property def root(self): return self.requirements.interface_uri