16 |
16 |
17 from logilab.common.decorators import cached |
17 from logilab.common.decorators import cached |
18 from logilab.common.configuration import REQUIRED, read_old_config |
18 from logilab.common.configuration import REQUIRED, read_old_config |
19 |
19 |
20 from cubicweb import ConfigurationError |
20 from cubicweb import ConfigurationError |
21 |
|
22 |
|
23 def migration_files(config, toupgrade): |
|
24 """return an orderer list of path of scripts to execute to upgrade |
|
25 an installed application according to installed cube and cubicweb versions |
|
26 """ |
|
27 merged = [] |
|
28 for cube, fromversion, toversion in toupgrade: |
|
29 if cube == 'cubicweb': |
|
30 migrdir = config.migration_scripts_dir() |
|
31 else: |
|
32 migrdir = config.cube_migration_scripts_dir(cube) |
|
33 scripts = filter_scripts(config, migrdir, fromversion, toversion) |
|
34 merged += [s[1] for s in scripts] |
|
35 if config.accept_mode('Any'): |
|
36 migrdir = config.migration_scripts_dir() |
|
37 merged.insert(0, join(migrdir, 'bootstrapmigration_repository.py')) |
|
38 return merged |
|
39 |
21 |
40 |
22 |
41 def filter_scripts(config, directory, fromversion, toversion, quiet=True): |
23 def filter_scripts(config, directory, fromversion, toversion, quiet=True): |
42 """return a list of paths of migration files to consider to upgrade |
24 """return a list of paths of migration files to consider to upgrade |
43 from a version to a greater one |
25 from a version to a greater one |
124 self.__context = {'confirm': self.confirm, |
106 self.__context = {'confirm': self.confirm, |
125 'config': self.config, |
107 'config': self.config, |
126 'interactive_mode': interactive, |
108 'interactive_mode': interactive, |
127 } |
109 } |
128 |
110 |
|
111 def __getattribute__(self, name): |
|
112 try: |
|
113 return object.__getattribute__(self, name) |
|
114 except AttributeError: |
|
115 cmd = 'cmd_%s' % name |
|
116 if hasattr(self, cmd): |
|
117 meth = getattr(self, cmd) |
|
118 return lambda *args, **kwargs: self.interact(args, kwargs, |
|
119 meth=meth) |
|
120 raise |
|
121 raise AttributeError(name) |
|
122 |
129 def repo_connect(self): |
123 def repo_connect(self): |
130 return self.config.repository() |
124 return self.config.repository() |
131 |
125 |
132 def migrate(self, vcconf, toupgrade, options): |
126 def migrate(self, vcconf, toupgrade, options): |
133 """upgrade the given set of cubes |
127 """upgrade the given set of cubes |
142 def accept_mode(mode): |
136 def accept_mode(mode): |
143 if mode == 'Any': |
137 if mode == 'Any': |
144 return False |
138 return False |
145 return orig_accept_mode(mode) |
139 return orig_accept_mode(mode) |
146 self.config.accept_mode = accept_mode |
140 self.config.accept_mode = accept_mode |
147 scripts = migration_files(self.config, toupgrade) |
141 # may be an iterator |
148 if scripts: |
142 toupgrade = tuple(toupgrade) |
149 vmap = dict( (pname, (fromver, tover)) for pname, fromver, tover in toupgrade) |
143 vmap = dict( (cube, (fromver, tover)) for cube, fromver, tover in toupgrade) |
150 self.__context.update({'applcubicwebversion': vcconf['cubicweb'], |
144 ctx = self.__context |
151 'cubicwebversion': self.config.cubicweb_version(), |
145 ctx['versions_map'] = vmap |
152 'versions_map': vmap}) |
146 if self.config.accept_mode('Any') and 'cubicweb' in vmap: |
153 self.scripts_session(scripts) |
147 migrdir = self.config.migration_scripts_dir() |
154 else: |
148 self.process_script(join(migrdir, 'bootstrapmigration_repository.py')) |
155 print 'no migration script to execute' |
149 for cube, fromversion, toversion in toupgrade: |
|
150 if cube == 'cubicweb': |
|
151 migrdir = self.config.migration_scripts_dir() |
|
152 else: |
|
153 migrdir = self.config.cube_migration_scripts_dir(cube) |
|
154 scripts = filter_scripts(self.config, migrdir, fromversion, toversion) |
|
155 if scripts: |
|
156 for version, script in scripts: |
|
157 self.process_script(script) |
|
158 self.cube_upgraded(cube, version) |
|
159 if version != toversion: |
|
160 self.cube_upgraded(cube, toversion) |
|
161 else: |
|
162 self.cube_upgraded(cube, toversion) |
|
163 |
|
164 def cube_upgraded(self, cube, version): |
|
165 pass |
156 |
166 |
157 def shutdown(self): |
167 def shutdown(self): |
158 pass |
168 pass |
159 |
|
160 def __getattribute__(self, name): |
|
161 try: |
|
162 return object.__getattribute__(self, name) |
|
163 except AttributeError: |
|
164 cmd = 'cmd_%s' % name |
|
165 if hasattr(self, cmd): |
|
166 meth = getattr(self, cmd) |
|
167 return lambda *args, **kwargs: self.interact(args, kwargs, |
|
168 meth=meth) |
|
169 raise |
|
170 raise AttributeError(name) |
|
171 |
169 |
172 def interact(self, args, kwargs, meth): |
170 def interact(self, args, kwargs, meth): |
173 """execute the given method according to user's confirmation""" |
171 """execute the given method according to user's confirmation""" |
174 msg = 'execute command: %s(%s) ?' % ( |
172 msg = 'execute command: %s(%s) ?' % ( |
175 meth.__name__[4:], |
173 meth.__name__[4:], |
203 if answer in ('n', 'no'): |
201 if answer in ('n', 'no'): |
204 return False |
202 return False |
205 if answer in ('r', 'retry'): |
203 if answer in ('r', 'retry'): |
206 return 2 |
204 return 2 |
207 if answer in ('a', 'abort'): |
205 if answer in ('a', 'abort'): |
208 self.rollback() |
|
209 raise SystemExit(1) |
206 raise SystemExit(1) |
210 if shell and answer in ('s', 'shell'): |
207 if shell and answer in ('s', 'shell'): |
211 self.interactive_shell() |
208 self.interactive_shell() |
212 return self.confirm(question) |
209 return self.confirm(question) |
213 return True |
210 return True |
282 except KeyError: |
279 except KeyError: |
283 self.critical('no %s in script %s', funcname, migrscript) |
280 self.critical('no %s in script %s', funcname, migrscript) |
284 return None |
281 return None |
285 return func(*args, **kwargs) |
282 return func(*args, **kwargs) |
286 |
283 |
287 def scripts_session(self, migrscripts): |
|
288 """execute some scripts in a transaction""" |
|
289 try: |
|
290 for migrscript in migrscripts: |
|
291 self.process_script(migrscript) |
|
292 self.commit() |
|
293 except: |
|
294 self.rollback() |
|
295 raise |
|
296 |
|
297 def cmd_option_renamed(self, oldname, newname): |
284 def cmd_option_renamed(self, oldname, newname): |
298 """a configuration option has been renamed""" |
285 """a configuration option has been renamed""" |
299 self._option_changes.append(('renamed', oldname, newname)) |
286 self._option_changes.append(('renamed', oldname, newname)) |
300 |
287 |
301 def cmd_option_group_change(self, option, oldgroup, newgroup): |
288 def cmd_option_group_change(self, option, oldgroup, newgroup): |