migration.py
branchstable
changeset 5425 7c84e3f370de
parent 5423 e15abfdcce38
child 5426 0d4853a6e5ee
equal deleted inserted replaced
5421:8167de96c523 5425:7c84e3f370de
    27 from os.path import exists, join, basename, splitext
    27 from os.path import exists, join, basename, splitext
    28 
    28 
    29 from logilab.common.decorators import cached
    29 from logilab.common.decorators import cached
    30 from logilab.common.configuration import REQUIRED, read_old_config
    30 from logilab.common.configuration import REQUIRED, read_old_config
    31 from logilab.common.shellutils import ASK
    31 from logilab.common.shellutils import ASK
       
    32 from logilab.common.changelog import Version
    32 
    33 
    33 from cubicweb import ConfigurationError
    34 from cubicweb import ConfigurationError
    34 
    35 
    35 
    36 
    36 def filter_scripts(config, directory, fromversion, toversion, quiet=True):
    37 def filter_scripts(config, directory, fromversion, toversion, quiet=True):
   385 
   386 
   386 
   387 
   387 from logging import getLogger
   388 from logging import getLogger
   388 from cubicweb import set_log_methods
   389 from cubicweb import set_log_methods
   389 set_log_methods(MigrationHelper, getLogger('cubicweb.migration'))
   390 set_log_methods(MigrationHelper, getLogger('cubicweb.migration'))
       
   391 
       
   392 
       
   393 def version_strictly_lower(a, b):
       
   394     if a:
       
   395         a = Version(a)
       
   396     if b:
       
   397         b = Version(b)
       
   398     return a < b
       
   399 
       
   400 def max_version(a, b):
       
   401     return str(max(Version(a), Version(b)))
       
   402 
       
   403 class ConfigurationProblem(object):
       
   404     """Each cube has its own list of dependencies on other cubes/versions.
       
   405 
       
   406     The ConfigurationProblem is used to record the loaded cubes, then to detect
       
   407     inconsistencies in their dependencies.
       
   408 
       
   409     See configuration management on wikipedia for litterature.
       
   410     """
       
   411 
       
   412     def __init__(self, config):
       
   413         self.cubes = {}
       
   414         self.config = config
       
   415 
       
   416     def add_cube(self, name, version):
       
   417         self.cubes[name] = version
       
   418 
       
   419     def solve(self):
       
   420         self.warnings = []
       
   421         self.errors = []
       
   422         self.read_constraints()
       
   423         for cube, versions in sorted(self.constraints.items()):
       
   424             oper, version = None, None
       
   425             # simplify constraints
       
   426             if versions:
       
   427                 for constraint in versions:
       
   428                     op, ver = constraint
       
   429                     if oper is None:
       
   430                         oper = op
       
   431                         version = ver
       
   432                     elif op == '>=' and oper == '>=':
       
   433                         version = max_version(ver, version)
       
   434                     else:
       
   435                         print 'unable to handle this case', oper, version, op, ver
       
   436             # "solve" constraint satisfaction problem
       
   437             if cube not in self.cubes:
       
   438                 self.errors.append( ('add', cube, version) )
       
   439             elif versions:
       
   440                 lower_strict = version_strictly_lower(self.cubes[cube], version)
       
   441                 if oper in ('>=','='):
       
   442                     if lower_strict:
       
   443                         self.errors.append( ('update', cube, version) )
       
   444                 else:
       
   445                     print 'unknown operator', oper
       
   446 
       
   447     def read_constraints(self):
       
   448         self.constraints = {}
       
   449         self.reverse_constraints = {}
       
   450         for cube in self.cubes:
       
   451             use = self.config.cube_dependencies(cube)
       
   452             for name, constraint in use.iteritems():
       
   453                 self.constraints.setdefault(name,set())
       
   454                 if constraint:
       
   455                     try:
       
   456                         oper, version = constraint.split()
       
   457                         self.constraints[name].add( (oper, version) )
       
   458                     except:
       
   459                         self.warnings.append(
       
   460                             'cube %s depends on %s but constraint badly '
       
   461                             'formatted: %s' % (cube, name, constraint))
       
   462                 self.reverse_constraints.setdefault(name, set()).add(cube)