Back to index

plone3  3.1.7
upgrade.py
Go to the documentation of this file.
00001 ##############################################################################
00002 #
00003 # Copyright (c) 2005 Nuxeo SARL <http://nuxeo.com>
00004 #
00005 # This software is subject to the provisions of the Zope Public License,
00006 # Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
00007 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
00008 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00009 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
00010 # FOR A PARTICULAR PURPOSE.
00011 #
00012 ##############################################################################
00013 
00014 from BTrees.OOBTree import OOBTree
00015 
00016 from registry import _profile_registry
00017 
00018 class UpgradeRegistry(object):
00019     """Registry of upgrade steps, by profile.
00020     
00021     Registry keys are profile ids.
00022 
00023     Each registry value is a nested mapping:
00024       - id -> step for single steps
00025       - id -> [ (id1, step1), (id2, step2) ] for nested steps
00026     """
00027     def __init__(self):
00028         self._registry = OOBTree()
00029 
00030     def __getitem__(self, key):
00031         return self._registry.get(key)
00032 
00033     def keys(self):
00034         return self._registry.keys()
00035 
00036     def clear(self):
00037         self._registry.clear()
00038 
00039     def getUpgradeStepsForProfile(self, profile_id):
00040         """Return the upgrade steps mapping for a given profile, or
00041         None if there are no steps registered for a profile matching
00042         that id.
00043         """
00044         profile_steps = self._registry.get(profile_id, None)
00045         if profile_steps is None:
00046             self._registry[profile_id] = OOBTree()
00047             profile_steps = self._registry.get(profile_id)
00048         return profile_steps
00049 
00050     def getUpgradeStep(self, profile_id, step_id):
00051         """Returns the specified upgrade step for the specified
00052         profile, or None if it doesn't exist.
00053         """
00054         profile_steps = self._registry.get(profile_id, None)
00055         if profile_steps is not None:
00056             step = profile_steps.get(step_id, None)
00057             if step is None:
00058                 for key in profile_steps.keys():
00059                     if type(profile_steps[key]) == list:
00060                         subs = dict(profile_steps[key])
00061                         step = subs.get(step_id, None)
00062                         if step is not None:
00063                             break
00064             elif type(step) == list:
00065                 subs = dict(step)
00066                 step = subs.get(step_id, None)
00067             return step
00068 
00069 _upgrade_registry = UpgradeRegistry()
00070 
00071 class UpgradeStep(object):
00072     """A step to upgrade a component.
00073     """
00074     def __init__(self, title, profile, source, dest, desc, handler,
00075                  checker=None, sortkey=0):
00076         self.id = str(abs(hash('%s%s%s%s' % (title, source, dest, sortkey))))
00077         self.title = title
00078         if source == '*':
00079             source = None
00080         elif isinstance(source, basestring):
00081             source = tuple(source.split('.'))
00082         self.source = source
00083         if dest == '*':
00084             dest = None
00085         elif isinstance(dest, basestring):
00086             dest = tuple(dest.split('.'))
00087         self.dest = dest
00088         self.description = desc
00089         self.handler = handler
00090         self.checker = checker
00091         self.sortkey = sortkey
00092         self.profile = profile
00093 
00094     def versionMatch(self, source):
00095         return (source is None or
00096                 self.source is None or
00097                 source <= self.source)
00098 
00099     def isProposed(self, tool, source):
00100         """Check if a step can be applied.
00101 
00102         False means already applied or does not apply.
00103         True means can be applied.
00104         """
00105         checker = self.checker
00106         if checker is None:
00107             return self.versionMatch(source)
00108         else:
00109             return checker(tool)
00110 
00111     def doStep(self, tool):
00112         self.handler(tool)
00113 
00114 def _registerUpgradeStep(step):
00115     profile_id = step.profile
00116     profile_steps = _upgrade_registry.getUpgradeStepsForProfile(profile_id)
00117     profile_steps[step.id] = step
00118 
00119 def _registerNestedUpgradeStep(step, outer_id):
00120     profile_id = step.profile
00121     profile_steps = _upgrade_registry.getUpgradeStepsForProfile(profile_id)
00122     nested_steps = profile_steps.get(outer_id, [])
00123     nested_steps.append((step.id, step))
00124     profile_steps[outer_id] = nested_steps
00125 
00126 def _extractStepInfo(tool, id, step, source):
00127     """Returns the info data structure for a given step.
00128     """
00129     proposed = step.isProposed(tool, source)
00130     if (not proposed
00131         and source is not None
00132         and (step.source is None or source > step.source)):
00133         return
00134     info = {
00135         'id': id,
00136         'step': step,
00137         'title': step.title,
00138         'source': step.source,
00139         'dest': step.dest,
00140         'description': step.description,
00141         'proposed': proposed,
00142         'sortkey': step.sortkey,
00143         }
00144     return info
00145 
00146 def listProfilesWithUpgrades():
00147     return _upgrade_registry.keys()
00148 
00149 def listUpgradeSteps(tool, profile_id, source):
00150     """Lists upgrade steps available from a given version, for a given
00151     profile id.
00152     """
00153     res = []
00154     profile_steps = _upgrade_registry.getUpgradeStepsForProfile(profile_id)
00155     for id, step in profile_steps.items():
00156         if type(step) == UpgradeStep:
00157             info = _extractStepInfo(tool, id, step, source)
00158             if info is None:
00159                 continue
00160             res.append(((step.source or '', step.sortkey, info['proposed']), info))
00161         else: # nested steps
00162             nested = []
00163             outer_proposed = False
00164             for inner_id, inner_step in step:
00165                 info = _extractStepInfo(tool, inner_id, inner_step, source)
00166                 if info is None:
00167                     continue
00168                 nested.append(info)
00169                 outer_proposed = outer_proposed or info['proposed']
00170             if nested:
00171                 src = nested[0]['source']
00172                 sortkey = nested[0]['sortkey']
00173                 res.append(((src or '', sortkey, outer_proposed), nested))
00174     res.sort()
00175     res = [i[1] for i in res]
00176     return res