1 """utility to ease migration of application version to newly installed |
1 """utility to ease migration of application version to newly installed |
2 version |
2 version |
3 |
3 |
4 :organization: Logilab |
4 :organization: Logilab |
5 :copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
5 :copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
6 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr |
6 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr |
7 """ |
7 """ |
8 __docformat__ = "restructuredtext en" |
8 __docformat__ = "restructuredtext en" |
9 |
9 |
10 import sys |
10 import sys |
123 'interactive_mode': interactive, |
123 'interactive_mode': interactive, |
124 } |
124 } |
125 |
125 |
126 def repo_connect(self): |
126 def repo_connect(self): |
127 return self.config.repository() |
127 return self.config.repository() |
128 |
128 |
129 def migrate(self, vcconf, toupgrade, options): |
129 def migrate(self, vcconf, toupgrade, options): |
130 """upgrade the given set of cubes |
130 """upgrade the given set of cubes |
131 |
131 |
132 `cubes` is an ordered list of 3-uple: |
132 `cubes` is an ordered list of 3-uple: |
133 (cube, fromversion, toversion) |
133 (cube, fromversion, toversion) |
134 """ |
134 """ |
135 if options.fs_only: |
135 if options.fs_only: |
136 # monkey path configuration.accept_mode so database mode (e.g. Any) |
136 # monkey path configuration.accept_mode so database mode (e.g. Any) |
147 self.__context.update({'applcubicwebversion': vcconf['cubicweb'], |
147 self.__context.update({'applcubicwebversion': vcconf['cubicweb'], |
148 'cubicwebversion': self.config.cubicweb_version(), |
148 'cubicwebversion': self.config.cubicweb_version(), |
149 'versions_map': vmap}) |
149 'versions_map': vmap}) |
150 self.scripts_session(scripts) |
150 self.scripts_session(scripts) |
151 else: |
151 else: |
152 print 'no migration script to execute' |
152 print 'no migration script to execute' |
153 |
153 |
154 def shutdown(self): |
154 def shutdown(self): |
155 pass |
155 pass |
156 |
156 |
157 def __getattribute__(self, name): |
157 def __getattribute__(self, name): |
158 try: |
158 try: |
159 return object.__getattribute__(self, name) |
159 return object.__getattribute__(self, name) |
160 except AttributeError: |
160 except AttributeError: |
161 cmd = 'cmd_%s' % name |
161 cmd = 'cmd_%s' % name |
162 if hasattr(self, cmd): |
162 if hasattr(self, cmd): |
163 meth = getattr(self, cmd) |
163 meth = getattr(self, cmd) |
164 return lambda *args, **kwargs: self.interact(args, kwargs, |
164 return lambda *args, **kwargs: self.interact(args, kwargs, |
165 meth=meth) |
165 meth=meth) |
166 raise |
166 raise |
167 raise AttributeError(name) |
167 raise AttributeError(name) |
168 |
168 |
169 def interact(self, args, kwargs, meth): |
169 def interact(self, args, kwargs, meth): |
170 """execute the given method according to user's confirmation""" |
170 """execute the given method according to user's confirmation""" |
171 msg = 'execute command: %s(%s) ?' % ( |
171 msg = 'execute command: %s(%s) ?' % ( |
172 meth.__name__[4:], |
172 meth.__name__[4:], |
173 ', '.join([repr(arg) for arg in args] + |
173 ', '.join([repr(arg) for arg in args] + |
222 import readline |
222 import readline |
223 from rlcompleter import Completer |
223 from rlcompleter import Completer |
224 except ImportError: |
224 except ImportError: |
225 # readline not available |
225 # readline not available |
226 pass |
226 pass |
227 else: |
227 else: |
228 readline.set_completer(Completer(local_ctx).complete) |
228 readline.set_completer(Completer(local_ctx).complete) |
229 readline.parse_and_bind('tab: complete') |
229 readline.parse_and_bind('tab: complete') |
230 histfile = os.path.join(os.environ["HOME"], ".eshellhist") |
230 histfile = os.path.join(os.environ["HOME"], ".eshellhist") |
231 try: |
231 try: |
232 readline.read_history_file(histfile) |
232 readline.read_history_file(histfile) |
254 if self.need_wrap: |
254 if self.need_wrap: |
255 context[attr[4:]] = getattr(self, attr[4:]) |
255 context[attr[4:]] = getattr(self, attr[4:]) |
256 else: |
256 else: |
257 context[attr[4:]] = getattr(self, attr) |
257 context[attr[4:]] = getattr(self, attr) |
258 return context |
258 return context |
259 |
259 |
260 def process_script(self, migrscript, funcname=None, *args, **kwargs): |
260 def process_script(self, migrscript, funcname=None, *args, **kwargs): |
261 """execute a migration script |
261 """execute a migration script |
262 in interactive mode, display the migration script path, ask for |
262 in interactive mode, display the migration script path, ask for |
263 confirmation and execute it if confirmed |
263 confirmation and execute it if confirmed |
264 """ |
264 """ |
278 assert callable(func), '%s (%s) is not callable' % (func, funcname) |
278 assert callable(func), '%s (%s) is not callable' % (func, funcname) |
279 except KeyError: |
279 except KeyError: |
280 self.critical('no %s in script %s', funcname, migrscript) |
280 self.critical('no %s in script %s', funcname, migrscript) |
281 return None |
281 return None |
282 return func(*args, **kwargs) |
282 return func(*args, **kwargs) |
283 |
283 |
284 def scripts_session(self, migrscripts): |
284 def scripts_session(self, migrscripts): |
285 """execute some scripts in a transaction""" |
285 """execute some scripts in a transaction""" |
286 try: |
286 try: |
287 for migrscript in migrscripts: |
287 for migrscript in migrscripts: |
288 self.process_script(migrscript) |
288 self.process_script(migrscript) |
309 #self._option_changes.append(('removed', optname)) |
309 #self._option_changes.append(('removed', optname)) |
310 |
310 |
311 def cmd_option_type_changed(self, optname, oldtype, newvalue): |
311 def cmd_option_type_changed(self, optname, oldtype, newvalue): |
312 """a configuration option's type has changed""" |
312 """a configuration option's type has changed""" |
313 self._option_changes.append(('typechanged', optname, oldtype, newvalue)) |
313 self._option_changes.append(('typechanged', optname, oldtype, newvalue)) |
314 |
314 |
315 def cmd_add_cubes(self, cubes): |
315 def cmd_add_cubes(self, cubes): |
316 """modify the list of used cubes in the in-memory config |
316 """modify the list of used cubes in the in-memory config |
317 returns newly inserted cubes, including dependencies |
317 returns newly inserted cubes, including dependencies |
318 """ |
318 """ |
319 if isinstance(cubes, basestring): |
319 if isinstance(cubes, basestring): |
320 cubes = (cubes,) |
320 cubes = (cubes,) |
321 origcubes = self.config.cubes() |
321 origcubes = self.config.cubes() |
322 newcubes = [p for p in self.config.expand_cubes(cubes) |
322 newcubes = [p for p in self.config.expand_cubes(cubes) |
323 if not p in origcubes] |
323 if not p in origcubes] |
324 if newcubes: |
324 if newcubes: |
325 for cube in cubes: |
325 for cube in cubes: |
326 assert cube in newcubes |
326 assert cube in newcubes |
327 self.config.add_cubes(newcubes) |
327 self.config.add_cubes(newcubes) |
338 self.config._cubes = tuple(self.config.expand_cubes(basecubes)) |
338 self.config._cubes = tuple(self.config.expand_cubes(basecubes)) |
339 removed = [p for p in origcubes if not p in self.config._cubes] |
339 removed = [p for p in origcubes if not p in self.config._cubes] |
340 assert cube in removed, \ |
340 assert cube in removed, \ |
341 "can't remove cube %s, used as a dependancy" % cube |
341 "can't remove cube %s, used as a dependancy" % cube |
342 return removed |
342 return removed |
343 |
343 |
344 def rewrite_configuration(self): |
344 def rewrite_configuration(self): |
345 # import locally, show_diffs unavailable in gae environment |
345 # import locally, show_diffs unavailable in gae environment |
346 from cubicweb.toolsutils import show_diffs |
346 from cubicweb.toolsutils import show_diffs |
347 configfile = self.config.main_config_file() |
347 configfile = self.config.main_config_file() |
348 if self._option_changes: |
348 if self._option_changes: |