cwctl.py
branchstable
changeset 4656 027bbff3659f
parent 4610 7bf205b9a845
child 4684 876a79ece6f7
equal deleted inserted replaced
4655:573a6451b424 4656:027bbff3659f
   156                 self.run_arg(appid)
   156                 self.run_arg(appid)
   157 
   157 
   158 
   158 
   159 # base commands ###############################################################
   159 # base commands ###############################################################
   160 
   160 
       
   161 def version_strictly_lower(a,b):
       
   162     if a:
       
   163         a = a.split('.')
       
   164     if b:
       
   165         b = b.split('.')
       
   166     return a < b
       
   167 
       
   168 def max_version(a, b):
       
   169     return '.'.join(max(a.split('.'), b.split('.')))
       
   170 
       
   171 class ConfigurationProblem(object):
       
   172     """Each cube has its own list of dependencies on other cubes/versions.
       
   173 
       
   174     The ConfigurationProblem is used to record the loaded cubes, then to detect
       
   175     inconsistencies in their dependencies.
       
   176 
       
   177     See configuration management on wikipedia for litterature.
       
   178     """
       
   179 
       
   180     def __init__(self):
       
   181         self.cubes = {}
       
   182 
       
   183     def add_cube(self, name, info):
       
   184         self.cubes[name] = info
       
   185 
       
   186     def solve(self):
       
   187         self.warnings = []
       
   188         self.errors = []
       
   189         self.read_constraints()
       
   190         for cube, versions in sorted(self.constraints.items()):
       
   191             oper, version = None, None
       
   192             # simplify constraints
       
   193             if versions:
       
   194                 for constraint in versions:
       
   195                     op, ver = constraint.split()
       
   196                     if oper is None:
       
   197                         oper = op
       
   198                         version = ver
       
   199                     elif op == '>=' and oper == '>=':
       
   200                         version = max_version(ver, version)
       
   201                     else:
       
   202                         print 'unable to handle this case', oper, version, op, ver
       
   203             # "solve" constraint satisfaction problem
       
   204             if cube not in self.cubes:
       
   205                 self.errors.append( ('add', cube, version) )
       
   206             elif versions:
       
   207                 lower_strict = version_strictly_lower(self.cubes[cube].version, version)
       
   208                 if oper in ('>=','='):
       
   209                     if lower_strict:
       
   210                         self.errors.append( ('update', cube, version) )
       
   211                 else:
       
   212                     print 'unknown operator', oper
       
   213 
       
   214     def read_constraints(self):
       
   215         self.constraints = {}
       
   216         self.reverse_constraints = {}
       
   217         for cube, info in self.cubes.items():
       
   218             if hasattr(info,'__depends_cubes__'):
       
   219                 use = info.__depends_cubes__
       
   220                 if not isinstance(use, dict):
       
   221                     use = dict((key,None) for key in use)
       
   222                     self.warnings.append('cube %s should define __depends_cubes__ as a dict not a list')
       
   223             else:
       
   224                 self.warnings.append('cube %s should define __depends_cubes__' % cube)
       
   225                 use = dict((key,None) for key in info.__use__)
       
   226             for name, constraint in use.items():
       
   227                 self.constraints.setdefault(name,set())
       
   228                 if constraint:
       
   229                     self.constraints[name].add(constraint)
       
   230                 self.reverse_constraints.setdefault(name, set()).add(cube)
       
   231 
   161 class ListCommand(Command):
   232 class ListCommand(Command):
   162     """List configurations, cubes and instances.
   233     """List configurations, cubes and instances.
   163 
   234 
   164     list available configurations, installed cubes, and registered instances
   235     list available configurations, installed cubes, and registered instances
   165     """
   236     """
   183                 line = line.strip()
   254                 line = line.strip()
   184                 if not line:
   255                 if not line:
   185                     continue
   256                     continue
   186                 print '   ', line
   257                 print '   ', line
   187         print
   258         print
       
   259         cfgpb = ConfigurationProblem()
   188         try:
   260         try:
   189             cubesdir = pathsep.join(cwcfg.cubes_search_path())
   261             cubesdir = pathsep.join(cwcfg.cubes_search_path())
   190             namesize = max(len(x) for x in cwcfg.available_cubes())
   262             namesize = max(len(x) for x in cwcfg.available_cubes())
   191         except ConfigurationError, ex:
   263         except ConfigurationError, ex:
   192             print 'No cubes available:', ex
   264             print 'No cubes available:', ex
   198                 if cube in ('CVS', '.svn', 'shared', '.hg'):
   270                 if cube in ('CVS', '.svn', 'shared', '.hg'):
   199                     continue
   271                     continue
   200                 try:
   272                 try:
   201                     tinfo = cwcfg.cube_pkginfo(cube)
   273                     tinfo = cwcfg.cube_pkginfo(cube)
   202                     tversion = tinfo.version
   274                     tversion = tinfo.version
       
   275                     cfgpb.add_cube(cube, tinfo)
   203                 except ConfigurationError:
   276                 except ConfigurationError:
   204                     tinfo = None
   277                     tinfo = None
   205                     tversion = '[missing cube information]'
   278                     tversion = '[missing cube information]'
   206                 print '* %s %s' % (cube.ljust(namesize), tversion)
   279                 print '* %s %s' % (cube.ljust(namesize), tversion)
   207                 if self.config.verbose:
   280                 if self.config.verbose:
   233                     print '    (BROKEN instance, %s)' % exc
   306                     print '    (BROKEN instance, %s)' % exc
   234                     continue
   307                     continue
   235         else:
   308         else:
   236             print 'No instance available in %s' % regdir
   309             print 'No instance available in %s' % regdir
   237         print
   310         print
   238 
   311         # configuration management problem solving
       
   312         cfgpb.solve()
       
   313         if cfgpb.warnings:
       
   314             print 'Warnings:\n', '\n'.join('* '+txt for txt in cfgpb.warnings)
       
   315         if cfgpb.errors:
       
   316             print 'Errors:'
       
   317             for op, cube, version in cfgpb.errors:
       
   318                 if op == 'add':
       
   319                     print '* cube', cube,
       
   320                     if version:
       
   321                         print ' version', version,
       
   322                     print 'is not installed, but required by %s' % ' '.join(cfgpb.reverse_constraints[cube])
       
   323                 else:
       
   324                     print '* cube %s version %s is installed, but version %s is required by (%s)' % (
       
   325                         cube, cfgpb.cubes[cube].version, version, ', '.join(cfgpb.reverse_constraints[cube]))
   239 
   326 
   240 class CreateInstanceCommand(Command):
   327 class CreateInstanceCommand(Command):
   241     """Create an instance from a cube. This is an unified
   328     """Create an instance from a cube. This is an unified
   242     command which can handle web / server / all-in-one installation
   329     command which can handle web / server / all-in-one installation
   243     according to available parts of the software library and of the
   330     according to available parts of the software library and of the