[Zope-CVS] SVN: zpkgtools/branches/fdrake-zconfig-branch/ snapshot: almost there, but not all the tests are passing

Fred L. Drake, Jr. fdrake at gmail.com
Tue Aug 30 01:08:17 EDT 2005


Log message for revision 38153:
  snapshot: almost there, but not all the tests are passing

Changed:
  _U  zpkgtools/branches/fdrake-zconfig-branch/
  U   zpkgtools/branches/fdrake-zconfig-branch/zpkgsetup/cfgparser.py
  U   zpkgtools/branches/fdrake-zconfig-branch/zpkgsetup/package.py
  A   zpkgtools/branches/fdrake-zconfig-branch/zpkgsetup/package.xml
  D   zpkgtools/branches/fdrake-zconfig-branch/zpkgsetup/tests/test_cfgparser.py
  U   zpkgtools/branches/fdrake-zconfig-branch/zpkgsetup/urlutils.py
  U   zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/config.py
  A   zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/config.xml
  U   zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/include.py
  A   zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/include.xml
  U   zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/locationmap.py
  U   zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/tests/test_include.py

-=-

Property changes on: zpkgtools/branches/fdrake-zconfig-branch
___________________________________________________________________
Name: svn:externals
   + ZConfig  svn://svn.zope.org/repos/main/ZConfig/trunk


Modified: zpkgtools/branches/fdrake-zconfig-branch/zpkgsetup/cfgparser.py
===================================================================
--- zpkgtools/branches/fdrake-zconfig-branch/zpkgsetup/cfgparser.py	2005-08-30 05:06:48 UTC (rev 38152)
+++ zpkgtools/branches/fdrake-zconfig-branch/zpkgsetup/cfgparser.py	2005-08-30 05:08:16 UTC (rev 38153)
@@ -1,360 +1,154 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Extra-lite parser for a `ZConfig`_-like configuration syntax.
+"""Configuration parsing based on ZConfig instead of the bastard parser.
 
-There is no support for external schemas; schemas are simpler and must
-be specified using Python data structures.
-
-There is no support for any %-directives, but dollar signs in values
-must be doubled to ensure compatibility with `ZConfig`_.
-
-.. _ZConfig:  http://www.zope.org/Members/fdrake/zconfig/
-
 """
+__docformat__ = "reStructuredText"
 
-import re
+import os
+import sys
 
+import ZConfig.cfgparser
+import ZConfig.cmdline
+import ZConfig.datatypes
+import ZConfig.loader
 
-class ConfigurationError(Exception):
-    """Exception raised for errors in a configuration file.
+from ZConfig import ConfigurationError
 
-    :ivar url: URL of the resource being read when the error was
-      detected.
 
-    :ivar lineno: Line number within the resource at which the
-      error was detected.
+# This is new:
 
-    """
+def cachedSchemaLoader(filename="schema.xml", package=None):
+    if package is None:
+        frame = sys._getframe(1)
+        __path__ = _get_path_from_frame(frame)
+    elif package == "":
+        __path__ = sys.path
+    else:
+        __import__(package)
+        __path__ = sys.modules[package].__path__
 
-    def __init__(self, message, url=None, lineno=None):
-        """Initialize the ConfigurationError instance.
+    cache = []
+    def loadSchemaCache():
+        if cache:
+            return cache[0]
+        for p in __path__:
+            path = os.path.join(p, filename)
+            if os.path.isfile(path):
+                schema = loadSchema(path)
+                cache.append(schema)
+                return schema
+        raise ValueError("could not locate schema %r for package %r (path=%r)"
+                         % (filename, package, __path__))
 
-        :param message: Text of the error message.
+    return loadSchemaCache
 
-        :param url: URL of the resource being read when the error was
-          detected.
+def _get_path_from_frame(frame):
+    globs = frame.f_globals
+    if "__path__" in globs:
+        return globs["__path__"]
+    path = globs.get("__file__")
+    module = globs.get("__name__")
+    if (path and module):
+        dir, fn = os.path.split(path)
+        fnbase, ext = os.path.splitext(fn)
+        if "." in module and fnbase == "__init__":
+            package = module[:module.rindex(".")]
+            return sys.modules[package].__path__
+    if "." in module:
+        # the module is likely still being imported for the first
+        # time; just drop the module name and check the package
+        package = module[:module.rindex(".")]
+        return sys.modules[package].__path__
+    return sys.path
 
-        :param lineno: Line number within the resource at which the
-          error was detected.
 
-        """
-        Exception.__init__(self, message)
-        self.url = url
-        self.lineno = lineno
 
-    def __str__(self):
-        s = Exception.__str__(self)
-        if self.url:
-            s = "%s\n(%s" % (s, self.url)
-            if self.lineno is not None:
-                s = "%s, line %s" % (s, self.lineno)
-            s += ")"
-        return s
 
+def loadSchema(url):
+    return SchemaLoader().loadURL(url)
 
-class Schema:
-    """Schema definition that can be used by the Parser class to
-    construct a configuration.
+def loadSchemaFile(file, url=None):
+    return SchemaLoader().loadFile(file, url)
 
-    The definition is defined as a set of *type definitions*.  Each
-    type definition is a triple containing a dictionary, a list, and a
-    function (or `None`).  The dictionary maps the names of the keys
-    allowed in the section to conversion functions for the values (or
-    None if no conversion is required).  The list names the section
-    types which can occur in the section.  The function is used to
-    convert a `SectionValue` representing the collected values to the
-    actual value of the section itself; if `None` is used, no
-    conversion is performed.
+def loadConfig(schema, url, overrides=()):
+    return _get_config_loader(schema, overrides).loadURL(url)
 
-    """
+def loadConfigFile(schema, file, url=None, overrides=()):
+    return _get_config_loader(schema, overrides).loadFile(file, url)
 
-    def __init__(self, toplevel, typedefs=None):
-        """Initialize a schema definition based on type definitions.
 
-        :param toplevel: Type definition that represents the otherwise
-          anonymous top-level section of a configuration.
+def _get_config_loader(schema, overrides):
+    if overrides:
+        loader = ExtendedConfigLoader(schema)
+        for opt in overrides:
+            loader.addOption(opt)
+    else:
+        loader = ConfigLoader(schema)
+    return loader
 
-        :param typedefs: Mapping from typenames (which must be given
-          as lower-case strings) to type definitions.  Only section
-          types specified in `typedefs` can be used anywhere in
-          configurations described by the schema.
 
-        """
-        self._toplevel = toplevel
-        if typedefs is None:
-            typedefs = {}
-        self._typedefs = typedefs
+# These classes override enough to get case-sensitive behavior by default; 
 
-    def getConfiguration(self):
-        """Return a configuration object for the top-level section.
+class Parser(ZConfig.cfgparser.ZConfigParser):
+    """ZConfig-parser that doesn't lower-case section types and names."""
 
-        :return: New configuration object.
+    def _normalize_case(self, string):
+        return string
 
-        The attributes of the configuration object represent values
-        that have not been specified in a configuration file; these
-        will be filled in during parsing.
-        """
-        return self.createSection(None, None, self._toplevel)
 
-    def startSection(self, parent, typename, name):
-        # make sure typename is defined:
-        typedef = self._typedefs.get(typename)
-        if typedef is None:
-            raise ConfigurationError("unknown section type: %s" % typename)
-        # make sure typename is allowed:
-        x, sects, x = parent.getSectionDefinition()
-        if typename not in sects:
-            parent_type = parent.getSectionType()
-            if parent_type:
-                msg = ("%r sections not allowed in %r sections"
-                       % (typename, parent_type))
-            else:
-                msg = "%r sections not allowed" % typename
-            raise ConfigurationError(msg)
-        return self.createSection(name, typename, typedef)
+class BasicKeyConversion(ZConfig.datatypes.BasicKeyConversion):
+    """Alternate basic-key type that does no case-normalizing."""
 
-    def createSection(self, name, typename, typedef):
-        child = SectionValue(name, typename, typedef)
-        keys, sects, x = typedef
-        # initialize the defaults:
-        for name in keys:
-            name = name.lower().replace("-", "_")
-            setattr(child, name, [])
-        for name in sects:
-            name = name.lower().replace("-", "_")
-            setattr(child, name, [])
-        return child
+    def __call__(self, value):
+        value = str(value)
+        return ZConfig.datatypes.RegularExpressionConversion.__call__(
+            self, value)
 
-    def finishSection(self, section):
-        x, x, datatype = section.getSectionDefinition()
-        if datatype is not None:
-            typename = section.getSectionType()
-            try:
-                section = datatype(section)
-            except ValueError, e:
-                raise ConfigurationError(
-                    "could not convert %r section value: %s"
-                    % (typename, e))
-        return section
 
-    def endSection(self, parent, typename, name, child):
-        value = self.finishSection(child)
-        getattr(parent, typename).append(value)
+def SchemaLoader(registry=None):
+    if registry is None:
+        registry = ZConfig.datatypes.Registry()
+        registry._stock["basic-key"] = BasicKeyConversion()
+    return ZConfig.loader.SchemaLoader(registry)
 
-    def addValue(self, section, key, value):
-        keys, x, x = section.getSectionDefinition()
-        keyname = key.lower()
-        if keyname not in keys:
-            typename = section.getSectionType()
-            if typename:
-                msg = "key %r not defined in %r sections" % (key, typename)
-            else:
-                msg = "key %r not defined" % key
-            raise ConfigurationError(msg)
-        datatype = keys[keyname]
-        if datatype is not None:
-            try:
-                value = datatype(value)
-            except ValueError, e:
-                raise ConfigurationError("could not convert value: %s" % e)
-        attrname = keyname.replace("-", "_")
-        getattr(section, attrname).append(value)
 
+class ConfigLoaderMixin:
 
-# These regular expressions should match the corresponding definitions
-# in ZConfig.cfgparser since this needs to be a format that could be
-# read by ZConfig with an appropriate schema definition.
-#
-_name_re = r"[^\s()]+"
-_keyvalue_rx = re.compile(r"(?P<key>%s)\s*(?P<value>[^\s].*)?$"
-                          % _name_re)
-_section_start_rx = re.compile(r"(?P<type>%s)"
-                               r"(?:\s+(?P<name>%s))?"
-                               r"$"
-                               % (_name_re, _name_re))
+    def _parse_resource(self, matcher, resource, defines=None):
+        parser = Parser(resource, self, defines)
+        parser.parse(matcher)
 
-_nulljoin = "".join
 
+class ConfigLoader(ConfigLoaderMixin, ZConfig.loader.ConfigLoader):
+    pass
 
-class Parser:
-    """Parser for ZConfig-like configuration files."""
 
-    def __init__(self, file, url, schema):
-        self.schema = schema
-        self.file = file
-        self.url = url
-        self.lineno = 0
-        self.stack = []   # [(type, name, prevmatcher), ...]
+class ExtendedConfigLoader(ConfigLoaderMixin,
+                           ZConfig.cmdline.ExtendedConfigLoader):
 
-    def nextline(self):
-        line = self.file.readline()
-        if line:
-            self.lineno += 1
-            return False, line.strip()
+    def cook(self):
+        if self.clopts:
+            return OptionBag(self.schema, self.schema, self.clopts)
         else:
-            return True, None
+            return None
 
-    def load(self):
-        section = self.schema.getConfiguration()
-        self.parse(section)
-        try:
-            return self.schema.finishSection(section)
-        except ConfigurationError, e:
-            e.lineno = self.lineno
-            e.url = self.url
-            raise
 
-    def parse(self, section):
-        done, line = self.nextline()
-        while not done:
-            if line[:1] in ("", "#"):
-                # blank line or comment
-                pass
+class OptionBag(ZConfig.cmdline.OptionBag):
 
-            elif line[:2] == "</":
-                # section end
-                if line[-1] != ">":
-                    self.error("malformed section end")
-                section = self.end_section(section, line[2:-1])
-
-            elif line[0] == "<":
-                # section start
-                if line[-1] != ">":
-                    self.error("malformed section start")
-                section = self.start_section(section, line[1:-1])
-
-            elif line[0] == "%":
-                self.error("ZConfig-style directives are not supported")
-
+    def get_section_info(self, type, name):
+        L = []  # what pertains to the child section
+        R = []  # what we keep
+        for item in self.sectitems:
+            optpath, val, pos = item
+            s = optpath[0]
+            bk = self.basic_key(s, pos)
+            if name and s == name:
+                L.append((optpath[1:], val, pos))
+            elif bk == type:
+                L.append((optpath[1:], val, pos))
             else:
-                self.handle_key_value(section, line)
-
-            done, line = self.nextline()
-
-        if self.stack:
-            self.error("unclosed sections not allowed")
-
-    def start_section(self, section, rest):
-        isempty = rest[-1:] == "/"
-        if isempty:
-            text = rest[:-1].rstrip()
+                R.append(item)
+        if L:
+            self.sectitems[:] = R
+            return OptionBag(self.schema, self.schema.gettype(type), L)
         else:
-            text = rest.rstrip()
-        # parse section start stuff here
-        m = _section_start_rx.match(text)
-        if not m:
-            self.error("malformed section header")
-        type, name = m.group('type', 'name')
-        type = type.lower()
-        #
-        # XXX Argh!  Converting section names to lower-case was a
-        # mistake in ZConfig, but we have to honor case here for
-        # <extension> sections.  We need to add some way to control
-        # the "nametype" of sections in ZConfig anyway.
-        #
-        # if name:
-        #    name = name.lower()
-        #
-        try:
-            newsect = self.schema.startSection(section, type, name)
-        except ConfigurationError, e:
-            e.lineno = self.lineno
-            e.url = self.url
-            raise
-        if isempty:
-            try:
-                self.schema.endSection(section, type, name, newsect)
-            except ConfigurationError, e:
-                e.lineno = self.lineno
-                e.url = self.url
-                raise
-            return section
-        else:
-            self.stack.append((type, name, section))
-            return newsect
-
-    def end_section(self, section, rest):
-        if not self.stack:
-            self.error("unexpected section end")
-        type = rest.rstrip().lower()
-        opentype, name, prevsection = self.stack.pop()
-        if type != opentype:
-            self.error("unbalanced section end")
-        try:
-            self.schema.endSection(prevsection, type, name, section)
-        except ConfigurationError, e:
-            e.lineno = self.lineno
-            e.url = self.url
-            raise
-        return prevsection
-
-    def handle_key_value(self, section, rest):
-        m = _keyvalue_rx.match(rest)
-        if not m:
-            self.error("malformed configuration data")
-        key, value = m.group('key', 'value')
-        if value:
-            value = self.replace(value)
-        else:
-            value = ''
-        try:
-            self.schema.addValue(section, key, value)
-        except ConfigurationError, e:
-            e.lineno = self.lineno
-            e.url = self.url
-            raise
-
-    def replace(self, text):
-        parts = []
-        rest = text
-        while "$" in rest:
-            i = rest.index("$")
-            if i:
-                parts.append(rest[:i])
-            rest = rest[i+1:]
-            if not rest:
-                self.error("text cannot end with a bare '$'")
-            if rest[0] == "$":
-                parts.append("$")
-                rest = rest[1:]
-            else:
-                self.error("unsupported substitution syntax")
-        parts.append(rest)
-        return _nulljoin(parts)
-
-    def error(self, message):
-        raise ConfigurationError(message, self.url, self.lineno)
-
-
-class SectionValue:
-    """Generic bag-of-values object for a section."""
-
-    def __init__(self, name, typename, typedef):
-        self._name = name
-        self._typename = typename
-        self._typedef = typedef
-
-    def getSectionName(self):
-        """Return the name of the section, or `None`."""
-        return self._name
-
-    def getSectionType(self):
-        """Return the name of the section type."""
-        return self._typename
-
-    def getSectionDefinition(self):
-        """Return the data structure that represents the type of this
-        section value.
-        """
-        return self._typedef
+            return None

Modified: zpkgtools/branches/fdrake-zconfig-branch/zpkgsetup/package.py
===================================================================
--- zpkgtools/branches/fdrake-zconfig-branch/zpkgsetup/package.py	2005-08-30 05:06:48 UTC (rev 38152)
+++ zpkgtools/branches/fdrake-zconfig-branch/zpkgsetup/package.py	2005-08-30 05:08:16 UTC (rev 38153)
@@ -55,7 +55,7 @@
 :Groups:
   - `Public interface`: loadCollectionInfo loadPackageInfo
   - `Helper functions`: create_extension expand_globs read_package_info
-  - `Datatype functions`: cpp_definition cpp_names path_ref extension
+  - `Datatype functions`: cpp_definition cpp_names path_ref
 
 """
 
@@ -74,7 +74,9 @@
 
 PACKAGE_CONF = "SETUP.cfg"
 
+get_schema = cfgparser.cachedSchemaLoader("package.xml")
 
+
 class Header(object):
     """Information about a header file and the package that provides it."""
 
@@ -103,7 +105,7 @@
     """
     pkginfo = read_package_info(directory, reldir)
     pkginfo.extensions = [create_extension(ext, pkgname, reldir)
-                          for ext in pkginfo.extension]
+                          for ext in pkginfo.extensions]
     pkginfo.package_headers = [Header(pkgname, path)
                                for path in pkginfo.header]
     return pkginfo
@@ -123,7 +125,7 @@
     """
     pkginfo = read_package_info(directory, reldir)
     pkginfo.extensions = [create_extension(ext, None, reldir)
-                          for ext in pkginfo.extension]
+                          for ext in pkginfo.extensions]
     pkginfo.package_headers = [Header(None, path)
                                for path in pkginfo.header]
     return pkginfo
@@ -154,10 +156,11 @@
         url = "<no file>"
         f = StringIO("")
     try:
-        p = cfgparser.Parser(f, url, PackageSchema(directory, reldir))
-        pkginfo = p.load()
+        pkginfo, _ = cfgparser.loadConfigFile(get_schema(), f, url)
     finally:
         f.close()
+    for name, data_files in pkginfo.data_files:
+        data_files[:] = expand_globs(directory, reldir, data_files)
     pkginfo.documentation = expand_globs(directory, reldir,
                                          pkginfo.documentation)
     pkginfo.header = expand_globs(directory, reldir, pkginfo.header)
@@ -243,9 +246,9 @@
     """
     kwargs = {}
     if pkgname:
-        kwargs["name"] = "%s.%s" % (pkgname, section.name)
+        kwargs["name"] = "%s.%s" % (pkgname, section.getSectionName())
     else:
-        kwargs["name"] = section.name
+        kwargs["name"] = section.getSectionName()
     kwargs["sources"] = [posixpath.join(reldir, fn)
                          for fn in section.source]
     if section.define:
@@ -385,22 +388,12 @@
 _cpp_ident_match = re.compile("[A-Za-z_][A-Za-z_0-9]*$").match
 
 
-def extension(section):
-    """Transform `section`, checking several fields for valid values.
+def empty_string(s):
+    if s:
+        raise ValueError("data-file specifications may not have values")
+    return s
 
-    :param section: Configuration section.
-    :return: Modified section.
-    """
-    section.name = section.getSectionName()
-    if not section.name:
-        raise ValueError("extensions must be named")
-    if not section.source:
-        raise ValueError("at least one extension source file must be listed")
-    if len(section.language) > 1:
-        raise ValueError("language can only be specified once")
-    return section
 
-
 def path_ref(s):
     """Datatype for a local path reference.
 
@@ -456,80 +449,6 @@
     return p
 
 
-class PackageSchema(cfgparser.Schema):
-    """Schema implementation with a <data-files> section type.
-
-    The <data-files> sections have keys that are glob-expanded (based
-    on information passed to the constructor) and combined into a
-    single ``data_files`` member on the resulting package information
-    object.  The value of the ``data_files`` attribute is suitable for
-    passing to the `distutils.core.setup()` function.
-
-    """
-
-    def __init__(self, directory, reldir):
-        cfgparser.Schema.__init__(
-            self,
-            ({"script": path_ref,
-              "documentation": path_ref,
-              "header": path_ref},
-             ["extension"], None),
-            {"extension": ({"source": path_ref, "depends-on": path_ref,
-                            "define" : cpp_definition, "undefine": cpp_names,
-                            "language": str,
-                            },
-                           (), extension),
-             }
-            )
-        self.__cf = None
-        self.__datafiles = None
-        self.__directory = directory
-        self.__reldir = reldir
-
-    def getConfiguration(self):
-        assert self.__cf is None
-        self.__cf = cfgparser.Schema.getConfiguration(self)
-        self.__cf.data_files = []
-        return self.__cf
-
-    def startSection(self, parent, typename, name):
-        if self.__datafiles is not None:
-            raise cfgparser.ConfigurationError(
-                "can't nest another section inside <data-files> section")
-        if typename == "data-files":
-            if not name:
-                raise cfgparser.ConfigurationError(
-                    "<data-files> section must have a name")
-            normname = posixpath.normpath(name)
-            for target, files in self.__cf.data_files:
-                if target == normname:
-                    raise cfgparser.ConfigurationError(
-                        "can't have two sections of the same name:"
-                        " <data-files %s>" % name)
-            self.__datafiles = []
-            self.__cf.data_files.append((normname, self.__datafiles))
-            # The return value is passed around, but that's it
-            return ()
-        else:
-            return cfgparser.Schema.startSection(self, parent, typename, name)
-
-    def endSection(self, parent, typename, name, child):
-        if self.__datafiles is None:
-            cfgparser.Schema.endSection(self, parent, typename, name, child)
-        else:
-            # mutate self.__datafiles since the reference from
-            # self.__cf.data_files is what's actually used
-            self.__datafiles[:] = expand_globs(self.__directory,
-                                               self.__reldir,
-                                               self.__datafiles)
-            self.__datafiles = None
-
-    def addValue(self, section, key, value):
-        if self.__datafiles is not None:
-            if value:
-                raise cfgparser.ConfigurationError(
-                    "each entry in a <data-files> section must be"
-                    " a single glob pattern")
-            self.__datafiles.append(key)
-        else:
-            cfgparser.Schema.addValue(self, section, key, value)
+def data_file_section(section):
+    name = posixpath.normpath(section.getSectionName())
+    return name, section.files.keys()

Added: zpkgtools/branches/fdrake-zconfig-branch/zpkgsetup/package.xml
===================================================================
--- zpkgtools/branches/fdrake-zconfig-branch/zpkgsetup/package.xml	2005-08-30 05:06:48 UTC (rev 38152)
+++ zpkgtools/branches/fdrake-zconfig-branch/zpkgsetup/package.xml	2005-08-30 05:08:16 UTC (rev 38153)
@@ -0,0 +1,36 @@
+<schema prefix="zpkgsetup">
+  <description>
+    Schema for zpkg SETUP.cfg files, used to provide distutils
+    metadata for individual packages.
+  </description>
+
+  <sectiontype name="extension">
+    <key name="language" datatype="basic-key"/>
+    <multikey name="define" datatype=".package.cpp_definition"/>
+    <multikey name="undefine" datatype=".package.cpp_names"/>
+    <multikey name="source" datatype=".package.path_ref" required="yes"/>
+    <multikey name="depends-on" datatype=".package.path_ref"/>
+  </sectiontype>
+
+  <sectiontype name="data-files"
+               keytype=".package.path_ref"
+               datatype=".package.data_file_section">
+    <key name="+" attribute="files" datatype=".package.empty_string"/>
+  </sectiontype>
+
+  <multisection name="+" attribute="extensions" type="extension"/>
+  <multisection name="+" attribute="data_files" type="data-files"/>
+
+  <multikey name="documentation"
+            datatype=".package.path_ref">
+  </multikey>
+
+  <multikey name="header"
+            datatype=".package.path_ref">
+  </multikey>
+
+  <multikey name="script"
+            datatype=".package.path_ref">
+  </multikey>
+
+</schema>


Property changes on: zpkgtools/branches/fdrake-zconfig-branch/zpkgsetup/package.xml
___________________________________________________________________
Name: svn:eol-style
   + native

Deleted: zpkgtools/branches/fdrake-zconfig-branch/zpkgsetup/tests/test_cfgparser.py
===================================================================
--- zpkgtools/branches/fdrake-zconfig-branch/zpkgsetup/tests/test_cfgparser.py	2005-08-30 05:06:48 UTC (rev 38152)
+++ zpkgtools/branches/fdrake-zconfig-branch/zpkgsetup/tests/test_cfgparser.py	2005-08-30 05:08:16 UTC (rev 38153)
@@ -1,162 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Tests for zpkgtools.cfgparser."""
-
-import unittest
-
-from StringIO import StringIO
-
-from zpkgsetup import cfgparser
-
-
-class SimpleSection:
-
-    finished = False
-    ending_parent = None
-    ending_typename = None
-    ending_name = None
-
-    def __init__(self, parent=None, typename=None, name=None):
-        self.parent = parent
-        self.typename = typename
-        self.name = name
-
-
-class AnythingGoesSchema:
-
-    def getConfiguration(self):
-        return SimpleSection()
-
-    def startSection(self, parent, typename, name):
-        return SimpleSection(parent, typename, name)
-
-    def finishSection(self, section):
-        section.finished = True
-        return section
-
-    def endSection(self, parent, typename, name, child):
-        child.ending_parent = parent
-        child.ending_typename = typename
-        child.ending_name = name
-        if not hasattr(parent, typename):
-            setattr(parent, typename, [])
-        getattr(parent, typename).append(child)
-        self.finishSection(child)
-
-    def addValue(self, section, key, value):
-        key = key.lower().replace("-", "_")
-        if not hasattr(section, key):
-            setattr(section, key, [])
-        getattr(section, key).append(value)
-
-
-class ParserTestCase(unittest.TestCase):
-
-    schema = AnythingGoesSchema()
-
-    def createParser(self, text=""):
-        sio = StringIO(text)
-        self.parser = cfgparser.Parser(sio, "<some-url>", self.schema)
-        return self.parser
-
-    def test_replace(self):
-        # "legal" values are those that are legal in ZConfig
-        eq = self.assertEqual
-        raises = self.assertRaises
-        replace = self.createParser().replace
-
-        # some legal values that don't have '$':
-        eq(replace(""), "")
-        eq(replace(" foo bar "), " foo bar ")
-        eq(replace("x"), "x")
-
-        # legal, supported values with '$':
-        eq(replace("$$"), "$")
-        eq(replace("$$$$"), "$$")
-        eq(replace("$$xyz$$"), "$xyz$")
-
-        # legal, unsupported values (all have '$'):
-        raises(cfgparser.ConfigurationError, replace, "$foo")
-        raises(cfgparser.ConfigurationError, replace, "${foo-bar}")
-
-        # illegal values:
-        raises(cfgparser.ConfigurationError, replace, "$")
-        raises(cfgparser.ConfigurationError, replace, "foo$")
-
-    def test_schema_use(self):
-        eq = self.assertEqual
-        p = self.createParser("""
-            # This is a comment.
-
-            key value 1
-            key value 2
-            <section/>
-            <section foo/>
-            <section>
-              key  value 3
-            </section>
-            <section splat>
-              <inner>
-                key value 5
-              </inner>
-              key value 4
-            </section>
-            """)
-        cf = p.load()
-        self.check_section(cf, None, None, None, key=["value 1", "value 2"])
-        s1, s2, s3, s4 = cf.section
-        self.check_section(s1, cf, None, "section")
-        self.check_section(s2, cf, "foo", "section")
-        self.check_section(s3, cf, None, "section", key=["value 3"])
-        self.check_section(s4, cf, "splat", "section", key=["value 4"])
-        inner, = s4.inner
-        self.check_section(inner, s4, None, "inner", key=["value 5"])
-
-    def check_section(self, section, parent, name, typename, **attrs):
-        self.assert_(section.finished)
-        self.assert_(section.parent is parent)
-        self.assert_(section.parent is section.ending_parent)
-        self.assertEqual(section.name, name)
-        self.assertEqual(section.name, section.ending_name)
-        self.assertEqual(section.typename, typename)
-        self.assertEqual(section.typename, section.ending_typename)
-        for name, value in attrs.iteritems():
-            v = getattr(section, name)
-            self.assertEqual(v, value)
-
-
-class SchemaTestCase(unittest.TestCase):
-
-    top_level_converted = False
-
-    def setUp(self):
-        self.schema = cfgparser.Schema(
-            ({}, [], self.top_level_conversion))
-
-    def top_level_conversion(self, section):
-        self.top_level_converted = True
-        return section
-
-    def test_getConfiguration(self):
-        cf = self.schema.getConfiguration()
-        self.failIf(self.top_level_converted)
-
-
-def test_suite():
-    suite = unittest.makeSuite(ParserTestCase)
-    suite.addTest(unittest.makeSuite(SchemaTestCase))
-    return suite
-
-if __name__ == "__main__":
-    unittest.main(defaultTest="test_suite")

Modified: zpkgtools/branches/fdrake-zconfig-branch/zpkgsetup/urlutils.py
===================================================================
--- zpkgtools/branches/fdrake-zconfig-branch/zpkgsetup/urlutils.py	2005-08-30 05:06:48 UTC (rev 38152)
+++ zpkgtools/branches/fdrake-zconfig-branch/zpkgsetup/urlutils.py	2005-08-30 05:08:16 UTC (rev 38153)
@@ -17,8 +17,15 @@
 
 import posixpath
 import urllib
+import urlparse
 
+# svn: and svn+ssh: weren't handled properly by urlparse before Python
+# 2.4.2 and 2.5; this makes all versions handled them correctly:
+#
+if "svn" not in urlparse.uses_netloc:
+    urlparse.uses_netloc.extend(["svn", "svn+ssh"])
 
+
 def file_url(path):
     return "file://" + pathname2url(path)
 

Modified: zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/config.py
===================================================================
--- zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/config.py	2005-08-30 05:06:48 UTC (rev 38152)
+++ zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/config.py	2005-08-30 05:08:16 UTC (rev 38153)
@@ -32,16 +32,8 @@
 from zpkgtools import locationmap
 
 
-TRUE_STRINGS =("yes", "true", "on")
-FALSE_STRINGS = ("no", "false", "off")
+get_schema = cfgparser.cachedSchemaLoader("config.xml")
 
-def boolean(string):
-    s = string.lower()
-    if s in FALSE_STRINGS:
-        return False
-    if s in TRUE_STRINGS:
-        return True
-    raise ValueError("unknown boolean value: %r" % string)
 
 def non_empty_string(string):
     if not string:
@@ -49,44 +41,10 @@
     return string
 
 
-class Schema(cfgparser.Schema, object):
+def resource_map(value):
+    return value.map
 
-    def __init__(self, filename, locations):
-        # We can use the base schema for the top-level definitions,
-        # except for the <resources> section.
-        super(Schema, self).__init__(
-            ({"resource-map": non_empty_string,
-              "include-support-code": boolean,
-              "collect-dependencies": boolean,
-              "build-application": boolean,
-              "default-collection": non_empty_string,
-              }, ["resources"], None))
-        self.base = urlutils.file_url(filename)
-        self.filename = filename
-        self.locations = locations
 
-    def startSection(self, parent, typename, name):
-        if typename != "resources":
-            raise cfgparser.ConfigurationError(
-                "only <resources> sections are allowed")
-        if isinstance(parent, locationmap.MapLoader):
-            raise cfgparser.ConfigurationError(
-                "<resources> sections may not be nested")
-        return locationmap.MapLoader(self.base, self.filename, self.locations)
-
-    def addValue(self, section, key, value):
-        if isinstance(section, locationmap.MapLoader):
-            section.add(key, value)
-        else:
-            super(Schema, self).addValue(section, key, value)
-
-    def finishSection(self, section):
-        if isinstance(section, locationmap.MapLoader):
-            return section.mapping
-        return super(Schema, self).finishSection(section)
-
-
-
 class Configuration:
     """Configuration settings for **zpkg**.
 
@@ -146,37 +104,27 @@
             basedir = os.path.abspath(basedir)
         else:
             basedir = os.getcwd()
-        p = cfgparser.Parser(f, path, Schema(os.path.abspath(path),
-                                             self.locations))
-        cf = p.load()
-        base = urlutils.file_url(basedir) + "/"
-        for value in cf.resource_map:
-            value = urlparse.urljoin(base, value)
+        schema = get_schema()
+        url = urlutils.file_url(os.path.abspath(path))
+        cf, _ = cfgparser.loadConfigFile(schema, f, url)
+        # deal with embedded resource maps:
+        for map in cf.resource_maps:
+            for key, value in map.iteritems():
+                value = urlparse.urljoin(url, value)
+                if key.endswith(".*"):
+                    wildcard = key[:-2]
+                    if not self.locations._have_wildcard(wildcard):
+                        self.locations._add_wildcard(wildcard, value)
+                elif key not in self.locations:
+                    self.locations[key] = value
+        self.application = cf.build_application
+        self.collect_dependencies = cf.collect_dependencies
+        self.default_collection = cf.default_collection
+        self.include_support_code = cf.include_support_code
+        self.resource_maps = cf.resource_maps
+        for value in cf.location_maps:
+            value = urlparse.urljoin(url, value)
             self.location_maps.append(value)
-        # include-support-code
-        if len(cf.include_support_code) > 1:
-            raise cfgparser.ConfigurationError(
-                "include-support-code can be specified at most once")
-        if cf.include_support_code:
-            self.include_support_code = cf.include_support_code[0]
-        # collect-dependencies
-        if len(cf.collect_dependencies) > 1:
-            raise cfgparser.ConfigurationError(
-                "collect-dependencies can be specified at most once")
-        if cf.collect_dependencies:
-            self.collect_dependencies = cf.collect_dependencies[0]
-        # build-application
-        if len(cf.build_application) > 1:
-            raise cfgparser.ConfigurationError(
-                "build-application can be specified at most once")
-        if cf.build_application:
-            self.application = cf.build_application[0]
-        # default-collection
-        if len(cf.default_collection) > 1:
-            raise cfgparser.ConfigurationError(
-                "default-collection can be specified at most once")
-        if cf.default_collection:
-            self.default_collection = cf.default_collection[0]
 
 
 def defaultConfigurationPath():

Added: zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/config.xml
===================================================================
--- zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/config.xml	2005-08-30 05:06:48 UTC (rev 38152)
+++ zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/config.xml	2005-08-30 05:08:16 UTC (rev 38153)
@@ -0,0 +1,59 @@
+<schema prefix="zpkgtools">
+  <description>
+    Schema for zpkg configuration files.
+  </description>
+
+  <sectiontype name="resources"
+               datatype=".config.resource_map"
+               keytype=".locationmap.resource_name"
+               >
+    <key name="+"
+         attribute="map"
+         type=".config.non_empty_string"
+         />
+  </sectiontype>
+
+  <multisection type="resources"
+               attribute="resource_maps"
+               >
+    <description>
+      Embedded resource maps.
+    </description>
+  </multisection>
+
+  <multikey name="resource-map"
+            attribute="location_maps"
+            required="no"
+            datatype=".config.non_empty_string"
+            >
+    <description>
+      Each 'resource-map' is a URL reference to a resource map in an
+      external resource.  Relative references are resolved relative to
+      the resource in which they're embedded.
+    </description>
+  </multikey>
+
+  <key name="build-application"
+       datatype="boolean"
+       required="no"
+       default="no"
+       />
+
+  <key name="collect-dependencies"
+       datatype="boolean"
+       required="no"
+       default="no"
+       />
+
+  <key name="default-collection"
+       datatype=".config.non_empty_string"
+       required="no"
+       />
+
+  <key name="include-support-code"
+       datatype="boolean"
+       required="no"
+       default="yes"
+       />
+
+</schema>


Property changes on: zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/config.xml
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/include.py
===================================================================
--- zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/include.py	2005-08-30 05:06:48 UTC (rev 38152)
+++ zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/include.py	2005-08-30 05:08:16 UTC (rev 38153)
@@ -27,6 +27,7 @@
 
 from zpkgsetup import cfgparser
 from zpkgsetup import loggingapi as logging
+from zpkgsetup import package
 from zpkgsetup import publication
 from zpkgsetup import setup
 from zpkgsetup import urlutils
@@ -41,6 +42,84 @@
 PACKAGE_CONF = "PACKAGE.cfg"
 
 
+get_schema = cfgparser.cachedSchemaLoader("include.xml")
+
+
+def collection_path_ref(value):
+    if value == "-":
+        return value
+    if value:
+        return normalize_path(value, "destination")
+    else:
+        return None
+
+def distribution_path_ref(value):
+    if value == "-":
+        raise ValueError("exclusion not allowed in <distribution>")
+    if value:
+        return normalize_path(value, "destination")
+    else:
+        return None
+
+def load_path_ref(value):
+    if value == "-":
+        raise ValueError("exclusion not allowed in <load>")
+    if not value:
+        raise ValueError("source must be specified in <load>")
+    return normalize_path_or_url(value, "source")
+
+def workspace_path_ref(value):
+    return normalize_path(value, "workspace file")
+
+
+def collection_section(section):
+    excludes = []
+    includes = {}
+    for (k, vs) in section.mapping.iteritems():
+        for v in vs:
+            if v == "-":
+                if len(vs) != 1:
+                    raise ValueError("too many exclusions specified for %s"
+                                     % k)
+                excludes.append(k)
+                continue
+            if v:
+                includes[k] = v
+            else:
+                L = includes.setdefault(None, [])
+                L.append(k)
+    if excludes and includes:
+        raise ValueError(
+            "includes and excludes cannot be mixed in <collection>")
+    section.excludes = excludes
+    section.includes = includes
+    return section
+
+def distribution_section(section):
+    includes = {}
+    for (k, v) in section.mapping.iteritems():
+        if v:
+            includes[v] = k
+        else:
+            L = includes.setdefault(None, [])
+            L.append(k)
+    section.excludes = {}
+    section.includes = includes
+    return section
+
+def load_section(section):
+    includes = {}
+    for (k, v) in section.mapping.iteritems():
+        if v:
+            includes[v] = k
+        else:
+            L = includes.setdefault(None, [])
+            L.append(k)
+    section.excludes = {}
+    section.includes = includes
+    return section
+
+
 class InclusionError(Error):
     """Raised to indicate errors processing inclusions."""
 
@@ -74,26 +153,37 @@
     If there is not specification file, return empty specifications.
     """
     package_conf = os.path.join(sourcedir, PACKAGE_CONF)
-    schema = SpecificationSchema(sourcedir, package_conf)
+    url = urlutils.file_url(os.path.abspath(package_conf))
     if os.path.isfile(package_conf):
-        f = open(package_conf, "rU")
-        try:
-            parser = cfgparser.Parser(f, package_conf, schema)
-            config = parser.load()
-        finally:
-            f.close()
-        if config.collection.excludes:
-            # XXX should make sure PACKAGE_CONF isn't already excluded
-            config.collection.excludes.append(PACKAGE_CONF)
-        elif not config.collection.includes:
-            # Nothing included or excluded; simply exclude PACKAGE_CONF:
-            config.collection.excludes.append(PACKAGE_CONF)
+        cf, _ = cfgparser.loadConfig(get_schema(), package_conf)
+        config = PackageConstruction(sourcedir, package_conf)
+        if cf.collection is not None:
+            if cf.collection.excludes:
+                # XXX should make sure PACKAGE_CONF isn't already excluded
+                cf.collection.excludes.append(PACKAGE_CONF)
+            elif not cf.collection.includes:
+                # Nothing included or excluded; simply exclude PACKAGE_CONF:
+                cf.collection.excludes.append(PACKAGE_CONF)
+            config.collection.excludes = cf.collection.excludes
+            config.collection.includes = cf.collection.includes
+        if cf.distribution is not None:
+            config.distribution.includes = cf.distribution.includes
+        if cf.loads is not None:
+            config.loads.includes = cf.loads.includes
     else:
-        config = schema.getConfiguration()
+        config = PackageConstruction(sourcedir, None)
     return config
 
 
-def normalize_path(path, type, group):
+class PackageConstruction(object):
+
+    def __init__(self, source, filename):
+        self.loads = Specification(source, filename, "load")
+        self.collection = Specification(source, filename, "collection")
+        self.distribution = Specification(source, filename, "distribution")
+
+
+def normalize_path(path, type):
     if ":" in path:
         scheme, rest = urllib.splittype(path)
         if len(scheme) == 1:
@@ -116,99 +206,99 @@
         return np.replace("/", os.sep)
 
 
-def normalize_path_or_url(path, type, group):
+def normalize_path_or_url(path, type):
     if ":" in path:
         scheme, rest = urllib.splittype(path)
         if len(scheme) != 1:
             # should normalize the URL, but skip that for now
             return path
-    return normalize_path(path, type, group)
+    return normalize_path(path, type)
 
 
-class SpecificationSchema(cfgparser.Schema):
-    """Specialized schema that handles populating a set of Specifications.
-    """
+##class SpecificationSchema(cfgparser.Schema):
+##    """Specialized schema that handles populating a set of Specifications.
+##    """
 
-    def __init__(self, source, filename):
-        self.filename = filename
-        self.source = source
+##    def __init__(self, source, filename):
+##        self.filename = filename
+##        self.source = source
 
-    def getConfiguration(self):
-        conf = cfgparser.SectionValue(None, None, None)
-        conf.loads = Specification(
-            self.source, self.filename, "load")
-        conf.collection = Specification(
-            self.source, self.filename, "collection")
-        conf.distribution = Specification(
-            self.source, self.filename, "distribution")
-        return conf
+##    def getConfiguration(self):
+##        conf = cfgparser.SectionValue(None, None, None)
+##        conf.loads = Specification(
+##            self.source, self.filename, "load")
+##        conf.collection = Specification(
+##            self.source, self.filename, "collection")
+##        conf.distribution = Specification(
+##            self.source, self.filename, "distribution")
+##        return conf
 
-    def startSection(self, parent, typename, name):
-        if not isinstance(parent, cfgparser.SectionValue):
-            raise cfgparser.ConfigurationError("unexpected section")
-        if typename == "collection":
-            return parent.collection
-        elif typename == "distribution":
-            return parent.distribution
-        elif typename == "load":
-            return parent.loads
-        raise cfgparser.ConfigurationError("unknown section type: %s"
-                                           % typename)
+##    def startSection(self, parent, typename, name):
+##        if not isinstance(parent, cfgparser.SectionValue):
+##            raise cfgparser.ConfigurationError("unexpected section")
+##        if typename == "collection":
+##            return parent.collection
+##        elif typename == "distribution":
+##            return parent.distribution
+##        elif typename == "load":
+##            return parent.loads
+##        raise cfgparser.ConfigurationError("unknown section type: %s"
+##                                           % typename)
 
-    def endSection(self, parent, typename, name, child):
-        if child.includes and child.excludes:
-            # XXX not sure what the exact semantics should be of
-            # allowing both inclusions and exclusions at the same
-            # time; which takes precedence?  what about precedence
-            # when wildcards are involved?
-            raise cfgparser.ConfigurationError(
-                "exclusions and inclusions cannot coexist in a single section")
+##    def endSection(self, parent, typename, name, child):
+##        if child.includes and child.excludes:
+##            # XXX not sure what the exact semantics should be of
+##            # allowing both inclusions and exclusions at the same
+##            # time; which takes precedence?  what about precedence
+##            # when wildcards are involved?
+##            raise cfgparser.ConfigurationError(
+##                "exclusions and inclusions cannot coexist in a single section")
 
-    def createSection(self, name, typename, typedef):
-        raise NotImplementedError(
-            "createSection() should not be called for SpecificationSchema")
+##    def createSection(self, name, typename, typedef):
+##        raise NotImplementedError(
+##            "createSection() should not be called for SpecificationSchema")
 
-    def finishSection(self, section):
-        return section
+##    def finishSection(self, section):
+##        return section
 
-    def addValue(self, section, workfile, other):
-        if not isinstance(section, Specification):
-            raise cfgparser.ConfigurationError(
-                "all inclusion lines must be in a section")
+##    def addValue(self, section, workfile, other):
+##        if not isinstance(section, Specification):
+##            raise cfgparser.ConfigurationError(
+##                "all inclusion lines must be in a section")
 
-        if other == "-":
-            # This is an exclusion.
-            if section.group != "collection":
-                raise cfgparser.ConfigurationError(
-                    "exclusions are only permitted in <collection>")
-            workfile = normalize_path(workfile, "exclusion", section.group)
-            section.excludes.append(workfile)
-            return
+##        if other == "-":
+##            # This is an exclusion.
+##            if section.group != "collection":
+##                raise cfgparser.ConfigurationError(
+##                    "exclusions are only permitted in <collection>")
+##            workfile = normalize_path(workfile, "exclusion", section.group)
+##            section.excludes.append(workfile)
+##            return
 
-        if section.group == "load":
-            if not other:
-                raise cfgparser.ConfigurationError(
-                    "referenced file must be named explicitly"
-                    " in <load> section")
-            # perhaps should make sure workfile and other don't refer
-            # to the same file
-            other = normalize_path_or_url(other, "source", section.group)
-        elif other:
-            # workfile and other have a backward relationship for this:
-            # <destination>
-            #   target workfile
-            # </destination>
-            other = normalize_path(other, "destination", section.group)
+##        if section.group == "load":
+##            if not other:
+##                raise cfgparser.ConfigurationError(
+##                    "referenced file must be named explicitly"
+##                    " in <load> section")
+##            # perhaps should make sure workfile and other don't refer
+##            # to the same file
+##            other = normalize_path_or_url(other, "source", section.group)
+##        elif other:
+##            # workfile and other have a backward relationship for this:
+##            # <destination>
+##            #   target workfile
+##            # </destination>
+##            other = normalize_path(other, "destination", section.group)
 
-        if workfile:
-            workfile = normalize_path(workfile, "workspace file",
-                                      section.group)
+##        if workfile:
+##            workfile = normalize_path(workfile, "workspace file",
+##                                      section.group)
 
-        if other:
-            section.includes[other] = workfile
-        else:
-            L = section.includes.setdefault(None, [])
-            L.append(workfile)
+##        if other:
+##            section.includes[other] = workfile
+##        else:
+##            L = section.includes.setdefault(None, [])
+##            L.append(workfile)
 
 
 class Specification:

Added: zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/include.xml
===================================================================
--- zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/include.xml	2005-08-30 05:06:48 UTC (rev 38152)
+++ zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/include.xml	2005-08-30 05:08:16 UTC (rev 38153)
@@ -0,0 +1,37 @@
+<schema prefix="zpkgtools">
+
+  <sectiontype name="collection"
+               datatype=".include.collection_section"
+               keytype=".include.workspace_path_ref">
+    <multikey name="+"
+             attribute="mapping"
+             datatype=".include.collection_path_ref"
+             />
+  </sectiontype>
+
+  <sectiontype name="distribution"
+               datatype=".include.distribution_section"
+               keytype=".include.workspace_path_ref">
+    <key name="+"
+        attribute="mapping"
+        datatype=".include.distribution_path_ref"
+        />
+  </sectiontype>
+
+  <sectiontype name="load"
+               datatype=".include.load_section"
+               keytype=".include.workspace_path_ref">
+    <key name="+"
+        attribute="mapping"
+        datatype=".include.load_path_ref"
+        />
+  </sectiontype>
+
+  <section type="collection"
+           attribute="collection"/>
+  <section type="distribution"
+           attribute="distribution"/>
+  <section type="load"
+           attribute="loads"/>
+
+</schema>


Property changes on: zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/include.xml
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/locationmap.py
===================================================================
--- zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/locationmap.py	2005-08-30 05:06:48 UTC (rev 38152)
+++ zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/locationmap.py	2005-08-30 05:08:16 UTC (rev 38153)
@@ -150,6 +150,17 @@
         self.path = path
 
 
+def resource_name(value):
+    if value.endswith(".*"):
+        if not is_module_name(value[:-2]):
+            raise ValueError("wildcard package name specified, but"
+                             " prefix is not a legal package name: %r"
+                             % value)
+    elif "*" in value:
+        raise ValueError("invalid wildcard specification: %r" % resource)
+    return value
+
+
 class MapLoader:
 
     def __init__(self, base, filename, mapping):

Modified: zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/tests/test_include.py
===================================================================
--- zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/tests/test_include.py	2005-08-30 05:06:48 UTC (rev 38152)
+++ zpkgtools/branches/fdrake-zconfig-branch/zpkgtools/tests/test_include.py	2005-08-30 05:08:16 UTC (rev 38153)
@@ -194,7 +194,7 @@
             </collection>
             """)
         specs = include.load(self.source)
-        self.assertRaises(include.InclusionSpecificationError,
+        self.assertRaises(cfgparser.ConfigurationError,
                           specs.collection.cook)
 
     def test_omitted_destination_keeps_name(self):
@@ -234,7 +234,7 @@
             </%s>
             """ % (sectionname, sectionname)
         self.write_file(include.PACKAGE_CONF, text)
-        self.assertRaises(include.InclusionSpecificationError,
+        self.assertRaises(cfgparser.ConfigurationError,
                           include.load, self.source)
 
     # These two tests are really checking internal helpers, but
@@ -251,29 +251,29 @@
         self.check_normalize_urls(normalize)
 
     def check_normalize_paths(self, normalize):
-        self.assertEqual(normalize("README.txt", "t", "group"),
+        self.assertEqual(normalize("README.txt", "t"),
                          "README.txt")
-        self.assertEqual(normalize("doc/README.txt", "t", "group"),
+        self.assertEqual(normalize("doc/README.txt", "t"),
                          join("doc", "README.txt"))
-        self.assertEqual(normalize(".", "t", "group"),
+        self.assertEqual(normalize(".", "t"),
                          os.curdir)
         # Ignore this because it looks like a Windows drive letter:
         self.assertRaises(include.InclusionSpecificationError,
-                          normalize, "c:foo/bar", "t", "group")
+                          normalize, "c:foo/bar", "t")
         # Absolute paths are an error as well:
         self.assertRaises(include.InclusionSpecificationError,
-                          normalize, "/absolute/path", "t", "group")
+                          normalize, "/absolute/path", "t")
         # Relative paths that point up the hierarchy are also disallowed:
         self.assertRaises(include.InclusionSpecificationError,
-                          normalize, "abc/../../def.txt", "t", "group")
+                          normalize, "abc/../../def.txt", "t")
         self.assertRaises(include.InclusionSpecificationError,
-                          normalize, "../def.txt", "t", "group")
+                          normalize, "../def.txt", "t")
 
     def check_normalize_urls(self, normalize):
         for url in ("http://www.example.com/index.html",
                     "repository:/Zope3/doc",
                     "cvs://cvs.zope.com/cvs-repository:/Zope3/doc:HEAD"):
-            self.assertEqual(normalize(url, "t", "group"), url)
+            self.assertEqual(normalize(url, "t"), url)
 
     def test_createDistributionTree_creates_destination(self):
         os.rmdir(self.destination)



More information about the Zope-CVS mailing list