--- 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
--- 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
--- 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.
<instance>
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': '<sources>',
- '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': '<host[:port]>',
+ '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):
--- 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__)
--- 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()
--- 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)
--- 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
--- 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)
--- 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'<div class="section">')
if showlabel:
self.w(u'<h4>%s</h4>' % 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'</div>')
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: