27 from glob import glob |
27 from glob import glob |
28 from warnings import warn |
28 from warnings import warn |
29 |
29 |
30 from logilab.common.deprecation import deprecated |
30 from logilab.common.deprecation import deprecated |
31 from logilab.common.decorators import cached, clear_cache |
31 from logilab.common.decorators import cached, clear_cache |
32 from logilab.common.adbh import get_adv_func_helper |
|
33 |
32 |
34 from yams.constraints import SizeConstraint |
33 from yams.constraints import SizeConstraint |
35 from yams.schema2sql import eschema2sql, rschema2sql |
34 from yams.schema2sql import eschema2sql, rschema2sql |
36 |
35 |
37 from cubicweb import AuthenticationError, ETYPE_NAME_MAP |
36 from cubicweb import AuthenticationError |
38 from cubicweb.schema import (META_RTYPES, VIRTUAL_RTYPES, |
37 from cubicweb.schema import (META_RTYPES, VIRTUAL_RTYPES, |
39 CubicWebRelationSchema, order_eschemas) |
38 CubicWebRelationSchema, order_eschemas) |
40 from cubicweb.dbapi import get_repository, repo_connect |
39 from cubicweb.dbapi import get_repository, repo_connect |
41 from cubicweb.common.migration import MigrationHelper, yes |
40 from cubicweb.migration import MigrationHelper, yes |
42 |
41 |
43 try: |
42 try: |
44 from cubicweb.server import SOURCE_TYPES, schemaserial as ss |
43 from cubicweb.server import SOURCE_TYPES, schemaserial as ss |
45 from cubicweb.server.utils import manager_userpasswd, ask_source_config |
44 from cubicweb.server.utils import manager_userpasswd, ask_source_config |
46 from cubicweb.server.sqlutils import sqlexec, SQL_PREFIX |
45 from cubicweb.server.sqlutils import sqlexec, SQL_PREFIX |
168 def restore_database(self, backupfile, drop=True, systemonly=True, |
167 def restore_database(self, backupfile, drop=True, systemonly=True, |
169 askconfirm=True): |
168 askconfirm=True): |
170 # check |
169 # check |
171 if not osp.exists(backupfile): |
170 if not osp.exists(backupfile): |
172 raise Exception("Backup file %s doesn't exist" % backupfile) |
171 raise Exception("Backup file %s doesn't exist" % backupfile) |
173 return |
|
174 if askconfirm and not self.confirm('Restore %s database from %s ?' |
172 if askconfirm and not self.confirm('Restore %s database from %s ?' |
175 % (self.config.appid, backupfile)): |
173 % (self.config.appid, backupfile)): |
176 return |
174 return |
177 # unpack backup |
175 # unpack backup |
178 tmpdir = tempfile.mkdtemp() |
176 tmpdir = tempfile.mkdtemp() |
179 try: |
177 try: |
180 bkup = tarfile.open(backupfile, 'r|gz') |
178 bkup = tarfile.open(backupfile, 'r|gz') |
181 except tarfile.ReadError: |
179 except tarfile.ReadError: |
182 # assume restoring old backup |
180 # assume restoring old backup |
183 shutil.copy(backupfile, osp.join(tmpdir, 'system')) |
181 shutil.copy(backupfile, osp.join(tmpdir, 'system')) |
184 else: |
182 else: |
185 for name in bkup.getnames(): |
183 for name in bkup.getnames(): |
186 if name[0] in '/.': |
184 if name[0] in '/.': |
187 raise Exception('Security check failed, path starts with "/" or "."') |
185 raise Exception('Security check failed, path starts with "/" or "."') |
188 bkup.close() # XXX seek error if not close+open !?! |
186 bkup.close() # XXX seek error if not close+open !?! |
189 bkup = tarfile.open(backupfile, 'r|gz') |
187 bkup = tarfile.open(backupfile, 'r|gz') |
190 bkup.extractall(path=tmpdir) |
188 bkup.extractall(path=tmpdir) |
191 bkup.close() |
189 bkup.close() |
192 |
|
193 self.config.open_connections_pools = False |
190 self.config.open_connections_pools = False |
194 repo = self.repo_connect() |
191 repo = self.repo_connect() |
195 for source in repo.sources: |
192 for source in repo.sources: |
196 if systemonly and source.uri != 'system': |
193 if systemonly and source.uri != 'system': |
197 continue |
194 continue |
198 try: |
195 try: |
199 source.restore(osp.join(tmpdir, source.uri), self.confirm, drop) |
196 source.restore(osp.join(tmpdir, source.uri), self.confirm, drop) |
200 except Exception, exc: |
197 except Exception, exc: |
201 print '-> error trying to restore [%s]' % exc |
198 print '-> error trying to restore %s [%s]' % (source.uri, exc) |
202 if not self.confirm('Continue anyway?', default='n'): |
199 if not self.confirm('Continue anyway?', default='n'): |
203 raise SystemExit(1) |
200 raise SystemExit(1) |
204 shutil.rmtree(tmpdir) |
201 shutil.rmtree(tmpdir) |
205 # call hooks |
202 # call hooks |
206 repo.open_connections_pools() |
203 repo.open_connections_pools() |
261 |
258 |
262 @cached |
259 @cached |
263 def _create_context(self): |
260 def _create_context(self): |
264 """return a dictionary to use as migration script execution context""" |
261 """return a dictionary to use as migration script execution context""" |
265 context = super(ServerMigrationHelper, self)._create_context() |
262 context = super(ServerMigrationHelper, self)._create_context() |
266 context.update({'checkpoint': self.checkpoint, |
263 context.update({'commit': self.checkpoint, |
|
264 'rollback': self.rollback, |
|
265 'checkpoint': deprecated('[3.6] use commit')(self.checkpoint), |
267 'sql': self.sqlexec, |
266 'sql': self.sqlexec, |
268 'rql': self.rqlexec, |
267 'rql': self.rqlexec, |
269 'rqliter': self.rqliter, |
268 'rqliter': self.rqliter, |
270 'schema': self.repo.get_schema(), |
269 'schema': self.repo.get_schema(), |
271 'cnx': self.cnx, |
270 'cnx': self.cnx, |
272 'fsschema': self.fs_schema, |
271 'fsschema': self.fs_schema, |
273 'session' : self.session, |
272 'session' : self.session, |
274 'repo' : self.repo, |
273 'repo' : self.repo, |
275 'synchronize_schema': deprecated()(self.cmd_sync_schema_props_perms), |
274 'synchronize_schema': deprecated()(self.cmd_sync_schema_props_perms), # 3.4 |
276 'synchronize_eschema': deprecated()(self.cmd_sync_schema_props_perms), |
275 'synchronize_eschema': deprecated()(self.cmd_sync_schema_props_perms), # 3.4 |
277 'synchronize_rschema': deprecated()(self.cmd_sync_schema_props_perms), |
276 'synchronize_rschema': deprecated()(self.cmd_sync_schema_props_perms), # 3.4 |
278 }) |
277 }) |
279 return context |
278 return context |
280 |
279 |
281 @cached |
280 @cached |
282 def group_mapping(self): |
281 def group_mapping(self): |
325 sqlexec(open(fpath).read(), self.session.system_sql, False, |
319 sqlexec(open(fpath).read(), self.session.system_sql, False, |
326 delimiter=';;') |
320 delimiter=';;') |
327 |
321 |
328 # schema synchronization internals ######################################## |
322 # schema synchronization internals ######################################## |
329 |
323 |
330 def _synchronize_permissions(self, ertype): |
324 def _synchronize_permissions(self, erschema, teid): |
331 """permission synchronization for an entity or relation type""" |
325 """permission synchronization for an entity or relation type""" |
332 if ertype in VIRTUAL_RTYPES: |
326 assert teid, erschema |
333 return |
327 if 'update' in erschema.ACTIONS or erschema.final: |
334 newrschema = self.fs_schema[ertype] |
|
335 teid = self.repo.schema[ertype].eid |
|
336 if 'update' in newrschema.ACTIONS or newrschema.final: |
|
337 # entity type |
328 # entity type |
338 exprtype = u'ERQLExpression' |
329 exprtype = u'ERQLExpression' |
339 else: |
330 else: |
340 # relation type |
331 # relation type |
341 exprtype = u'RRQLExpression' |
332 exprtype = u'RRQLExpression' |
342 assert teid, ertype |
|
343 gm = self.group_mapping() |
333 gm = self.group_mapping() |
344 confirm = self.verbosity >= 2 |
334 confirm = self.verbosity >= 2 |
345 # * remove possibly deprecated permission (eg in the persistent schema |
335 # * remove possibly deprecated permission (eg in the persistent schema |
346 # but not in the new schema) |
336 # but not in the new schema) |
347 # * synchronize existing expressions |
337 # * synchronize existing expressions |
348 # * add new groups/expressions |
338 # * add new groups/expressions |
349 for action in newrschema.ACTIONS: |
339 for action in erschema.ACTIONS: |
350 perm = '%s_permission' % action |
340 perm = '%s_permission' % action |
351 # handle groups |
341 # handle groups |
352 newgroups = list(newrschema.get_groups(action)) |
342 newgroups = list(erschema.get_groups(action)) |
353 for geid, gname in self.rqlexec('Any G, GN WHERE T %s G, G name GN, ' |
343 for geid, gname in self.rqlexec('Any G, GN WHERE T %s G, G name GN, ' |
354 'T eid %%(x)s' % perm, {'x': teid}, 'x', |
344 'T eid %%(x)s' % perm, {'x': teid}, 'x', |
355 ask_confirm=False): |
345 ask_confirm=False): |
356 if not gname in newgroups: |
346 if not gname in newgroups: |
357 if not confirm or self.confirm('remove %s permission of %s to %s?' |
347 if not confirm or self.confirm('Remove %s permission of %s to %s?' |
358 % (action, ertype, gname)): |
348 % (action, erschema, gname)): |
359 self.rqlexec('DELETE T %s G WHERE G eid %%(x)s, T eid %s' |
349 self.rqlexec('DELETE T %s G WHERE G eid %%(x)s, T eid %s' |
360 % (perm, teid), |
350 % (perm, teid), |
361 {'x': geid}, 'x', ask_confirm=False) |
351 {'x': geid}, 'x', ask_confirm=False) |
362 else: |
352 else: |
363 newgroups.remove(gname) |
353 newgroups.remove(gname) |
364 for gname in newgroups: |
354 for gname in newgroups: |
365 if not confirm or self.confirm('grant %s permission of %s to %s?' |
355 if not confirm or self.confirm('Grant %s permission of %s to %s?' |
366 % (action, ertype, gname)): |
356 % (action, erschema, gname)): |
367 self.rqlexec('SET T %s G WHERE G eid %%(x)s, T eid %s' |
357 self.rqlexec('SET T %s G WHERE G eid %%(x)s, T eid %s' |
368 % (perm, teid), |
358 % (perm, teid), |
369 {'x': gm[gname]}, 'x', ask_confirm=False) |
359 {'x': gm[gname]}, 'x', ask_confirm=False) |
370 # handle rql expressions |
360 # handle rql expressions |
371 newexprs = dict((expr.expression, expr) for expr in newrschema.get_rqlexprs(action)) |
361 newexprs = dict((expr.expression, expr) for expr in erschema.get_rqlexprs(action)) |
372 for expreid, expression in self.rqlexec('Any E, EX WHERE T %s E, E expression EX, ' |
362 for expreid, expression in self.rqlexec('Any E, EX WHERE T %s E, E expression EX, ' |
373 'T eid %s' % (perm, teid), |
363 'T eid %s' % (perm, teid), |
374 ask_confirm=False): |
364 ask_confirm=False): |
375 if not expression in newexprs: |
365 if not expression in newexprs: |
376 if not confirm or self.confirm('remove %s expression for %s permission of %s?' |
366 if not confirm or self.confirm('Remove %s expression for %s permission of %s?' |
377 % (expression, action, ertype)): |
367 % (expression, action, erschema)): |
378 # deleting the relation will delete the expression entity |
368 # deleting the relation will delete the expression entity |
379 self.rqlexec('DELETE T %s E WHERE E eid %%(x)s, T eid %s' |
369 self.rqlexec('DELETE T %s E WHERE E eid %%(x)s, T eid %s' |
380 % (perm, teid), |
370 % (perm, teid), |
381 {'x': expreid}, 'x', ask_confirm=False) |
371 {'x': expreid}, 'x', ask_confirm=False) |
382 else: |
372 else: |
383 newexprs.pop(expression) |
373 newexprs.pop(expression) |
384 for expression in newexprs.values(): |
374 for expression in newexprs.values(): |
385 expr = expression.expression |
375 expr = expression.expression |
386 if not confirm or self.confirm('add %s expression for %s permission of %s?' |
376 if not confirm or self.confirm('Add %s expression for %s permission of %s?' |
387 % (expr, action, ertype)): |
377 % (expr, action, erschema)): |
388 self.rqlexec('INSERT RQLExpression X: X exprtype %%(exprtype)s, ' |
378 self.rqlexec('INSERT RQLExpression X: X exprtype %%(exprtype)s, ' |
389 'X expression %%(expr)s, X mainvars %%(vars)s, T %s X ' |
379 'X expression %%(expr)s, X mainvars %%(vars)s, T %s X ' |
390 'WHERE T eid %%(x)s' % perm, |
380 'WHERE T eid %%(x)s' % perm, |
391 {'expr': expr, 'exprtype': exprtype, |
381 {'expr': expr, 'exprtype': exprtype, |
392 'vars': expression.mainvars, 'x': teid}, 'x', |
382 'vars': expression.mainvars, 'x': teid}, 'x', |
393 ask_confirm=False) |
383 ask_confirm=False) |
394 |
384 |
395 def _synchronize_rschema(self, rtype, syncrdefs=True, syncperms=True): |
385 def _synchronize_rschema(self, rtype, syncrdefs=True, syncperms=True, syncprops=True): |
396 """synchronize properties of the persistent relation schema against its |
386 """synchronize properties of the persistent relation schema against its |
397 current definition: |
387 current definition: |
398 |
388 |
399 * description |
389 * description |
400 * symetric, meta |
390 * symmetric, meta |
401 * inlined |
391 * inlined |
402 * relation definitions if `syncrdefs` |
392 * relation definitions if `syncrdefs` |
403 * permissions if `syncperms` |
393 * permissions if `syncperms` |
404 |
394 |
405 physical schema changes should be handled by repository's schema hooks |
395 physical schema changes should be handled by repository's schema hooks |
480 rschema = self.fs_schema.rschema(rtype) |
472 rschema = self.fs_schema.rschema(rtype) |
481 reporschema = self.repo.schema.rschema(rschema) |
473 reporschema = self.repo.schema.rschema(rschema) |
482 if (subjtype, rschema, objtype) in self._synchronized: |
474 if (subjtype, rschema, objtype) in self._synchronized: |
483 return |
475 return |
484 self._synchronized.add((subjtype, rschema, objtype)) |
476 self._synchronized.add((subjtype, rschema, objtype)) |
485 if rschema.symetric: |
477 if rschema.symmetric: |
486 self._synchronized.add((objtype, rschema, subjtype)) |
478 self._synchronized.add((objtype, rschema, subjtype)) |
|
479 rdef = rschema.rdef(subjtype, objtype) |
|
480 if rdef.infered: |
|
481 return # don't try to synchronize infered relation defs |
|
482 repordef = reporschema.rdef(subjtype, objtype) |
487 confirm = self.verbosity >= 2 |
483 confirm = self.verbosity >= 2 |
488 # properties |
484 if syncprops: |
489 self.rqlexecall(ss.updaterdef2rql(rschema, subjtype, objtype), |
485 # properties |
490 ask_confirm=confirm) |
486 self.rqlexecall(ss.updaterdef2rql(rschema, subjtype, objtype), |
491 # constraints |
487 ask_confirm=confirm) |
492 newconstraints = list(rschema.rproperty(subjtype, objtype, 'constraints')) |
488 # constraints |
493 # 1. remove old constraints and update constraints of the same type |
489 newconstraints = list(rdef.constraints) |
494 # NOTE: don't use rschema.constraint_by_type because it may be |
490 # 1. remove old constraints and update constraints of the same type |
495 # out of sync with newconstraints when multiple |
491 # NOTE: don't use rschema.constraint_by_type because it may be |
496 # constraints of the same type are used |
492 # out of sync with newconstraints when multiple |
497 for cstr in reporschema.rproperty(subjtype, objtype, 'constraints'): |
493 # constraints of the same type are used |
|
494 for cstr in repordef.constraints: |
|
495 for newcstr in newconstraints: |
|
496 if newcstr.type() == cstr.type(): |
|
497 break |
|
498 else: |
|
499 newcstr = None |
|
500 if newcstr is None: |
|
501 self.rqlexec('DELETE X constrained_by C WHERE C eid %(x)s', |
|
502 {'x': cstr.eid}, 'x', |
|
503 ask_confirm=confirm) |
|
504 else: |
|
505 newconstraints.remove(newcstr) |
|
506 value = unicode(newcstr.serialize()) |
|
507 if value != unicode(cstr.serialize()): |
|
508 self.rqlexec('SET X value %(v)s WHERE X eid %(x)s', |
|
509 {'x': cstr.eid, 'v': value}, 'x', |
|
510 ask_confirm=confirm) |
|
511 # 2. add new constraints |
498 for newcstr in newconstraints: |
512 for newcstr in newconstraints: |
499 if newcstr.type() == cstr.type(): |
513 self.rqlexecall(ss.constraint2rql(rschema, subjtype, objtype, |
500 break |
514 newcstr), |
501 else: |
515 ask_confirm=confirm) |
502 newcstr = None |
516 if syncperms and not rschema in VIRTUAL_RTYPES: |
503 if newcstr is None: |
517 self._synchronize_permissions(rdef, repordef.eid) |
504 self.rqlexec('DELETE X constrained_by C WHERE C eid %(x)s', |
|
505 {'x': cstr.eid}, 'x', |
|
506 ask_confirm=confirm) |
|
507 self.rqlexec('DELETE CWConstraint C WHERE C eid %(x)s', |
|
508 {'x': cstr.eid}, 'x', |
|
509 ask_confirm=confirm) |
|
510 else: |
|
511 newconstraints.remove(newcstr) |
|
512 values = {'x': cstr.eid, |
|
513 'v': unicode(newcstr.serialize())} |
|
514 self.rqlexec('SET X value %(v)s WHERE X eid %(x)s', |
|
515 values, 'x', ask_confirm=confirm) |
|
516 # 2. add new constraints |
|
517 for newcstr in newconstraints: |
|
518 self.rqlexecall(ss.constraint2rql(rschema, subjtype, objtype, |
|
519 newcstr), |
|
520 ask_confirm=confirm) |
|
521 |
518 |
522 # base actions ############################################################ |
519 # base actions ############################################################ |
523 |
520 |
524 def checkpoint(self): |
521 def checkpoint(self, ask_confirm=True): |
525 """checkpoint action""" |
522 """checkpoint action""" |
526 if self.confirm('commit now ?', shell=False): |
523 if not ask_confirm or self.confirm('Commit now ?', shell=False): |
527 self.commit() |
524 self.commit() |
528 |
525 |
529 def cmd_add_cube(self, cube, update_database=True): |
526 def cmd_add_cube(self, cube, update_database=True): |
530 self.cmd_add_cubes( (cube,), update_database) |
527 self.cmd_add_cubes( (cube,), update_database) |
531 |
528 |
683 if eschema.final: |
680 if eschema.final: |
684 instschema.del_entity_type(etype) |
681 instschema.del_entity_type(etype) |
685 else: |
682 else: |
686 eschema = self.fs_schema.eschema(etype) |
683 eschema = self.fs_schema.eschema(etype) |
687 confirm = self.verbosity >= 2 |
684 confirm = self.verbosity >= 2 |
|
685 groupmap = self.group_mapping() |
688 # register the entity into CWEType |
686 # register the entity into CWEType |
689 self.rqlexecall(ss.eschema2rql(eschema), ask_confirm=confirm) |
687 self.rqlexecall(ss.eschema2rql(eschema, groupmap), ask_confirm=confirm) |
690 # add specializes relation if needed |
688 # add specializes relation if needed |
691 self.rqlexecall(ss.eschemaspecialize2rql(eschema), ask_confirm=confirm) |
689 self.rqlexecall(ss.eschemaspecialize2rql(eschema), ask_confirm=confirm) |
692 # register groups / permissions for the entity |
|
693 self.rqlexecall(ss.erperms2rql(eschema, self.group_mapping()), |
|
694 ask_confirm=confirm) |
|
695 # register entity's attributes |
690 # register entity's attributes |
696 for rschema, attrschema in eschema.attribute_definitions(): |
691 for rschema, attrschema in eschema.attribute_definitions(): |
697 # ignore those meta relations, they will be automatically added |
692 # ignore those meta relations, they will be automatically added |
698 if rschema.type in META_RTYPES: |
693 if rschema.type in META_RTYPES: |
699 continue |
694 continue |
700 if not rschema.type in instschema: |
695 if not rschema.type in instschema: |
701 # need to add the relation type and to commit to get it |
696 # need to add the relation type and to commit to get it |
702 # actually in the schema |
697 # actually in the schema |
703 self.cmd_add_relation_type(rschema.type, False, commit=True) |
698 self.cmd_add_relation_type(rschema.type, False, commit=True) |
704 # register relation definition |
699 # register relation definition |
705 self.rqlexecall(ss.rdef2rql(rschema, etype, attrschema.type), |
700 self.rqlexecall(ss.rdef2rql(rschema, etype, attrschema.type, |
|
701 groupmap=groupmap), |
706 ask_confirm=confirm) |
702 ask_confirm=confirm) |
707 # take care to newly introduced base class |
703 # take care to newly introduced base class |
708 # XXX some part of this should probably be under the "if auto" block |
704 # XXX some part of this should probably be under the "if auto" block |
709 for spschema in eschema.specialized_by(recursive=False): |
705 for spschema in eschema.specialized_by(recursive=False): |
710 try: |
706 try: |
911 assert syncperms or syncprops, 'nothing to do' |
908 assert syncperms or syncprops, 'nothing to do' |
912 if ertype is not None: |
909 if ertype is not None: |
913 if isinstance(ertype, (tuple, list)): |
910 if isinstance(ertype, (tuple, list)): |
914 assert len(ertype) == 3, 'not a relation definition' |
911 assert len(ertype) == 3, 'not a relation definition' |
915 assert syncprops, 'can\'t update permission for a relation definition' |
912 assert syncprops, 'can\'t update permission for a relation definition' |
916 self._synchronize_rdef_schema(*ertype) |
913 self._synchronize_rdef_schema(ertype[0], ertype[1], ertype[2], |
917 elif syncprops: |
914 syncperms=syncperms, |
|
915 syncprops=syncprops) |
|
916 else: |
918 erschema = self.repo.schema[ertype] |
917 erschema = self.repo.schema[ertype] |
919 if isinstance(erschema, CubicWebRelationSchema): |
918 if isinstance(erschema, CubicWebRelationSchema): |
920 self._synchronize_rschema(erschema, syncperms=syncperms, |
919 self._synchronize_rschema(erschema, syncperms=syncperms, |
|
920 syncprops=syncprops, |
921 syncrdefs=syncrdefs) |
921 syncrdefs=syncrdefs) |
|
922 elif syncprops: |
|
923 self._synchronize_eschema(erschema, syncperms=syncperms) |
922 else: |
924 else: |
923 self._synchronize_eschema(erschema, syncperms=syncperms) |
925 self._synchronize_permissions(self.fs_schema[ertype], erschema.eid) |
924 else: |
|
925 self._synchronize_permissions(ertype) |
|
926 else: |
926 else: |
927 for etype in self.repo.schema.entities(): |
927 for etype in self.repo.schema.entities(): |
928 if syncprops: |
928 if syncprops: |
929 self._synchronize_eschema(etype, syncperms=syncperms) |
929 self._synchronize_eschema(etype, syncperms=syncperms) |
930 else: |
930 else: |
931 self._synchronize_permissions(etype) |
931 self._synchronize_permissions(self.fs_schema[etype], etype.eid) |
932 if commit: |
932 if commit: |
933 self.commit() |
933 self.commit() |
934 |
934 |
935 def cmd_change_relation_props(self, subjtype, rtype, objtype, |
935 def cmd_change_relation_props(self, subjtype, rtype, objtype, |
936 commit=True, **kwargs): |
936 commit=True, **kwargs): |
1043 {'et': etypes[0]}) |
1043 {'et': etypes[0]}) |
1044 if rset: |
1044 if rset: |
1045 return rset.get_entity(0, 0) |
1045 return rset.get_entity(0, 0) |
1046 return self.cmd_add_workflow('%s workflow' % ';'.join(etypes), etypes) |
1046 return self.cmd_add_workflow('%s workflow' % ';'.join(etypes), etypes) |
1047 |
1047 |
1048 @deprecated('[3.5] use add_workflow and Workflow.add_state method') |
1048 @deprecated('[3.5] use add_workflow and Workflow.add_state method', |
|
1049 stacklevel=3) |
1049 def cmd_add_state(self, name, stateof, initial=False, commit=False, **kwargs): |
1050 def cmd_add_state(self, name, stateof, initial=False, commit=False, **kwargs): |
1050 """method to ease workflow definition: add a state for one or more |
1051 """method to ease workflow definition: add a state for one or more |
1051 entity type(s) |
1052 entity type(s) |
1052 """ |
1053 """ |
1053 wf = self._get_or_create_wf(stateof) |
1054 wf = self._get_or_create_wf(stateof) |
1054 state = wf.add_state(name, initial, **kwargs) |
1055 state = wf.add_state(name, initial, **kwargs) |
1055 if commit: |
1056 if commit: |
1056 self.commit() |
1057 self.commit() |
1057 return state.eid |
1058 return state.eid |
1058 |
1059 |
1059 @deprecated('[3.5] use add_workflow and Workflow.add_transition method') |
1060 @deprecated('[3.5] use add_workflow and Workflow.add_transition method', |
|
1061 stacklevel=3) |
1060 def cmd_add_transition(self, name, transitionof, fromstates, tostate, |
1062 def cmd_add_transition(self, name, transitionof, fromstates, tostate, |
1061 requiredgroups=(), conditions=(), commit=False, **kwargs): |
1063 requiredgroups=(), conditions=(), commit=False, **kwargs): |
1062 """method to ease workflow definition: add a transition for one or more |
1064 """method to ease workflow definition: add a transition for one or more |
1063 entity type(s), from one or more state and to a single state |
1065 entity type(s), from one or more state and to a single state |
1064 """ |
1066 """ |
1121 entity = self._cw.create_entity(etype, **kwargs) |
1125 entity = self._cw.create_entity(etype, **kwargs) |
1122 if commit: |
1126 if commit: |
1123 self.commit() |
1127 self.commit() |
1124 return entity |
1128 return entity |
1125 |
1129 |
1126 @deprecated('use create_entity') |
1130 @deprecated('[3.5] use create_entity', stacklevel=3) |
1127 def cmd_add_entity(self, etype, *args, **kwargs): |
1131 def cmd_add_entity(self, etype, *args, **kwargs): |
1128 """add a new entity of the given type""" |
1132 """add a new entity of the given type""" |
1129 return self.cmd_create_entity(etype, *args, **kwargs).eid |
1133 return self.cmd_create_entity(etype, *args, **kwargs).eid |
1130 |
1134 |
1131 def sqlexec(self, sql, args=None, ask_confirm=True): |
1135 def sqlexec(self, sql, args=None, ask_confirm=True): |
1132 """execute the given sql if confirmed |
1136 """execute the given sql if confirmed |
1133 |
1137 |
1134 should only be used for low level stuff undoable with existing higher |
1138 should only be used for low level stuff undoable with existing higher |
1135 level actions |
1139 level actions |
1136 """ |
1140 """ |
1137 if not ask_confirm or self.confirm('execute sql: %s ?' % sql): |
1141 if not ask_confirm or self.confirm('Execute sql: %s ?' % sql): |
1138 self.session.set_pool() # ensure pool is set |
1142 self.session.set_pool() # ensure pool is set |
1139 try: |
1143 try: |
1140 cu = self.session.system_sql(sql, args) |
1144 cu = self.session.system_sql(sql, args) |
1141 except: |
1145 except: |
1142 ex = sys.exc_info()[1] |
1146 ex = sys.exc_info()[1] |
1143 if self.confirm('error: %s\nabort?' % ex): |
1147 if self.confirm('Error: %s\nabort?' % ex): |
1144 raise |
1148 raise |
1145 return |
1149 return |
1146 try: |
1150 try: |
1147 return cu.fetchall() |
1151 return cu.fetchall() |
1148 except: |
1152 except: |
1152 def rqlexec(self, rql, kwargs=None, cachekey=None, ask_confirm=True): |
1156 def rqlexec(self, rql, kwargs=None, cachekey=None, ask_confirm=True): |
1153 """rql action""" |
1157 """rql action""" |
1154 if not isinstance(rql, (tuple, list)): |
1158 if not isinstance(rql, (tuple, list)): |
1155 rql = ( (rql, kwargs), ) |
1159 rql = ( (rql, kwargs), ) |
1156 res = None |
1160 res = None |
|
1161 try: |
|
1162 execute = self._cw.unsafe_execute |
|
1163 except AttributeError: |
|
1164 execute = self._cw.execute |
1157 for rql, kwargs in rql: |
1165 for rql, kwargs in rql: |
1158 if kwargs: |
1166 if kwargs: |
1159 msg = '%s (%s)' % (rql, kwargs) |
1167 msg = '%s (%s)' % (rql, kwargs) |
1160 else: |
1168 else: |
1161 msg = rql |
1169 msg = rql |
1162 if not ask_confirm or self.confirm('execute rql: %s ?' % msg): |
1170 if not ask_confirm or self.confirm('Execute rql: %s ?' % msg): |
1163 try: |
1171 try: |
1164 res = self._cw.execute(rql, kwargs, cachekey) |
1172 res = execute(rql, kwargs, cachekey) |
1165 except Exception, ex: |
1173 except Exception, ex: |
1166 if self.confirm('error: %s\nabort?' % ex): |
1174 if self.confirm('Error: %s\nabort?' % ex): |
1167 raise |
1175 raise |
1168 return res |
1176 return res |
1169 |
1177 |
1170 def rqliter(self, rql, kwargs=None, ask_confirm=True): |
1178 def rqliter(self, rql, kwargs=None, ask_confirm=True): |
1171 return ForRqlIterator(self, rql, None, ask_confirm) |
1179 return ForRqlIterator(self, rql, None, ask_confirm) |
1172 |
1180 |
1173 def cmd_deactivate_verification_hooks(self): |
1181 def cmd_deactivate_verification_hooks(self): |
1174 self.repo.hm.deactivate_verification_hooks() |
1182 self.config.disabled_hooks_categories.add('integrity') |
1175 |
1183 |
1176 def cmd_reactivate_verification_hooks(self): |
1184 def cmd_reactivate_verification_hooks(self): |
1177 self.repo.hm.reactivate_verification_hooks() |
1185 self.config.disabled_hooks_categories.remove('integrity') |
1178 |
1186 |
1179 # broken db commands ###################################################### |
1187 # broken db commands ###################################################### |
1180 |
1188 |
1181 def cmd_change_attribute_type(self, etype, attr, newtype, commit=True): |
1189 def cmd_change_attribute_type(self, etype, attr, newtype, commit=True): |
1182 """low level method to change the type of an entity attribute. This is |
1190 """low level method to change the type of an entity attribute. This is |