Commit cdbf2463 authored by Nicolas Delaby's avatar Nicolas Delaby

Fix reinstallation of BT with local modifications in workflow_chain...

Fix reinstallation of BT with local modifications in workflow_chain (test_165_checkCopyBuildInstall)
  * _importFile and build are now consistent: they use same keys and 
values are list.
  * various optimisation, and coding style.
  * Naming convention compliancy.
  * replace self.__class__.__name__[:-12]] by self.getTemplateTypeName()
atomic patch which can not be splitted.



git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@33767 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 8fbf2dd8
...@@ -1769,6 +1769,9 @@ class PortalTypeTemplateItem(ObjectTemplateItem): ...@@ -1769,6 +1769,9 @@ class PortalTypeTemplateItem(ObjectTemplateItem):
class PortalTypeWorkflowChainTemplateItem(BaseTemplateItem): class PortalTypeWorkflowChainTemplateItem(BaseTemplateItem):
_chain_string_prefix = 'chain_'
_chain_string_separator = ', '
def build(self, context, **kw): def build(self, context, **kw):
# we can either specify nothing, +, - or = before the chain # we can either specify nothing, +, - or = before the chain
# this is used to know how to manage the chain # this is used to know how to manage the chain
...@@ -1786,24 +1789,18 @@ class PortalTypeWorkflowChainTemplateItem(BaseTemplateItem): ...@@ -1786,24 +1789,18 @@ class PortalTypeWorkflowChainTemplateItem(BaseTemplateItem):
# portal type with no workflow defined # portal type with no workflow defined
portal_type = wflist[0][:-2] portal_type = wflist[0][:-2]
workflow = '' workflow = ''
if chain_dict.has_key('chain_%s' % portal_type): portal_type_key = '%s%s' % (self._chain_string_prefix, portal_type)
if workflow[0] in ['+', '-', '=']: if portal_type_key in chain_dict:
workflow_name = workflow[1:] workflow_name = workflow.lstrip('+-=')
else: if workflow[0] != '-' and workflow_name not in \
workflow_name = workflow chain_dict[portal_type_key].split(self._chain_string_separator):
if workflow[0] != '-' and \
workflow_name not in chain_dict['chain_%s' % portal_type].split(', '):
if not self.is_bt_for_diff: if not self.is_bt_for_diff:
# here, we use 'LOG' instead of 'raise', because it can # here, we use 'LOG' instead of 'raise', because it can
# happen when a workflow is removed from the chain by # happen when a workflow is removed from the chain by
# another business template. # another business template.
LOG('BusinessTemplate', WARNING, 'workflow %s not found in chain for portal_type %s'\ LOG('BusinessTemplate', WARNING, 'workflow %s not found'\
% (workflow, portal_type)) 'in chain for portal_type %s' % (workflow_name, portal_type))
if self._objects.has_key(portal_type): self._objects.setdefault(portal_type, []).append(workflow_name)
# other workflow id already defined for this portal type
self._objects[portal_type].append(workflow)
else:
self._objects[portal_type] = [workflow,]
elif not self.is_bt_for_diff: elif not self.is_bt_for_diff:
raise NotFound, 'No workflow chain found for portal type %s. This '\ raise NotFound, 'No workflow chain found for portal type %s. This '\
'is probably a sign of a missing dependency.'\ 'is probably a sign of a missing dependency.'\
...@@ -1812,22 +1809,20 @@ class PortalTypeWorkflowChainTemplateItem(BaseTemplateItem): ...@@ -1812,22 +1809,20 @@ class PortalTypeWorkflowChainTemplateItem(BaseTemplateItem):
# Function to generate XML Code Manually # Function to generate XML Code Manually
def generateXml(self, path=None): def generateXml(self, path=None):
xml_data = '<workflow_chain>' xml_data = '<workflow_chain>'
keys = self._objects.keys() key_list = self._objects.keys()
keys.sort() key_list.sort()
for key in keys: for key in key_list:
workflow_list = self._objects[key] workflow_list = self._objects[key]
# XXX Not always a list
if isinstance(workflow_list, str):
workflow_list = [workflow_list]
xml_data += '\n <chain>' xml_data += '\n <chain>'
xml_data += '\n <type>%s</type>' %(key,) xml_data += '\n <type>%s</type>' %(key,)
xml_data += '\n <workflow>%s</workflow>' %(', '.join(sorted(workflow_list))) xml_data += '\n <workflow>%s</workflow>' %(
self._chain_string_separator.join(sorted(workflow_list)))
xml_data += '\n </chain>' xml_data += '\n </chain>'
xml_data += '\n</workflow_chain>' xml_data += '\n</workflow_chain>'
return xml_data return xml_data
def export(self, context, bta, **kw): def export(self, context, bta, **kw):
if len(self._objects.keys()) == 0: if not self._objects:
return return
root_path = os.path.join(bta.path, self.__class__.__name__) root_path = os.path.join(bta.path, self.__class__.__name__)
bta.addFolder(name=root_path) bta.addFolder(name=root_path)
...@@ -1841,61 +1836,69 @@ class PortalTypeWorkflowChainTemplateItem(BaseTemplateItem): ...@@ -1841,61 +1836,69 @@ class PortalTypeWorkflowChainTemplateItem(BaseTemplateItem):
# We now need to setup the list of workflows corresponding to # We now need to setup the list of workflows corresponding to
# each portal type # each portal type
(default_chain, chain_dict) = getChainByType(context) (default_chain, chain_dict) = getChainByType(context)
# First convert all workflow_ids into list.
for key in chain_dict:
chain_dict.update({key: chain_dict[key].\
split(self._chain_string_separator)})
# Set the default chain to the empty string is probably the # Set the default chain to the empty string is probably the
# best solution, by default it is 'default_workflow', which is # best solution, by default it is 'default_workflow', which is
# not very usefull # not very usefull
default_chain = '' default_chain = ''
for path in self._objects.keys(): for path in self._objects:
if update_dict.has_key(path) or force: if path in update_dict or force:
if not force: if not force:
action = update_dict[path] action = update_dict[path]
if action == 'nothing': if action == 'nothing':
continue continue
path_splitted = path.split('/', 1) path_splitted = path.split('/', 1)
# XXX: to avoid crashing when no portal_type # XXX: to avoid crashing when no portal_type
if len(path_splitted) < 1: if not path_splitted:
continue continue
portal_type = path_splitted[-1] portal_type = path_splitted[-1]
if chain_dict.has_key('chain_%s' % portal_type): chain_key = '%s%s' % (self._chain_string_prefix, portal_type)
old_chain_dict = chain_dict['chain_%s' % portal_type] if chain_key in chain_dict:
# XXX we don't use the chain (Default) in erp5 so don't keep it # XXX we don't use the chain (Default) in erp5 so don't keep it
if old_chain_dict != '(Default)' and old_chain_dict != '': old_chain_list = [workflow_id for workflow_id in\
old_chain_workflow_id_set = {} chain_dict[chain_key] if workflow_id not in\
# get existing workflow id list ('(Default)', '',)]
for wf_id in old_chain_dict.split(', '): old_chain_workflow_id_set = set(old_chain_list)
old_chain_workflow_id_set[wf_id] = 1 # get new workflow id list
# get new workflow id list workflow_id_list = self._objects[path]
for wf_id in self._objects[path].split(', '): for wf_id in workflow_id_list:
if wf_id[0] == '-': if wf_id[0] == '-':
# remove wf id if already present # remove wf id if already present
if old_chain_workflow_id_set.has_key(wf_id[1:]): if wf_id[1:] in old_chain_workflow_id_set:
old_chain_workflow_id_set.pop(wf_id[1:]) old_chain_workflow_id_set.remove(wf_id[1:])
elif wf_id[0] == '=': elif wf_id[0] == '=':
# replace existing chain by this one # replace existing chain by this one
old_chain_workflow_id_set = {} old_chain_workflow_id_set = set()
old_chain_workflow_id_set[wf_id[1:]] = 1 old_chain_workflow_id_set.add(wf_id[1:])
# then either '+' or nothing, add wf id to the list # then either '+' or nothing, add wf id to the list
elif wf_id[0] == '+': elif wf_id[0] == '+':
old_chain_workflow_id_set[wf_id[1:]] = 1 old_chain_workflow_id_set.add(wf_id[1:])
else: else:
old_chain_workflow_id_set[wf_id] = 1 old_chain_workflow_id_set.add(wf_id)
# create the new chain # create the new chain
chain_dict['chain_%s' % portal_type] = ', '.join( chain_dict[chain_key] = list(old_chain_workflow_id_set)
old_chain_workflow_id_set.keys()) if not workflow_id_list:
else:
# Check if it has normally to remove a workflow chain, in order to # Check if it has normally to remove a workflow chain, in order to
# improve the error message # improve the error message
for wf_id in self._objects[path].split(', '): for wf_id in self._objects[path]:
if wf_id.startswith('-'): if wf_id.startswith('-'):
raise ValueError, '"%s" is not a workflow ID for %s' % \ raise ValueError, '"%s" is not a workflow ID for %s' % \
(wf_id, portal_type) (wf_id, portal_type)
chain_dict['chain_%s' % portal_type] = self._objects[path] chain_dict[chain_key] = self._objects[path]
else: else:
if portal_type not in context.portal_types.objectIds(): if portal_type not in context.portal_types.objectIds():
raise ValueError('Cannot chain workflow %r to non existing ' raise ValueError('Cannot chain workflow %r to non existing '
'portal type %r' % (self._objects[path], 'portal type %r' % (self._chain_string_separator\
portal_type)) .join(self._objects[path])
chain_dict['chain_%s' % portal_type] = self._objects[path] , portal_type))
chain_dict[chain_key] = self._objects[path]
# convert workflow list into string only at the end.
for key in chain_dict:
chain_dict.update({key: self._chain_string_separator.\
join(chain_dict[key])})
context.portal_workflow.manage_changeWorkflows(default_chain, context.portal_workflow.manage_changeWorkflows(default_chain,
props=chain_dict) props=chain_dict)
...@@ -1903,61 +1906,57 @@ class PortalTypeWorkflowChainTemplateItem(BaseTemplateItem): ...@@ -1903,61 +1906,57 @@ class PortalTypeWorkflowChainTemplateItem(BaseTemplateItem):
(default_chain, chain_dict) = getChainByType(context) (default_chain, chain_dict) = getChainByType(context)
object_path = kw.get('object_path', None) object_path = kw.get('object_path', None)
if object_path is not None: if object_path is not None:
object_keys = [object_path] object_key_list = [object_path]
else: else:
object_keys = self._objects.keys() object_key_list = self._objects.keys()
for path in object_keys: for object_key in object_key_list:
path_splitted = path.split('/', 1) path_splitted = object_key.split('/', 1)
if len(path_splitted) < 2: if len(path_splitted) < 2:
continue continue
portal_type = path_splitted[1] portal_type = path_splitted[1]
id = 'chain_%s' % portal_type path = '%s%s' % (self._chain_string_prefix, portal_type)
if id in chain_dict.keys(): if path in chain_dict:
chain = chain_dict[id] workflow_id_list = chain_dict[path].\
# It should be better to use regexp split(self._chain_string_separator)
chain = chain.replace(' ', '') removed_workflow_id_list = self._objects[object_key]
workflow_list = chain.split(',') for workflow_id in removed_workflow_id_list:
workflow_id = self._objects[path] for i in range(workflow_id_list.count(workflow_id)):
for i in range(workflow_list.count(workflow_id)): workflow_id_list.remove(workflow_id)
workflow_list.remove(workflow_id) if not workflow_id_list:
chain = ', '.join(workflow_list) del chain_dict[path]
if chain == '':
del chain_dict[id]
else: else:
chain_dict[id] = chain chain_dict[path] = self._chain_string_separator.\
context.portal_workflow.manage_changeWorkflows('', props=chain_dict) join(workflow_id_list)
context.getPortalObject().portal_workflow.\
manage_changeWorkflows('', props=chain_dict)
def preinstall(self, context, installed_item, **kw): def preinstall(self, context, installed_item, **kw):
modified_object_list = {} modified_object_list = {}
if context.getTemplateFormatVersion() == 1: if context.getTemplateFormatVersion() == 1:
new_keys = self._objects.keys() new_key_list = self._objects.keys()
new_dict = PersistentMapping() new_dict = PersistentMapping()
# Fix key from installed bt if necessary # Fix key from installed bt if necessary
for key in installed_item._objects.keys(): for key in installed_item._objects:
if not "portal_type_workflow_chain/" in key: if not 'portal_type_workflow_chain/' in key:
new_key = 'portal_type_workflow_chain/%s' %key key = 'portal_type_workflow_chain/%s' % (key)
new_dict[new_key] = installed_item._objects[key] new_dict[key] = installed_item._objects[key]
else: if new_dict:
new_dict[key] = installed_item._objects[key]
if len(new_dict):
installed_item._objects = new_dict installed_item._objects = new_dict
for path in new_keys: for path in new_key_list:
if installed_item._objects.has_key(path): if path in installed_item._objects:
# compare object to see it there is changes # compare object to see it there is changes
new_object = self._objects[path] new_object = self._objects[path]
old_object = installed_item._objects[path] old_object = installed_item._objects[path]
# compare same type of object new_object = self._chain_string_separator.join(new_object)
if isinstance(old_object, list) or isinstance(old_object, tuple): old_object = self._chain_string_separator.join(old_object)
old_object = ', '.join(old_object)
if new_object != old_object: if new_object != old_object:
modified_object_list.update({path : ['Modified', self.__class__.__name__[:-12]]}) modified_object_list.update({path : ['Modified', self.getTemplateTypeName()]})
else: # new object else: # new object
modified_object_list.update({path : ['New', self.__class__.__name__[:-12]]}) modified_object_list.update({path : ['New', self.getTemplateTypeName()]})
# get removed object # get removed object
old_keys = installed_item._objects.keys() for path in installed_item._objects:
for path in old_keys: if path not in new_key_list:
if path not in new_keys: modified_object_list.update({path : ['Removed', self.getTemplateTypeName()]})
modified_object_list.update({path : ['Removed', self.__class__.__name__[:-12]]})
return modified_object_list return modified_object_list
def _importFile(self, file_name, file): def _importFile(self, file_name, file):
...@@ -1970,10 +1969,12 @@ class PortalTypeWorkflowChainTemplateItem(BaseTemplateItem): ...@@ -1970,10 +1969,12 @@ class PortalTypeWorkflowChainTemplateItem(BaseTemplateItem):
chain_list = xml.findall('chain') chain_list = xml.findall('chain')
for chain in chain_list: for chain in chain_list:
portal_type = chain.find('type').text portal_type = chain.find('type').text
workflow = chain.find('workflow').text or '' workflow_chain = chain.find('workflow').text or ''
if 'portal_type_workflow_chain/' not in portal_type: if 'portal_type_workflow_chain/' not in portal_type:
portal_type = 'portal_type_workflow_chain/%s' % (portal_type,) key = 'portal_type_workflow_chain/%s' % (portal_type,)
result_dict[portal_type] = workflow else:
key = portal_type
result_dict[key] = workflow_chain.split(self._chain_string_separator)
self._objects = result_dict self._objects = result_dict
# just for backward compatibility # just for backward compatibility
...@@ -1988,7 +1989,7 @@ class PortalTypeAllowedContentTypeTemplateItem(BaseTemplateItem): ...@@ -1988,7 +1989,7 @@ class PortalTypeAllowedContentTypeTemplateItem(BaseTemplateItem):
business_template_class_property = '_portal_type_allowed_content_type_item' business_template_class_property = '_portal_type_allowed_content_type_item'
def build(self, context, **kw): def build(self, context, **kw):
types_tool = self.getPortalObject().portal_types types_tool = getToolByName(self.getPortalObject(), 'portal_types')
types_list = list(types_tool.objectIds()) types_list = list(types_tool.objectIds())
for key in self._archive.keys(): for key in self._archive.keys():
try: try:
...@@ -2004,35 +2005,32 @@ class PortalTypeAllowedContentTypeTemplateItem(BaseTemplateItem): ...@@ -2004,35 +2005,32 @@ class PortalTypeAllowedContentTypeTemplateItem(BaseTemplateItem):
raise ValueError, "%s %s not found in portal type %s" % ( raise ValueError, "%s %s not found in portal type %s" % (
getattr(self, 'name', self.__class__.__name__), getattr(self, 'name', self.__class__.__name__),
allowed_type, portal_type) allowed_type, portal_type)
if self.class_property not in portal_type:
if self._objects.has_key(portal_type): key = '%s/%s' % (self.class_property, portal_type)
allowed_list = self._objects[portal_type]
allowed_list.append(allowed_type)
self._objects[portal_type] = allowed_list
else: else:
self._objects[portal_type] = [allowed_type] key = portal_type
self._objects.setdefault(key, []).append(allowed_type)
# Function to generate XML Code Manually # Function to generate XML Code Manually
def generateXml(self, path=None): def generateXml(self, path=None):
dictio = self._objects
xml_data = '<%s>' %(self.xml_tag,) xml_data = '<%s>' %(self.xml_tag,)
keys = dictio.keys() key_list = self._objects.keys()
keys.sort() key_list.sort()
for key in keys: for key in key_list:
allowed_list = sorted(dictio[key]) allowed_item_list = sorted(self._objects[key])
xml_data += '\n <portal_type id="%s">' %(key,) xml_data += '\n <portal_type id="%s">' %(key,)
for allowed_item in allowed_list: for allowed_item in allowed_item_list:
xml_data += '\n <item>%s</item>' %(allowed_item,) xml_data += '\n <item>%s</item>' %(allowed_item,)
xml_data += '\n </portal_type>' xml_data += '\n </portal_type>'
xml_data += '\n</%s>' %(self.xml_tag,) xml_data += '\n</%s>' %(self.xml_tag,)
return xml_data return xml_data
def export(self, context, bta, **kw): def export(self, context, bta, **kw):
if len(self._objects.keys()) == 0: if not self._objects:
return return
path = os.path.join(bta.path, self.__class__.__name__) path = os.path.join(bta.path, self.__class__.__name__)
bta.addFolder(name=path) bta.addFolder(name=path)
path = self.__class__.__name__+os.sep+self.class_property path = os.sep.join((self.__class__.__name__, self.class_property,))
xml_data = self.generateXml(path=None) xml_data = self.generateXml(path=None)
bta.addObject(obj=xml_data, name=path, path=None) bta.addObject(obj=xml_data, name=path, path=None)
...@@ -2040,31 +2038,28 @@ class PortalTypeAllowedContentTypeTemplateItem(BaseTemplateItem): ...@@ -2040,31 +2038,28 @@ class PortalTypeAllowedContentTypeTemplateItem(BaseTemplateItem):
modified_object_list = {} modified_object_list = {}
if context.getTemplateFormatVersion() == 1: if context.getTemplateFormatVersion() == 1:
portal = context.getPortalObject() portal = context.getPortalObject()
new_keys = self._objects.keys() new_key_list = self._objects.keys()
new_dict = PersistentMapping() new_dict = PersistentMapping()
# fix key if necessary in installed bt for diff # fix key if necessary in installed bt for diff
for key in installed_item._objects.keys(): for key in installed_item._objects.keys():
if self.class_property not in key: if self.class_property not in key:
new_key = '%s/%s' % (self.class_property, key) key = '%s/%s' % (self.class_property, key)
new_dict[new_key] = installed_item._objects[key] new_dict[key] = installed_item._objects[key]
else: if new_dict:
new_dict[key] = installed_item._objects[key]
if len(new_dict):
installed_item._objects = new_dict installed_item._objects = new_dict
for path in new_keys: for path in new_key_list:
if installed_item._objects.has_key(path): if path in installed_item._objects:
# compare object to see it there is changes # compare object to see it there is changes
new_object = self._objects[path] new_object = self._objects[path]
old_object = installed_item._objects[path] old_object = installed_item._objects[path]
if new_object != old_object: if new_object != old_object:
modified_object_list.update({path : ['Modified', self.__class__.__name__[:-12]]}) modified_object_list.update({path : ['Modified', self.getTemplateTypeName()]})
else: # new object else: # new object
modified_object_list.update({path : ['New', self.__class__.__name__[:-12]]}) modified_object_list.update({path : ['New', self.getTemplateTypeName()]})
# get removed object # get removed object
old_keys = installed_item._objects.keys() for path in installed_item._objects:
for path in old_keys: if path not in new_key_list:
if path not in new_keys: modified_object_list.update({path : ['Removed', self.getTemplateTypeName()]})
modified_object_list.update({path : ['Removed', self.__class__.__name__[:-12]]})
return modified_object_list return modified_object_list
def _importFile(self, file_name, file): def _importFile(self, file_name, file):
......
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