Beispiel #1
0
    def providers_for(self, vpkg_spec):
        if self.provider_index is None:
            self.provider_index = ProviderIndex(self.all_package_names())

        providers = self.provider_index.providers_for(vpkg_spec)
        if not providers:
            raise UnknownPackageError("No such virtual package: %s" % vpkg_spec)
        return providers
Beispiel #2
0
class PackageDB(object):
    def __init__(self, root):
        """Construct a new package database from a root directory."""
        self.root = root
        self.instances = {}
        self.provider_index = None


    @_autospec
    def get(self, spec):
        if spec.virtual:
            raise UnknownPackageError(spec.name)

        if not spec in self.instances:
            package_class = self.get_class_for_package_name(spec.name)
            self.instances[spec.name] = package_class(spec)

        return self.instances[spec.name]


    @_autospec
    def get_installed(self, spec):
        """Get all the installed specs that satisfy the provided spec constraint."""
        return [s for s in self.installed_package_specs() if s.satisfies(spec)]


    @_autospec
    def providers_for(self, vpkg_spec):
        if self.provider_index is None:
            self.provider_index = ProviderIndex(self.all_package_names())

        providers = self.provider_index.providers_for(vpkg_spec)
        if not providers:
            raise UnknownPackageError("No such virtual package: %s" % vpkg_spec)
        return providers


    def dirname_for_package_name(self, pkg_name):
        """Get the directory name for a particular package.  This is the
           directory that contains its package.py file."""
        return join_path(self.root, pkg_name)


    def filename_for_package_name(self, pkg_name):
        """Get the filename for the module we should load for a particular
           package.  Packages for a pacakge DB live in
           ``$root/<package_name>/package.py``

           This will return a proper package.py path even if the
           package doesn't exist yet, so callers will need to ensure
           the package exists before importing.
        """
        validate_module_name(pkg_name)
        pkg_dir = self.dirname_for_package_name(pkg_name)
        return join_path(pkg_dir, _package_file_name)


    def installed_package_specs(self):
        """Read installed package names straight from the install directory
           layout.
        """
        return spack.install_layout.all_specs()


    @memoized
    def all_package_names(self):
        """Generator function for all packages.  This looks for
           ``<pkg_name>/package.py`` files within the root direcotry"""
        all_package_names = []
        for pkg_name in os.listdir(self.root):
            pkg_dir  = join_path(self.root, pkg_name)
            pkg_file = join_path(pkg_dir, _package_file_name)
            if os.path.isfile(pkg_file):
                all_package_names.append(pkg_name)
            all_package_names.sort()
        return all_package_names


    def all_packages(self):
        for name in self.all_package_names():
            yield self.get(name)


    def exists(self, pkg_name):
        """Whether a package with the supplied name exists ."""
        return os.path.exists(self.filename_for_package_name(pkg_name))


    @memoized
    def get_class_for_package_name(self, pkg_name):
        """Get an instance of the class for a particular package.

           This method uses Python's ``imp`` package to load python
           source from a Spack package's ``package.py`` file.  A
           normal python import would only load each package once, but
           because we do this dynamically, the method needs to be
           memoized to ensure there is only ONE package class
           instance, per package, per database.
        """
        file_path = self.filename_for_package_name(pkg_name)

        if os.path.exists(file_path):
            if not os.path.isfile(file_path):
                tty.die("Something's wrong. '%s' is not a file!" % file_path)
            if not os.access(file_path, os.R_OK):
                tty.die("Cannot read '%s'!" % file_path)
        else:
            raise UnknownPackageError(pkg_name)

        class_name = mod_to_class(pkg_name)
        try:
            module_name = _imported_packages_module + '.' + pkg_name
            module = imp.load_source(module_name, file_path)

        except ImportError, e:
            tty.die("Error while importing %s from %s:\n%s" % (
                pkg_name, file_path, e.message))

        cls = getattr(module, class_name)
        if not inspect.isclass(cls):
            tty.die("%s.%s is not a class" % (pkg_name, class_name))

        return cls