Back to index

plone3  3.1.7
FSMetadata.py
Go to the documentation of this file.
00001 ##############################################################################
00002 #
00003 # Copyright (c) 2003 Zope Corporation and Contributors. All Rights Reserved.
00004 #
00005 # This software is subject to the provisions of the Zope Public License,
00006 # Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
00007 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
00008 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00009 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
00010 # FOR A PARTICULAR PURPOSE.
00011 #
00012 ##############################################################################
00013 """ Handles reading the properties for an object that comes from the filesystem.
00014 
00015 $Id: FSMetadata.py 68525 2006-06-08 16:55:12Z efge $
00016 """
00017 
00018 import logging
00019 from os.path import exists
00020 from ConfigParser import ConfigParser
00021 from warnings import warn
00022 
00023 import re
00024 
00025 
00026 logger = logging.getLogger('CMFCore.FSMetadata')
00027 
00028 
00029 class CMFConfigParser(ConfigParser):
00030     """ This our wrapper around ConfigParser to
00031     solve a few minor niggles with the code """
00032     # adding in a space so that names can contain spaces
00033     OPTCRE = re.compile(
00034         r'(?P<option>[]\-[ \w_.*,(){}]+)'      # a lot of stuff found by IvL
00035         r'[ \t]*(?P<vi>[:=])[ \t]*'           # any number of space/tab,
00036                                               # followed by separator
00037                                               # (either : or =), followed
00038                                               # by any # space/tab
00039         r'(?P<value>.*)$'                     # everything up to eol
00040         )
00041 
00042     def optionxform(self, optionstr):
00043         """
00044         Stop converting the key to lower case, very annoying for security etc
00045         """
00046         return optionstr.strip()
00047 
00048 class FSMetadata:
00049     # public API
00050     def __init__(self, filename):
00051         self._filename = filename
00052 
00053     def read(self):
00054         """ Find the files to read, either the old security and
00055         properties type or the new metadata type """
00056         filename = self._filename + '.metadata'
00057         if exists(filename):
00058             # found the new type, lets use that
00059             self._readMetadata()
00060         else:
00061             # not found so try the old ones
00062             self._properties = self._old_readProperties()
00063             self._security = self._old_readSecurity()
00064 
00065     def getProxyRoles(self):
00066         """ Returns the proxy roles """
00067         if self.getProperties():
00068             pxy = self.getProperties().get('proxy')
00069             if pxy:
00070                 return [r.strip() for r in pxy.split(',') if r.strip()]
00071         return []
00072 
00073     def getSecurity(self):
00074         """ Gets the security settings """
00075         return self._security
00076 
00077     def getProperties(self):
00078         """ Gets the properties settings """
00079         return self._properties
00080 
00081     # private API
00082     def _readMetadata(self):
00083         """ Read the new file format using ConfigParser """
00084         self._properties = {}
00085         self._security = {}
00086 
00087         try:
00088             cfg = CMFConfigParser()
00089             cfg.read(self._filename + '.metadata')
00090 
00091             # the two sections we care about
00092             self._properties = self._getSectionDict(cfg, 'default')
00093             self._security = self._getSectionDict(cfg, 'security',
00094                                                   self._securityParser)
00095         except:
00096             logger.exception("Error parsing .metadata file")
00097 
00098         # to add in a new value such as proxy roles,
00099         # just add in the section, call it using getSectionDict
00100         # if you need a special parser for some whacky
00101         # config, then just pass through a special parser
00102 
00103     def _nullParser(self, data):
00104         """
00105         This is the standard rather boring null parser that does very little
00106         """
00107         return data
00108 
00109     def _securityParser(self, data):
00110         """ A specific parser for security lines
00111 
00112         Security lines must be of the format
00113 
00114         Permission = (0|1):Role[,Role...]
00115 
00116         Where 0|1 is the acquire permission setting
00117         and Role is the roles for this permission
00118         eg: 1:Manager or 0:Manager,Anonymous
00119         """
00120         if data.find(':') < 1:
00121             raise ValueError, "The security declaration of file " + \
00122                   "%r is in the wrong format" % self._filename
00123 
00124         acquire, roles = data.split(':')
00125         roles = [r.strip() for r in roles.split(',') if r.strip()]
00126         return (int(acquire), roles)
00127 
00128     def _getSectionDict(self, cfg, section, parser=None):
00129         """
00130         Get a section and put it into a dict, mostly a convenience
00131         function around the ConfigParser
00132 
00133         Note: the parser is a function to parse each value, so you can
00134         have custom values for the key value pairs
00135         """
00136         if parser is None:
00137             parser = self._nullParser
00138 
00139         props = {}
00140         if cfg.has_section(section):
00141             for opt in cfg.options(section):
00142                 props[opt] = parser(cfg.get(section, opt))
00143             return props
00144 
00145         # we need to return None if we have none to be compatible
00146         # with existing API
00147         return None
00148 
00149     def _old_readProperties(self):
00150         """
00151         Reads the properties file next to an object.
00152 
00153         Moved from DirectoryView.py to here with only minor
00154         modifications. Old and deprecated in favour of .metadata now
00155         """
00156         fp = self._filename + '.properties'
00157         try:
00158             f = open(fp, 'rt')
00159         except IOError:
00160             return None
00161         else:
00162             warn('.properties objects will disappear in CMF 2.0 - Use '
00163                  '.metadata objects instead.', DeprecationWarning)
00164             lines = f.readlines()
00165             f.close()
00166             props = {}
00167             for line in lines:
00168                 kv = line.split('=', 1)
00169                 if len(kv) == 2:
00170                     props[kv[0].strip()] = kv[1].strip()
00171                 else:
00172                     logger.exception("Error parsing .properties file")
00173 
00174             return props
00175 
00176     def _old_readSecurity(self):
00177         """
00178         Reads the security file next to an object.
00179 
00180         Moved from DirectoryView.py to here with only minor
00181         modifications. Old and deprecated in favour of .metadata now
00182         """
00183         fp = self._filename + '.security'
00184         try:
00185             f = open(fp, 'rt')
00186         except IOError:
00187             return None
00188         else:
00189             warn('.security objects will disappear in CMF 2.0 - Use '
00190                  '.metadata objects instead.', DeprecationWarning)
00191             lines = f.readlines()
00192             f.close()
00193             prm = {}
00194             for line in lines:
00195                 try:
00196                     c1 = line.index(':')+1
00197                     c2 = line.index(':',c1)
00198                     permission = line[:c1-1]
00199                     acquire = bool(line[c1:c2])
00200                     proles = line[c2+1:].split(',')
00201                     roles=[]
00202                     for role in proles:
00203                         role = role.strip()
00204                         if role:
00205                             roles.append(role)
00206                 except:
00207                     logger.exception("Error reading permission "
00208                                      "from .security file")
00209                 prm[permission]=(acquire,roles)
00210             return prm