[CMF-checkins] CVS: CMF/CMFCore - FSMetadata.py:1.1 DirectoryView.py:1.36

Andy McKay andy@agmweb.ca
Wed, 12 Mar 2003 00:07:06 -0500


Update of /cvs-repository/CMF/CMFCore
In directory cvs.zope.org:/tmp/cvs-serv19816

Modified Files:
	DirectoryView.py 
Added Files:
	FSMetadata.py 
Log Message:
Add new .metadata file which combines previous formats into a ConfigParser type format. Proxy role stuff to come


=== Added File CMF/CMFCore/FSMetadata.py ===
""" Handles reading the properties for an object that comes from the filesystem.

$Id: FSMetadata.py,v 1.1 2003/03/12 05:06:28 andym Exp $
"""

from zLOG import LOG, ERROR
from sys import exc_info
from os.path import exists
from ConfigParser import ConfigParser

import re

class CMFConfigParser(ConfigParser):
    """ This our wrapper around ConfigParser to 
    solve a few minor niggles with the code """
    # adding in a space so that names can contain spaces
    OPTCRE = re.compile(
        r'(?P<option>[]\-[ \w_.*,(){}]+)'      # a lot of stuff found by IvL
        r'[ \t]*(?P<vi>[:=])[ \t]*'           # any number of space/tab,
                                              # followed by separator
                                              # (either : or =), followed
                                              # by any # space/tab
        r'(?P<value>.*)$'                     # everything up to eol
        )    

    def optionxform(self, optionstr):
        """ 
        Stop converting the key to lower case, very annoying for security etc 
        """
        return optionstr.strip()

class FSMetadata:
    # public API
    def __init__(self, filename):
        self._filename = filename

    def read(self):
        """ Find the files to read, either the old security and properties type or
        the new metadata type """
        filename = self._filename + '.metadata'
        if exists(filename):
            # found the new type, lets use that
            self._readMetadata()
        else:
            # not found so try the old ones
            self._properties = self._old_readProperties()
            self._security = self._old_readSecurity()

    def getSecurity(self):
        """ Gets the security settings """
        return self._security

    def getProperties(self):
        """ Gets the properties settings """
        return self._properties

    # private API
    def _readMetadata(self):
        """ Read the new file format using ConfigParser """
        cfg = CMFConfigParser()
        cfg.read(self._filename + '.metadata')

        # the two sections we care about
        self._properties = self._getSectionDict(cfg, 'default')
        self._security = self._getSectionDict(cfg, 'security', self._securityParser)
        # to add in a new value such as proxy roles,
        # just add in the section, call it using getSectionDict
        # if you need a special parser for some whacky
        # config, then just pass through a special parser
    
    def _nullParser(self, data):
        """ 
        This is the standard rather boring null parser that does very little 
        """
        return data
    
    def _securityParser(self, data):
        """ A specific parser for security lines 
        
        Security lines must be of the format
        
        (0|1):Role[,Role...]
        
        Where 0|1 is the acquire permission setting
        and Role is the roles for this permission
        eg: 1:Manager or 0:Manager,Anonymous
        """
        if data.find(':') < 1: 
            raise ValueError, "The security declaration is in the wrong format"
            
        acquire, roles = data.split(':')
        roles = [r.strip() for r in roles.split(',') if r.strip()]
        return (acquire, roles)

    def _getSectionDict(self, cfg, section, parser=None):
        """ 
        Get a section and put it into a dict, mostly a convenience
        function around the ConfigParser
        
        Note: the parser is a function to parse each value, so you can
        have custom values for the key value pairs 
        """
        if parser is None: 
            parser = self._nullParser

        props = {}
        if cfg.has_section(section):
            for opt in cfg.options(section):
                props[opt] = parser(cfg.get(section, opt))
            return props

        # we need to return None if we have none to be compatible
        # with existing API
        return None

    def _old_readProperties(self):
        """
        Reads the properties file next to an object.
        
        Moved from DirectoryView.py to here with only minor
        modifications. Old and deprecated in favour of .metadata now
        """
        fp = self._filename + '.properties'
        try:
            f = open(fp, 'rt')
        except IOError:
            return None
        else:
            lines = f.readlines()
            f.close()
            props = {}
            for line in lines:
                try: key, value = split(line, '=',1)
                except: pass
                else:
                    props[strip(key)] = strip(value)
            return props
    
    def _old_readSecurity(self):
        """
        Reads the security file next to an object.
        
        Moved from DirectoryView.py to here with only minor
        modifications. Old and deprecated in favour of .metadata now
        """
        fp = self._filename + '.security'
        try:
            f = open(fp, 'rt')
        except IOError:
            return None        
        else:
            lines = f.readlines()
            f.close()
            prm = {}
            for line in lines:
                try:
                    c1 = line.index(':')+1
                    c2 = line.index(':',c1)
                    permission = line[:c1-1]
                    acquire = not not line[c1:c2] # get boolean                    
                    proles = line[c2+1:].split(',')
                    roles=[]
                    for role in proles:
                        role = role.strip()
                        if role:
                            roles.append(role)
                except:
                    LOG('DirectoryView',
                        ERROR,
                        'Error reading permission from .security file',
                        error=exc_info())
                        # warning use of exc_info is deprecated
                prm[permission]=(acquire,roles)
            return prm


=== CMF/CMFCore/DirectoryView.py 1.35 => 1.36 ===
--- CMF/CMFCore/DirectoryView.py:1.35	Thu Jan 23 09:31:12 2003
+++ CMF/CMFCore/DirectoryView.py	Wed Mar 12 00:06:28 2003
@@ -32,6 +32,7 @@
 from zLOG import LOG, ERROR
 from sys import exc_info
 from types import StringType
+from FSMetadata import FSMetadata
 
 _dtmldir = path.join( package_home( globals() ), 'dtml' )
 
@@ -99,56 +100,6 @@
                     types[strip(obname)] = strip(meta_type)
         return types
 
-
-    def _readProperties(self, fp):
-        """Reads the properties file next to an object.
-        """
-        try:
-            f = open(fp, 'rt')
-        except IOError:
-            return None
-        else:
-            lines = f.readlines()
-            f.close()
-            props = {}
-            for line in lines:
-                try: key, value = split(line, '=',1)
-                except: pass
-                else:
-                    props[strip(key)] = strip(value)
-            return props
-
-    def _readSecurity(self, fp):
-        """Reads the security file next to an object.
-        """
-        try:
-            f = open(fp, 'rt')
-        except IOError:
-            return None        
-        else:
-            lines = f.readlines()
-            f.close()
-            prm = {}
-            for line in lines:
-                try:
-                    c1 = line.index(':')+1
-                    c2 = line.index(':',c1)
-                    permission = line[:c1-1]
-                    acquire = not not line[c1:c2] # get boolean                    
-                    proles = line[c2+1:].split(',')
-                    roles=[]
-                    for role in proles:
-                        role = role.strip()
-                        if role:
-                            roles.append(role)
-                except:
-                    LOG('DirectoryView',
-                        ERROR,
-                        'Error reading permission from .security file',
-                        error=exc_info())
-                prm[permission]=(acquire,roles)
-            return prm
-
     if Globals.DevelopmentMode:
 
         def _changed(self):
@@ -253,11 +204,11 @@
                     t = registry.getTypeByExtension(ext)
                 
                 if t is not None:
-                    properties = self._readProperties(
-                        e_fp + '.properties')
+                    metadata = FSMetadata(e_fp)
+                    metadata.read()
                     try:
                         ob = t(name, e_filepath, fullname=entry,
-                               properties=properties)
+                               properties=metadata.getProperties())
                     except:
                         import traceback
                         typ, val, tb = exc_info()
@@ -278,7 +229,7 @@
                             
                     # FS-based security
                     try:
-                        permissions = self._readSecurity(e_fp + '.security')
+                        permissions = metadata.getSecurity()
                         if permissions is not None:
                             for name in permissions.keys():
                                 acquire,roles = permissions[name]