[Zope-CVS] CVS: Packages/zpkgtools/zpkgtools - locationmap.py:1.18

Fred L. Drake, Jr. fred at zope.com
Tue Jun 8 23:07:35 EDT 2004


Update of /cvs-repository/Packages/zpkgtools/zpkgtools
In directory cvs.zope.org:/tmp/cvs-serv22672/zpkgtools

Modified Files:
	locationmap.py 
Log Message:
Change the syntax for package wildcards, with new tests.
- must be explicitly specified
- tests broken by Jim's implementation now pass
- wildcards must be specified with a trailing ".*" now


=== Packages/zpkgtools/zpkgtools/locationmap.py 1.17 => 1.18 ===
--- Packages/zpkgtools/zpkgtools/locationmap.py:1.17	Thu Jun  3 23:50:31 2004
+++ Packages/zpkgtools/zpkgtools/locationmap.py	Tue Jun  8 23:07:00 2004
@@ -16,10 +16,12 @@
 import logging
 import os.path
 import posixpath
+import re
 import sets
 import urllib
 import urllib2
 import urlparse
+import UserDict
 
 from zpkgtools import cvsloader
 from zpkgtools import loader
@@ -35,79 +37,107 @@
         self.lineno = lineno
         ValueError.__init__(self, message)
 
-class LocationMap(dict):
 
-    def get(self, name, default=None):
-        """Look up an entry froma map
+class LocationMap(UserDict.UserDict):
 
-        If an entry isn't found directly, check for a prefix
+    def __init__(self, *args, **kw):
+        UserDict.UserDict.__init__(self, *args, **kw)
+        self._wildcards = {}
+
+    def __getitem__(self, key):
+        if key in self.data:
+            v = self.data[key]
+            if v is None:
+                raise KeyError(key)
+            return v
+        # might be supported by the wildcards
+        v = self._get_from_wildcards(key)
+        if v is None:
+            raise KeyError(key)
+        return v
+
+    def __setitem__(self, key, item):
+        self.data[key] = item
+
+    def __delitem__(self, key):
+        if key in self.data and self.data[key] != None:
+            del self.data[key]
+        elif key in self:
+            # must be here as a wildcard
+            self.data[key] = None
+        else:
+            raise KeyError(key)
+
+    def get(self, key, default=None):
+        if key in self.data:
+            v = self.data[key]
+            if v is None:
+                v = default
+            return v
+        try:
+            return self._get_from_wildcards(key)
+        except KeyError:
+            return default
+
+    def has_key(self, key):
+        if key in self.data:
+            return self.data[key] is not None
+        else:
+            return self._get_from_wildcards(key) is not None
+
+    def update(self, dict=None, **kwargs):
+        if dict:
+            for key, value in dict.iteritems():
+                self.data[key] = value
+        if len(kwargs):
+            self.update(kwargs)
+
+    def pop(self, key, *args):
+        return self.data.pop(key, *args)
+
+    def __contains__(self, key):
+        if key in self.data:
+            return self.data[key] is not None
+        else:
+            return self._get_from_wildcards(key) is not None
 
-          >>> map = LocationMap({'foo': 'svn://spam.com/repos/foo'})
-          >>> map.get('foo')
-          'svn://spam.com/repos/foo'
-          >>> map.get('foo.bar')
-          'svn://spam.com/repos/foo/bar'
-          >>> map.get('foo.bar.baz')
-          'svn://spam.com/repos/foo/bar/baz'
-          >>> map.get('z')
-          >>> map.get('z.x')
-          >>> map.get('z.x.y')
-
-        """
-
-        r = dict.get(self, name)
-        if r:
-            return r
-
-        suffix = ''
-        while 1:
-            l = name.rfind('.')
-            if l > 0:
-                suffix = '/'+ name[l+1:] + suffix
-                name = name[:l]
+    def _add_wildcard(self, key, location):
+        """Add a location for a wildcarded package."""
+        self._wildcards[key] = location
+
+    def _get_from_wildcards(self, key):
+        """Return location based on wildcards, or None."""
+        prefix = key
+        suffix = ""
+        while "." in prefix:
+            pos = prefix.rfind(".")
+            name = prefix[pos+1:]
+            prefix = prefix[:pos]
+            if suffix:
+                suffix = "%s/%s" % (name, suffix)
             else:
-                break
-            r = dict.get(self, name)
-            if r:
-                return r + suffix
-
-        return default
-
-    __contains__ = get
-
-    def __getitem__(self, name):
-        """Look up an entry froma map
-
-        If an entry isn't found directly, check for a prefix
-
-          >>> map = LocationMap({'foo': 'svn://spam.com/repos/foo'})
-          >>> map['foo']
-          'svn://spam.com/repos/foo'
-          >>> map['foo.bar']
-          'svn://spam.com/repos/foo/bar'
-          >>> map['foo.bar.baz']
-          'svn://spam.com/repos/foo/bar/baz'
-
-          >>> map['z']
-          Traceback (most recent call last):
-          ...
-          KeyError: 'z'
-
-          >>> map['z.x']
-          Traceback (most recent call last):
-          ...
-          KeyError: 'z.x'
-
-          >>> map['z.x.y']
-          Traceback (most recent call last):
-          ...
-          KeyError: 'z.x.y'
-
-        """
-        r = self.get(name)
-        if r:
-            return r
-        raise KeyError, name
+                suffix = name
+            base = self._wildcards.get(prefix)
+            if base:
+                # join suffix with the path portion of the base
+                try:
+                    parsed = loader.parse(base)
+                except ValueError:
+                    # we should distinguish between URLs and local paths here
+                    parts = list(urlparse.urlsplit(base))
+                    if parts[2]:
+                        parts[2] = posixpath.join(parts[2], suffix)
+                    else:
+                        parts[2] = posixpath.join("", suffix)
+                    return urlparse.urlunsplit(parts)
+                else:
+                    pathpart = cvsloader.RepositoryUrl(suffix)
+                    return parsed.join(pathpart).getUrl()
+        return None
+
+    def _have_wildcard(self, key):
+        """Return true iff we already have a wildcard for key."""
+        return key in self._wildcards
 
 
 def load(f, base=None, mapping=None):
@@ -159,16 +189,30 @@
 
                 url = cvsurl.getUrl()
 
-        # We only want to add it once, so that loading several
-        # mappings causes the first defining a resource to "win":
-        if resource not in mapping:
-            mapping[resource] = url
-        elif resource in local_entries:
+        if resource in local_entries:
             _logger.warn(
                 "found duplicate entry for resource %r in %s at line %d",
                 resource, getattr(f, "name", "<unknown>"), lineno)
+        elif resource.endswith(".*"):
+            # Deal with wildcarded resources;
+            # need to check if it's already there
+            wildcard = resource[:-2]
+            if not is_module_name(wildcard):
+                raise MapLoadingError("wildcard package name specified, but"
+                                      " prefix is not a legal package name: %r"
+                                      % wildcard,
+                                      getattr(f, "name", "<unknown>"), lineno)
+            if not mapping._have_wildcard(wildcard):
+                mapping._add_wildcard(wildcard, url)
+        elif "*" in resource:
+            raise MapLoadingError("invalid wildcard specification: %r"
+                                  % resource,
+                                  getattr(f, "name", "<unknown>"), lineno)
+        elif resource not in mapping:
+            # We only want to add it once, so that loading several
+            # mappings causes the first defining a resource to "win":
+            mapping[resource] = url
         local_entries.add(resource)
-        # else tell the user of the conflict?
 
     return mapping
 
@@ -194,3 +238,10 @@
         return load(f, base, mapping)
     finally:
         f.close()
+
+
+_ident = "[a-zA-Z_][a-zA-Z_0-9]*"
+_module_match = re.compile(r"%s(\.%s)*$" % (_ident, _ident)).match
+
+def is_module_name(string):
+    return _module_match(string) is not None




More information about the Zope-CVS mailing list