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 |
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: |