Commit f73b625c authored by Julien Muchembled's avatar Julien Muchembled

BT: don't export 'revision' anymore

Because on DVCS with branches, history is not always linear, we must stop
using increasing integer for revisions because they cause too many conflicts
and a higher revision number does not necessarily means the a BT newer.
They're now a cryptographic hash of all the contents of the Business Template,
and they're computed automatically:
- by genbt5list
- at download
- at building (by default)
- at export
parent ce483b26
...@@ -85,6 +85,8 @@ import posixpath ...@@ -85,6 +85,8 @@ import posixpath
import transaction import transaction
import threading import threading
from Products.ERP5.genbt5list import BusinessTemplateRevision, \
item_name_list, item_set
CACHE_DATABASE_PATH = None CACHE_DATABASE_PATH = None
try: try:
...@@ -306,6 +308,7 @@ class BusinessTemplateArchive(object): ...@@ -306,6 +308,7 @@ class BusinessTemplateArchive(object):
""" """
def __init__(self, path, **kw): def __init__(self, path, **kw):
self.path = path self.path = path
self.revision = BusinessTemplateRevision()
def addObject(self, obj, name, path=None, ext='.xml'): def addObject(self, obj, name, path=None, ext='.xml'):
if path: if path:
...@@ -320,15 +323,23 @@ class BusinessTemplateArchive(object): ...@@ -320,15 +323,23 @@ class BusinessTemplateArchive(object):
if not isinstance(obj, str): if not isinstance(obj, str):
obj.seek(0) obj.seek(0)
obj = obj.read() obj = obj.read()
self.revision.hash(path, obj)
self._writeString(obj, path) self._writeString(obj, path)
else: else:
if isinstance(obj, str): if isinstance(obj, str):
self.revision.hash(path, obj)
obj = StringIO(obj) obj = StringIO(obj)
else:
obj.seek(0)
self.revision.hash(path, obj.read())
write(obj, path) write(obj, path)
def finishCreation(self): def finishCreation(self):
pass pass
def getRevision(self):
return self.revision.digest()
class BusinessTemplateFolder(BusinessTemplateArchive): class BusinessTemplateFolder(BusinessTemplateArchive):
""" """
Class archiving business template into a folder tree Class archiving business template into a folder tree
...@@ -348,9 +359,8 @@ class BusinessTemplateFolder(BusinessTemplateArchive): ...@@ -348,9 +359,8 @@ class BusinessTemplateFolder(BusinessTemplateArchive):
Import file from a local folder Import file from a local folder
""" """
join = os.path.join join = os.path.join
path = os.path.normpath(self.path) item_name = item.__class__.__name__
class_name = item.__class__.__name__ root = join(os.path.normpath(self.path), item_name, '')
root = join(path, class_name, '')
root_path_len = len(root) root_path_len = len(root)
if CACHE_DATABASE_PATH: if CACHE_DATABASE_PATH:
try: try:
...@@ -362,9 +372,13 @@ class BusinessTemplateFolder(BusinessTemplateArchive): ...@@ -362,9 +372,13 @@ class BusinessTemplateFolder(BusinessTemplateArchive):
for file_name in files: for file_name in files:
file_name = join(root, file_name) file_name = join(root, file_name)
with open(file_name, 'rb') as f: with open(file_name, 'rb') as f:
file_name = file_name[root_path_len:] file_name = posixpath.normpath(file_name[root_path_len:])
if '%' in file_name: if '%' in file_name:
file_name = unquote(file_name) file_name = unquote(file_name)
elif item_name == 'bt' and file_name == 'revision':
continue
self.revision.hash(item_name + '/' + file_name, f.read())
f.seek(0)
item._importFile(file_name, f) item._importFile(file_name, f)
finally: finally:
if hasattr(cache_database, 'db'): if hasattr(cache_database, 'db'):
...@@ -411,10 +425,16 @@ class BusinessTemplateTarball(BusinessTemplateArchive): ...@@ -411,10 +425,16 @@ class BusinessTemplateTarball(BusinessTemplateArchive):
Import all file from the archive to the site Import all file from the archive to the site
""" """
extractfile = self.tar.extractfile extractfile = self.tar.extractfile
for file_name, info in self.item_dict.get(item.__class__.__name__, ()): item_name = item.__class__.__name__
for file_name, info in self.item_dict.get(item_name, ()):
if '%' in file_name: if '%' in file_name:
file_name = unquote(file_name) file_name = unquote(file_name)
item._importFile(file_name, extractfile(info)) elif item_name == 'bt' and file_name == 'revision':
continue
f = extractfile(info)
self.revision.hash(item_name + '/' + file_name, f.read())
f.seek(0)
item._importFile(file_name, f)
class TemplateConditionError(Exception): pass class TemplateConditionError(Exception): pass
class TemplateConflictError(Exception): pass class TemplateConflictError(Exception): pass
...@@ -4782,63 +4802,6 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -4782,63 +4802,6 @@ Business Template is a set of definitions, such as skins, portal types and categ
, 'filter_content_types' : 1 , 'filter_content_types' : 1
} }
# This is a global variable
# Order is important for installation
# We want to have:
# * path after module, because path can be module content
# * path after categories, because path can be categories content
# * path after portal types roles so that roles in the current bt can be used
# * path before workflow chain, because path can be a portal type
# (until chains are set on portal types with categories)
# * skin after paths, because we can install a custom connection string as
# path and use it with SQLMethods in a skin.
# ( and more )
_item_name_list = [
'_registered_version_priority_selection_item',
'_product_item',
'_document_item',
'_property_sheet_item',
'_constraint_item',
'_extension_item',
'_test_item',
'_role_item',
'_tool_item',
'_message_translation_item',
'_workflow_item',
'_site_property_item',
'_portal_type_item',
#'_portal_type_workflow_chain_item',
'_portal_type_allowed_content_type_item',
'_portal_type_hidden_content_type_item',
'_portal_type_property_sheet_item',
'_portal_type_base_category_item',
'_category_item',
'_module_item',
'_portal_type_roles_item',
'_path_item',
'_skin_item',
'_registered_skin_selection_item',
'_preference_item',
'_action_item',
'_local_roles_item',
'_portal_type_workflow_chain_item',
'_catalog_method_item',
'_catalog_result_key_item',
'_catalog_related_key_item',
'_catalog_result_table_item',
'_catalog_search_key_item',
'_catalog_keyword_key_item',
'_catalog_datetime_key_item',
'_catalog_full_text_key_item',
'_catalog_request_key_item',
'_catalog_multivalue_key_item',
'_catalog_topic_key_item',
'_catalog_scriptable_key_item',
'_catalog_role_key_item',
'_catalog_local_role_key_item',
'_catalog_security_uid_column_item',
]
def __init__(self, *args, **kw): def __init__(self, *args, **kw):
XMLObject.__init__(self, *args, **kw) XMLObject.__init__(self, *args, **kw)
self._clean() self._clean()
...@@ -4870,23 +4833,10 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -4870,23 +4833,10 @@ Business Template is a set of definitions, such as skins, portal types and categ
self.workflow_history[ self.workflow_history[
'business_template_installation_workflow'] = None 'business_template_installation_workflow'] = None
security.declareProtected(Permissions.AccessContentsInformation, def getShortRevision(self):
'getRevision') """Returned a shortened revision"""
def getRevision(self): r = self.getRevision()
"""returns the revision property. return r and r[:5]
This is a workaround for #461.
"""
return self._baseGetRevision()
def updateRevisionNumber(self):
"""Increment bt revision number.
"""
revision_number = self.getRevision()
if revision_number is None or revision_number.strip() == '':
revision_number = 1
else:
revision_number = int(revision_number)+1
self.setRevision(revision_number)
security.declareProtected(Permissions.ManagePortal, 'storeTemplateItemData') security.declareProtected(Permissions.ManagePortal, 'storeTemplateItemData')
def storeTemplateItemData(self): def storeTemplateItemData(self):
...@@ -5009,7 +4959,7 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -5009,7 +4959,7 @@ Business Template is a set of definitions, such as skins, portal types and categ
pass pass
security.declareProtected(Permissions.ManagePortal, 'build') security.declareProtected(Permissions.ManagePortal, 'build')
def build(self, no_action=0): def build(self, no_action=0, update_revision=True):
""" """
Copy existing portal objects to self Copy existing portal objects to self
""" """
...@@ -5018,19 +4968,11 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -5018,19 +4968,11 @@ Business Template is a set of definitions, such as skins, portal types and categ
# Make sure that everything is sane. # Make sure that everything is sane.
self.clean() self.clean()
try:
from Products.ERP5VCS.WorkingCopy import NotAWorkingCopyError
try:
self.setRevision(self.getVcsTool().newRevision())
except NotAWorkingCopyError:
raise ImportError
except ImportError:
self.updateRevisionNumber()
self._setTemplateFormatVersion(1) self._setTemplateFormatVersion(1)
self.storeTemplateItemData() self.storeTemplateItemData()
# Build each part # Build each part
for item_name in self._item_name_list: for item_name in item_name_list:
item = getattr(self, item_name) item = getattr(self, item_name)
if item is None: if item is None:
continue continue
...@@ -5039,6 +4981,8 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -5039,6 +4981,8 @@ Business Template is a set of definitions, such as skins, portal types and categ
item.build(self) item.build(self)
# update _p_jar property of objects cleaned by removeProperties # update _p_jar property of objects cleaned by removeProperties
transaction.savepoint(optimistic=True) transaction.savepoint(optimistic=True)
if update_revision:
self._export()
def publish(self, url, username=None, password=None): def publish(self, url, username=None, password=None):
""" """
...@@ -5118,14 +5062,14 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -5118,14 +5062,14 @@ Business Template is a set of definitions, such as skins, portal types and categ
return modified_object_list return modified_object_list
elif installed_bt_format == 0 and new_bt_format == 1: elif installed_bt_format == 0 and new_bt_format == 1:
# return list of all object in bt # return list of all object in bt
for item_name in self._item_name_list: for item_name in item_name_list:
item = getattr(self, item_name, None) item = getattr(self, item_name, None)
if item is not None: if item is not None:
for path in item._objects.keys(): for path in item._objects.keys():
modified_object_list.update({path : ['New', item.__class__.__name__[:-12]]}) modified_object_list.update({path : ['New', item.__class__.__name__[:-12]]})
return modified_object_list return modified_object_list
for item_name in self._item_name_list: for item_name in item_name_list:
new_item = getattr(self, item_name, None) new_item = getattr(self, item_name, None)
installed_item = getattr(installed_bt, item_name, None) installed_item = getattr(installed_bt, item_name, None)
if new_item is not None: if new_item is not None:
...@@ -5186,7 +5130,7 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -5186,7 +5130,7 @@ Business Template is a set of definitions, such as skins, portal types and categ
# Install everything # Install everything
if len(object_to_update) or force: if len(object_to_update) or force:
for item_name in self._item_name_list: for item_name in item_name_list:
item = getattr(self, item_name, None) item = getattr(self, item_name, None)
if item is not None: if item is not None:
item.install(self, force=force, object_to_update=object_to_update, item.install(self, force=force, object_to_update=object_to_update,
...@@ -5211,7 +5155,7 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -5211,7 +5155,7 @@ Business Template is a set of definitions, such as skins, portal types and categ
# remove object from old business template # remove object from old business template
if len(remove_object_dict): if len(remove_object_dict):
# XXX: this code assumes that there is an installed_bt # XXX: this code assumes that there is an installed_bt
for item_name in reversed(installed_bt._item_name_list): for item_name in reversed(item_name_list):
item = getattr(installed_bt, item_name, None) item = getattr(installed_bt, item_name, None)
if item is not None: if item is not None:
item.remove(self, remove_object_dict=remove_object_dict, trashbin=trashbin) item.remove(self, remove_object_dict=remove_object_dict, trashbin=trashbin)
...@@ -5255,7 +5199,7 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -5255,7 +5199,7 @@ Business Template is a set of definitions, such as skins, portal types and categ
not remove all items. not remove all items.
""" """
# Trash everything # Trash everything
for item_name in self._item_name_list[::-1]: for item_name in reversed(item_name_list):
item = getattr(self, item_name, None) item = getattr(self, item_name, None)
if item is not None: if item is not None:
item.trash( item.trash(
...@@ -5268,7 +5212,7 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -5268,7 +5212,7 @@ Business Template is a set of definitions, such as skins, portal types and categ
""" """
# Uninstall everything # Uninstall everything
# Trash everything # Trash everything
for item_name in self._item_name_list[::-1]: for item_name in reversed(item_name_list):
item = getattr(self, item_name, None) item = getattr(self, item_name, None)
if item is not None: if item is not None:
item.uninstall(self, **kw) item.uninstall(self, **kw)
...@@ -5296,7 +5240,7 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -5296,7 +5240,7 @@ Business Template is a set of definitions, such as skins, portal types and categ
if hasattr(self, attr): if hasattr(self, attr):
delattr(self, attr) delattr(self, attr)
# Secondly, make attributes empty. # Secondly, make attributes empty.
for item_name in self._item_name_list: for item_name in item_name_list:
setattr(self, item_name, None) setattr(self, item_name, None)
security.declareProtected(Permissions.ManagePortal, 'clean') security.declareProtected(Permissions.ManagePortal, 'clean')
...@@ -5558,7 +5502,9 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -5558,7 +5502,9 @@ Business Template is a set of definitions, such as skins, portal types and categ
if self.getBuildingState() != 'built': if self.getBuildingState() != 'built':
raise TemplateConditionError, \ raise TemplateConditionError, \
'Business Template must be built before export' 'Business Template must be built before export'
return self._export(path, local, bta)
def _export(self, path=None, local=0, bta=None):
if bta is None: if bta is None:
if local: if local:
# we export into a folder tree # we export into a folder tree
...@@ -5573,7 +5519,7 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -5573,7 +5519,7 @@ Business Template is a set of definitions, such as skins, portal types and categ
for prop in self.propertyMap(): for prop in self.propertyMap():
prop_type = prop['type'] prop_type = prop['type']
id = prop['id'] id = prop['id']
if id in ('id', 'uid', 'rid', 'sid', 'id_group', 'last_id', if id in ('id', 'uid', 'rid', 'sid', 'id_group', 'last_id', 'revision',
'install_object_list_list', 'id_generator', 'bt_for_diff'): 'install_object_list_list', 'id_generator', 'bt_for_diff'):
continue continue
value = self.getProperty(id) value = self.getProperty(id)
...@@ -5585,11 +5531,12 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -5585,11 +5531,12 @@ Business Template is a set of definitions, such as skins, portal types and categ
bta.addObject('\n'.join(value), name=id, path='bt', ext='') bta.addObject('\n'.join(value), name=id, path='bt', ext='')
# Export each part # Export each part
for item_name in self._item_name_list: for item_name in item_name_list:
item = getattr(self, item_name, None) item = getattr(self, item_name, None)
if item is not None: if item is not None:
item.export(context=self, bta=bta) item.export(context=self, bta=bta)
self._setRevision(bta.getRevision())
return bta.finishCreation() return bta.finishCreation()
security.declareProtected(Permissions.ManagePortal, 'importFile') security.declareProtected(Permissions.ManagePortal, 'importFile')
...@@ -5630,7 +5577,7 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -5630,7 +5577,7 @@ Business Template is a set of definitions, such as skins, portal types and categ
setattr(module, template_id, type(template_id, setattr(module, template_id, type(template_id,
(SimpleItem.SimpleItem,), {'__module__': module_id})) (SimpleItem.SimpleItem,), {'__module__': module_id}))
for item_name in self._item_name_list: for item_name in item_name_list:
item_object = getattr(self, item_name, None) item_object = getattr(self, item_name, None)
# this check is due to backwards compatability when there can be a # this check is due to backwards compatability when there can be a
# difference between install erp5_property_sheets (esp. BusinessTemplate # difference between install erp5_property_sheets (esp. BusinessTemplate
...@@ -5643,11 +5590,13 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -5643,11 +5590,13 @@ Business Template is a set of definitions, such as skins, portal types and categ
for module_id in module_id_list: for module_id in module_id_list:
del sys.modules[module_id] del sys.modules[module_id]
self._setRevision(bta.getRevision())
def getItemsList(self): def getItemsList(self):
"""Return list of items in business template """Return list of items in business template
""" """
items_list = [] items_list = []
for item_name in self._item_name_list: for item_name in item_name_list:
item = getattr(self, item_name, None) item = getattr(self, item_name, None)
if item is not None: if item is not None:
items_list.extend(item.getKeys()) items_list.extend(item.getKeys())
...@@ -6106,5 +6055,7 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -6106,5 +6055,7 @@ Business Template is a set of definitions, such as skins, portal types and categ
# Block acquisition on all _item_name_list properties by setting # Block acquisition on all _item_name_list properties by setting
# a default class value to None # a default class value to None
for key in BusinessTemplate._item_name_list: for key in item_name_list:
setattr(BusinessTemplate, key, None) setattr(BusinessTemplate, key, None)
# Check naming convention of items.
assert item_set.issubset(globals()), item_set.difference(globals())
...@@ -44,6 +44,7 @@ from Products.ERP5Type.Tool.BaseTool import BaseTool ...@@ -44,6 +44,7 @@ from Products.ERP5Type.Tool.BaseTool import BaseTool
from Products.ERP5Type.Cache import transactional_cached from Products.ERP5Type.Cache import transactional_cached
from Products.ERP5Type import Permissions from Products.ERP5Type import Permissions
from Products.ERP5.Document.BusinessTemplate import BusinessTemplateMissingDependency from Products.ERP5.Document.BusinessTemplate import BusinessTemplateMissingDependency
from Products.ERP5.genbt5list import generateInformation
from Acquisition import aq_base from Acquisition import aq_base
from tempfile import mkstemp, mkdtemp from tempfile import mkstemp, mkdtemp
from Products.ERP5 import _dtmldir from Products.ERP5 import _dtmldir
...@@ -124,23 +125,19 @@ class TemplateTool (BaseTool): ...@@ -124,23 +125,19 @@ class TemplateTool (BaseTool):
# However, that unlikely happens, and using a Z SQL Method has a # However, that unlikely happens, and using a Z SQL Method has a
# potential danger because business templates may exchange catalog # potential danger because business templates may exchange catalog
# methods, so the database could be broken temporarily. # methods, so the database could be broken temporarily.
latest_bt = None last_bt = last_time = None
latest_revision = 0 for bt in self.objectValues(portal_type='Business Template'):
for bt in self.contentValues(filter={'portal_type':'Business Template'}):
if bt.getTitle() == title or title in bt.getProvisionList(): if bt.getTitle() == title or title in bt.getProvisionList():
installation_state = bt.getInstallationState() state = bt.getInstallationState()
if installation_state == 'installed': if state == 'installed':
latest_bt = bt return bt
break if state == 'replaced' and not strict:
elif strict is False and installation_state == 'replaced': t = bt.workflow_history \
revision = bt.getRevision() ['business_template_installation_workflow'][-1]['time']
try: if last_time < t:
revision = int(revision) last_bt = bt
except ValueError: last_time = t
continue return last_bt
if revision > latest_revision:
latest_bt = bt
return latest_bt
def getInstalledBusinessTemplatesList(self): def getInstalledBusinessTemplatesList(self):
"""Deprecated. """Deprecated.
...@@ -180,20 +177,12 @@ class TemplateTool (BaseTool): ...@@ -180,20 +177,12 @@ class TemplateTool (BaseTool):
return bt.getRevision() return bt.getRevision()
return None return None
def getBuiltBusinessTemplatesList(self):
"""Deprecated.
"""
DeprecationWarning('getBuiltBusinessTemplatesList is deprecated; Use getBuiltBusinessTemplateList instead.', DeprecationWarning)
return self.getBuiltBusinessTemplateList()
def getBuiltBusinessTemplateList(self): def getBuiltBusinessTemplateList(self):
"""Get the list of built and not installed business templates. """Get the list of built and not installed business templates.
""" """
built_bts = [] return [bt for bt in self.objectValues(portal_type='Business Template')
for bt in self.contentValues(portal_type='Business Template'): if bt.getInstallationState() == 'not_installed' and
if bt.getInstallationState() == 'not_installed' and bt.getBuildingState() == 'built': bt.getBuildingState() == 'built']
built_bts.append(bt)
return built_bts
@property @property
def asRepository(self): def asRepository(self):
...@@ -201,7 +190,7 @@ class TemplateTool (BaseTool): ...@@ -201,7 +190,7 @@ class TemplateTool (BaseTool):
"""Export business template by their title """Export business template by their title
Provides a view of template tool allowing a user to download the last Provides a view of template tool allowing a user to download the last
revision of a business template with a URL like: edited business template with a URL like:
http://.../erp5/portal_templates/asRepository/erp5_core http://.../erp5/portal_templates/asRepository/erp5_core
""" """
def __before_publishing_traverse__(self, self2, request): def __before_publishing_traverse__(self, self2, request):
...@@ -213,9 +202,9 @@ class TemplateTool (BaseTool): ...@@ -213,9 +202,9 @@ class TemplateTool (BaseTool):
last_bt = None, None last_bt = None, None
for bt in self.aq_parent.searchFolder(title=title): for bt in self.aq_parent.searchFolder(title=title):
bt = bt.getObject() bt = bt.getObject()
revision = int(bt.getRevision()) modified = bt.getModificationDate()
if last_bt[0] < revision and bt.getInstallationState() != 'deleted': if last_bt[0] < modified and bt.getInstallationState() != 'deleted':
last_bt = revision, bt last_bt = modified, bt
if last_bt[1] is None: if last_bt[1] is None:
return RESPONSE.notFoundError(title) return RESPONSE.notFoundError(title)
RESPONSE.setHeader('Content-type', 'application/data') RESPONSE.setHeader('Content-type', 'application/data')
...@@ -342,18 +331,6 @@ class TemplateTool (BaseTool): ...@@ -342,18 +331,6 @@ class TemplateTool (BaseTool):
finally: finally:
shutil.rmtree(svn_checkout_tmp_dir) shutil.rmtree(svn_checkout_tmp_dir)
def assertBtPathExists(self, url):
"""
Check if bt is present on the system
"""
urltype, name = splittype(url)
# Windows compatibility
if WIN:
if os.path.isdir(os.path.normpath(url)) or \
os.path.isfile(os.path.normpath(url)):
name = os.path.normpath(url)
return os.path.exists(os.path.normpath(name))
security.declareProtected( 'Import/Export objects', 'download' ) security.declareProtected( 'Import/Export objects', 'download' )
def download(self, url, id=None, REQUEST=None): def download(self, url, id=None, REQUEST=None):
""" """
...@@ -368,13 +345,9 @@ class TemplateTool (BaseTool): ...@@ -368,13 +345,9 @@ class TemplateTool (BaseTool):
id = self.generateNewId() id = self.generateNewId()
urltype, name = splittype(url) urltype, name = splittype(url)
# Windows compatibility if WIN and urltype and '\\' in name:
if WIN: urltype = None
if os.path.isdir(os.path.normpath(url)) or \ name = url
os.path.isfile(os.path.normpath(url)):
urltype = 'file'
name = os.path.normpath(url)
if urltype and urltype != 'file': if urltype and urltype != 'file':
if '/portal_templates/asRepository/' in url: if '/portal_templates/asRepository/' in url:
# In this case, the downloaded BT is already built. # In this case, the downloaded BT is already built.
...@@ -384,7 +357,7 @@ class TemplateTool (BaseTool): ...@@ -384,7 +357,7 @@ class TemplateTool (BaseTool):
return self[self._setObject(id, bt)] return self[self._setObject(id, bt)]
bt = self._download_url(url, id) bt = self._download_url(url, id)
else: else:
bt = self._download_local(name, id) bt = self._download_local(os.path.normpath(name), id)
bt.build(no_action=True) bt.build(no_action=True)
return bt return bt
...@@ -592,9 +565,12 @@ class TemplateTool (BaseTool): ...@@ -592,9 +565,12 @@ class TemplateTool (BaseTool):
'updateRepositoryBusinessTemplateList' ) 'updateRepositoryBusinessTemplateList' )
def updateRepositoryBusinessTemplateList(self, repository_list, def updateRepositoryBusinessTemplateList(self, repository_list,
REQUEST=None, RESPONSE=None, **kw): REQUEST=None, RESPONSE=None, genbt5list=0, **kw):
""" """
Update the information on Business Templates from repositories. Update the information on Business Templates from repositories.
For local repositories, if bt5list is missing or if genbt5list > 1,
bt5list is automatically generated (but not saved on disk).
""" """
self.repository_dict = PersistentMapping() self.repository_dict = PersistentMapping()
property_list = ('title', 'version', 'revision', 'description', 'license', property_list = ('title', 'version', 'revision', 'description', 'license',
...@@ -602,9 +578,19 @@ class TemplateTool (BaseTool): ...@@ -602,9 +578,19 @@ class TemplateTool (BaseTool):
#LOG('updateRepositoryBusiessTemplateList', 0, #LOG('updateRepositoryBusiessTemplateList', 0,
# 'repository_list = %r' % (repository_list,)) # 'repository_list = %r' % (repository_list,))
for repository in repository_list: for repository in repository_list:
url = '/'.join([repository, 'bt5list']) urltype, url = splittype(repository)
f = urlopen(url) if WIN and urltype and '\\' in url:
property_dict_list = [] urltype = None
url = repository
if urltype and urltype != 'file':
f = urlopen(repository + '/bt5list')
else:
bt5list = os.path.join(url, 'bt5list')
if genbt5list > os.path.exists(bt5list):
f = generateInformation(url)
f.seek(0)
else:
f = open(bt5list, 'rb')
try: try:
try: try:
doc = parse(f) doc = parse(f)
...@@ -618,6 +604,7 @@ class TemplateTool (BaseTool): ...@@ -618,6 +604,7 @@ class TemplateTool (BaseTool):
else: else:
raise RuntimeError, 'Invalid repository: %s' % repository raise RuntimeError, 'Invalid repository: %s' % repository
try: try:
property_dict_list = []
root = doc.documentElement root = doc.documentElement
for template in root.getElementsByTagName("template"): for template in root.getElementsByTagName("template"):
id = template.getAttribute('id') id = template.getAttribute('id')
...@@ -958,9 +945,6 @@ class TemplateTool (BaseTool): ...@@ -958,9 +945,6 @@ class TemplateTool (BaseTool):
update_only: return only bt that needs to be updated update_only: return only bt that needs to be updated
template_list: only returns bt within the given list template_list: only returns bt within the given list
""" """
version_state_title_dict = { 'new' : 'New', 'present' : 'Present',
'old' : 'Old' }
from Products.ERP5Type.Document import newTempBusinessTemplate from Products.ERP5Type.Document import newTempBusinessTemplate
result_list = [] result_list = []
template_set = None template_set = None
...@@ -987,14 +971,8 @@ class TemplateTool (BaseTool): ...@@ -987,14 +971,8 @@ class TemplateTool (BaseTool):
# if this business template is newer. # if this business template is newer.
previous_repository, previous_property_dict = \ previous_repository, previous_property_dict = \
template_item_dict[title] template_item_dict[title]
diff_version = self.compareVersions(previous_property_dict['version'], if self.compareVersions(previous_property_dict['version'],
property_dict['version']) property_dict['version']) < 0:
if diff_version < 0:
template_item_dict[title] = (repository, property_dict)
elif diff_version == 0 \
and previous_property_dict['revision'] \
and property_dict['revision'] \
and int(previous_property_dict['revision']) < int(property_dict['revision']):
template_item_dict[title] = (repository, property_dict) template_item_dict[title] = (repository, property_dict)
# Next, select only updated business templates. # Next, select only updated business templates.
if update_only: if update_only:
...@@ -1007,9 +985,8 @@ class TemplateTool (BaseTool): ...@@ -1007,9 +985,8 @@ class TemplateTool (BaseTool):
if diff_version < 0: if diff_version < 0:
template_item_list.append((repository, property_dict)) template_item_list.append((repository, property_dict))
elif diff_version == 0 \ elif diff_version == 0 \
and installed_bt.getRevision() \
and property_dict['revision'] \ and property_dict['revision'] \
and int(installed_bt.getRevision()) < int(property_dict['revision']): and installed_bt.getRevision() != property_dict['revision']:
template_item_list.append((repository, property_dict)) template_item_list.append((repository, property_dict))
elif template_list is not None: elif template_list is not None:
template_item_list.append((repository, property_dict)) template_item_list.append((repository, property_dict))
...@@ -1017,29 +994,24 @@ class TemplateTool (BaseTool): ...@@ -1017,29 +994,24 @@ class TemplateTool (BaseTool):
# Create temporary Business Template objects for displaying. # Create temporary Business Template objects for displaying.
for repository, property_dict in template_item_list: for repository, property_dict in template_item_list:
property_dict = property_dict.copy() property_dict = property_dict.copy()
id = property_dict['id'] id = filename = property_dict.pop('id')
filename = property_dict['id']
del property_dict['id']
revision = property_dict['revision']
version_state = 'new'
installed_bt = \ installed_bt = \
self.getInstalledBusinessTemplate(property_dict['title']) self.getInstalledBusinessTemplate(property_dict['title'])
if installed_bt is not None: if installed_bt is not None:
installed_version = installed_bt.getVersion() installed_version = installed_bt.getVersion()
installed_revision = installed_bt.getRevision() installed_revision = installed_bt.getShortRevision()
result = self.compareVersions(installed_revision, revision) if installed_bt.getRevision() == property_dict['revision']:
if result == 0:
version_state = 'present' version_state = 'present'
elif result < 0: else:
version_state = 'old' version_state = 'different'
else: else:
installed_version = '' installed_version = ''
installed_revision = '' installed_revision = ''
version_state_title = version_state_title_dict[version_state] version_state = 'new'
uid = self.encodeRepositoryBusinessTemplateUid(repository, id) uid = self.encodeRepositoryBusinessTemplateUid(repository, id)
obj = newTempBusinessTemplate(self, 'temp_' + uid, obj = newTempBusinessTemplate(self, 'temp_' + uid,
version_state = version_state, version_state = version_state,
version_state_title = version_state_title, version_state_title=version_state.title(),
filename = filename, filename = filename,
installed_version = installed_version, installed_version = installed_version,
installed_revision = installed_revision, installed_revision = installed_revision,
...@@ -1104,10 +1076,9 @@ class TemplateTool (BaseTool): ...@@ -1104,10 +1076,9 @@ class TemplateTool (BaseTool):
return 0 return 0
def _getBusinessTemplateUrlDict(self, newest_only=False): def _getBusinessTemplateUrlDict(self):
business_template_url_dict = {} business_template_url_dict = {}
for bt in self.getRepositoryBusinessTemplateList(\ for bt in self.getRepositoryBusinessTemplateList():
newest_only=newest_only):
url, name = self.decodeRepositoryBusinessTemplateUid(bt.getUid()) url, name = self.decodeRepositoryBusinessTemplateUid(bt.getUid())
if name.endswith('.bt5'): if name.endswith('.bt5'):
name = name[:-4] name = name[:-4]
...@@ -1119,14 +1090,11 @@ class TemplateTool (BaseTool): ...@@ -1119,14 +1090,11 @@ class TemplateTool (BaseTool):
security.declareProtected(Permissions.ManagePortal, security.declareProtected(Permissions.ManagePortal,
'installBusinessTemplatesFromRepositories') 'installBusinessTemplatesFromRepositories')
def installBusinessTemplatesFromRepositories(self, template_list, def installBusinessTemplatesFromRepositories(self, *args, **kw):
only_newer=True, update_catalog=_MARKER, activate=False,
install_dependency=False):
"""Deprecated. """Deprecated.
""" """
DeprecationWarning('installBusinessTemplatesFromRepositories is deprecated; Use self.installBusinessTemplateListFromRepository instead.', DeprecationWarning) DeprecationWarning('installBusinessTemplatesFromRepositories is deprecated; Use self.installBusinessTemplateListFromRepository instead.', DeprecationWarning)
return self.installBusinessTemplateListFromRepository(template_list, return self.installBusinessTemplateListFromRepository(*args, **kw)
only_newer, update_catalog, activate, install_dependency)
security.declareProtected(Permissions.ManagePortal, security.declareProtected(Permissions.ManagePortal,
'resolveBusinessTemplateListDependency') 'resolveBusinessTemplateListDependency')
...@@ -1187,7 +1155,7 @@ class TemplateTool (BaseTool): ...@@ -1187,7 +1155,7 @@ class TemplateTool (BaseTool):
security.declareProtected(Permissions.ManagePortal, security.declareProtected(Permissions.ManagePortal,
'installBusinessTemplateListFromRepository') 'installBusinessTemplateListFromRepository')
def installBusinessTemplateListFromRepository(self, template_list, def installBusinessTemplateListFromRepository(self, template_list,
only_newer=True, update_catalog=_MARKER, activate=False, only_different=True, update_catalog=_MARKER, activate=False,
install_dependency=False): install_dependency=False):
"""Installs template_list from configured repositories by default only newest""" """Installs template_list from configured repositories by default only newest"""
# XXX-Luke: This method could replace # XXX-Luke: This method could replace
...@@ -1197,12 +1165,13 @@ class TemplateTool (BaseTool): ...@@ -1197,12 +1165,13 @@ class TemplateTool (BaseTool):
operation_log = [] operation_log = []
resolved_template_list = self.resolveBusinessTemplateListDependency( resolved_template_list = self.resolveBusinessTemplateListDependency(
template_list) template_list)
installed_bt5_dict = dict((x.getTitle(), x.getRevision())
installed_bt5_set = set([x.title for x in self.getInstalledBusinessTemplateList())
for x in self.getInstalledBusinessTemplatesList()]) if only_different:
template_url_dict = self._getBusinessTemplateUrlDict()
def checkAvailability(bt_title): def checkAvailability(bt_title):
return bt_title in template_list or bt_title in installed_bt5_set return bt_title in template_list or bt_title in installed_bt5_dict
missing_dependency_list = [i for i in resolved_template_list missing_dependency_list = [i for i in resolved_template_list
if not checkAvailability(i[1].replace(".bt5", ""))] if not checkAvailability(i[1].replace(".bt5", ""))]
...@@ -1211,17 +1180,14 @@ class TemplateTool (BaseTool): ...@@ -1211,17 +1180,14 @@ class TemplateTool (BaseTool):
"Impossible to install, please install the following dependencies before: %s" \ "Impossible to install, please install the following dependencies before: %s" \
% [x[1] for x in missing_dependency_list] % [x[1] for x in missing_dependency_list]
template_url_dict = self._getBusinessTemplateUrlDict()
activate_kw = dict(activity="SQLQueue", tag="start_%s" % (time.time())) activate_kw = dict(activity="SQLQueue", tag="start_%s" % (time.time()))
for repository, bt_id in resolved_template_list: for repository, bt_id in resolved_template_list:
if only_different:
bt = template_url_dict.get(bt_id) bt = template_url_dict.get(bt_id)
if bt is not None and bt_id in installed_bt5_set: if bt is not None and bt['revision'] == installed_bt5_dict.get(bt_id):
revision = int(bt['revision'])
installed_bt5 = self.getInstalledBusinessTemplate(bt_id)
if int(installed_bt5.getRevision()) <= revision and only_newer:
continue continue
bt_url = '%s/%s' % (repository, bt_id) bt_url = '%s/%s' % (repository, bt_id)
param_dict = dict(download_url=bt_url, only_newer=only_newer) param_dict = dict(download_url=bt_url, only_different=only_different)
if update_catalog is not _MARKER: if update_catalog is not _MARKER:
param_dict["update_catalog"] = update_catalog param_dict["update_catalog"] = update_catalog
...@@ -1234,7 +1200,7 @@ class TemplateTool (BaseTool): ...@@ -1234,7 +1200,7 @@ class TemplateTool (BaseTool):
else: else:
document = self.updateBusinessTemplateFromUrl(**param_dict) document = self.updateBusinessTemplateFromUrl(**param_dict)
operation_log.append('Installed %s with revision %s' % ( operation_log.append('Installed %s with revision %s' % (
document.getTitle(), document.getRevision())) document.getTitle(), document.getShortRevision()))
return operation_log return operation_log
...@@ -1248,7 +1214,7 @@ class TemplateTool (BaseTool): ...@@ -1248,7 +1214,7 @@ class TemplateTool (BaseTool):
reinstall=False, reinstall=False,
active_process=None, active_process=None,
force_keep_list=None, force_keep_list=None,
only_newer=True): only_different=True):
""" """
This method download and install a bt5, from a URL. This method download and install a bt5, from a URL.
...@@ -1284,18 +1250,13 @@ class TemplateTool (BaseTool): ...@@ -1284,18 +1250,13 @@ class TemplateTool (BaseTool):
if reinstall: if reinstall:
install_kw = None install_kw = None
else: else:
if only_different:
previous_bt5 = self.getInstalledBusinessTemplate(bt_title) previous_bt5 = self.getInstalledBusinessTemplate(bt_title)
if (previous_bt5 is not None) and only_newer: if previous_bt5 and \
try: imported_bt5.getRevision() == previous_bt5.getRevision():
imported_revision = int(imported_bt5.getRevision()) log("%s is already installed with revision %s"
previous_revision = int(previous_bt5.getRevision()) % (bt_title, imported_bt5.getShortRevision()))
if imported_revision <= previous_revision:
log("%s is already installed with revision %i, which is same or "
"newer revision than new revision %i." % (bt_title,
previous_revision, imported_revision))
return imported_bt5 return imported_bt5
except ValueError:
pass
install_kw = {} install_kw = {}
for listbox_line in imported_bt5.BusinessTemplate_getModifiedObject(): for listbox_line in imported_bt5.BusinessTemplate_getModifiedObject():
......
...@@ -31,59 +31,147 @@ ...@@ -31,59 +31,147 @@
"""Generate repository information on Business Templates. """Generate repository information on Business Templates.
""" """
import posixpath
import tarfile import tarfile
import os import os
import sys import sys
import cgi import cgi
from base64 import b64encode
from cStringIO import StringIO from cStringIO import StringIO
from hashlib import sha1
from urllib import unquote
property_list = '''
# Order is important for installation
# We want to have:
# * path after module, because path can be module content
# * path after categories, because path can be categories content
# * path after portal types roles so that roles in the current bt can be used
# * path before workflow chain, because path can be a portal type
# (until chains are set on portal types with categories)
# * skin after paths, because we can install a custom connection string as
# path and use it with SQLMethods in a skin.
# ( and more )
item_name_list = (
'registered_version_priority_selection',
'product',
'document',
'property_sheet',
'constraint',
'extension',
'test',
'role',
'tool',
'message_translation',
'workflow',
'site_property',
'portal_type',
'portal_type_allowed_content_type',
'portal_type_hidden_content_type',
'portal_type_property_sheet',
'portal_type_base_category',
'category',
'module',
'portal_type_roles',
'path',
'skin',
'registered_skin_selection',
'preference',
'action',
'local_roles',
'portal_type_workflow_chain',
'catalog_method',
'catalog_result_key',
'catalog_related_key',
'catalog_result_table',
'catalog_search_key',
'catalog_keyword_key',
'catalog_datetime_key',
'catalog_full_text_key',
'catalog_request_key',
'catalog_multivalue_key',
'catalog_topic_key',
'catalog_scriptable_key',
'catalog_role_key',
'catalog_local_role_key',
'catalog_security_uid_column',
)
item_set = set(('CatalogDateTimeKey' if x == 'catalog_datetime_key' else
''.join(map(str.title, x.split('_')))) + 'TemplateItem'
for x in item_name_list)
item_set.add('bt')
item_name_list = tuple('_%s_item' % x for x in item_name_list)
class BusinessTemplateRevision(list):
def hash(self, path, text):
self.append((path, sha1(text).digest()))
def digest(self):
self.sort()
return b64encode(sha1('\0'.join(h + p for (h, p) in self)).digest())
class BusinessTemplate(dict):
property_list = frozenset('''
title title
version version
revision
description description
license license
dependency_list dependency_list
provision_list provision_list
copyright_list copyright_list
'''.split() '''.split())
bt_title_path = os.path.join('bt', 'title') def __init__(self):
self.revision = BusinessTemplateRevision()
def readProperty(property_dict, property_name, property_file): def _read(self, path, file):
try: try:
text = property_file.read() text = file.read()
if property_name.endswith('_list'):
property_dict[property_name[:-5]] = text.splitlines()
else:
property_dict[property_name] = text
finally: finally:
property_file.close() file.close()
if path.startswith('bt/'):
name = path[3:]
if name in self.property_list:
if name.endswith('_list'):
self[name[:-5]] = text.splitlines()
else:
self[name] = text
elif name == 'revision':
return
self.revision.hash(unquote(path) if '%' in path else path, text)
def readBusinessTemplate(tar): def __iter__(self):
"""Read an archived Business Template info. self['revision'] = self.revision.digest()
""" return iter(sorted(self.iteritems()))
property_dict = {}
@classmethod
def fromTar(cls, tar):
"""Read an archived Business Template info"""
self = cls()
for info in tar: for info in tar:
name_list = info.name.split('/') if not info.isdir():
if len(name_list) == 3 and name_list[1] == 'bt' and name_list[2] in property_list: name = info.name.split('/', 1)[1]
property_file = tar.extractfile(info) if name.split('/', 1)[0] in item_set:
property_name = name_list[2] self._read(name, tar.extractfile(info))
readProperty(property_dict, property_name, property_file) return iter(self)
return property_dict @classmethod
def fromDir(cls, dir):
def readBusinessTemplateDirectory(dir): """Read Business Template Directory info"""
"""Read Business Template Directory info. self = cls()
""" lstrip_len = len(dir + os.sep)
property_dict = {} for root, dirs, files in os.walk(dir):
for property_name in property_list: if root:
filename = os.path.join(dir, 'bt', property_name) for path in files:
if os.path.isfile(filename): path = os.path.join(root, path)
property_file = open(filename, 'rb') self._read(posixpath.normpath(path[lstrip_len:]), open(path, 'rb'))
readProperty(property_dict, property_name, property_file) else:
dirs[:] = item_set.intersection(dirs)
return property_dict return iter(self)
def generateInformation(dir, info=id, err=None): def generateInformation(dir, info=id, err=None):
xml = StringIO() xml = StringIO()
...@@ -100,16 +188,16 @@ def generateInformation(dir, info=id, err=None): ...@@ -100,16 +188,16 @@ def generateInformation(dir, info=id, err=None):
continue continue
raise raise
try: try:
property_dict = readBusinessTemplate(tar) property_list = BusinessTemplate.fromTar(tar)
finally: finally:
tar.close() tar.close()
elif os.path.isfile(os.path.join(path, bt_title_path)): elif os.path.isfile(os.path.join(path, 'bt', 'title')):
info('Reading Directory %s... ' % name) info('Reading Directory %s... ' % name)
property_dict = readBusinessTemplateDirectory(path) property_list = BusinessTemplate.fromDir(path)
else: else:
continue continue
xml.write(' <template id="%s">\n' % name) xml.write(' <template id="%s">\n' % name)
for k, v in sorted(property_dict.iteritems()): for k, v in property_list:
for v in (v,) if type(v) is str else v: for v in (v,) if type(v) is str else v:
xml.write(' <%s>%s</%s>\n' % (k, cgi.escape(v), k)) xml.write(' <%s>%s</%s>\n' % (k, cgi.escape(v), k))
xml.write(' </template>\n') xml.write(' </template>\n')
......
...@@ -108,7 +108,7 @@ ...@@ -108,7 +108,7 @@
<string>my_id</string> <string>my_id</string>
<string>my_title</string> <string>my_title</string>
<string>my_version</string> <string>my_version</string>
<string>my_revision</string> <string>my_short_revision</string>
<string>my_translated_building_state_title</string> <string>my_translated_building_state_title</string>
<string>my_translated_installation_state_title</string> <string>my_translated_installation_state_title</string>
<string>my_description</string> <string>my_description</string>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="StringField" module="Products.Formulator.StandardFields"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>my_revision</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
<item>
<key> <string>required_not_found</string> </key>
<value> <string>Input is required but no input given.</string> </value>
</item>
<item>
<key> <string>too_long</string> </key>
<value> <string>Too much input was given.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>truncate</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>truncate</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>the number of revision used by the business template. This number increases each time we commit a modification</string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <int>20</int> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Revision Number</string> </value>
</item>
<item>
<key> <string>truncate</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <int>0</int> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>description</string>
<string>editable</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_short_revision</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>description</string> </key>
<value> <string>A shortened hash of the contents of the Business Template. The hash is computed at download, build and export.</string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_string_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Revision Number</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -349,7 +349,7 @@ ...@@ -349,7 +349,7 @@
<string>Version</string> <string>Version</string>
</tuple> </tuple>
<tuple> <tuple>
<string>revision</string> <string>short_revision</string>
<string>Revision</string> <string>Revision</string>
</tuple> </tuple>
<tuple> <tuple>
......
...@@ -340,7 +340,7 @@ ...@@ -340,7 +340,7 @@
<string>Version</string> <string>Version</string>
</tuple> </tuple>
<tuple> <tuple>
<string>revision</string> <string>short_revision</string>
<string>Revision</string> <string>Revision</string>
</tuple> </tuple>
<tuple> <tuple>
......
...@@ -343,14 +343,14 @@ ...@@ -343,14 +343,14 @@
<string>version</string> <string>version</string>
<string>Version</string> <string>Version</string>
</tuple> </tuple>
<tuple>
<string>revision</string>
<string>Revision</string>
</tuple>
<tuple> <tuple>
<string>installed_version</string> <string>installed_version</string>
<string>Installed Version</string> <string>Installed Version</string>
</tuple> </tuple>
<tuple>
<string>short_revision</string>
<string>Revision</string>
</tuple>
<tuple> <tuple>
<string>installed_revision</string> <string>installed_revision</string>
<string>Installed Revision</string> <string>Installed Revision</string>
...@@ -367,10 +367,6 @@ ...@@ -367,10 +367,6 @@
<string>license</string> <string>license</string>
<string>License</string> <string>License</string>
</tuple> </tuple>
<tuple>
<string>version_state_title</string>
<string>State</string>
</tuple>
</list> </list>
</value> </value>
</item> </item>
......
bin/genbt5list
\ No newline at end of file
...@@ -2824,24 +2824,6 @@ class BusinessTemplateMixin(TestDeveloperMixin, ERP5TypeTestCase, LogInterceptor ...@@ -2824,24 +2824,6 @@ class BusinessTemplateMixin(TestDeveloperMixin, ERP5TypeTestCase, LogInterceptor
self.failUnless(base_category_obj is not None) self.failUnless(base_category_obj is not None)
self.assertEquals(len(base_category_obj.objectIds()), 0) self.assertEquals(len(base_category_obj.objectIds()), 0)
def stepCheckInitialRevision(self, sequence=None, **kw):
""" Check if revision of a new bt is an empty string
"""
bt = sequence.get('current_bt')
self.assertEqual(bt.getRevision(), '')
def stepCheckFirstRevision(self, sequence=None, **kw):
""" Check if revision of the bt is 1
"""
bt = sequence.get('current_bt')
self.assertEqual(bt.getRevision(), '1')
def stepCheckSecondRevision(self, sequence=None, **kw):
""" Check if revision of the bt is 2
"""
bt = sequence.get('current_bt')
self.assertEqual(bt.getRevision(), '2')
def stepCheckNoMissingDependencies(self, sequence=None, **kw): def stepCheckNoMissingDependencies(self, sequence=None, **kw):
""" Check if bt has no missing dependency """ Check if bt has no missing dependency
""" """
...@@ -5126,26 +5108,6 @@ class TestBusinessTemplate(BusinessTemplateMixin): ...@@ -5126,26 +5108,6 @@ class TestBusinessTemplate(BusinessTemplateMixin):
sequence_list.addSequenceString(sequence_string) sequence_list.addSequenceString(sequence_string)
sequence_list.play(self) sequence_list.play(self)
# test of portal types
def test_22_RevisionNumberIsIncremented(self):
"""Test is revision number is incremented with the bt is built"""
sequence_list = SequenceList()
sequence_string = '\
CreatePortalType \
CreateNewBusinessTemplate \
UseExportBusinessTemplate \
CheckInitialRevision \
BuildBusinessTemplate \
CheckBuiltBuildingState \
stepCheckFirstRevision \
BuildBusinessTemplate \
stepCheckSecondRevision \
RemoveBusinessTemplate \
RemovePortalType \
'
sequence_list.addSequenceString(sequence_string)
sequence_list.play(self)
def test_23_CheckNoDependencies(self): def test_23_CheckNoDependencies(self):
"""Test if a new Business Template has no dependencies""" """Test if a new Business Template has no dependencies"""
sequence_list = SequenceList() sequence_list = SequenceList()
......
...@@ -31,7 +31,7 @@ import os ...@@ -31,7 +31,7 @@ import os
import shutil import shutil
import unittest import unittest
import random import random
import transaction import tempfile
from App.config import getConfiguration from App.config import getConfiguration
from Products.ERP5VCS.WorkingCopy import getVcsTool from Products.ERP5VCS.WorkingCopy import getVcsTool
...@@ -99,32 +99,23 @@ class TestTemplateTool(ERP5TypeTestCase): ...@@ -99,32 +99,23 @@ class TestTemplateTool(ERP5TypeTestCase):
def testUpdateBT5FromRepository(self, quiet=quiet, run=run_all_test): def testUpdateBT5FromRepository(self, quiet=quiet, run=run_all_test):
""" Test the list of bt5 returned for upgrade """ """ Test the list of bt5 returned for upgrade """
# edit bt5 revision so that it will be marked as updatable # edit bt5 revision so that it will be marked as updatable
bt_list = self.templates_tool.searchFolder(title='erp5_base') erp5_base = self.templates_tool.getInstalledBusinessTemplate('erp5_base',
self.assertEquals(len(bt_list), 1) strict=True)
erp5_base = bt_list[0].getObject() erp5_base._setRevision('')
try:
erp5_base.edit(revision=0)
updatable_bt_list = \ self.assertTrue("erp5_base" in (bt.getTitle() for bt in
self.templates_tool.getRepositoryBusinessTemplateList(update_only=True) self.templates_tool.getRepositoryBusinessTemplateList(update_only=True)))
self.assertEqual(
[i.title for i in updatable_bt_list if i.title == "erp5_base"],
["erp5_base"])
erp5_base.replace() erp5_base.replace()
updatable_bt_list = \ self.assertFalse("erp5_base" in (bt.getTitle() for bt in
self.templates_tool.getRepositoryBusinessTemplateList(update_only=True) self.templates_tool.getRepositoryBusinessTemplateList(update_only=True)))
self.assertEqual( self.abort()
[i.title for i in updatable_bt_list if i.title == "erp5_base"],
[])
finally:
erp5_base.edit(revision=int(erp5_base.getRevision()) + 10)
def test_download_http(self): def test_download_http(self):
test_web = self.portal.portal_templates.download( test_web = self.portal.portal_templates.download(
'http://www.erp5.org/dists/snapshot/test_bt5/test_web.bt5') 'http://www.erp5.org/dists/snapshot/test_bt5/test_web.bt5')
self.assertEquals(test_web.getPortalType(), 'Business Template') self.assertEquals(test_web.getPortalType(), 'Business Template')
self.assertEquals(test_web.getTitle(), 'test_web') self.assertEquals(test_web.getTitle(), 'test_web')
self.assertTrue(test_web.getRevision()) self.assertEqual(len(test_web.getRevision()), 28)
def _svn_setup_ssl(self): def _svn_setup_ssl(self):
""" """
...@@ -148,20 +139,20 @@ class TestTemplateTool(ERP5TypeTestCase): ...@@ -148,20 +139,20 @@ class TestTemplateTool(ERP5TypeTestCase):
test_web = self.portal.portal_templates.download(bt5_url) test_web = self.portal.portal_templates.download(bt5_url)
self.assertEquals(test_web.getPortalType(), 'Business Template') self.assertEquals(test_web.getPortalType(), 'Business Template')
self.assertEquals(test_web.getTitle(), 'test_web') self.assertEquals(test_web.getTitle(), 'test_web')
self.assertTrue(test_web.getRevision()) self.assertEqual(len(test_web.getRevision()), 28)
def test_updateBusinessTemplateFromUrl_simple(self): def test_updateBusinessTemplateFromUrl_simple(self):
""" """
Test updateBusinessTemplateFromUrl method Test updateBusinessTemplateFromUrl method
By default if a new business template has revision >= previous one By default if a new business template has revision != previous one
the new bt5 is not installed, only imported. the new bt5 is not installed, only imported.
""" """
self._svn_setup_ssl() self._svn_setup_ssl()
template_tool = self.portal.portal_templates template_tool = self.portal.portal_templates
old_bt = template_tool.getInstalledBusinessTemplate('erp5_csv_style') old_bt = template_tool.getInstalledBusinessTemplate('erp5_csv_style')
# change revision to an old revision # fake different revision
old_bt.setRevision(0.0001) old_bt.setRevision('')
url = 'https://svn.erp5.org/repos/public/erp5/trunk/bt5/erp5_csv_style' url = 'https://svn.erp5.org/repos/public/erp5/trunk/bt5/erp5_csv_style'
template_tool.updateBusinessTemplateFromUrl(url) template_tool.updateBusinessTemplateFromUrl(url)
new_bt = template_tool.getInstalledBusinessTemplate('erp5_csv_style') new_bt = template_tool.getInstalledBusinessTemplate('erp5_csv_style')
...@@ -170,7 +161,7 @@ class TestTemplateTool(ERP5TypeTestCase): ...@@ -170,7 +161,7 @@ class TestTemplateTool(ERP5TypeTestCase):
# Test Another time with definning an ID # Test Another time with definning an ID
old_bt = new_bt old_bt = new_bt
old_bt.setRevision(0.0002) old_bt.setRevision('')
template_tool.updateBusinessTemplateFromUrl(url, id="new_erp5_csv_style") template_tool.updateBusinessTemplateFromUrl(url, id="new_erp5_csv_style")
new_bt = template_tool.getInstalledBusinessTemplate('erp5_csv_style') new_bt = template_tool.getInstalledBusinessTemplate('erp5_csv_style')
self.assertNotEquals(old_bt, new_bt) self.assertNotEquals(old_bt, new_bt)
...@@ -184,8 +175,7 @@ class TestTemplateTool(ERP5TypeTestCase): ...@@ -184,8 +175,7 @@ class TestTemplateTool(ERP5TypeTestCase):
self.assertEquals(old_bt, new_bt) self.assertEquals(old_bt, new_bt)
self.assertEquals('erp5_csv_style', new_bt.getTitle()) self.assertEquals('erp5_csv_style', new_bt.getTitle())
self.assertEquals('new_erp5_csv_style', new_bt.getId()) self.assertEquals('new_erp5_csv_style', new_bt.getId())
not_installed_bt5 = getattr(template_tool, "not_installed_bt5", None) not_installed_bt5 = template_tool['not_installed_bt5']
self.assertNotEquals(not_installed_bt5, None)
self.assertEquals('erp5_csv_style', not_installed_bt5.getTitle()) self.assertEquals('erp5_csv_style', not_installed_bt5.getTitle())
self.assertEquals(not_installed_bt5.getInstallationState(), self.assertEquals(not_installed_bt5.getInstallationState(),
"not_installed") "not_installed")
...@@ -204,10 +194,8 @@ class TestTemplateTool(ERP5TypeTestCase): ...@@ -204,10 +194,8 @@ class TestTemplateTool(ERP5TypeTestCase):
keep_original_list=keep_original_list) keep_original_list=keep_original_list)
bt = template_tool.getInstalledBusinessTemplate('test_core') bt = template_tool.getInstalledBusinessTemplate('test_core')
self.assertNotEquals(None, bt) self.assertNotEquals(None, bt)
erp5_test = getattr(self.portal.portal_skins, 'erp5_test', None) erp5_test = self.portal.portal_skins['erp5_test']
self.assertNotEquals(None, erp5_test) self.assertFalse(erp5_test.hasObject('test_file'))
test_file = getattr(erp5_test, 'test_file', None)
self.assertEquals(None, test_file)
def test_updateBusinessTemplateFromUrl_after_before_script(self): def test_updateBusinessTemplateFromUrl_after_before_script(self):
""" """
...@@ -248,48 +236,6 @@ class TestTemplateTool(ERP5TypeTestCase): ...@@ -248,48 +236,6 @@ class TestTemplateTool(ERP5TypeTestCase):
self.assertEquals(bt.getChangeLog(), 'MODIFIED') self.assertEquals(bt.getChangeLog(), 'MODIFIED')
self.assertEquals(portal.getTitle(), 'MODIFIED') self.assertEquals(portal.getTitle(), 'MODIFIED')
def test_updateBusinessTemplateFromUrl_stringCastingBug(self):
pt = self.getTemplateTool()
template = pt.newContent(portal_type='Business Template')
self.failUnless(template.getBuildingState() == 'draft')
self.failUnless(template.getInstallationState() == 'not_installed')
title = 'install_casting_to_int_bug_check'
template.edit(title=title,
version='1.0',
description='bt for unit_test')
self.commit()
template.build()
self.commit()
cfg = getConfiguration()
template_path = os.path.join(cfg.instancehome, 'tests', '%s' % (title,))
# remove previous version of bt it exists
if os.path.exists(template_path):
shutil.rmtree(template_path)
template.export(path=template_path, local=1)
self.failUnless(os.path.exists(template_path))
# setup version '9'
first_revision = '9'
open(os.path.join(template_path, 'bt', 'revision'), 'w').write(first_revision)
pt.updateBusinessTemplateFromUrl(template_path)
new_bt = pt.getInstalledBusinessTemplate(title)
self.assertEqual(new_bt.getRevision(), first_revision)
# setup revision '11', becasue: '11' < '9' (string comp), but 11 > 9 (int comp)
second_revision = '11'
self.assertTrue(second_revision < first_revision)
self.assertTrue(int(second_revision) > int(first_revision))
open(os.path.join(template_path, 'bt', 'revision'), 'w').write(second_revision)
pt.updateBusinessTemplateFromUrl(template_path)
newer_bt = pt.getInstalledBusinessTemplate(title)
self.assertNotEqual(new_bt, newer_bt)
self.assertEqual(newer_bt.getRevision(), second_revision)
def test_CompareVersions(self): def test_CompareVersions(self):
"""Tests compare version on template tool. """ """Tests compare version on template tool. """
compareVersions = self.getPortal().portal_templates.compareVersions compareVersions = self.getPortal().portal_templates.compareVersions
...@@ -320,12 +266,45 @@ class TestTemplateTool(ERP5TypeTestCase): ...@@ -320,12 +266,45 @@ class TestTemplateTool(ERP5TypeTestCase):
self.assertEquals(None, self.getPortal()\ self.assertEquals(None, self.getPortal()\
.portal_templates.getInstalledBusinessTemplate('erp5_toto')) .portal_templates.getInstalledBusinessTemplate('erp5_toto'))
def test_getInstalledBusinessTemplateRevision(self): def test_revision(self):
self.assertTrue(300 < self.getPortal()\ template_tool = self.portal.portal_templates
.portal_templates.getInstalledBusinessTemplateRevision('erp5_core')) getInstalledRevision = template_tool.getInstalledBusinessTemplateRevision
self.assertEqual(None, getInstalledRevision('erp5_toto'))
self.assertEquals(None, self.getPortal()\ available_bt, = template_tool.getRepositoryBusinessTemplateList(
.portal_templates.getInstalledBusinessTemplateRevision('erp5_toto')) template_list=('test_core',))
revision = available_bt.getRevision()
self.assertEqual('PN8VPt52MbdHtxfjKvL+MBsNbzM=', revision)
installed_bt = template_tool.download("%s/%s" % (available_bt.repository,
available_bt.filename))
self.assertEqual(revision, installed_bt.getRevision())
installed_bt.install()
self.assertEqual(revision, getInstalledRevision('test_core'))
bt = installed_bt.Base_createCloneDocument(batch_mode=1)
bt.build(update_revision=False)
root = tempfile.mkdtemp()
try:
bt.export(root, local=1)
with open(os.path.join(root, 'bt', 'title')) as f:
self.assertTrue('test_core', f.read())
# We don't export revision anymore.
self.assertFalse(os.path.exists(os.path.join(root, 'bt', 'revision')))
# Computed at download ...
self.assertEqual(revision, template_tool.download(root).getRevision())
finally:
shutil.rmtree(root)
bt._setVersion("2.0")
# ... at building by default ...
bt.build()
revision = bt.getRevision()
self.assertEqual('tPNr/gGXaa0fYCsFUWe8nqzSNLc=', revision)
self.portal.portal_skins.erp5_test.manage_renameObject('test_file',
'test_file2')
bt.build(update_revision=False)
self.assertEqual(revision, bt.getRevision())
# ... and at export.
bt.export(str(random.random()))
self.assertEqual('Nup/xsO1xpsmdJ5GTdknuVJyOr8=', bt.getRevision())
self.abort()
def test_getInstalledBusinessTemplateList(self): def test_getInstalledBusinessTemplateList(self):
templates_tool = self.getPortal().portal_templates templates_tool = self.getPortal().portal_templates
...@@ -479,9 +458,9 @@ class TestTemplateTool(ERP5TypeTestCase): ...@@ -479,9 +458,9 @@ class TestTemplateTool(ERP5TypeTestCase):
bt_old = self.templates_tool.getInstalledBusinessTemplate(bt5_name, strict=True) bt_old = self.templates_tool.getInstalledBusinessTemplate(bt5_name, strict=True)
self.assertEquals(bt.getId(), bt_old.getId()) self.assertEquals(bt.getId(), bt_old.getId())
# Repeat operation, new bt5 should be inslalled due only_newer = False # Repeat operation, new bt5 should be inslalled due only_different = False
operation_log = self.templates_tool.installBusinessTemplateListFromRepository( operation_log = self.templates_tool.installBusinessTemplateListFromRepository(
[bt5_name], only_newer=False) [bt5_name], only_different=False)
self.assertTrue("Installed %s with" % bt5_name in operation_log[-1]) self.assertTrue("Installed %s with" % bt5_name in operation_log[-1])
bt_new = self.templates_tool.getInstalledBusinessTemplate(bt5_name, bt_new = self.templates_tool.getInstalledBusinessTemplate(bt5_name,
...@@ -498,7 +477,7 @@ class TestTemplateTool(ERP5TypeTestCase): ...@@ -498,7 +477,7 @@ class TestTemplateTool(ERP5TypeTestCase):
bt = template_tool.getInstalledBusinessTemplate(bt5_name) bt = template_tool.getInstalledBusinessTemplate(bt5_name)
self.assertEquals(bt, None) self.assertEquals(bt, None)
operation_log = template_tool.installBusinessTemplateListFromRepository([bt5_name], operation_log = template_tool.installBusinessTemplateListFromRepository([bt5_name],
only_newer=False, update_catalog=0) only_different=False, update_catalog=0)
self.assertTrue("Installed %s with" % bt5_name in operation_log[0]) self.assertTrue("Installed %s with" % bt5_name in operation_log[0])
bt = template_tool.getInstalledBusinessTemplate(bt5_name) bt = template_tool.getInstalledBusinessTemplate(bt5_name)
...@@ -514,7 +493,7 @@ class TestTemplateTool(ERP5TypeTestCase): ...@@ -514,7 +493,7 @@ class TestTemplateTool(ERP5TypeTestCase):
bt5_name = 'erp5_odt_style' bt5_name = 'erp5_odt_style'
operation_log = template_tool.installBusinessTemplateListFromRepository([bt5_name], operation_log = template_tool.installBusinessTemplateListFromRepository([bt5_name],
only_newer=False, update_catalog=1) only_different=False, update_catalog=1)
self.assertTrue("Installed %s with" % bt5_name in operation_log[-1]) self.assertTrue("Installed %s with" % bt5_name in operation_log[-1])
bt = template_tool.getInstalledBusinessTemplate(bt5_name) bt = template_tool.getInstalledBusinessTemplate(bt5_name)
self.assertEquals(bt.getTitle(), bt5_name) self.assertEquals(bt.getTitle(), bt5_name)
...@@ -524,7 +503,7 @@ class TestTemplateTool(ERP5TypeTestCase): ...@@ -524,7 +503,7 @@ class TestTemplateTool(ERP5TypeTestCase):
# Install again should not force catalog to be updated # Install again should not force catalog to be updated
operation_log = template_tool.installBusinessTemplateListFromRepository( operation_log = template_tool.installBusinessTemplateListFromRepository(
[bt5_name], only_newer=False) [bt5_name], only_different=False)
self.assertTrue("Installed %s with" % bt5_name in operation_log[-1]) self.assertTrue("Installed %s with" % bt5_name in operation_log[-1])
bt = template_tool.getInstalledBusinessTemplate(bt5_name) bt = template_tool.getInstalledBusinessTemplate(bt5_name)
self.assertNotEquals(bt, None) self.assertNotEquals(bt, None)
...@@ -609,7 +588,7 @@ class TestTemplateTool(ERP5TypeTestCase): ...@@ -609,7 +588,7 @@ class TestTemplateTool(ERP5TypeTestCase):
self.assertNotEquals(bt, None) self.assertNotEquals(bt, None)
bt = template_tool.getInstalledBusinessTemplate("erp5_workflow") bt = template_tool.getInstalledBusinessTemplate("erp5_workflow")
self.assertNotEquals(bt, None) self.assertNotEquals(bt, None)
transaction.abort() self.abort()
# Same as above but also check that dependencies are properly resolved if # Same as above but also check that dependencies are properly resolved if
# one of the dependency is explicitly added to the list of bt5 to be # one of the dependency is explicitly added to the list of bt5 to be
...@@ -625,22 +604,23 @@ class TestTemplateTool(ERP5TypeTestCase): ...@@ -625,22 +604,23 @@ class TestTemplateTool(ERP5TypeTestCase):
self.assertNotEquals(bt, None) self.assertNotEquals(bt, None)
bt = template_tool.getInstalledBusinessTemplate("erp5_workflow") bt = template_tool.getInstalledBusinessTemplate("erp5_workflow")
self.assertNotEquals(bt, None) self.assertNotEquals(bt, None)
transaction.abort() self.abort()
def test_installBusinessTemplateListFromRepository_ignore_when_installed(self): def test_installBusinessTemplateListFromRepository_ignore_when_installed(self):
"""Check that install one business template, this method does not download """Check that install one business template, this method does not download
many business templates that are already installed many business templates that are already installed
""" """
template_tool = self.portal.portal_templates template_tool = self.portal.portal_templates
# Delete not installed bt5 to check easily if more not installed was before = dict((bt.getTitle(), bt.getId())
# created for bt in template_tool.getInstalledBusinessTemplateList())
for bt5 in template_tool.getBuiltBusinessTemplateList(): bt_title = 'erp5_calendar'
bt5.delete() template_tool.installBusinessTemplateListFromRepository([bt_title],
bt5_name_list = ['erp5_calendar']
template_tool.installBusinessTemplateListFromRepository(bt5_name_list,
install_dependency=True) install_dependency=True)
self.tic() self.tic()
self.assertEquals(template_tool.getBuiltBusinessTemplateList(), []) after = dict((bt.getTitle(), bt.getId())
for bt in template_tool.getInstalledBusinessTemplateList())
del after[bt_title]
self.assertEqual(before, after)
def test_sortBusinessTemplateList(self): def test_sortBusinessTemplateList(self):
"""Check sorting of a list of business template by their dependencies """Check sorting of a list of business template by their dependencies
......
...@@ -461,43 +461,15 @@ class ERP5TypeTestCaseMixin(ProcessingNodeTestCase, PortalTestCase): ...@@ -461,43 +461,15 @@ class ERP5TypeTestCaseMixin(ProcessingNodeTestCase, PortalTestCase):
DeprecationWarning) DeprecationWarning)
return self.createUserAssignment(user, assignment_kw) return self.createUserAssignment(user, assignment_kw)
def setupAutomaticBusinessTemplateRepository(self, accept_public=True, def setupAutomaticBusinessTemplateRepository(self,
searchable_business_template_list=None): searchable_business_template_list=("erp5_base",)):
# Try to setup some valid Repository List by reusing ERP5TypeTestCase API. template_tool = self.portal.portal_templates
# if accept_public we can accept public repository can be set, otherwise bt_set = set(searchable_business_template_list).difference(x['title']
# we let failure happens. for x in template_tool.repository_dict.itervalues() for x in x)
if searchable_business_template_list is None: if bt_set:
searchable_business_template_list = ["erp5_base"] template_tool.updateRepositoryBusinessTemplateList(set(
os.path.dirname(x[0]) for x in self._getBTPathAndIdList(bt_set)),
# Assume that the public official repository is a valid repository genbt5list=1)
public_bt5_repository_list = ['http://www.erp5.org/dists/snapshot/bt5/']
template_list = []
for bt_id in searchable_business_template_list:
bt_template_list = self._getBTPathAndIdList([bt_id])
if len(bt_template_list):
template_list.append(bt_template_list[0])
if len(template_list) > 0:
bt5_repository_path_list = ["/".join(x[0].split("/")[:-1])
for x in template_list]
if accept_public:
try:
self.portal.portal_templates.updateRepositoryBusinessTemplateList(
bt5_repository_path_list, None)
except (RuntimeError, IOError), e:
# If bt5 repository is not a repository use public one.
self.portal.portal_templates.updateRepositoryBusinessTemplateList(
public_bt5_repository_list)
else:
self.portal.portal_templates.updateRepositoryBusinessTemplateList(
bt5_repository_path_list, None)
elif accept_public:
self.portal.portal_templates.updateRepositoryBusinessTemplateList(
public_bt5_repository_list)
else:
raise ValueError("ERP5 was unable to determinate a valid local " + \
"repository, please check your environment or " + \
"use accept_public as True")
def failIfDifferentSet(self, a, b, msg=""): def failIfDifferentSet(self, a, b, msg=""):
if not msg: if not msg:
......
...@@ -187,7 +187,7 @@ class WorkingCopy(Implicit): ...@@ -187,7 +187,7 @@ class WorkingCopy(Implicit):
""" """
if business_template.getBuildingState() == 'draft': if business_template.getBuildingState() == 'draft':
business_template.edit() business_template.edit()
business_template.build() business_template.build(update_revision=False)
self._export(business_template) self._export(business_template)
def _export(self, business_template): def _export(self, business_template):
...@@ -200,16 +200,6 @@ class WorkingCopy(Implicit): ...@@ -200,16 +200,6 @@ class WorkingCopy(Implicit):
def update(self, keep=False): def update(self, keep=False):
raise NotAWorkingCopyError raise NotAWorkingCopyError
def newRevision(self):
path = os.path.join('bt', 'revision')
try:
revision = int(self.showOld(path)) + 1
except NotVersionedError:
return 1
with open(os.path.join(self.working_copy, path), 'w') as file:
file.write(str(revision))
return revision
def hasDiff(self, path): def hasDiff(self, path):
try: try:
hasDiff = aq_base(self).__hasDiff hasDiff = aq_base(self).__hasDiff
...@@ -329,7 +319,7 @@ class WorkingCopy(Implicit): ...@@ -329,7 +319,7 @@ class WorkingCopy(Implicit):
title='tmp_bt_revert', title='tmp_bt_revert',
template_path_list=path_added_list) template_path_list=path_added_list)
tmp_bt.edit() tmp_bt.edit()
tmp_bt.build() tmp_bt.build(update_revision=False)
# Install then uninstall it to remove objects from ZODB # Install then uninstall it to remove objects from ZODB
tmp_bt.install() tmp_bt.install()
tmp_bt.uninstall() tmp_bt.uninstall()
......
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