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

"Fred L. Drake, Jr." <[email protected]>
Newsgroups gmane.comp.web.zope.public-cvs
Message-ID <[email protected]>
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)

_______________________________________________
Zope-CVS maillist  -  [email protected]
http://mail.zope.org/mailman/listinfo/zope-cvs

Zope CVS instructions: http://dev.zope.org/CVS
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.