Example #1
0
    def _compute_packages_changes(self):
        """Analyse changes in the universe of known packages.

        This method will verify if there are packages that:

        - are now installed, and were not;
        - are now available, and were not;
        - are now locked, and were not;
        - were previously available but are not anymore;
        - were previously installed but are not anymore;
        - were previously locked but are not anymore;

        Additionally it will report package locks that:

        - are now set, and were not;
        - were previously set but are not anymore;

        In all cases, the server is notified of the new situation
        with a "packages" message.

        @return: A deferred resulting in C{True} if package changes were
            detected with respect to the previous run, or C{False} otherwise.
        """
        self._facade.ensure_channels_reloaded()

        old_installed = set(self._store.get_installed())
        old_available = set(self._store.get_available())
        old_upgrades = set(self._store.get_available_upgrades())
        old_locked = set(self._store.get_locked())

        current_installed = set()
        current_available = set()
        current_upgrades = set()
        current_locked = set()

        for package in self._facade.get_packages():
            hash = self._facade.get_package_hash(package)
            id = self._store.get_hash_id(hash)
            if id is not None:
                if self._facade.is_package_installed(package):
                    current_installed.add(id)
                    if self._facade.is_package_available(package):
                        current_available.add(id)
                else:
                    current_available.add(id)

                # Are there any packages that this package is an upgrade for?
                if self._facade.is_package_upgrade(package):
                    current_upgrades.add(id)

        for package in self._facade.get_locked_packages():
            hash = self._facade.get_package_hash(package)
            id = self._store.get_hash_id(hash)
            if id is not None:
                current_locked.add(id)

        new_installed = current_installed - old_installed
        new_available = current_available - old_available
        new_upgrades = current_upgrades - old_upgrades
        new_locked = current_locked - old_locked

        not_installed = old_installed - current_installed
        not_available = old_available - current_available
        not_upgrades = old_upgrades - current_upgrades
        not_locked = old_locked - current_locked

        message = {}
        if new_installed:
            message["installed"] = \
                list(sequence_to_ranges(sorted(new_installed)))
        if new_available:
            message["available"] = \
                list(sequence_to_ranges(sorted(new_available)))
        if new_upgrades:
            message["available-upgrades"] = \
                list(sequence_to_ranges(sorted(new_upgrades)))
        if new_locked:
            message["locked"] = \
                list(sequence_to_ranges(sorted(new_locked)))

        if not_installed:
            message["not-installed"] = \
                list(sequence_to_ranges(sorted(not_installed)))
        if not_available:
            message["not-available"] = \
                list(sequence_to_ranges(sorted(not_available)))
        if not_upgrades:
            message["not-available-upgrades"] = \
                list(sequence_to_ranges(sorted(not_upgrades)))
        if not_locked:
            message["not-locked"] = \
                list(sequence_to_ranges(sorted(not_locked)))

        if not message:
            return succeed(False)

        message["type"] = "packages"
        result = self.send_message(message)

        logging.info("Queuing message with changes in known packages: "
                     "%d installed, %d available, %d available upgrades, "
                     "%d locked, %d not installed, %d not available, "
                     "%d not available upgrades, %d not locked."
                     % (len(new_installed), len(new_available),
                        len(new_upgrades), len(new_locked),
                        len(not_installed), len(not_available),
                        len(not_upgrades), len(not_locked)))

        def update_currently_known(result):
            if new_installed:
                self._store.add_installed(new_installed)
            if not_installed:
                self._store.remove_installed(not_installed)
            if new_available:
                self._store.add_available(new_available)
            if new_locked:
                self._store.add_locked(new_locked)
            if not_available:
                self._store.remove_available(not_available)
            if new_upgrades:
                self._store.add_available_upgrades(new_upgrades)
            if not_upgrades:
                self._store.remove_available_upgrades(not_upgrades)
            if not_locked:
                self._store.remove_locked(not_locked)
            # Something has changed wrt the former run, let's update the
            # timestamp and return True.
            stamp_file = self._config.detect_package_changes_stamp
            touch_file(stamp_file)
            return True

        result.addCallback(update_currently_known)

        return result
Example #2
0
    def _compute_packages_changes(self):
        """Analyse changes in the universe of known packages.

        This method will verify if there are packages that:

        - are now installed, and were not;
        - are now available, and were not;
        - are now locked, and were not;
        - were previously available but are not anymore;
        - were previously installed but are not anymore;
        - were previously locked but are not anymore;

        Additionally it will report package locks that:

        - are now set, and were not;
        - were previously set but are not anymore;

        Also, packages coming from the security pocket will be
        reported as such.

        In all cases, the server is notified of the new situation
        with a "packages" message.

        @return: A deferred resulting in C{True} if package changes were
            detected with respect to the previous run, or C{False} otherwise.
        """
        self._facade.ensure_channels_reloaded()

        old_installed = set(self._store.get_installed())
        old_available = set(self._store.get_available())
        old_upgrades = set(self._store.get_available_upgrades())
        old_locked = set(self._store.get_locked())
        old_autoremovable = set(self._store.get_autoremovable())
        old_security = set(self._store.get_security())

        current_installed = set()
        current_available = set()
        current_upgrades = set()
        current_locked = set()
        current_autoremovable = set()
        current_security = set()
        lsb = parse_lsb_release(LSB_RELEASE_FILENAME)
        backports_archive = "{}-backports".format(lsb["code-name"])
        security_archive = "{}-security".format(lsb["code-name"])

        for package in self._facade.get_packages():
            # Don't include package versions from the official backports
            # archive. The backports archive is enabled by default since
            # xenial with a pinning policy of 100. Ideally we would
            # support pinning, but we don't yet. In the mean time, we
            # ignore backports, so that packages don't get automatically
            # upgraded to the backports version.
            backport_origins = [
                origin for origin in package.origins
                if origin.archive == backports_archive]
            if backport_origins and (
                    len(backport_origins) == len(package.origins)):
                # Ignore the version if it's only in the official
                # backports archive. If it's somewhere else as well,
                # e.g. a PPA, we assume it was added manually and the
                # user wants to get updates from it.
                continue
            hash = self._facade.get_package_hash(package)
            id = self._store.get_hash_id(hash)
            if id is not None:
                if self._facade.is_package_installed(package):
                    current_installed.add(id)
                    if self._facade.is_package_available(package):
                        current_available.add(id)
                    if self._facade.is_package_autoremovable(package):
                        current_autoremovable.add(id)
                else:
                    current_available.add(id)

                # Are there any packages that this package is an upgrade for?
                if self._facade.is_package_upgrade(package):
                    current_upgrades.add(id)

                # Is this package present in the security pocket?
                security_origins = any(
                    origin for origin in package.origins
                    if origin.archive == security_archive)
                if security_origins:
                    current_security.add(id)

        for package in self._facade.get_locked_packages():
            hash = self._facade.get_package_hash(package)
            id = self._store.get_hash_id(hash)
            if id is not None:
                current_locked.add(id)

        new_installed = current_installed - old_installed
        new_available = current_available - old_available
        new_upgrades = current_upgrades - old_upgrades
        new_locked = current_locked - old_locked
        new_autoremovable = current_autoremovable - old_autoremovable
        new_security = current_security - old_security

        not_installed = old_installed - current_installed
        not_available = old_available - current_available
        not_upgrades = old_upgrades - current_upgrades
        not_locked = old_locked - current_locked
        not_autoremovable = old_autoremovable - current_autoremovable
        not_security = old_security - current_security

        message = {}
        if new_installed:
            message["installed"] = \
                list(sequence_to_ranges(sorted(new_installed)))
        if new_available:
            message["available"] = \
                list(sequence_to_ranges(sorted(new_available)))
        if new_upgrades:
            message["available-upgrades"] = \
                list(sequence_to_ranges(sorted(new_upgrades)))
        if new_locked:
            message["locked"] = \
                list(sequence_to_ranges(sorted(new_locked)))

        if new_autoremovable:
            message["autoremovable"] = list(
                sequence_to_ranges(sorted(new_autoremovable)))
        if not_autoremovable:
            message["not-autoremovable"] = list(
                sequence_to_ranges(sorted(not_autoremovable)))

        if new_security:
            message["security"] = list(
                sequence_to_ranges(sorted(new_security)))
        if not_security:
            message["not-security"] = list(
                sequence_to_ranges(sorted(not_security)))

        if not_installed:
            message["not-installed"] = \
                list(sequence_to_ranges(sorted(not_installed)))
        if not_available:
            message["not-available"] = \
                list(sequence_to_ranges(sorted(not_available)))
        if not_upgrades:
            message["not-available-upgrades"] = \
                list(sequence_to_ranges(sorted(not_upgrades)))
        if not_locked:
            message["not-locked"] = \
                list(sequence_to_ranges(sorted(not_locked)))

        if not message:
            return succeed(False)

        message["type"] = "packages"
        result = self.send_message(message)

        logging.info(
            "Queuing message with changes in known packages: "
            "%(installed)d installed, %(available)d available, "
            "%(upgrades)d available upgrades, %(locked)d locked, "
            "%(auto)d autoremovable, %(security)d security, "
            "%(not_installed)d not installed, "
            "%(not_available)d not available, "
            "%(not_upgrades)d not available upgrades, "
            "%(not_locked)d not locked, "
            "%(not_auto)d not autoremovable, "
            "%(not_security)d not security.",
            dict(
                installed=len(new_installed), available=len(new_available),
                upgrades=len(new_upgrades), locked=len(new_locked),
                auto=len(new_autoremovable), not_installed=len(not_installed),
                not_available=len(not_available),
                not_upgrades=len(not_upgrades), not_locked=len(not_locked),
                not_auto=len(not_autoremovable), security=len(new_security),
                not_security=len(not_security)))

        def update_currently_known(result):
            if new_installed:
                self._store.add_installed(new_installed)
            if not_installed:
                self._store.remove_installed(not_installed)
            if new_available:
                self._store.add_available(new_available)
            if new_locked:
                self._store.add_locked(new_locked)
            if new_autoremovable:
                self._store.add_autoremovable(new_autoremovable)
            if not_available:
                self._store.remove_available(not_available)
            if new_upgrades:
                self._store.add_available_upgrades(new_upgrades)
            if not_upgrades:
                self._store.remove_available_upgrades(not_upgrades)
            if not_locked:
                self._store.remove_locked(not_locked)
            if not_autoremovable:
                self._store.remove_autoremovable(not_autoremovable)
            if new_security:
                self._store.add_security(new_security)
            if not_security:
                self._store.remove_security(not_security)
            # Something has changed wrt the former run, let's update the
            # timestamp and return True.
            stamp_file = self._config.detect_package_changes_stamp
            touch_file(stamp_file)
            return True

        result.addCallback(update_currently_known)

        return result
 def test_three_elements(self):
     self.assertEqual(list(sequence_to_ranges([1, 2, 3])), [(1, 3)])
 def test_many_elements(self):
     sequence = [1, 2, 15, 16, 17, 19, 21, 22, 23, 24, 26, 27]
     self.assertEqual(list(sequence_to_ranges(sequence)),
                      [1, 2, (15, 17), 19, (21, 24), 26, 27])
 def test_two_elements(self):
     self.assertEqual(list(sequence_to_ranges([1, 2])), [1, 2])
 def test_one_element(self):
     self.assertEqual(list(sequence_to_ranges([1])), [1])
 def test_empty(self):
     self.assertEqual(list(sequence_to_ranges([])), [])
 def test_duplicated_item(self):
     self.assertRaises(SequenceError, next, sequence_to_ranges([1, 1]))
 def test_out_of_order(self):
     self.assertRaises(SequenceError, next, sequence_to_ranges([2, 1]))