[CMF-checkins] SVN: CMF/branches/tseaver-pkg_resources/C Finish
repairing test / usage stuff for "package resource" skins.
Tres Seaver
tseaver at palladion.com
Thu Oct 27 14:20:13 EDT 2005
Log message for revision 39678:
Finish repairing test / usage stuff for "package resource" skins.
N.B.: Skin paths now normalize to include 'Products/' prefix;
old skin directories will be upgraded in place.
Changed:
U CMF/branches/tseaver-pkg_resources/CHANGES.txt
U CMF/branches/tseaver-pkg_resources/CMFCore/DirectoryView.py
U CMF/branches/tseaver-pkg_resources/CMFCore/FSFile.py
U CMF/branches/tseaver-pkg_resources/CMFCore/FSObject.py
U CMF/branches/tseaver-pkg_resources/CMFCore/tests/test_DirectoryView.py
U CMF/branches/tseaver-pkg_resources/CMFCore/utils.py
U CMF/branches/tseaver-pkg_resources/CMFDefault/profiles/default/skins.xml
-=-
Modified: CMF/branches/tseaver-pkg_resources/CHANGES.txt
===================================================================
--- CMF/branches/tseaver-pkg_resources/CHANGES.txt 2005-10-27 18:17:21 UTC (rev 39677)
+++ CMF/branches/tseaver-pkg_resources/CHANGES.txt 2005-10-27 18:20:13 UTC (rev 39678)
@@ -136,6 +136,9 @@
Others
+ - Skin paths now normalize to include 'Products/' prefix; old skin
+ directories will be upgraded in place.
+
- {CMFCalendar,CMFActionIcons,CMFDefault,CMFTopic}/__init__.py:
Don't register skin directories when being imported by the testrunner
without 'Products' in our package name.
Modified: CMF/branches/tseaver-pkg_resources/CMFCore/DirectoryView.py
===================================================================
--- CMF/branches/tseaver-pkg_resources/CMFCore/DirectoryView.py 2005-10-27 18:17:21 UTC (rev 39677)
+++ CMF/branches/tseaver-pkg_resources/CMFCore/DirectoryView.py 2005-10-27 18:20:13 UTC (rev 39678)
@@ -41,7 +41,6 @@
from permissions import AccessContentsInformation
from permissions import ManagePortal
from utils import _dtmldir
-from utils import minimalpath
from utils import normalize
@@ -288,10 +287,11 @@
LOG( 'DirectoryView', ERROR,
'\n'.join(exc_lines) )
- ob = BadFile( name,
- entry_minimal_fp,
- exc_str='\r\n'.join(exc_lines),
- fullname=entry )
+ ob = BadFile( name
+ , filepath=entry_minimal_fp
+ , fullname=entry
+ , exc_str='\r\n'.join(exc_lines)
+ )
finally:
tb = None # Avoid leaking frame!
@@ -328,19 +328,19 @@
""" DI for directories read using pkg_resources API.
"""
- def __init__(self, pname, name, ignore=ignore):
- self._pname = pname
+ def __init__(self, package, name, ignore=ignore):
+ self._package = package
self._name = name
self.ignore = base_ignore + tuple(ignore)
subdirs = []
for entry in self._listEntries():
entry_subpath = self._getEntrySubpath(entry)
- if resource_isdir(pname, entry_subpath):
+ if resource_isdir(package, entry_subpath):
subdirs.append(entry)
self.subdirs = tuple(subdirs)
def _listEntries(self):
- for entry in resource_listdir(self._pname, self._name):
+ for entry in resource_listdir(self._package, self._name):
if entry not in self.ignore and not ignore_re.match(entry):
yield entry
@@ -349,8 +349,8 @@
def readFile(self, filename, mode='ignored'):
try:
- return resource_string(self._pname, '%s/%s' % (self._name,
- filename))
+ return resource_string(self._package, '%s/%s'
+ % (self._name, filename))
except IOError:
return None
@@ -358,11 +358,11 @@
# Creates objects for each file.
data = {}
objects = []
- pname = self._pname
+ package = self._package
types = self._readTypesFile()
- faux_path_prefix = pname.split('.')
+ faux_path_prefix = package.split('.')
- for entry in resource_listdir(self._pname, self._name):
+ for entry in resource_listdir(self._package, self._name):
if not self._isAllowableFilename(entry):
continue
@@ -379,7 +379,7 @@
# Register unknown subdirs
registry.registerDirectoryByGlobals(entry_subpath,
{'__name__' :
- self._pname },
+ self._package },
ignore=self.ignore,
)
info = registry.getDirectoryInfo(faux_path)
@@ -395,11 +395,12 @@
t = registry.getTypeByMetaType(mt)
if t is None:
t = DirectoryView
- metadata = FSMetadata(package=pname,
+ metadata = FSMetadata(package=package,
entry_subpath=entry_subpath)
metadata.read()
ob = t( entry
- , entry_minimal_fp
+ , package=package
+ , entry_subpath=entry_subpath
, properties=metadata.getProperties()
)
ob_id = ob.getId()
@@ -430,12 +431,12 @@
t = registry.getTypeByExtension(ext)
if t is not None:
- metadata = FSMetadata(package=pname,
+ metadata = FSMetadata(package=package,
entry_subpath=entry_subpath)
metadata.read()
try:
ob = t(name,
- package=pname,
+ package=package,
entry_subpath=entry_subpath,
fullname=entry,
properties=metadata.getProperties(),
@@ -451,7 +452,8 @@
'\n'.join(exc_lines) )
ob = BadFile( name,
- entry_minimal_fp,
+ package=package,
+ entry_subpath=entry_subpath,
exc_str='\r\n'.join(exc_lines),
fullname=entry )
finally:
@@ -517,18 +519,18 @@
def registerDirectoryByGlobals(self, name, pglobals,
subdirs=1, ignore=ignore):
- pname = pglobals['__name__']
- faux_path_elements = pname.split('.')
+ package = pglobals['__name__']
+ faux_path_elements = package.split('.')
faux_path_elements.append(name)
faux_path = '/'.join(faux_path_elements)
- info = ResourceDirectoryInformation(pname, name, ignore=ignore)
+ info = ResourceDirectoryInformation(package, name, ignore=ignore)
self._directories[faux_path] = info
if subdirs:
- for entry in resource_listdir(pname, name):
+ for entry in resource_listdir(package, name):
if entry in ignore:
continue
sub_name = '%s/%s' % (name, entry)
- if resource_isdir(pname, sub_name):
+ if resource_isdir(package, sub_name):
self.registerDirectoryByGlobals( sub_name
, pglobals
, subdirs
@@ -542,7 +544,7 @@
# The idea is that the registry will only contain
# small paths that are likely to work across platforms
# and SOFTWARE_HOME, INSTANCE_HOME and PRODUCTS_PATH setups
- minimal_fp = minimalpath(filepath)
+ minimal_fp = _normalizeDirPath(filepath)
info = DirectoryInformation(filepath, minimal_fp, ignore=ignore)
self._directories[minimal_fp] = info
if subdirs:
@@ -640,6 +642,9 @@
if index != -1:
dirpath = dirpath[index+len('products/'):]
info = _dirreg.getDirectoryInfo(dirpath)
+ if info is None and not dirpath.startswith('/'): #BBB
+ dirpath = 'Products/%s' % dirpath
+ info = _dirreg.getDirectoryInfo(dirpath)
if info is not None:
# update the directory view with a corrected path
self._dirpath = dirpath
@@ -661,6 +666,16 @@
InitializeClass(DirectoryView)
+def _normalizeDirPath(dirpath):
+ dirpath = normalize(dirpath)
+ index = dirpath.rfind('Products')
+ if index == -1:
+ index = dirpath.rfind('products')
+ if index != -1:
+ dirpath = dirpath[index+len('products/'):]
+ if not dirpath.startswith('/') and ':' not in dirpath:
+ dirpath = 'Products/%s' % dirpath
+ return dirpath
class DirectoryViewSurrogate (Folder):
""" Folderish DirectoryView.
@@ -696,7 +711,7 @@
def manage_properties( self, dirpath, REQUEST=None ):
""" Update the directory path of the DirectoryView.
"""
- self.__dict__['_real']._dirpath = dirpath
+ self.__dict__['_real']._dirpath = _normalizeDirPath(dirpath)
if REQUEST is not None:
REQUEST['RESPONSE'].redirect( '%s/manage_propertiesForm'
% self.absolute_url() )
@@ -735,6 +750,9 @@
""" Add either a DirectoryView or a derivative object.
"""
info = _dirreg.getDirectoryInfo(minimal_fp)
+ if info is None: # maybe old data
+ minimal_fp = _normalizeDirPath(minimal_fp)
+ info = _dirreg.getDirectoryInfo(minimal_fp)
if info is None:
raise ValueError('Not a registered directory: %s' % minimal_fp)
if not id:
@@ -753,16 +771,16 @@
"""
if isinstance(_prefix, basestring):
filepath = path.join(_prefix, name)
- adjusted = minimalpath(filepath)
+ adjusted = _normalizeDirPath(filepath)
else:
- pname = _prefix['__name__']
- elements = pname.split('.') + [name]
+ package = _prefix['__name__']
+ elements = package.split('.') + [name]
adjusted = '/'.join(elements)
info = _dirreg.getDirectoryInfo(adjusted)
if info is None:
- raise ValueError('Not a registered directory: %s' % minimal_fp)
+ raise ValueError('Not a registered directory: %s' % adjusted)
for entry in info.getSubdirs():
entry_subname = '%s/%s' % (adjusted, entry)
Modified: CMF/branches/tseaver-pkg_resources/CMFCore/FSFile.py
===================================================================
--- CMF/branches/tseaver-pkg_resources/CMFCore/FSFile.py 2005-10-27 18:17:21 UTC (rev 39677)
+++ CMF/branches/tseaver-pkg_resources/CMFCore/FSFile.py 2005-10-27 18:20:13 UTC (rev 39678)
@@ -82,7 +82,7 @@
def _getFilename(self):
path = self._filepath or self._entry_subpath
- dir, fn = os.path.split(self._filepath)
+ dir, fn = os.path.split(path)
return fn
def _readFile(self, reparse):
Modified: CMF/branches/tseaver-pkg_resources/CMFCore/FSObject.py
===================================================================
--- CMF/branches/tseaver-pkg_resources/CMFCore/FSObject.py 2005-10-27 18:17:21 UTC (rev 39677)
+++ CMF/branches/tseaver-pkg_resources/CMFCore/FSObject.py 2005-10-27 18:20:13 UTC (rev 39678)
@@ -15,12 +15,20 @@
$Id$
"""
-from os import path
-from os import stat
-from pkg_resources import resource_string
-from pkg_resources import get_provider
+import os
+import sys
import time
+try:
+ from pkg_resources import resource_string
+ from pkg_resources import get_provider
+ from pkg_resources import ZipProvider
+ _HAS_PKG_RESOURCES = True
+except ImportError:
+ _HAS_PKG_RESOURCES = False
+ class ZipProvider: # silence!
+ pass
+
import Globals
from AccessControl import ClassSecurityInfo
from AccessControl.Role import RoleManager
@@ -184,12 +192,13 @@
if self._filepath:
fp = expandpath(self._filepath)
try:
- statinfo = stat(fp)
+ statinfo = os.stat(fp)
size, mtime = statinfo[6], statinfo[8]
except:
size = mtime = 0
else:
- size, mtime = _getZipStatInfo(self._package, self._entry_subpath)
+ size, mtime = _getResourceStatInfo(self._package,
+ self._entry_subpath)
if not parsed or mtime != self._file_mod_time:
# if we have to read the file again, remove the cache
@@ -253,6 +262,11 @@
<dtml-var manage_tabs>
<h2> Bad Filesystem Object: &dtml-getId; </h2>
+<h3> File Path </h3>
+<pre>
+<dtml-var getFilePath>
+</pre>
+
<h3> File Contents </h3>
<pre>
<dtml-var getFileContents>
@@ -269,22 +283,43 @@
{'label':'Error', 'action':'manage_showError'},
)
- def __init__( self, id, filepath, exc_str=''
- , fullname=None, properties=None):
+ def __init__( self, id, package=None, entry_subpath=None, filepath=None
+ , fullname=None, properties=None, exc_str=''
+ ):
id = fullname or id # Use the whole filename.
self.exc_str = exc_str
self.file_contents = ''
- FSObject.__init__(self, id, filepath, fullname, properties)
+ FSObject.__init__(self, id, package, entry_subpath, filepath,
+ fullname, properties)
security = ClassSecurityInfo()
+ security.declarePrivate('showError')
showError = Globals.HTML( BAD_FILE_VIEW )
+
+ security.declarePrivate('_readFile')
+ def _readFile(self, reparse):
+ """ Stub this out.
+ """
+ pass
+
security.declareProtected(ManagePortal, 'manage_showError')
def manage_showError( self, REQUEST ):
+ """ Render the error page.
"""
- """
return self.showError( self, REQUEST )
+ security.declarePublic( 'getFilePath' )
+ def getFilePath( self ):
+ """
+ Return the path to the file.
+ """
+ if self._filepath:
+ return self._filepath
+ else:
+ return 'package: %s, subpath: %s' % (self._package,
+ self._entry_subpath)
+
security.declarePublic( 'getFileContents' )
def getFileContents( self ):
"""
@@ -302,21 +337,33 @@
Globals.InitializeClass( BadFile )
-def _getZipStatInfo(package, subpath):
+def _getResourceStatInfo(package, subpath):
provider = get_provider(package)
- zip_stat = provider.zipinfo.get(subpath)
- if zip_stat is None:
- return None, None
- path, compression, csize, size, date, time, crc = zip_stat
- date_time = ((date >> 9) + 1980, # year
- (date >> 5) & 0xF, # month
- date & 0x1F, # day
- (time & 0xFFFF) >> 11, # hour
- (time >> 5) & 0x3F, # minute
- (time & 0x1F) * 2, # second
- 0, # ?
- 0, # ?
- -1, # ?
- )
- return size, time.mktime(date_time)
+ if _HAS_PKG_RESOURCES and isinstance(provider, ZipProvider):
+ zip_stat = provider.zipinfo.get(subpath)
+ if zip_stat is None:
+ return None, None
+ path, compression, csize, size, date, time, crc = zip_stat
+ date_time = ((date >> 9) + 1980, # year
+ (date >> 5) & 0xF, # month
+ date & 0x1F, # day
+ (time & 0xFFFF) >> 11, # hour
+ (time >> 5) & 0x3F, # minute
+ (time & 0x1F) * 2, # second
+ 0, # ?
+ 0, # ?
+ -1, # ?
+ )
+ return size, time.mktime(date_time)
+
+ module = sys.modules[package]
+ path = os.path.split(module.__file__)
+
+ try:
+ statinfo = os.stat(path)
+ size, mtime = statinfo[6], statinfo[8]
+ except:
+ size = mtime = 0
+
+ return size, mtime
Modified: CMF/branches/tseaver-pkg_resources/CMFCore/tests/test_DirectoryView.py
===================================================================
--- CMF/branches/tseaver-pkg_resources/CMFCore/tests/test_DirectoryView.py 2005-10-27 18:17:21 UTC (rev 39677)
+++ CMF/branches/tseaver-pkg_resources/CMFCore/tests/test_DirectoryView.py 2005-10-27 18:20:13 UTC (rev 39678)
@@ -60,6 +60,8 @@
skin.manage_properties(r'Products\CMFCore\tests\fake_skins\fake_skin')
self.failUnless( hasattr(self.ob.fake_skin, 'test1'),
self.ob.fake_skin.getDirPath() )
+ self.assertEqual(skin._dirpath,
+ 'Products/CMFCore/tests/fake_skins/fake_skin')
# windows SOFTWARE_HOME
def test_getDirectoryInfo2(self):
@@ -68,6 +70,8 @@
r'C:\Zope\2.5.1\Products\CMFCore\tests\fake_skins\fake_skin')
self.failUnless( hasattr(self.ob.fake_skin, 'test1'),
self.ob.fake_skin.getDirPath() )
+ self.assertEqual(skin._dirpath,
+ 'Products/CMFCore/tests/fake_skins/fake_skin')
# *nix INSTANCE_HOME
def test_getDirectoryInfo3(self):
@@ -75,6 +79,8 @@
skin.manage_properties('Products/CMFCore/tests/fake_skins/fake_skin')
self.failUnless( hasattr(self.ob.fake_skin, 'test1'),
self.ob.fake_skin.getDirPath() )
+ self.assertEqual(skin._dirpath,
+ 'Products/CMFCore/tests/fake_skins/fake_skin')
# *nix SOFTWARE_HOME
def test_getDirectoryInfo4(self):
@@ -83,6 +89,8 @@
'/usr/local/zope/2.5.1/Products/CMFCore/tests/fake_skins/fake_skin')
self.failUnless( hasattr(self.ob.fake_skin, 'test1'),
self.ob.fake_skin.getDirPath() )
+ self.assertEqual(skin._dirpath,
+ 'Products/CMFCore/tests/fake_skins/fake_skin')
# windows PRODUCTS_PATH
def test_getDirectoryInfo5(self):
@@ -91,6 +99,8 @@
r'\Products\CMFCore\tests\fake_skins\fake_skin')
self.failUnless( hasattr(self.ob.fake_skin, 'test1'),
self.ob.fake_skin.getDirPath() )
+ self.assertEqual(skin._dirpath,
+ 'Products/CMFCore/tests/fake_skins/fake_skin')
# linux PRODUCTS_PATH
def test_getDirectoryInfo6(self):
@@ -99,6 +109,8 @@
'/Products/CMFCore/tests/fake_skins/fake_skin')
self.failUnless( hasattr(self.ob.fake_skin, 'test1'),
self.ob.fake_skin.getDirPath() )
+ self.assertEqual(skin._dirpath,
+ 'Products/CMFCore/tests/fake_skins/fake_skin')
# second 'Products' in path
def test_getDirectoryInfo7(self):
@@ -107,7 +119,18 @@
r'C:\CoolProducts\Zope\Products\CMFCore\tests\fake_skins\fake_skin')
self.failUnless( hasattr(self.ob.fake_skin, 'test1'),
self.ob.fake_skin.getDirPath() )
+ self.assertEqual(skin._dirpath,
+ 'Products/CMFCore/tests/fake_skins/fake_skin')
+ # *No* 'Products' in path (typical for sites upgraded from 1.5.x)
+ def test_getDirectoryInfo8(self):
+ skin = self.ob.fake_skin
+ skin.manage_properties('CMFCore/tests/fake_skins/fake_skin')
+ self.failUnless( hasattr(self.ob.fake_skin, 'test1'),
+ self.ob.fake_skin.getDirPath() )
+ self.assertEqual(skin._dirpath,
+ 'Products/CMFCore/tests/fake_skins/fake_skin')
+
# Test we do nothing if given a really wacky path
def test_UnhandleableExpandPath( self ):
from tempfile import mktemp
@@ -137,10 +160,11 @@
def test_registerDirectoryMinimalPath(self):
from Products.CMFCore.DirectoryView import _dirreg
dirs = _dirreg._directories
- self.failUnless( dirs.has_key('CMFCore/tests/fake_skins/fake_skin'),
+ self.failUnless( dirs.has_key(
+ 'Products/CMFCore/tests/fake_skins/fake_skin'),
dirs.keys() )
self.assertEqual( self.ob.fake_skin.getDirPath(),
- 'CMFCore/tests/fake_skins/fake_skin' )
+ 'Products/CMFCore/tests/fake_skins/fake_skin' )
class DirectoryViewTests( FSDVTest ):
@@ -290,7 +314,52 @@
self.failUnless('Products/Rotten/skins' in added)
self.failUnless('Products/Rotten/skins/rotten' in added)
+class Test_normalizeDirPath( TestCase ):
+ def _check(self, before, after):
+ from Products.CMFCore.DirectoryView import _normalizeDirPath
+ self.assertEqual(_normalizeDirPath(before), after)
+
+ def test__nDP_already_normalized(self):
+ BEFORE = 'Products/CMFCore/skins/foo'
+ AFTER = 'Products/CMFCore/skins/foo'
+ self._check(BEFORE, AFTER)
+
+ def test__nDP_product_but_backward_slashes(self):
+ BEFORE = r'Products\CMFCore\skins\foo'
+ AFTER = 'Products/CMFCore/skins/foo'
+ self._check(BEFORE, AFTER)
+
+ def test__nDP_no_Products_forward_slashes(self):
+ BEFORE = 'CMFCore/skins/foo'
+ AFTER = 'Products/CMFCore/skins/foo'
+ self._check(BEFORE, AFTER)
+
+ def test__nDP_no_Products_backward_slashes(self):
+ BEFORE = r'CMFCore\skins\foo'
+ AFTER = 'Products/CMFCore/skins/foo'
+ self._check(BEFORE, AFTER)
+
+ def test__nDP_leading_path_forward_slashes(self):
+ BEFORE = '/var/zope_instance/Products/CMFCore/skins/foo'
+ AFTER = 'Products/CMFCore/skins/foo'
+ self._check(BEFORE, AFTER)
+
+ def test__nDP_leading_path_backward_slashes(self):
+ BEFORE = r'C:\zope_instance\Products\CMFCore\skins\foo'
+ AFTER = 'Products/CMFCore/skins/foo'
+ self._check(BEFORE, AFTER)
+
+ def test__nDP_abs_path_no_products_forward_slashes(self):
+ BEFORE = '/var/zope_instance/CMFCore/skins/foo'
+ AFTER = '/var/zope_instance/CMFCore/skins/foo'
+ self._check(BEFORE, AFTER)
+
+ def test__nDP_abs_path_backward_slashes(self):
+ BEFORE = r'C:\zope_instance\CMFCore\skins\foo'
+ AFTER = r'C:/zope_instance/CMFCore/skins/foo'
+ self._check(BEFORE, AFTER)
+
if DevelopmentMode:
class DebugModeTests( FSDVTest ):
@@ -369,6 +438,7 @@
makeSuite(DirectoryViewIgnoreTests),
makeSuite(DirectoryViewFolderTests),
makeSuite(DirectoryViewEggTests),
+ makeSuite(Test_normalizeDirPath),
makeSuite(DebugModeTests),
))
Modified: CMF/branches/tseaver-pkg_resources/CMFCore/utils.py
===================================================================
--- CMF/branches/tseaver-pkg_resources/CMFCore/utils.py 2005-10-27 18:17:21 UTC (rev 39677)
+++ CMF/branches/tseaver-pkg_resources/CMFCore/utils.py 2005-10-27 18:20:13 UTC (rev 39678)
@@ -757,6 +757,9 @@
if os_path.isabs(p):
return p
+ if p.startswith('Products'):
+ p = p[len('Products/'):]
+
for ppath in ProductsPath:
abs = os_path.join(ppath, p)
if os_path.exists(abs):
Modified: CMF/branches/tseaver-pkg_resources/CMFDefault/profiles/default/skins.xml
===================================================================
--- CMF/branches/tseaver-pkg_resources/CMFDefault/profiles/default/skins.xml 2005-10-27 18:17:21 UTC (rev 39677)
+++ CMF/branches/tseaver-pkg_resources/CMFDefault/profiles/default/skins.xml 2005-10-27 18:20:13 UTC (rev 39678)
@@ -3,13 +3,13 @@
request_varname="portal_skin" allow_any="0"
cookie_persistence="0">
<skin-directory id="Images"
- directory="CMFDefault/skins/Images"/>
+ directory="Products/CMFDefault/skins/Images"/>
<skin-directory id="zpt_content"
- directory="CMFDefault/skins/zpt_content"/>
+ directory="Products/CMFDefault/skins/zpt_content"/>
<skin-directory id="zpt_control"
- directory="CMFDefault/skins/zpt_control"/>
+ directory="Products/CMFDefault/skins/zpt_control"/>
<skin-directory id="zpt_generic"
- directory="CMFDefault/skins/zpt_generic"/>
+ directory="Products/CMFDefault/skins/zpt_generic"/>
<skin-path id="Basic">
<layer name="custom"/>
<layer name="zpt_content"/>
More information about the CMF-checkins
mailing list