Example #1
0
    def download_selections(self, sels):
        """Download any missing implementations in the given selections.
		If no downloads are needed, but we haven't checked for a while, start
		a background process to check for updates (but return None immediately).
		@return: a blocker which resolves when all needed implementations are available
		@rtype: L{tasks.Blocker} | None
		"""
        # Check the selections are still available
        blocker = sels.download_missing(self.config)  # TODO: package impls

        if blocker:
            return blocker
        else:
            # Nothing to download, but is it time for a background update?
            timestamp_path = os.path.join(self.path, 'last-checked')
            try:
                utime = os.stat(timestamp_path).st_mtime
                staleness = time.time() - utime
                logger.info("Staleness of app %s is %d hours", self,
                            staleness / (60 * 60))
                freshness_threshold = self.config.freshness
                need_update = freshness_threshold > 0 and staleness >= freshness_threshold

                if need_update:
                    last_check_attempt_path = os.path.join(
                        self.path, 'last-check-attempt')
                    if os.path.exists(last_check_attempt_path):
                        last_check_attempt = os.stat(
                            last_check_attempt_path).st_mtime
                        if last_check_attempt + 60 * 60 > time.time():
                            logger.info(
                                "Tried to check within last hour; not trying again now"
                            )
                            need_update = False
            except Exception as ex:
                logger.warn("Failed to get time-stamp of %s: %s",
                            timestamp_path, ex)
                need_update = True

            if need_update:
                self.set_last_check_attempt()
                from zeroinstall.injector import background
                r = self.get_requirements()
                background.spawn_background_update2(r, False, self)
Example #2
0
    def download_selections(self, sels):
        """Download any missing implementations in the given selections.
		If no downloads are needed, but we haven't checked for a while, start
		a background process to check for updates (but return None immediately).
		@return: a blocker which resolves when all needed implementations are available
		@rtype: L{tasks.Blocker} | None
		"""
        # Check the selections are still available
        blocker = sels.download_missing(self.config)  # TODO: package impls

        if blocker:
            return blocker
        else:
            # Nothing to download, but is it time for a background update?
            timestamp_path = os.path.join(self.path, "last-checked")
            try:
                utime = os.stat(timestamp_path).st_mtime
                staleness = time.time() - utime
                logger.info("Staleness of app %s is %d hours", self, staleness / (60 * 60))
                freshness_threshold = self.config.freshness
                need_update = freshness_threshold > 0 and staleness >= freshness_threshold

                if need_update:
                    last_check_attempt_path = os.path.join(self.path, "last-check-attempt")
                    if os.path.exists(last_check_attempt_path):
                        last_check_attempt = os.stat(last_check_attempt_path).st_mtime
                        if last_check_attempt + 60 * 60 > time.time():
                            logger.info("Tried to check within last hour; not trying again now")
                            need_update = False
            except Exception as ex:
                logger.warn("Failed to get time-stamp of %s: %s", timestamp_path, ex)
                need_update = True

            if need_update:
                self.set_last_check_attempt()
                from zeroinstall.injector import background

                r = self.get_requirements()
                background.spawn_background_update2(r, False, self)
Example #3
0
	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
Example #4
0
	def _check_for_updates(self, sels):
		"""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.
		We also schedule a background update from time-to-time anyway.
		@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

		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)
				feed = iface_cache.get_feed(sel.feed)
				if not feed:
					raise IOError("Input %s missing; update" % sel.feed)
				else:
					if feed.local_path:
						yield feed.local_path
					else:
						yield (feed.url, feed.last_modified)

				# 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
		iface_cache = self.config.iface_cache
		try:
			for item in get_inputs():
				if not item: continue
				if isinstance(item, tuple):
					path, mtime = item
				else:
					path = item
					mtime = os.stat(path).st_mtime

				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 need_solve:
			from zeroinstall.injector.driver import Driver
			driver = Driver(config = self.config, requirements = self.get_requirements())
			if driver.need_download():
				# Continue with the current (hopefully cached) selections while we download
				need_update = True
			else:
				old_sels = sels
				sels = driver.solver.selections
				from zeroinstall.support import xmltools
				if not xmltools.nodes_equal(sels.toDOM(), old_sels.toDOM()):
					self.set_selections(sels, set_last_checked = False)
			self._touch('last-solve')

		# 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:
			self.set_last_check_attempt()
			from zeroinstall.injector import background
			r = self.get_requirements()
			background.spawn_background_update2(r, False, self)

		return sels
Example #5
0
    def _check_for_updates(self, sels):
        """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.
		We also schedule a background update from time-to-time anyway.
		@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

        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)
                feed = iface_cache.get_feed(sel.feed)
                if not feed:
                    raise IOError("Input %s missing; update" % sel.feed)
                else:
                    if feed.local_path:
                        yield feed.local_path
                    else:
                        yield (feed.url, feed.last_modified)

                # 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
        iface_cache = self.config.iface_cache
        try:
            for item in get_inputs():
                if not item: continue
                if isinstance(item, tuple):
                    path, mtime = item
                else:
                    path = item
                    mtime = os.stat(path).st_mtime

                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 need_solve:
            from zeroinstall.injector.driver import Driver
            driver = Driver(config=self.config,
                            requirements=self.get_requirements())
            if driver.need_download():
                # Continue with the current (hopefully cached) selections while we download
                need_update = True
            else:
                old_sels = sels
                sels = driver.solver.selections
                from zeroinstall.support import xmltools
                if not xmltools.nodes_equal(sels.toDOM(), old_sels.toDOM()):
                    self.set_selections(sels, set_last_checked=False)
            self._touch('last-solve')

        # 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:
            self.set_last_check_attempt()
            from zeroinstall.injector import background
            r = self.get_requirements()
            background.spawn_background_update2(r, False, self)

        return sels
Example #6
0
    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