Example #1
0
    def accept(self, source):
        val = source.pop_word(self)

        if ':' in val:
            try:
                (pkgname, vers) = pinfo.parse_package_version_spec(val)
                return (pkgname, vers)
            except:
                raise CommandError('Invalid package name: ' + val)

        try:
            pinfo.parse_package_name(val)
        except:
            raise CommandError('Invalid package name: ' + val)

        pkgname = val
        val = None
        vers = None

        if not source.is_empty():
            val = source.pop_word(self)
            try:
                vers = Version(val)
            except InvalidVersion:
                if self.greedy:
                    raise CommandError('Invalid version number: ' + val)
                if not (val is None):
                    source.push_word(val)
        return (pkgname, vers)
Example #2
0
 def accept(self, source):
     val = source.pop_word(self)
     try:
         pinfo.parse_package_name(val)
     except:
         raise CommandError('Invalid package name: ' + val)
     return val
Example #3
0
    def discover_all_groups(self):
        """discover_all_groups() -> None

        Search through the collection directory, and load all the PackageGroups
        that are available.

        This only searches the on-disk directory the first time you call
        it. To force it to re-scan the directory, call clear_cache() first.
        """
        
        if (self.collection_scanned):
            return

        # This is a little tricky. We go through the collection tree, but
        # we also have to go through the external directory list. (Because
        # there might be some external packages that do not correspond
        # to any group in the collection tree.)
            
        dirlist = os.listdir(self.collecdir)
        for key in dirlist:
            if (key.startswith('.')):
                continue
            dirname = os.path.join(self.collecdir, key)
            # Directories might appear to have upper-case names, but
            # the group name must be lower-case. (This will fail to load
            # an upper-case directory on a case-sensitive filesystem. It
            # will work in a case-preserving filesystem.)
            key = key.lower()
            if (not os.path.isdir(dirname)):
                continue
            try:
                parse_package_name(key)
                self.load_group(key)
            except:
                continue

        # Go through the external directory list. If the external package
        # is not already in a loaded group, load its group. (The load_group
        # method is smart enough to find it, even though there is no
        # matching directory in the collection tree.)

        for (name, vers) in self.external_dirs.keys():
            if (not self.package_groups.has_key(name)):
                try:
                    self.load_group(name)
                except:
                    continue

        # Now we never need to do this again. (Until the cache is cleared.)
        self.collection_scanned = True
Example #4
0
    def accept(self, source):
        val = source.pop_word(self)

        if ':' in val and not (val.startswith('/') or val.startswith('\\')
                               or val.startswith('.')):
            pos = val.find(':')
            dotpos = val.find('.')
            if dotpos < 0 or dotpos > pos:
                return (collect.Source_URL, val)

        if val.endswith('.zip') or val.endswith(collect.Suffix_PackageArchive):
            return (collect.Source_FILE, val)

        if ':' in val:
            try:
                (pkgname, vers) = pinfo.parse_package_version_spec(val)
                return (collect.Source_PACKAGE, (pkgname, vers))
            except:
                pass

        try:
            pinfo.parse_package_name(val)
        except:
            return (collect.Source_FILE, val)

        pkgname = val
        val = None
        vers = None

        if not source.is_empty():
            val = source.pop_word(self)
            try:
                vers = Version(val)
            except InvalidVersion:
                if self.greedy:
                    raise CommandError('Invalid version number: ' + val)
                if not (val is None):
                    source.push_word(val)
        return (collect.Source_PACKAGE, (pkgname, vers))
Example #5
0
    def test_parse_package_name(self):
        valid_list = [
            ('hello', ['hello']),
            ('h.e.l.l.o', ['h', 'e', 'l', 'l', 'o']),
            ('x_00t_99', ['x_00t_99']),
            ('t0.t1', ['t0', 't1']),
            ('_._005_.a', ['_', '_005_', 'a']),
        ]
        invalid_list = [
            '',
            ' ',
            '.',
            'a.',
            '.b',
            '.c.',
            'd..e',
            '..',
            'x ',
            ' y',
            'a b',
            'a. b',
            'a .b',
            '0',
            '0x',
            'a.0',
            'x.y.9z',
            'A',
            'Hello',
            'hello.There',
            'olleH',
            'a,b',
            'a-b',
            'a+b',
            'a/b',
            'a\\b',
        ]

        for (name, result) in valid_list:
            res = parse_package_name(name)
            self.assertEqual(res, result)

        for name in invalid_list:
            self.assertRaises(ValueError, parse_package_name, name)
Example #6
0
    def add_external_package(self, dirname, metadata=None, resources=None):
        """add_external_package(dirname, metadata=None, resources=None) ->
            (str, VersionNumber)

        Add an external directory to load a package from. The argument
        must be a complete (unpacked) Boodler directory, with a
        Metadata file. That package will then be loadable (possibly
        hiding a package in the collection directory).

        The metadata and resources fields, if supplied, override the 
        Metadata and Resources files in the directory. (The files do not
        even have to exist.) If the metadata and resources fields are
        None, the directory's files are checked as usual. (This override
        feature is used by the package creation tool. It should not be
        used for any other purpose.)

        Returns the name and version of the package that was found.

        Since this changes the set of what packages are available,
        it implicitly invokes clear_cache().

        The external package facility is not intended to be how most
        packages are loaded. Most packages should be in the collection
        directory. You might add an external package in your development
        workspace (while developing a soundscape), or in a temporary
        download directory (while deciding whether to install a newly-
        downloaded package).
        """

        label = '<external '+dirname+'>'
        exrec = ExternalDir(dirname, metadata, resources)

        if (not os.path.isdir(dirname)):
            raise PackageLoadError(label,
                'not a directory')

        # Load the metadata file, and see what package/version we are
        # dealing with. (But only if a metadata object wasn't handed to
        # us!)

        if (not metadata):
            metadatafile = os.path.join(dirname, Filename_Metadata)
            if (not os.path.isfile(metadatafile)):
                raise PackageLoadError(label,
                    'package has no metadata file')
        
            fl = open(metadatafile, 'rbU')
            try:
                metadata = boopak.pinfo.Metadata(label, fl)
            finally:
                fl.close()

        val = metadata.get_one('boodler.package')
        if (not val):
            raise PackageLoadError(label,
                'no boodler.package metadata entry')
        parse_package_name(val)
        pkgname = str(val)
        
        val = metadata.get_one('boodler.version')
        if (not val):
            vers = version.VersionNumber()
        else:
            vers = version.VersionNumber(val)

        # Add this to the external directory table. (We have not actually
        # loaded the package.)

        self.external_dirs[(pkgname, vers)] = exrec
        self.clear_cache()
        return (pkgname, vers)
Example #7
0
    def load_specific(self, pkgname, vers):
        """load_specific(pkgname, vers) -> PackageInfo

        Load a package, given its name and a specific version number.
        (The version number may be a VersionNumber or a string that
        can be converted to one.)

        This is an internal call; external callers should use load().

        (load_specific() is intended to be called by a package
        function which has already consulted package_groups and a
        PackageGroup object. If you bypass those, you might load
        a package which is not part of any PackageGroup. That would
        leave the cache in a confusing state.)
        """
        
        if (type(vers) in [str, unicode]):
            vers = version.VersionNumber(vers)
            
        pkg = self.packages.get( (pkgname, vers) )
        if (pkg):
            return pkg

        # Make sure the name is valid.
        parse_package_name(pkgname)
        pkgname = str(pkgname)

        exrec = self.external_dirs.get( (pkgname, vers) )
        if (exrec is None):
            is_external = False
            dirname = self.generate_package_path(pkgname, vers)
        else:
            is_external = True
            dirname = exrec.dirname

        # dirname is now the directory where the package should reside.
        # This may be in the collection or external.
            
        if (not os.path.isdir(dirname)):
            raise PackageNotFoundError(pkgname,
                'package version directory does not exist')

        # Read the metadata. (But if the external directory record has
        # an overriding Metadata object, use that instead.)

        if (is_external and exrec.metadata):
            metadata = exrec.metadata
        else:
            metadatafile = os.path.join(dirname, Filename_Metadata)
            if (not os.path.isfile(metadatafile)):
                raise PackageLoadError(pkgname,
                    'package has no metadata file')

            fl = open(metadatafile, 'rbU')
            try:
                metadata = boopak.pinfo.Metadata(pkgname, fl)
            finally:
                fl.close()

        # Read the resources (if there are any). Again, there may be an
        # overriding Resources object.

        if (is_external and exrec.resources):
            resources = exrec.resources
        else:
            resourcesfile = os.path.join(dirname, Filename_Resources)
            if (os.path.isfile(resourcesfile)):
                fl = open(resourcesfile, 'rbU')
                try:
                    resources = boopak.pinfo.Resources(pkgname, fl)
                finally:
                    fl.close()
            else:
                # Create an empty resources object
                resources = boopak.pinfo.Resources(pkgname)

        # Create the PackageInfo object and look through its metadata.
        pkg = PackageInfo(self, pkgname, vers, dirname,
            metadata, resources, is_external)
        pkg.validate_metadata()

        # Valid; we can now add it to the cache.
        self.packages[(pkgname, vers)] = pkg
        self.package_names[pkg.encoded_name] = pkg
        return pkg
Example #8
0
    def load_group(self, pkgname):
        """load_group(self, pkgname) -> PackageGroup

        Load a PackageGroup, given its package name.

        This is not tremendously useful for outside users, although you
        can call it if you want. A PackageGroup represents all the
        available versions of a particular package.
        """
        
        pgroup = self.package_groups.get(pkgname)
        if (pgroup):
            return pgroup

        # Make sure the name is valid.
        parse_package_name(pkgname)
        pkgname = str(pkgname)

        dirname = None
        versionfile = None

        # We determine the list of available versions by listing the
        # package directory in the collection tree. But we have to include
        # any versions that come in through external directories, too.
        
        # Create a list of external versions.
        external_versions = []
        for (name, vers) in self.external_dirs.keys():
            if (pkgname == name):
                external_versions.append(vers)

        # Find the package directory. (But it's possible that there *is*
        # no package directory. That's an error, unless we have external
        # versions -- in which case we keep trucking forward with the
        # dirname set to None.)

        dirname = self.generate_package_path(pkgname)
        if (not os.path.isdir(dirname)):
            if (not external_versions):
                raise PackageNotFoundError(pkgname,
                    'package directory does not exist')
            dirname = None

        # Open the Versions file in the package directory. (If we have
        # a package directory, and a Versions file.)

        if (dirname):
            versionfile = os.path.join(dirname, Filename_Versions)
            if (not os.path.isfile(versionfile)):
                # We don't raise an exception here, because the install
                # command needs to tolerate a screwy Collection long
                # enough to fix it.
                versionfile = None

        # Create the PackageGroup object itself.
        pgroup = PackageGroup(self, pkgname, dirname)

        fl = None
        try:
            if (dirname and versionfile):
                fl = open(versionfile, 'rbU')
            # Go through the Versions file and the external versions list
            # (either of which may be nonexistent).
            pgroup.discover_versions(fl, external_versions)
        finally:
            if (not (fl is None)):
                fl.close()

        # Add the new group to the cache.
        self.package_groups[pkgname] = pgroup
        return pgroup