예제 #1
0
    def _entropy(self):
        """
        Return the Entropy Server instance object.
        """
        with self._real_entropy_lock:
            if self._real_entropy is None:
                try:
                    self._real_entropy = Server()
                except PermissionDenied as err:
                    raise EntropyBinaryPMS.BinaryPMSLoadError(err)

        return self._real_entropy
예제 #2
0
 def __init__(self, cwd, nsargs):
     """
     Constructor.
     """
     if nsargs.entropy_community:
         os.environ['ETP_COMMUNITY_MODE'] = "1"
     super(EntropyBinaryPMS, self).__init__(cwd, nsargs)
     try:
         self._entropy = Server()
     except PermissionDenied as err:
         raise EntropyBinaryPMS.BinaryPMSLoadError(err)
예제 #3
0
    def _entropy(self):
        """
        Return the Entropy Server instance object.
        """
        with self._real_entropy_lock:
            if self._real_entropy is None:
                try:
                    self._real_entropy = Server()
                except PermissionDenied as err:
                    raise EntropyBinaryPMS.BinaryPMSLoadError(err)

        return self._real_entropy
예제 #4
0
 def _entropy(self, *args, **kwargs):
     """
     Return the Entropy Server object.
     This method is not thread safe.
     """
     return Server(*args, **kwargs)
예제 #5
0
class EntropyBinaryPMS(BaseBinaryPMS):
    """
    Class implementing a Binary Package Manager
    System for Matter based on Entropy.
    """

    # Set myself as the default PMS
    DEFAULT = True
    NAME = "entropy"

    class BinaryPMSLoadError(BaseBinaryPMS.BinaryPMSLoadError):
        """ Raised when the BinaryPMS system cannot be initalized. """

    class SpecParserError(BaseBinaryPMS.SpecParserError):
        """ Raised when an invalid SpecParser object is found. """

    class SystemValidationError(BaseBinaryPMS.SystemValidationError):
        """ Raised when the System is not able to accept a Matter run. """

    class RepositoryCommitError(BaseBinaryPMS.RepositoryCommitError):
        """ Raised when a repository push fails. """

    class RepositoryPushError(BaseBinaryPMS.RepositoryPushError):
        """ Raised when a repository push fails. """

    @staticmethod
    def extend_parser(parser):
        """
        Extend Matter ArgumentParser with extra arguments specific
        to this class.
        """
        group = parser.add_argument_group("Entropy Binary PMS")
        group.add_argument(
            "--entropy-community",
            help="enable Community Repository mode",
            action="store_true")

    def __init__(self, cwd, nsargs):
        """
        Constructor.
        """
        if nsargs.entropy_community:
            os.environ['ETP_COMMUNITY_MODE'] = "1"
        super(EntropyBinaryPMS, self).__init__(cwd, nsargs)

        self._real_entropy = None
        self._real_entropy_lock = threading.Lock()

    @property
    def _entropy(self):
        """
        Return the Entropy Server instance object.
        """
        with self._real_entropy_lock:
            if self._real_entropy is None:
                try:
                    self._real_entropy = Server()
                except PermissionDenied as err:
                    raise EntropyBinaryPMS.BinaryPMSLoadError(err)

        return self._real_entropy

    def get_resource_lock(self, blocking):
        """
        Overridden from BaseBinaryPMS.
        """
        return EntropyResourceLock(blocking)

    def shutdown(self):
        """
        Overridden from BaseBinaryPMS.
        """
        with self._real_entropy_lock:
            if self._real_entropy is not None:
                self._real_entropy.shutdown()

    def validate_spec(self, spec):
        """
        Overridden from BaseBinaryPMS.
        """
        repositories = self._entropy.repositories()
        spec_repo = spec["repository"]
        if spec_repo not in repositories:
            raise EntropyBinaryPMS.SpecParserError(
                "invalid repository: %s" % (spec_repo,))

    def validate_system(self):
        """
        Overridden from BaseBinaryPMS.
        """
        super(EntropyBinaryPMS, self).validate_system()

        if self._nsargs.gentle:
            # check if there is something to do
            to_be_added, _to_be_removed, _to_be_injected = \
                self._entropy.scan_package_changes()
            if to_be_added: # only check this, others we can ignore
                to_be_added = [x[0] for x in to_be_added]
                to_be_added.sort()
                err_msg = "--gentle specified, and "
                err_msg += "unstaged packages found:\n"
                for name in to_be_added:
                    err_msg += "  %s\n" % (name,)
                raise EntropyBinaryPMS.SystemValidationError(err_msg)

            # also check for uncommitted configuration files changed
            problems = self._entropy._check_config_file_updates()
            if problems:
                err_msg = "some configuration files have "
                err_msg += "to be merged manually"
                raise EntropyBinaryPMS.SystemValidationError(err_msg)

    def best_available(self, package):
        """
        Overridden from BaseBinaryPMS.
        """
        package_id, repository_id = self._entropy.atom_match(package)
        if package_id == -1:
            return
        atom = self._entropy.open_repository(
            repository_id).retrieveAtom(package_id)
        # revert any entropy related mangling
        atom = entropy.dep.remove_tag(atom)
        return atom

    def _push_packages(self, repository):
        """
        Upload newly built packages.
        """
        (_mirrors_tainted, mirrors_errors,
         successfull_mirrors,
         _broken_mirrors, _check_data) = \
             self._entropy.Mirrors.sync_packages(
                 repository, ask=False, pretend=False)
        if mirrors_errors and not successfull_mirrors:
            return 1
        return 0

    def _push_repository(self, repository):
        """
        Update remote repository.
        """
        return self._entropy.Mirrors.sync_repository(repository)

    def _commit_build_only(self, spec, packages):
        """
        Commit packages that have been built with -B.
        Overridden from BaseBinaryPMS.
        """
        settings, _trees, _db = self.load_emerge_config()
        pkgdir = settings["PKGDIR"]
        repository = spec["repository"]
        drop_old_injected = spec["drop-old-injected"] == "yes"

        print_info("committing build-only packages: %s, to repository: %s" % (
            ", ".join(sorted(packages)), repository,))

        exit_st = 0
        package_files = []
        for package in packages:
            tbz2_atom = package + ".tbz2"
            source_path = os.path.join(pkgdir, tbz2_atom)
            if not os.path.isfile(source_path):
                print_warning(
                    "cannot find package tarball: %s" % (source_path,))
                exit_st = 1
                continue
            package_files.append(source_path)

        pkg_files = [([x], True) for x in package_files]
        package_ids = self._entropy.add_packages_to_repository(
            repository, pkg_files, ask=False)
        self._entropy.commit_repositories()

        if package_ids:

            # drop old injected packages if they are in the
            # same key + slot of the newly added ones.
            # This is not atomic, but we don't actually care.
            if drop_old_injected:
                repo = self._entropy.open_repository(repository)

                key_slots = set()
                for package_id in package_ids:
                    key, slot = repo.retrieveKeySlot(package_id)
                    key_slots.add((key, slot))

                key_slot_package_ids = set()
                for key, slot in key_slots:
                    ks_package_ids = [x for x in repo.searchKeySlot(key, slot) \
                                          if repo.isInjected(x)]
                    key_slot_package_ids.update(ks_package_ids)
                # remove the newly added packages, of course
                key_slot_package_ids -= package_ids
                key_slot_package_ids = sorted(key_slot_package_ids)
                if key_slot_package_ids:
                    print_info("removing old injected packages, "
                               "as per drop-old-injected:")
                    for package_id in key_slot_package_ids:
                        atom = repo.retrieveAtom(package_id)
                        print_info("  %s" % (atom,))
                    self._entropy.remove_packages(
                        repository, key_slot_package_ids)

            self._entropy.dependencies_test(repository)

        return exit_st

    def _commit(self, spec, packages):
        """
        Commit packages that have been merged into the system.
        Overridden from BaseBinaryPMS.
        """
        repository = spec["repository"]
        spm = self._entropy.Spm()
        spm_atoms = set()
        exit_st = 0

        print_info("committing packages: %s, to repository: %s" % (
            ", ".join(sorted(packages)), repository,))

        # if we get here, something has been compiled
        # successfully
        for package in packages:
            try:
                spm_atom = spm.match_installed_package(package)
                spm_atoms.add(spm_atom)
            except KeyError:
                exit_st = 1
                print_warning(
                    "cannot find installed package: %s" % (
                        package,))
                continue

        if not spm_atoms:
            return exit_st

        print_info("about to commit:")
        spm_packages = sorted(spm_atoms)

        for atom in spm_packages:
            item_txt = atom

            # this is a spm atom
            spm_key = portage.dep.dep_getkey("=%s" % (atom,))
            try:
                spm_slot = spm.get_installed_package_metadata(
                    atom, "SLOT")
                spm_repo = spm.get_installed_package_metadata(
                    atom, "repository")
            except KeyError:
                spm_slot = None
                spm_repo = None

            etp_repo = None
            if spm_repo is not None:
                pkg_id, repo_id = self._entropy.atom_match(spm_key,
                    match_slot = spm_slot)
                if repo_id != 1:
                    repo_db = self._entropy.open_repository(repo_id)
                    etp_repo = repo_db.retrieveSpmRepository(pkg_id)

                    if (etp_repo is not None) and (etp_repo != spm_repo):
                        item_txt += ' [%s {%s=>%s}]' % ("warning",
                            etp_repo, spm_repo,)

            print_info(item_txt)

        # always stuff new configuration files here
        # if --gentle was specified, the uncommitted stuff here belongs
        # to our packages.
        # if --gentle was NOT specified, we just don't give a shit
        # Due to bug #2480 -- sometimes (app-misc/tracker)
        # _check_config_file_updates() doesn't return all the files
        subprocess.call("echo -5 | etc-update", shell = True)
        uncommitted = self._entropy._check_config_file_updates()
        if uncommitted:
            # ouch, wtf? better aborting
            print_error("tried to commit configuration file changes and failed")
            return 1

        print_info("about to compress:")

        store_dir = self._entropy._get_local_store_directory(repository)
        package_paths = []
        for atom in spm_packages:
            print_info(atom)
            try:
                pkg_list = spm.generate_package(atom, store_dir)
            except OSError:
                print_traceback()
                print_error("problem during package generation, aborting")
                return 1
            except Exception:
                print_traceback()
                print_error("problem during package generation (2), aborting")
                return 1
            package_paths.append(pkg_list)

        etp_pkg_files = [(pkg_list, False) for pkg_list in package_paths]
        # NOTE: any missing runtime dependency will be added
        # (beside those blacklisted), since this execution is not interactive
        try:
            package_ids = self._entropy.add_packages_to_repository(
                repository, etp_pkg_files, ask=False)
        except OnlineMirrorError as err:
            print_traceback()
            print_error("problem during package commit: %s" % (err,))
            return 1

        self._entropy.commit_repositories()

        if package_ids:
            self._entropy.dependencies_test(repository)

        return exit_st

    def push(self, repository):
        """
        Overridden from BaseBinaryPMS.
        """
        exit_st = self._push_packages(repository)
        if exit_st != 0:
            raise EntropyBinaryPMS.RepositoryPushError(
                "ouch during packages push")

        exit_st = self._push_repository(repository)
        if exit_st != 0:
            raise EntropyBinaryPMS.RepositoryPushError(
                "ouch during repo push")
예제 #6
0
class EntropyBinaryPMS(BaseBinaryPMS):
    """
    Class implementing a Binary Package Manager
    System for Matter based on Entropy.
    """

    # Set myself as the default PMS
    DEFAULT = True
    NAME = "entropy"

    class BinaryPMSLoadError(BaseBinaryPMS.BinaryPMSLoadError):
        """ Raised when the BinaryPMS system cannot be initalized. """

    class SpecParserError(BaseBinaryPMS.SpecParserError):
        """ Raised when an invalid SpecParser object is found. """

    class SystemValidationError(BaseBinaryPMS.SystemValidationError):
        """ Raised when the System is not able to accept a Matter run. """

    class RepositoryCommitError(BaseBinaryPMS.RepositoryCommitError):
        """ Raised when a repository push fails. """

    class RepositoryPushError(BaseBinaryPMS.RepositoryPushError):
        """ Raised when a repository push fails. """

    @staticmethod
    def extend_parser(parser):
        """
        Extend Matter ArgumentParser with extra arguments specific
        to this class.
        """
        group = parser.add_argument_group("Entropy Binary PMS")
        group.add_argument("--entropy-community",
                           help="enable Community Repository mode",
                           action="store_true")

    def __init__(self, cwd, nsargs):
        """
        Constructor.
        """
        if nsargs.entropy_community:
            os.environ['ETP_COMMUNITY_MODE'] = "1"
        super(EntropyBinaryPMS, self).__init__(cwd, nsargs)

        self._real_entropy = None
        self._real_entropy_lock = threading.Lock()

    @property
    def _entropy(self):
        """
        Return the Entropy Server instance object.
        """
        with self._real_entropy_lock:
            if self._real_entropy is None:
                try:
                    self._real_entropy = Server()
                except PermissionDenied as err:
                    raise EntropyBinaryPMS.BinaryPMSLoadError(err)

        return self._real_entropy

    def get_resource_lock(self, blocking):
        """
        Overridden from BaseBinaryPMS.
        """
        return EntropyResourceLock(blocking)

    def shutdown(self):
        """
        Overridden from BaseBinaryPMS.
        """
        with self._real_entropy_lock:
            if self._real_entropy is not None:
                self._real_entropy.shutdown()

    def validate_spec(self, spec):
        """
        Overridden from BaseBinaryPMS.
        """
        repositories = self._entropy.repositories()
        spec_repo = spec["repository"]
        if spec_repo not in repositories:
            raise EntropyBinaryPMS.SpecParserError("invalid repository: %s" %
                                                   (spec_repo, ))

    def validate_system(self):
        """
        Overridden from BaseBinaryPMS.
        """
        super(EntropyBinaryPMS, self).validate_system()

        if self._nsargs.gentle:
            # check if there is something to do
            to_be_added, _to_be_removed, _to_be_injected = \
                self._entropy.scan_package_changes()
            if to_be_added:  # only check this, others we can ignore
                to_be_added = [x[0] for x in to_be_added]
                to_be_added.sort()
                err_msg = "--gentle specified, and "
                err_msg += "unstaged packages found:\n"
                for name in to_be_added:
                    err_msg += "  %s\n" % (name, )
                raise EntropyBinaryPMS.SystemValidationError(err_msg)

            # also check for uncommitted configuration files changed
            problems = self._entropy._check_config_file_updates()
            if problems:
                err_msg = "some configuration files have "
                err_msg += "to be merged manually"
                raise EntropyBinaryPMS.SystemValidationError(err_msg)

    def best_available(self, package):
        """
        Overridden from BaseBinaryPMS.
        """
        package_id, repository_id = self._entropy.atom_match(package)
        if package_id == -1:
            return
        atom = self._entropy.open_repository(repository_id).retrieveAtom(
            package_id)
        # revert any entropy related mangling
        atom = entropy.dep.remove_tag(atom)
        return atom

    def _push_packages(self, repository):
        """
        Upload newly built packages.
        """
        (_mirrors_tainted, mirrors_errors,
         successfull_mirrors,
         _broken_mirrors, _check_data) = \
             self._entropy.Mirrors.sync_packages(
                 repository, ask=False, pretend=False)
        if mirrors_errors and not successfull_mirrors:
            return 1
        return 0

    def _push_repository(self, repository):
        """
        Update remote repository.
        """
        return self._entropy.Mirrors.sync_repository(repository)

    def _commit_build_only(self, spec, packages):
        """
        Commit packages that have been built with -B.
        Overridden from BaseBinaryPMS.
        """
        settings, _trees, _db = self.load_emerge_config()
        pkgdir = settings["PKGDIR"]
        repository = spec["repository"]
        drop_old_injected = spec["drop-old-injected"] == "yes"

        print_info("committing build-only packages: %s, to repository: %s" % (
            ", ".join(sorted(packages)),
            repository,
        ))

        exit_st = 0
        package_files = []
        for package in packages:
            tbz2_atom = package + ".tbz2"
            source_path = os.path.join(pkgdir, tbz2_atom)
            if not os.path.isfile(source_path):
                print_warning("cannot find package tarball: %s" %
                              (source_path, ))
                exit_st = 1
                continue
            package_files.append(source_path)

        pkg_files = [([x], True) for x in package_files]
        package_ids = self._entropy.add_packages_to_repository(repository,
                                                               pkg_files,
                                                               ask=False)
        self._entropy.commit_repositories()

        if package_ids:

            # drop old injected packages if they are in the
            # same key + slot of the newly added ones.
            # This is not atomic, but we don't actually care.
            if drop_old_injected:
                repo = self._entropy.open_repository(repository)

                key_slots = set()
                for package_id in package_ids:
                    key, slot = repo.retrieveKeySlot(package_id)
                    key_slots.add((key, slot))

                key_slot_package_ids = set()
                for key, slot in key_slots:
                    ks_package_ids = [x for x in repo.searchKeySlot(key, slot) \
                                          if repo.isInjected(x)]
                    key_slot_package_ids.update(ks_package_ids)
                # remove the newly added packages, of course
                key_slot_package_ids -= package_ids
                key_slot_package_ids = sorted(key_slot_package_ids)
                if key_slot_package_ids:
                    print_info("removing old injected packages, "
                               "as per drop-old-injected:")
                    for package_id in key_slot_package_ids:
                        atom = repo.retrieveAtom(package_id)
                        print_info("  %s" % (atom, ))
                    self._entropy.remove_packages(repository,
                                                  key_slot_package_ids)

            self._entropy.dependencies_test(repository)

        return exit_st

    def _commit(self, spec, packages):
        """
        Commit packages that have been merged into the system.
        Overridden from BaseBinaryPMS.
        """
        repository = spec["repository"]
        spm = self._entropy.Spm()
        spm_atoms = set()
        exit_st = 0

        print_info("committing packages: %s, to repository: %s" % (
            ", ".join(sorted(packages)),
            repository,
        ))

        # if we get here, something has been compiled
        # successfully
        for package in packages:
            try:
                spm_atom = spm.match_installed_package(package)
                spm_atoms.add(spm_atom)
            except KeyError:
                exit_st = 1
                print_warning("cannot find installed package: %s" %
                              (package, ))
                continue

        if not spm_atoms:
            return exit_st

        print_info("about to commit:")
        spm_packages = sorted(spm_atoms)

        for atom in spm_packages:
            item_txt = atom

            # this is a spm atom
            spm_key = portage.dep.dep_getkey("=%s" % (atom, ))
            try:
                spm_slot = spm.get_installed_package_metadata(atom, "SLOT")
                spm_repo = spm.get_installed_package_metadata(
                    atom, "repository")
            except KeyError:
                spm_slot = None
                spm_repo = None

            etp_repo = None
            if spm_repo is not None:
                pkg_id, repo_id = self._entropy.atom_match(spm_key,
                                                           match_slot=spm_slot)
                if repo_id != 1:
                    repo_db = self._entropy.open_repository(repo_id)
                    etp_repo = repo_db.retrieveSpmRepository(pkg_id)

                    if (etp_repo is not None) and (etp_repo != spm_repo):
                        item_txt += ' [%s {%s=>%s}]' % (
                            "warning",
                            etp_repo,
                            spm_repo,
                        )

            print_info(item_txt)

        # always stuff new configuration files here
        # if --gentle was specified, the uncommitted stuff here belongs
        # to our packages.
        # if --gentle was NOT specified, we just don't give a shit
        # Due to bug #2480 -- sometimes (app-misc/tracker)
        # _check_config_file_updates() doesn't return all the files
        subprocess.call("echo -5 | etc-update", shell=True)
        uncommitted = self._entropy._check_config_file_updates()
        if uncommitted:
            # ouch, wtf? better aborting
            print_error(
                "tried to commit configuration file changes and failed")
            return 1

        print_info("about to compress:")

        store_dir = self._entropy._get_local_store_directory(repository)
        package_paths = []
        for atom in spm_packages:
            print_info(atom)
            try:
                pkg_list = spm.generate_package(atom, store_dir)
            except OSError:
                print_traceback()
                print_error("problem during package generation, aborting")
                return 1
            except Exception:
                print_traceback()
                print_error("problem during package generation (2), aborting")
                return 1
            package_paths.append(pkg_list)

        etp_pkg_files = [(pkg_list, False) for pkg_list in package_paths]
        # NOTE: any missing runtime dependency will be added
        # (beside those blacklisted), since this execution is not interactive
        try:
            package_ids = self._entropy.add_packages_to_repository(
                repository, etp_pkg_files, ask=False)
        except OnlineMirrorError as err:
            print_traceback()
            print_error("problem during package commit: %s" % (err, ))
            return 1

        self._entropy.commit_repositories()

        if package_ids:
            self._entropy.dependencies_test(repository)

        return exit_st

    def push(self, repository):
        """
        Overridden from BaseBinaryPMS.
        """
        exit_st = self._push_packages(repository)
        if exit_st != 0:
            raise EntropyBinaryPMS.RepositoryPushError(
                "ouch during packages push")

        exit_st = self._push_repository(repository)
        if exit_st != 0:
            raise EntropyBinaryPMS.RepositoryPushError("ouch during repo push")

        return exit_st

    def clear_cache(self):
        """
        Overridden from BaseBinaryPMS.
        """
        for repository_id in self._entropy.repositories():
            repo = self._entropy.open_repository(repository_id)
            repo.clearCache()