Commit c56dd40c authored by Hanno Schlichting's avatar Hanno Schlichting

Removed various persistent product related code and options. The...

Removed various persistent product related code and options. The `enable-product-installation` `zope.conf` setting is now a no-op.
parent 96d3f682
......@@ -33,6 +33,9 @@ Features Added
Restructuring
+++++++++++++
- Removed various persistent product related code and options. The
`enable-product-installation` `zope.conf` setting is now a no-op.
- Changed the value for `default-zpublisher-encoding` and
`management_page_charset` to `utf-8`.
......
......@@ -254,7 +254,7 @@ InitializeClass(DebugManager)
class ApplicationManager(Folder,CacheManager):
class ApplicationManager(Folder, CacheManager):
"""System management
"""
__roles__ = ('Manager',)
......
......@@ -98,13 +98,7 @@ class ProductDispatcher(Implicit):
'__FactoryDispatcher__',
FactoryDispatcher)
productfolder = self.aq_acquire('_getProducts')()
try:
product = productfolder._product(name)
except AttributeError:
# If we do not have a persistent product entry, return
product = Product(name)
product = Product(name)
dispatcher=dispatcher_class(product, self.aq_parent, REQUEST)
return dispatcher.__of__(self)
......
......@@ -10,37 +10,9 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Product objects
"""
# The new Product model:
#
# Products may be defined in the Products folder or by placing directories
# in lib/python/Products.
#
# Products in lib/python/Products may have up to three sources of information:
#
# - Static information defined via Python. This information is
# described and made available via __init__.py.
#
# - Dynamic object data that gets copied into the Bobobase.
# This is contained in product.dat (which is obfuscated).
#
# - Static extensions supporting the dynamic data. These too
# are obfuscated.
#
# Products may be copied and pasted only within the products folder.
#
# If a product is deleted (or cut), it is automatically recreated
# on restart if there is still a product directory.
import os
from AccessControl.class_init import InitializeClass
from AccessControl.owner import UnownableOwner
from AccessControl.SecurityInfo import ClassSecurityInfo
from AccessControl.unauthorized import Unauthorized
from App.special_dtml import DTMLFile
from OFS.Folder import Folder
......@@ -65,225 +37,3 @@ class ProductFolder(Folder):
return 0
InitializeClass(ProductFolder)
class Product(Folder):
"""Model a product that can be created through the web.
"""
security = ClassSecurityInfo()
meta_type='Product'
icon='p_/Product_icon'
version=''
configurable_objects_=()
import_error_=None
manage_options = (
(Folder.manage_options[0],) +
tuple(Folder.manage_options[2:])
)
_properties = Folder._properties+(
{'id':'version', 'type': 'string'},
)
_reserved_names=('Help',)
def __init__(self, id, title):
from HelpSys.HelpSys import ProductHelp
self.id = id
self.title = title
self._setObject('Help', ProductHelp('Help', id))
security.declarePublic('Destination')
def Destination(self):
"Return the destination for factory output"
return self
security.declarePublic('DestinationURL')
def DestinationURL(self):
"Return the URL for the destination for factory output"
return self.REQUEST['BASE4']
manage_traceback = DTMLFile('dtml/traceback', globals())
manage_readme = DTMLFile('dtml/readme', globals())
def manage_get_product_readme__(self):
for name in ('README.txt', 'README.TXT', 'readme.txt'):
path = os.path.join(self.home, name)
if os.path.isfile(path):
return open(path).read()
return ''
def permissionMappingPossibleValues(self):
return self.possible_permissions()
def getProductHelp(self):
"""Returns the ProductHelp object associated with the Product.
"""
from HelpSys.HelpSys import ProductHelp
if not hasattr(self, 'Help'):
self._setObject('Help', ProductHelp('Help', self.id))
return self.Help
#
# Product refresh
#
_refresh_dtml = DTMLFile('dtml/refresh', globals())
def _readRefreshTxt(self, pid=None):
import Products
refresh_txt = None
if pid is None:
pid = self.id
for productDir in Products.__path__:
found = 0
for name in ('refresh.txt', 'REFRESH.txt', 'REFRESH.TXT'):
p = os.path.join(productDir, pid, name)
if os.path.exists(p):
found = 1
break
if found:
try:
file = open(p)
text = file.read()
file.close()
refresh_txt = text
break
except:
# Not found here.
pass
return refresh_txt
def manage_performRefresh(self, REQUEST=None):
""" Attempts to perform a refresh operation.
"""
from App.RefreshFuncs import performFullRefresh
if self._readRefreshTxt() is None:
raise Unauthorized, 'refresh.txt not found'
message = None
if performFullRefresh(self._p_jar, self.id):
from ZODB import Connection
Connection.resetCaches() # Clears cache in future connections.
message = 'Product refreshed.'
else:
message = 'An exception occurred.'
if REQUEST is not None:
return self.manage_refresh(REQUEST, manage_tabs_message=message)
def manage_enableAutoRefresh(self, enable=0, REQUEST=None):
""" Changes the auto refresh flag for this product.
"""
from App.RefreshFuncs import enableAutoRefresh
if self._readRefreshTxt() is None:
raise Unauthorized, 'refresh.txt not created'
enableAutoRefresh(self._p_jar, self.id, enable)
if enable:
message = 'Enabled auto refresh.'
else:
message = 'Disabled auto refresh.'
if REQUEST is not None:
return self.manage_refresh(REQUEST, manage_tabs_message=message)
def manage_selectDependentProducts(self, selections=(), REQUEST=None):
""" Selects which products to refresh simultaneously.
"""
from App.RefreshFuncs import setDependentProducts
if self._readRefreshTxt() is None:
raise Unauthorized, 'refresh.txt not created'
setDependentProducts(self._p_jar, self.id, selections)
if REQUEST is not None:
return self.manage_refresh(REQUEST)
InitializeClass(Product)
def initializeProduct(productp, name, home, app):
# Initialize a persistent product
assert doInstall()
fver = ''
if hasattr(productp, '__import_error__'):
ie = productp.__import_error__
else:
ie = None
# Retrieve version number from any suitable version.txt
for fname in ('version.txt', 'VERSION.txt', 'VERSION.TXT'):
try:
fpath = os.path.join(home, fname)
fhandle = open(fpath, 'r')
fver = fhandle.read().strip()
fhandle.close()
break
except IOError:
continue
old = None
products = app.Control_Panel.Products
try:
if ihasattr(products, name):
old=getattr(products, name)
if ihasattr(old,'version') and old.version==fver:
if hasattr(old, 'import_error_') and \
old.import_error_==ie:
# Version hasn't changed. Don't reinitialize.
return old
except:
pass
f = fver and (" (%s)" % fver)
product=Product(name, 'Installed product %s%s' % (name, f))
if old is not None:
app._manage_remove_product_meta_type(product)
products._delObject(name)
for id, v in old.objectItems():
try:
product._setObject(id, v)
except:
pass
products._setObject(name, product)
product.home = home
if ie:
product.import_error_=ie
product.title='Broken product %s' % name
product.icon='p_/BrokenProduct_icon'
product.manage_options=(
{'label':'Traceback', 'action':'manage_traceback'},
)
for name in ('README.txt', 'README.TXT', 'readme.txt'):
path = os.path.join(home, name)
if os.path.isfile(path):
product.manage_options=product.manage_options+(
{'label':'README', 'action':'manage_readme'},
)
break
# Ensure this product has a refresh tab.
found = 0
for option in product.manage_options:
if option.get('label') == 'Refresh':
found = 1
break
if not found:
product.manage_options = product.manage_options + (
{'label':'Refresh', 'action':'manage_refresh'},
)
return product
def ihasattr(o, name):
return hasattr(o, name) and o.__dict__.has_key(name)
def doInstall():
from App.config import getConfiguration
return getConfiguration().enable_product_installation
......@@ -190,9 +190,7 @@ class ProductContext:
# currently also required by the _verifyObjectPaste
# method of CopyContainers like Folders.
'action': ('manage_addProduct/%s/%s' % (pid, name)),
# 'product': Used by ProductRegistry for TTW products and by
# OFS.Application for refreshing products.
# This key might not be available.
# 'product': No longer used
'product': pid,
# 'permission': Guards the add action.
'permission': permission,
......
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# 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
#
##############################################################################
# Product registry and new product factory model. There will be a new
# mechanism for defining actions for meta types. If an action is of
# the form:
#
# manage_addProduct-name-factoryid
#
# Then the machinery that invokes an add-product form
# will return:
# ....what?
class ProductRegistryMixin:
# This class implements a protocol for registering products that
# are defined through the web.
# This class is a mix-in class for the top-level application object.
def _manage_remove_product_meta_type(self, product,
id=None, meta_type=None):
r=[]
pid=product.id
for mt in self._getProductRegistryMetaTypes():
if 'product' in mt:
if mt['product']==pid and (
meta_type is None or meta_type==mt['name']):
continue
elif meta_type==mt['name']: continue
r.append(mt)
self._setProductRegistryMetaTypes(tuple(r))
def _constructor_prefix_string(self, pid):
return 'manage_addProduct/%s/' % pid
def _manage_add_product_meta_type(self, product, id, meta_type,
permission=''):
pid=product.id
meta_types=self._getProductRegistryMetaTypes()
for mt in meta_types:
if mt['name']==meta_type:
if 'product' not in mt: mt['product']=pid
if mt['product'] != pid:
raise ValueError, (
'The type <em>%s</em> is already defined.' % meta_type)
mt['action']='%s%s' % (
self._constructor_prefix_string(pid), id)
if permission: mt['permission']=permission
return
mt={
'name': meta_type,
'action': ('%s%s' % (
self._constructor_prefix_string(pid), id)),
'product': pid
}
if permission: mt['permission']=permission
self._setProductRegistryMetaTypes(meta_types+(mt,))
# HACK - sometimes an unwrapped App object seems to be passed as
# self to these methods, which means that they dont have an aq_aquire
# method. Until Jim has time to look into this, this aq_maybe method
# appears to be an effective work-around...
def aq_maybe(self, name):
if hasattr(self, name):
return getattr(self, name)
return self.aq_acquire(name)
def _manage_add_product_data(self, type, product, id, **data):
values=filter(
lambda d, product=product, id=id:
not (d['product']==product and d['id']==id),
list(self.aq_maybe('_getProductRegistryData')(type))
)
data['product']=product
data['id']=id
values.append(data)
self.aq_maybe('_setProductRegistryData')(type, tuple(values))
def _manage_remove_product_data(self, type, product, id):
values=filter(
lambda d, product=product, id=id:
not (d['product']==product and d['id']==id),
self.aq_maybe('_getProductRegistryData')(type)
)
self.aq_maybe('_setProductRegistryData')(type, tuple(values))
class ProductRegistry(ProductRegistryMixin):
# This class implements a protocol for registering products that
# are defined through the web. It also provides methods for
# getting hold of the Product Registry, Control_Panel.Products.
# This class is a mix-in class for the top-level application object.
def _getProducts(self): return self.Control_Panel.Products
_product_meta_types=()
def _getProductRegistryMetaTypes(self):
return self._product_meta_types
def _setProductRegistryMetaTypes(self, v):
self._product_meta_types=v
def _getProductRegistryData(self, name):
return getattr(self, '_product_%s' % name)
def _setProductRegistryData(self, name, v):
name='_product_%s' % name
if hasattr(self, name):
return setattr(self, name, v)
else:
raise AttributeError, name
This diff is collapsed.
<dtml-var manage_page_header>
<dtml-var manage_tabs>
<dtml-var manage_get_product_readme__ fmt=structured-text>
<dtml-var manage_page_footer>
<dtml-comment>
Arguments for this method:
id, refresh_txt, error_type, error_value, error_tb, devel_mode,
auto_refresh_enabled, auto_refresh_other, dependent_products,
loaded_modules
</dtml-comment>
<dtml-let form_title="'Refresh product: ' + id">
<dtml-if manage_page_header>
<dtml-var manage_page_header>
<dtml-else>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html lang="en">
<head>
<title>&dtml-form_title;</title>
</head>
<body bgcolor="#FFFFFF" link="#000099" vlink="#555555">
<h3>&dtml-form_title;</h3>
</dtml-if>
</dtml-let>
<dtml-var manage_tabs>
<dtml-if expr="refresh_txt == _.None">
<p>The refresh function, designed to ease the development of Zope
products, is not currently enabled for this product.
To make it available, put a file named "refresh.txt" in the &dtml-id;
product directory. Please note that not all products are
compatible with the refresh function.</p>
<dtml-else>
<dtml-if error_type>
<p><b>An exception occurred during the last refresh.</b><br />
Exception type: <b>&dtml-error_type;</b> <br />
Exception value: <b>&dtml-error_value;</b>
</p>
<pre>&dtml-error_tb;</pre>
<hr />
</dtml-if>
<form action="&dtml-absolute_url;" method="POST">
<table border="0">
<tr>
<td valign="top">
<dtml-if expr="_.string.strip(refresh_txt)">
<p>
<b>Important information about refreshing this product:</b><br />
<dtml-var refresh_txt fmt="structured-text">
</p>
</dtml-if>
<div align="center"><input type="submit"
name="manage_performRefresh:method" value="Refresh this product" />
</div>
<p>
<dtml-if auto_refresh_enabled>
<dtml-if devel_mode>
Auto refresh is enabled. Zope will repeatedly scan for
changes to the Python modules that make up this product and
execute a refresh when needed.
<dtml-else>
Although auto refresh is enabled, Zope is not in development
mode so auto refresh is not available. Use the "-D" argument
when starting Zope to enable development mode.
</dtml-if>
<dtml-else>
Auto refresh is disabled. Enable auto refresh
to cause Zope to frequently scan this product for changes.
Note that auto refresh can slow down Zope considerably
if enabled for more than a few products.
</dtml-if>
<br />
<dtml-let checked="auto_refresh_enabled and 'checked' or ' '">
<input type="checkbox" name="enable" value="1" &dtml-checked; />
Auto refresh mode &nbsp;
<input type="submit" name="manage_enableAutoRefresh:method"
value="Change" />
</dtml-let>
</p>
<dtml-if auto_refresh_other>
<p>Select dependent auto-refreshable products to be refreshed
simultaneously.<br />
<dtml-in auto_refresh_other sort>
<dtml-let checked="(_['sequence-item'] in dependent_products) and
'checked' or ' '">
<input type="checkbox" name="selections:list"
value="&dtml-sequence-item;" &dtml-checked; />
</dtml-let>
</dtml-in>
<input type="submit" name="manage_selectDependentProducts:method"
value="Change" />
</p>
</dtml-if>
</td>
<td valign="top" class="row-hilite">
<p><b>Refreshable product modules:</b></p>
<ul>
<dtml-in loaded_modules sort>
<li>&dtml-sequence-item;</li>
</dtml-in>
</ul>
</td>
</tr>
</table>
</form>
</dtml-if>
<dtml-if manage_page_footer>
<dtml-var manage_page_footer>
<dtml-else>
</body></html>
</dtml-if>
<dtml-var manage_page_header>
<dtml-var manage_tabs>
<h3>Import Traceback</h3>
<pre>&dtml-import_error_;</pre>
<dtml-var manage_page_footer>
......@@ -350,11 +350,6 @@ class ApplicationManagerTests(ConfigTestBase,
am = self._makeOne()
self.assertEqual(am.sys_platform(), sys.platform)
def test_ctor_initializes_Products(self):
from App.Product import ProductFolder
am = self._makeOne()
self.assertTrue(isinstance(am.Products, ProductFolder))
def test__canCopy(self):
am = self._makeOne()
self.assertFalse(am._canCopy())
......
This diff is collapsed.
......@@ -210,14 +210,6 @@ class ObjectManager(CopyContainer,
import Products
external_candidates = []
# Look at _product_meta_types, if there is one
_pmt=()
if hasattr(self, '_product_meta_types'): _pmt=self._product_meta_types
elif hasattr(self, 'aq_acquire'):
try: _pmt=self.aq_acquire('_product_meta_types')
except: pass
external_candidates.extend(list(_pmt))
# Look at all globally visible meta types.
for entry in getattr(Products, 'meta_types', ()):
if ( (interfaces is not None) or (entry.get("visibility", None)=="Global") ):
......
......@@ -221,22 +221,10 @@ class TestProductInit( unittest.TestCase ):
self.configure(cfg)
app = getApp()
from OFS.Application import install_products
install_products(app)
install_products()
obids = app.Control_Panel.Products.keys()
self.assertEquals(obids, [])
def test_install_products_enabled(self):
self.makeFakeProducts()
cfg2 = cfg + '\nenable-product-installation on'
self.configure(cfg2)
app = getApp()
from OFS.Application import install_products
install_products(app)
obids = app.Control_Panel.Products.keys()
for name in FAKEPRODUCTS:
self.assert_(name in obids)
def test_suite():
suite = unittest.TestSuite()
......
......@@ -51,9 +51,7 @@ def test_registerPackage():
>>> import Zope2
>>> from OFS.Application import install_products
>>> app = Zope2.app()
>>> install_products(app)
>>> install_products()
pythonproduct2 initialized
Make sure it is registered:
......
......@@ -176,11 +176,10 @@ def _installProduct(name, quiet=0):
if _patched and not _installedProducts.has_key(name):
for priority, product_name, index, product_dir in get_products():
if product_name == name:
if not quiet: _print('Installing %s ... ' % product_name)
# We want to fail immediately if a product throws an exception
# during install, so we set the raise_exc flag.
if not quiet:
_print('Installing %s ... ' % product_name)
install_product(_theApp, product_dir, product_name, meta_types,
get_folder_permissions(), raise_exc=1)
get_folder_permissions())
_installedProducts[product_name] = 1
Products.meta_types = Products.meta_types + tuple(meta_types)
InitializeClass(Folder)
......@@ -207,10 +206,9 @@ def _installPackage(name, quiet=0):
if _patched and not _installedPackages.has_key(name):
for module, init_func in get_packages_to_initialize():
if module.__name__ == name:
if not quiet: _print('Installing %s ... ' % module.__name__)
# We want to fail immediately if a package throws an exception
# during install, so we set the raise_exc flag.
install_package(_theApp, module, init_func, raise_exc=1)
if not quiet:
_print('Installing %s ... ' % module.__name__)
install_package(_theApp, module, init_func)
_installedPackages[module.__name__] = 1
if not quiet:
_print('done (%.3fs)\n' % (time.time() - start))
......
......@@ -127,10 +127,6 @@ def startup():
# Initialize the app object
application = app()
OFS.Application.initialize(application)
if getConfiguration().debug_mode:
# Set up auto-refresh.
from App.RefreshFuncs import setupAutoRefresh
setupAutoRefresh(application._p_jar)
application._p_jar.close()
# "Log off" as system user
......
......@@ -414,10 +414,7 @@
<key name="enable-product-installation" datatype="boolean" default="off">
<description>
If this directive is turned on, Zope performs 'product installation'
(the registration of Python modules in various Products directories)
at startup. Only turn this on if your code relies on the Products section
in the Control_Panel to be populated.
BBB: This directive has no effect anymore.
</description>
<metadefault>off</metadefault>
</key>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment