# HG changeset patch # User Alexandre Fayolle # Date 1255711468 -7200 # Node ID a090324efefe8c8a0c0e03da2de7caa0bf0988b4 # Parent 4b8d7838d74d298746f4e579763e651e01c1aa19# Parent 5bfdb591050af502191e1045a379b06be145d218 merge diff -r 4b8d7838d74d -r a090324efefe __init__.py --- a/__init__.py Fri Oct 16 18:41:40 2009 +0200 +++ b/__init__.py Fri Oct 16 18:44:28 2009 +0200 @@ -141,11 +141,12 @@ restrictions = set() cachekey = [] pending_relations = [] - for attr, value in kwargs.iteritems(): + for attr, value in kwargs.items(): if isinstance(value, (tuple, list, set, frozenset)): if len(value) == 1: value = iter(value).next() else: + del kwargs[attr] pending_relations.append( (attr, value) ) continue if hasattr(value, 'eid'): # non final relation diff -r 4b8d7838d74d -r a090324efefe common/migration.py --- a/common/migration.py Fri Oct 16 18:41:40 2009 +0200 +++ b/common/migration.py Fri Oct 16 18:44:28 2009 +0200 @@ -92,7 +92,9 @@ def __init__(self, config, interactive=True, verbosity=1): self.config = config - self.config.init_log(logthreshold=logging.ERROR, debug=True) + if config: + # no config on shell to a remote instance + self.config.init_log(logthreshold=logging.ERROR, debug=True) # 0: no confirmation, 1: only main commands confirmed, 2 ask for everything self.verbosity = verbosity self.need_wrap = True diff -r 4b8d7838d74d -r a090324efefe cwctl.py --- a/cwctl.py Fri Oct 16 18:41:40 2009 +0200 +++ b/cwctl.py Fri Oct 16 18:44:28 2009 +0200 @@ -685,10 +685,16 @@ class ShellCommand(Command): - """Run an interactive migration shell. This is a python shell with - enhanced migration commands predefined in the namespace. An additional - argument may be given corresponding to a file containing commands to - execute in batch mode. + """Run an interactive migration shell on an instance. This is a python shell + with enhanced migration commands predefined in the namespace. An additional + argument may be given corresponding to a file containing commands to execute + in batch mode. + + By default it will connect to a local instance using an in memory + connection, unless -P option is specified, in which case you will be + connected through pyro. In the later case, you won't have access to + repository internals (session, etc...) so most migration commands won't be + available. the identifier of the instance to connect. @@ -698,46 +704,87 @@ options = ( ('system-only', {'short': 'S', 'action' : 'store_true', - 'default': False, 'help': 'only connect to the system source when the instance is ' 'using multiple sources. You can\'t use this option and the ' - '--ext-sources option at the same time.'}), + '--ext-sources option at the same time.', + 'group': 'local' + }), ('ext-sources', {'short': 'E', 'type' : 'csv', 'metavar': '', - 'default': None, 'help': "For multisources instances, specify to which sources the \ repository should connect to for upgrading. When unspecified or 'all' given, \ will connect to all defined sources. If 'migration' is given, appropriate \ sources for migration will be automatically selected.", + 'group': 'local' }), ('force', {'short': 'f', 'action' : 'store_true', - 'default' : False, - 'help': 'don\'t check instance is up to date.'} - ), + 'help': 'don\'t check instance is up to date.', + 'group': 'local' + }), + + ('pyro', + {'short': 'P', 'action' : 'store_true', + 'help': 'connect to a running instance through Pyro.', + 'group': 'remote', + }), + ('pyro-ns-host', + {'short': 'H', 'type' : 'string', 'metavar': '', + 'help': 'Pyro name server host. If not set, will be detected by ' + 'using a broadcast query.', + 'group': 'remote' + }), ) def run(self, args): appid = pop_arg(args, 99, msg="No instance specified !") - config = cwcfg.config_for(appid) - if self.config.ext_sources: - assert not self.config.system_only - sources = self.config.ext_sources - elif self.config.system_only: - sources = ('system',) + if self.config.pyro: + from cubicweb import AuthenticationError + from cubicweb.dbapi import connect + from cubicweb.server.utils import manager_userpasswd + from cubicweb.server.migractions import ServerMigrationHelper + while True: + try: + login, pwd = manager_userpasswd(msg=None) + cnx = connect(appid, login=login, password=pwd, + host=self.config.pyro_ns_host, mulcnx=False) + except AuthenticationError, ex: + print ex + except (KeyboardInterrupt, EOFError): + print + sys.exit(0) + else: + break + cnx.load_appobjects() + repo = cnx._repo + mih = ServerMigrationHelper(None, repo=repo, cnx=cnx, + # hack so it don't try to load fs schema + schema=1) else: - sources = ('all',) - config.set_sources_mode(sources) - config.repairing = self.config.force - mih = config.migration_handler() - if args: - for arg in args: - mih.process_script(arg) - else: - mih.interactive_shell() - mih.shutdown() + config = cwcfg.config_for(appid) + if self.config.ext_sources: + assert not self.config.system_only + sources = self.config.ext_sources + elif self.config.system_only: + sources = ('system',) + else: + sources = ('all',) + config.set_sources_mode(sources) + config.repairing = self.config.force + mih = config.migration_handler() + try: + if args: + for arg in args: + mih.process_script(arg) + else: + mih.interactive_shell() + finally: + if not self.config.pyro: + mih.shutdown() + else: + cnx.close() class RecompileInstanceCatalogsCommand(InstanceCommand): diff -r 4b8d7838d74d -r a090324efefe cwvreg.py --- a/cwvreg.py Fri Oct 16 18:41:40 2009 +0200 +++ b/cwvreg.py Fri Oct 16 18:44:28 2009 +0200 @@ -65,16 +65,28 @@ for appobject in appobjects: appobject.vreg_initialization_completed() - def render(self, __oid, req, __fallback_oid=None, rset=None, **kwargs): - """select object, or fallback object if specified and the first one - isn't selectable, then render it + def render(self, __oid, req, __fallback_oid=None, rset=None, initargs=None, + **kwargs): + """Select object with the given id (`__oid`) then render it. If the + object isn't selectable, try to select fallback object if + `__fallback_oid` is specified. + + If specified `initargs` is expected to be a dictionnary containing + arguments that should be given to selection (hence to object's __init__ + as well), but not to render(). Other arbitrary keyword arguments will be + given to selection *and* to render(), and so should be handled by + object's call or cell_call method.. """ + if initargs is None: + initargs = kwargs + else: + initargs.update(kwargs) try: - obj = self.select(__oid, req, rset=rset, **kwargs) + obj = self.select(__oid, req, rset=rset, **initargs) except NoSelectableObject: if __fallback_oid is None: raise - obj = self.select(__fallback_oid, req, rset=rset, **kwargs) + obj = self.select(__fallback_oid, req, rset=rset, **initargs) return obj.render(**kwargs) def select_vobject(self, oid, *args, **kwargs): @@ -374,6 +386,8 @@ implemented_interfaces = set() if 'Any' in self.get('etypes', ()): for etype in self.schema.entities(): + if etype.final: + continue cls = self['etypes'].etype_class(etype) for iface in cls.__implements__: implemented_interfaces.update(iface.__mro__) diff -r 4b8d7838d74d -r a090324efefe dbapi.py --- a/dbapi.py Fri Oct 16 18:41:40 2009 +0200 +++ b/dbapi.py Fri Oct 16 18:44:28 2009 +0200 @@ -446,7 +446,7 @@ return self._repo.get_schema() def load_appobjects(self, cubes=_MARKER, subpath=None, expand=True, - force_reload=None): + force_reload=None): config = self.vreg.config if cubes is _MARKER: cubes = self._repo.get_cubes() diff -r 4b8d7838d74d -r a090324efefe server/__init__.py --- a/server/__init__.py Fri Oct 16 18:41:40 2009 +0200 +++ b/server/__init__.py Fri Oct 16 18:44:28 2009 +0200 @@ -176,6 +176,10 @@ # reloging using the admin user config._cubes = None # avoid assertion error repo, cnx = in_memory_cnx(config, login, pwd) + # trigger vreg initialisation of entity classes + config.cubicweb_appobject_path = set(('entities',)) + config.cube_appobject_path = set(('entities',)) + repo.vreg.set_schema(repo.schema) assert len(repo.sources) == 1, repo.sources handler = config.migration_handler(schema, interactive=False, cnx=cnx, repo=repo) diff -r 4b8d7838d74d -r a090324efefe server/migractions.py --- a/server/migractions.py Fri Oct 16 18:41:40 2009 +0200 +++ b/server/migractions.py Fri Oct 16 18:44:28 2009 +0200 @@ -54,6 +54,7 @@ def __init__(self, config, schema, interactive=True, repo=None, cnx=None, verbosity=1, connect=True): MigrationHelper.__init__(self, config, interactive, verbosity) + # no config on shell to a remote instance if not interactive: assert cnx assert repo @@ -61,7 +62,8 @@ assert repo self._cnx = cnx self.repo = repo - self.session.data['rebuild-infered'] = False + if config is not None: + self.session.data['rebuild-infered'] = False elif connect: self.repo_connect() if not schema: @@ -233,7 +235,10 @@ @property def session(self): - return self.repo._get_session(self.cnx.sessionid) + if self.config is not None: + return self.repo._get_session(self.cnx.sessionid) + # no access to session on remote instance + return None def commit(self): if hasattr(self, '_cnx'): @@ -255,7 +260,8 @@ 'sql': self.sqlexec, 'rql': self.rqlexec, 'rqliter': self.rqliter, - 'schema': self.repo.schema, + 'schema': self.repo.get_schema(), + 'cnx': self.cnx, 'fsschema': self.fs_schema, 'session' : self.session, 'repo' : self.repo, @@ -268,8 +274,7 @@ @cached def group_mapping(self): """cached group mapping""" - self.session.set_pool() - return ss.group_mapping(self.session) + return ss.group_mapping(self._cw) def exec_event_script(self, event, cubepath=None, funcname=None, *args, **kwargs): @@ -981,7 +986,6 @@ :rtype: `Workflow` """ - self.session.set_pool() # ensure pool is set wf = self.cmd_create_entity('Workflow', name=unicode(name), **kwargs) if not isinstance(wfof, (list, tuple)): @@ -1001,7 +1005,6 @@ # XXX remove once cmd_add_[state|transition] are removed def _get_or_create_wf(self, etypes): - self.session.set_pool() # ensure pool is set if not isinstance(etypes, (list, tuple)): etypes = (etypes,) rset = self.rqlexec('Workflow X WHERE X workflow_of ET, ET name %(et)s', @@ -1041,16 +1044,14 @@ """set or add (if `reset` is False) groups and conditions for a transition """ - self.session.set_pool() # ensure pool is set - tr = self.session.entity_from_eid(treid) + tr = self._cw.entity_from_eid(treid) tr.set_transition_permissions(requiredgroups, conditions, reset) if commit: self.commit() @deprecated('[3.5] use entity.fire_transition("transition") or entity.change_state("state")') def cmd_set_state(self, eid, statename, commit=False): - self.session.set_pool() # ensure pool is set - self.session.entity_from_eid(eid).change_state(statename) + self._cw.entity_from_eid(eid).change_state(statename) if commit: self.commit() @@ -1074,11 +1075,18 @@ # other data migration commands ########################################### - def cmd_create_entity(self, etype, *args, **kwargs): + @property + def _cw(self): + session = self.session + if session is not None: + session.set_pool() + return session + return self.cnx.request() + + def cmd_create_entity(self, etype, **kwargs): """add a new entity of the given type""" commit = kwargs.pop('commit', False) - self.session.set_pool() - entity = self.session.create_entity(etype, *args, **kwargs) + entity = self._cw.create_entity(etype, **kwargs) if commit: self.commit() return entity @@ -1114,7 +1122,6 @@ if not isinstance(rql, (tuple, list)): rql = ( (rql, kwargs), ) res = None - self.session.set_pool() for rql, kwargs in rql: if kwargs: msg = '%s (%s)' % (rql, kwargs) @@ -1122,7 +1129,7 @@ msg = rql if not ask_confirm or self.confirm('execute rql: %s ?' % msg): try: - res = self.session.execute(rql, kwargs, cachekey) + res = self._cw.execute(rql, kwargs, cachekey) except Exception, ex: if self.confirm('error: %s\nabort?' % ex): raise @@ -1211,9 +1218,8 @@ if self.ask_confirm: if not self._h.confirm('execute rql: %s ?' % msg): raise StopIteration - self._h.session.set_pool() try: - rset = self._h.session.execute(rql, kwargs) + rset = self._h._cw.execute(rql, kwargs) except Exception, ex: if self._h.confirm('error: %s\nabort?' % ex): raise diff -r 4b8d7838d74d -r a090324efefe server/utils.py --- a/server/utils.py Fri Oct 16 18:41:40 2009 +0200 +++ b/server/utils.py Fri Oct 16 18:44:28 2009 +0200 @@ -71,7 +71,8 @@ def manager_userpasswd(user=None, msg=DEFAULT_MSG, confirm=False, passwdmsg='password'): if not user: - print msg + if msg: + print msg while not user: user = raw_input('login: ') user = unicode(user, sys.stdin.encoding) diff -r 4b8d7838d74d -r a090324efefe web/views/primary.py --- a/web/views/primary.py Fri Oct 16 18:41:40 2009 +0200 +++ b/web/views/primary.py Fri Oct 16 18:44:28 2009 +0200 @@ -187,7 +187,8 @@ self.w(u'
') if showlabel: self.w(u'

%s

' % self.req._(dispctrl['label'])) - self.wview(dispctrl.get('vid', defaultvid), rset, dispctrl=dispctrl) + self.wview(dispctrl.get('vid', defaultvid), rset, + initargs={'dispctrl': dispctrl}) self.w(u'
') def _render_attribute(self, rschema, value, role='subject'): @@ -202,12 +203,14 @@ class RelatedView(EntityView): id = 'autolimited' - def call(self, dispctrl=None, **kwargs): + def call(self, **kwargs): # nb: rset retreived using entity.related with limit + 1 if any # because of that, we known that rset.printable_rql() will return # rql with no limit set anyway (since it's handled manually) - if dispctrl is not None: - limit = dispctrl.get('limit') + if 'dispctrl' in self.extra_kwargs: + limit = self.extra_kwargs['dispctrl'].get('limit') + else: + limit = None # if not too many entities, show them all in a list if limit is None or self.rset.rowcount <= limit: if self.rset.rowcount == 1: