migration.py
changeset 5027 d688daf0a62c
parent 4721 8f63691ccb7f
child 5423 e15abfdcce38
equal deleted inserted replaced
5026:1f8238eaec9b 5027:d688daf0a62c
    14 from os.path import exists, join, basename, splitext
    14 from os.path import exists, join, basename, splitext
    15 
    15 
    16 from logilab.common.decorators import cached
    16 from logilab.common.decorators import cached
    17 from logilab.common.configuration import REQUIRED, read_old_config
    17 from logilab.common.configuration import REQUIRED, read_old_config
    18 from logilab.common.shellutils import ASK
    18 from logilab.common.shellutils import ASK
       
    19 from logilab.common.changelog import Version
    19 
    20 
    20 from cubicweb import ConfigurationError
    21 from cubicweb import ConfigurationError
    21 
    22 
    22 
    23 
    23 def filter_scripts(config, directory, fromversion, toversion, quiet=True):
    24 def filter_scripts(config, directory, fromversion, toversion, quiet=True):
   372 
   373 
   373 
   374 
   374 from logging import getLogger
   375 from logging import getLogger
   375 from cubicweb import set_log_methods
   376 from cubicweb import set_log_methods
   376 set_log_methods(MigrationHelper, getLogger('cubicweb.migration'))
   377 set_log_methods(MigrationHelper, getLogger('cubicweb.migration'))
       
   378 
       
   379 
       
   380 def version_strictly_lower(a, b):
       
   381     if a:
       
   382         a = Version(a)
       
   383     if b:
       
   384         b = Version(b)
       
   385     return a < b
       
   386 
       
   387 def max_version(a, b):
       
   388     return str(max(Version(a), Version(b)))
       
   389 
       
   390 class ConfigurationProblem(object):
       
   391     """Each cube has its own list of dependencies on other cubes/versions.
       
   392 
       
   393     The ConfigurationProblem is used to record the loaded cubes, then to detect
       
   394     inconsistencies in their dependencies.
       
   395 
       
   396     See configuration management on wikipedia for litterature.
       
   397     """
       
   398 
       
   399     def __init__(self, config):
       
   400         self.cubes = {}
       
   401         self.config = config
       
   402 
       
   403     def add_cube(self, name, version):
       
   404         self.cubes[name] = version
       
   405 
       
   406     def solve(self):
       
   407         self.warnings = []
       
   408         self.errors = []
       
   409         self.read_constraints()
       
   410         for cube, versions in sorted(self.constraints.items()):
       
   411             oper, version = None, None
       
   412             # simplify constraints
       
   413             if versions:
       
   414                 for constraint in versions:
       
   415                     op, ver = constraint
       
   416                     if oper is None:
       
   417                         oper = op
       
   418                         version = ver
       
   419                     elif op == '>=' and oper == '>=':
       
   420                         version = max_version(ver, version)
       
   421                     else:
       
   422                         print 'unable to handle this case', oper, version, op, ver
       
   423             # "solve" constraint satisfaction problem
       
   424             if cube not in self.cubes:
       
   425                 self.errors.append( ('add', cube, version) )
       
   426             elif versions:
       
   427                 lower_strict = version_strictly_lower(self.cubes[cube], version)
       
   428                 if oper in ('>=','='):
       
   429                     if lower_strict:
       
   430                         self.errors.append( ('update', cube, version) )
       
   431                 else:
       
   432                     print 'unknown operator', oper
       
   433 
       
   434     def read_constraints(self):
       
   435         self.constraints = {}
       
   436         self.reverse_constraints = {}
       
   437         for cube in self.cubes:
       
   438             use = self.config.cube_dependencies(cube)
       
   439             for name, constraint in use.iteritems():
       
   440                 self.constraints.setdefault(name,set())
       
   441                 if constraint:
       
   442                     try:
       
   443                         oper, version = constraint.split()
       
   444                         self.constraints[name].add( (oper, version) )
       
   445                     except:
       
   446                         self.warnings.append(
       
   447                             'cube %s depends on %s but constraint badly '
       
   448                             'formatted: %s' % (cube, name, constraint))
       
   449                 self.reverse_constraints.setdefault(name, set()).add(cube)