cwctl.py
changeset 5027 d688daf0a62c
parent 5026 1f8238eaec9b
child 5048 bf8a53a11b6d
equal deleted inserted replaced
5026:1f8238eaec9b 5027:d688daf0a62c
   167                 self.run_arg(appid)
   167                 self.run_arg(appid)
   168 
   168 
   169 
   169 
   170 # base commands ###############################################################
   170 # base commands ###############################################################
   171 
   171 
   172 def version_strictly_lower(a, b):
       
   173     from logilab.common.changelog import Version
       
   174     if a:
       
   175         a = Version(a)
       
   176     if b:
       
   177         b = Version(b)
       
   178     return a < b
       
   179 
       
   180 def max_version(a, b):
       
   181     from logilab.common.changelog import Version
       
   182     return str(max(Version(a), Version(b)))
       
   183 
       
   184 class ConfigurationProblem(object):
       
   185     """Each cube has its own list of dependencies on other cubes/versions.
       
   186 
       
   187     The ConfigurationProblem is used to record the loaded cubes, then to detect
       
   188     inconsistencies in their dependencies.
       
   189 
       
   190     See configuration management on wikipedia for litterature.
       
   191     """
       
   192 
       
   193     def __init__(self):
       
   194         self.cubes = {}
       
   195 
       
   196     def add_cube(self, name, info):
       
   197         self.cubes[name] = info
       
   198 
       
   199     def solve(self):
       
   200         self.warnings = []
       
   201         self.errors = []
       
   202         self.read_constraints()
       
   203         for cube, versions in sorted(self.constraints.items()):
       
   204             oper, version = None, None
       
   205             # simplify constraints
       
   206             if versions:
       
   207                 for constraint in versions:
       
   208                     op, ver = constraint
       
   209                     if oper is None:
       
   210                         oper = op
       
   211                         version = ver
       
   212                     elif op == '>=' and oper == '>=':
       
   213                         version = max_version(ver, version)
       
   214                     else:
       
   215                         print 'unable to handle this case', oper, version, op, ver
       
   216             # "solve" constraint satisfaction problem
       
   217             if cube not in self.cubes:
       
   218                 self.errors.append( ('add', cube, version) )
       
   219             elif versions:
       
   220                 lower_strict = version_strictly_lower(self.cubes[cube].version, version)
       
   221                 if oper in ('>=','='):
       
   222                     if lower_strict:
       
   223                         self.errors.append( ('update', cube, version) )
       
   224                 else:
       
   225                     print 'unknown operator', oper
       
   226 
       
   227     def read_constraints(self):
       
   228         self.constraints = {}
       
   229         self.reverse_constraints = {}
       
   230         for cube, info in self.cubes.items():
       
   231             if hasattr(info,'__depends_cubes__'):
       
   232                 use = info.__depends_cubes__
       
   233                 if not isinstance(use, dict):
       
   234                     use = dict((key, None) for key in use)
       
   235                     self.warnings.append('cube %s should define __depends_cubes__ as a dict not a list')
       
   236             else:
       
   237                 self.warnings.append('cube %s should define __depends_cubes__' % cube)
       
   238                 use = dict((key, None) for key in info.__use__)
       
   239             for name, constraint in use.items():
       
   240                 self.constraints.setdefault(name,set())
       
   241                 if constraint:
       
   242                     try:
       
   243                         oper, version = constraint.split()
       
   244                         self.constraints[name].add( (oper, version) )
       
   245                     except:
       
   246                         self.warnings.append('cube %s depends on %s but constraint badly formatted: %s'
       
   247                                              % (cube, name, constraint))
       
   248                 self.reverse_constraints.setdefault(name, set()).add(cube)
       
   249 
       
   250 class ListCommand(Command):
   172 class ListCommand(Command):
   251     """List configurations, cubes and instances.
   173     """List configurations, cubes and instances.
   252 
   174 
   253     list available configurations, installed cubes, and registered instances
   175     list available configurations, installed cubes, and registered instances
   254     """
   176     """
   261 
   183 
   262     def run(self, args):
   184     def run(self, args):
   263         """run the command with its specific arguments"""
   185         """run the command with its specific arguments"""
   264         if args:
   186         if args:
   265             raise BadCommandUsage('Too much arguments')
   187             raise BadCommandUsage('Too much arguments')
       
   188         from cubicweb.migration import ConfigurationProblem
   266         print 'CubicWeb %s (%s mode)' % (cwcfg.cubicweb_version(), cwcfg.mode)
   189         print 'CubicWeb %s (%s mode)' % (cwcfg.cubicweb_version(), cwcfg.mode)
   267         print
   190         print
   268         print 'Available configurations:'
   191         print 'Available configurations:'
   269         for config in CONFIGURATIONS:
   192         for config in CONFIGURATIONS:
   270             print '*', config.name
   193             print '*', config.name
   272                 line = line.strip()
   195                 line = line.strip()
   273                 if not line:
   196                 if not line:
   274                     continue
   197                     continue
   275                 print '   ', line
   198                 print '   ', line
   276         print
   199         print
   277         cfgpb = ConfigurationProblem()
   200         cfgpb = ConfigurationProblem(cwcfg)
   278         try:
   201         try:
   279             cubesdir = pathsep.join(cwcfg.cubes_search_path())
   202             cubesdir = pathsep.join(cwcfg.cubes_search_path())
   280             namesize = max(len(x) for x in cwcfg.available_cubes())
   203             namesize = max(len(x) for x in cwcfg.available_cubes())
   281         except ConfigurationError, ex:
   204         except ConfigurationError, ex:
   282             print 'No cubes available:', ex
   205             print 'No cubes available:', ex
   286             print 'Available cubes (%s):' % cubesdir
   209             print 'Available cubes (%s):' % cubesdir
   287             for cube in cwcfg.available_cubes():
   210             for cube in cwcfg.available_cubes():
   288                 try:
   211                 try:
   289                     tinfo = cwcfg.cube_pkginfo(cube)
   212                     tinfo = cwcfg.cube_pkginfo(cube)
   290                     tversion = tinfo.version
   213                     tversion = tinfo.version
   291                     cfgpb.add_cube(cube, tinfo)
   214                     cfgpb.add_cube(cube, tversion)
   292                 except ConfigurationError:
   215                 except ConfigurationError:
   293                     tinfo = None
   216                     tinfo = None
   294                     tversion = '[missing cube information]'
   217                     tversion = '[missing cube information]'
   295                 print '* %s %s' % (cube.ljust(namesize), tversion)
   218                 print '* %s %s' % (cube.ljust(namesize), tversion)
   296                 if self.config.verbose:
   219                 if self.config.verbose: