refactor login box & form to enable easy pluggability
* vregistry.selectable: get all selectable object of fixed oid with given context
* template headeri, logbox, logform: reorganize a bit the structure
# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr## This file is part of CubicWeb.## CubicWeb is free software: you can redistribute it and/or modify it under the# terms of the GNU Lesser General Public License as published by the Free# Software Foundation, either version 2.1 of the License, or (at your option)# any later version.## CubicWeb is distributed in the hope that it will be useful, but WITHOUT# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more# details.## You should have received a copy of the GNU Lesser General Public License along# with CubicWeb. If not, see <http://www.gnu.org/licenses/>."""cubicweb-ctl commands and command handlers specific to the repository"""__docformat__='restructuredtext en'# *ctl module should limit the number of import to be imported as quickly as# possible (for cubicweb-ctl reactivity, necessary for instance for usable bash# completion). So import locally in command helpers.importsysimportosfromlogilab.common.configurationimportConfigurationfromlogilab.common.shellutilsimportASKfromcubicwebimportAuthenticationError,ExecutionError,ConfigurationErrorfromcubicweb.toolsutilsimportCommand,CommandHandler,underline_titlefromcubicweb.cwctlimportCWCTLfromcubicweb.serverimportSOURCE_TYPESfromcubicweb.server.serverconfigimport(USER_OPTIONS,ServerConfiguration,SourceConfiguration)# utility functions ###########################################################defsource_cnx(source,dbname=None,special_privs=False,verbose=True):"""open and return a connection to the system database defined in the given server.serverconfig """fromgetpassimportgetpassfromlogilab.databaseimportget_connection,get_db_helperdbhost=source.get('db-host')ifdbnameisNone:dbname=source['db-name']driver=source['db-driver']dbhelper=get_db_helper(driver)ifverbose:print'-> connecting to %s database'%driver,ifdbhost:print'%s@%s'%(dbname,dbhost),else:printdbname,ifdbhelper.users_support:ifnotverboseor(notspecial_privsandsource.get('db-user')):user=source['db-user']ifverbose:print'as',userifsource.get('db-password'):password=source['db-password']else:password=getpass('password: ')else:printifspecial_privs:print'WARNING'print('the user will need the following special access rights ''on the database:')printspecial_privsprintdefault_user=source.get('db-user',os.environ.get('USER',''))user=raw_input('Connect as user ? [%r]: '%default_user)user=userordefault_userifuser==source.get('db-user')andsource.get('db-password'):password=source['db-password']else:password=getpass('password: ')else:user=password=Noneextra_args=source.get('db-extra-arguments')extra=extra_argsand{'extra_args':extra_args}or{}cnx=get_connection(driver,dbhost,dbname,user,password=password,port=source.get('db-port'),**extra)try:cnx.logged_user=userexceptAttributeError:# C object, __slots__fromlogilab.databaseimport_SimpleConnectionWrappercnx=_SimpleConnectionWrapper(cnx)cnx.logged_user=userreturncnxdefsystem_source_cnx(source,dbms_system_base=False,special_privs='CREATE/DROP DATABASE',verbose=True):"""shortcut to get a connextion to the instance system database defined in the given config. If <dbms_system_base> is True, connect to the dbms system database instead (for task such as create/drop the instance database) """ifdbms_system_base:fromlogilab.databaseimportget_db_helpersystem_db=get_db_helper(source['db-driver']).system_database()returnsource_cnx(source,system_db,special_privs=special_privs,verbose=verbose)returnsource_cnx(source,special_privs=special_privs,verbose=verbose)def_db_sys_cnx(source,what,db=None,user=None,verbose=True):"""return a connection on the RDMS system table (to create/drop a user or a database """importlogilab.commonaslgpfromlogilab.databaseimportget_db_helperlgp.USE_MX_DATETIME=Falsespecial_privs=''driver=source['db-driver']helper=get_db_helper(driver)ifuserisnotNoneandhelper.users_support:special_privs+='%s USER'%whatifdbisnotNone:special_privs+=' %s DATABASE'%what# connect on the dbms system base to create our basecnx=system_source_cnx(source,True,special_privs=special_privs,verbose=verbose)# disable autocommit (isolation_level(1)) because DROP and# CREATE DATABASE can't be executed in a transactiontry:cnx.set_isolation_level(0)exceptAttributeError:# set_isolation_level() is psycopg specificpassreturncnxdefrepo_cnx(config):"""return a in-memory repository and a db api connection it"""fromcubicweb.dbapiimportin_memory_cnxfromcubicweb.server.utilsimportmanager_userpasswdtry:login=config.sources()['admin']['login']pwd=config.sources()['admin']['password']exceptKeyError:login,pwd=manager_userpasswd()whileTrue:try:returnin_memory_cnx(config,login,password=pwd)exceptAuthenticationError:print'-> Error: wrong user/password.'# reset cubes else we'll have an assertion error on next retryconfig._cubes=Nonelogin,pwd=manager_userpasswd()# repository specific command handlers ########################################classRepositoryCreateHandler(CommandHandler):cmdname='create'cfgname='repository'defbootstrap(self,cubes,inputlevel=0):"""create an instance by copying files from the given cube and by asking information necessary to build required configuration files """fromcubicweb.server.utilsimportask_source_configconfig=self.configprintunderline_title('Configuring the repository')config.input_config('email',inputlevel)# ask for pyro configuration if pyro is activated and we're not using a# all-in-one config, in which case this is done by the web side command# handlerifconfig.pyro_enabled()andconfig.name!='all-in-one':config.input_config('pyro',inputlevel)print'\n'+underline_title('Configuring the sources')sourcesfile=config.sources_file()# XXX hack to make Method('default_instance_id') usable in db option# defs (in native.py)sconfig=SourceConfiguration(config,options=SOURCE_TYPES['native'].options)sconfig.adapter='native'sconfig.input_config(inputlevel=inputlevel)sourcescfg={'system':sconfig}forcubeincubes:# if a source is named as the cube containing it, we need the# source to use the cube, so add it.ifcubeinSOURCE_TYPES:sourcescfg[cube]=ask_source_config(cube,inputlevel)printwhileASK.confirm('Enter another source ?',default_is_yes=False):available=sorted(stypeforstypeinSOURCE_TYPESifnotstypeincubes)whileTrue:sourcetype=raw_input('source type (%s): '%', '.join(available))ifsourcetypeinavailable:breakprint'-> unknown source type, use one of the available types.'whileTrue:sourceuri=raw_input('source identifier (a unique name used to tell sources apart): ').strip()ifsourceuri!='admin'andsourceurinotinsourcescfg:breakprint'-> uri already used, choose another one.'sourcescfg[sourceuri]=ask_source_config(sourcetype,inputlevel)sourcemodule=SOURCE_TYPES[sourcetype].moduleifnotsourcemodule.startswith('cubicweb.'):# module names look like cubes.mycube.themodulesourcecube=SOURCE_TYPES[sourcetype].module.split('.',2)[1]# if the source adapter is coming from an external component,# ensure it's specified in used cubesifnotsourcecubeincubes:cubes.append(sourcecube)sconfig=Configuration(options=USER_OPTIONS)sconfig.input_config(inputlevel=inputlevel)sourcescfg['admin']=sconfigconfig.write_sources_file(sourcescfg)# remember selected cubes for later initialization of the databaseconfig.write_bootstrap_cubes_file(cubes)defpostcreate(self):ifASK.confirm('Run db-create to create the system database ?'):verbosity=(self.config.mode=='installed')and'y'or'n'CWCTL.run(['db-create',self.config.appid,'--verbose=%s'%verbosity])else:print('-> nevermind, you can do it later with ''"cubicweb-ctl db-create %s".'%self.config.appid)classRepositoryDeleteHandler(CommandHandler):cmdname='delete'cfgname='repository'defcleanup(self):"""remove instance's configuration and database"""fromlogilab.databaseimportget_db_helpersource=self.config.sources()['system']dbname=source['db-name']helper=get_db_helper(source['db-driver'])ifASK.confirm('Delete database %s ?'%dbname):ifsource['db-driver']=='sqlite':os.unlink(source['db-name'])returnuser=source['db-user']orNonecnx=_db_sys_cnx(source,'DROP DATABASE',user=user)cursor=cnx.cursor()try:cursor.execute('DROP DATABASE %s'%dbname)print'-> database %s dropped.'%dbname# XXX should check we are not connected as userifuserandhelper.users_supportand \ASK.confirm('Delete user %s ?'%user,default_is_yes=False):cursor.execute('DROP USER %s'%user)print'-> user %s dropped.'%usercnx.commit()except:cnx.rollback()raiseclassRepositoryStartHandler(CommandHandler):cmdname='start'cfgname='repository'defstart_server(self,config):command=['cubicweb-ctl start-repository ']ifconfig.debugmode:command.append('--debug')command.append('--loglevel %s'%config['log-threshold'].lower())command.append(config.appid)os.system(' '.join(command))classRepositoryStopHandler(CommandHandler):cmdname='stop'cfgname='repository'defpoststop(self):"""if pyro is enabled, ensure the repository is correctly unregistered """ifself.config.pyro_enabled():fromcubicweb.server.repositoryimportpyro_unregisterpyro_unregister(self.config)# repository specific commands ################################################defcreatedb(helper,source,dbcnx,cursor,**kwargs):ifdbcnx.logged_user!=source['db-user']:helper.create_database(cursor,source['db-name'],source['db-user'],source['db-encoding'],**kwargs)else:helper.create_database(cursor,source['db-name'],dbencoding=source['db-encoding'],**kwargs)classCreateInstanceDBCommand(Command):"""Create the system database of an instance (run after 'create'). You will be prompted for a login / password to use to connect to the system database. The given user should have almost all rights on the database (ie a super user on the dbms allowed to create database, users, languages...). <instance> the identifier of the instance to initialize. """name='db-create'arguments='<instance>'min_args=max_args=1options=(('create-db',{'short':'c','type':'yn','metavar':'<y or n>','default':True,'help':'create the database (yes by default)'}),('verbose',{'short':'v','type':'yn','metavar':'<verbose>','default':'n','help':'verbose mode: will ask all possible configuration questions',}),('automatic',{'short':'a','type':'yn','metavar':'<auto>','default':'n','help':'automatic mode: never ask and use default answer to every question',}),)defrun(self,args):"""run the command with its specific arguments"""fromlogilab.databaseimportget_db_helperverbose=self.get('verbose')automatic=self.get('automatic')appid=args.pop()config=ServerConfiguration.config_for(appid)source=config.sources()['system']dbname=source['db-name']driver=source['db-driver']helper=get_db_helper(driver)ifdriver=='sqlite':ifos.path.exists(dbname)and(automaticorASK.confirm('Database %s already exists. Drop it?'%dbname)):os.unlink(dbname)elifself.config.create_db:print'\n'+underline_title('Creating the system database')# connect on the dbms system base to create our basedbcnx=_db_sys_cnx(source,'CREATE DATABASE and / or USER',verbose=verbose)cursor=dbcnx.cursor()try:ifhelper.users_support:user=source['db-user']ifnothelper.user_exists(cursor,user)and(automaticor \ASK.confirm('Create db user %s ?'%user,default_is_yes=False)):helper.create_user(source['db-user'],source['db-password'])print'-> user %s created.'%userifdbnameinhelper.list_databases(cursor):ifautomaticorASK.confirm('Database %s already exists -- do you want to drop it ?'%dbname):cursor.execute('DROP DATABASE %s'%dbname)else:returncreatedb(helper,source,dbcnx,cursor)dbcnx.commit()print'-> database %s created.'%dbnameexcept:dbcnx.rollback()raisecnx=system_source_cnx(source,special_privs='LANGUAGE C',verbose=verbose)cursor=cnx.cursor()helper.init_fti_extensions(cursor)# postgres specific stuffifdriver=='postgres':# install plpythonu/plpgsql language if not installed by the cubelangs=sys.platform=='win32'and('plpgsql',)or('plpythonu','plpgsql')forextlanginlangs:helper.create_language(cursor,extlang)cursor.close()cnx.commit()print'-> database for instance %s created and necessary extensions installed.'%appidprintifautomaticorASK.confirm('Run db-init to initialize the system database ?'):CWCTL.run(['db-init',config.appid])else:print('-> nevermind, you can do it later with ''"cubicweb-ctl db-init %s".'%config.appid)classInitInstanceCommand(Command):"""Initialize the system database of an instance (run after 'db-create'). You will be prompted for a login / password to use to connect to the system database. The given user should have the create tables, and grant permissions. <instance> the identifier of the instance to initialize. """name='db-init'arguments='<instance>'min_args=max_args=1options=(('drop',{'short':'d','action':'store_true','default':False,'help':'insert drop statements to remove previously existant \tables, indexes... (no by default)'}),)defrun(self,args):print'\n'+underline_title('Initializing the system database')fromcubicweb.serverimportinit_repositoryfromlogilab.databaseimportget_connectionappid=args[0]config=ServerConfiguration.config_for(appid)try:system=config.sources()['system']extra_args=system.get('db-extra-arguments')extra=extra_argsand{'extra_args':extra_args}or{}get_connection(system['db-driver'],database=system['db-name'],host=system.get('db-host'),port=system.get('db-port'),user=system.get('db-user'),password=system.get('db-password'),**extra)exceptException,ex:raiseConfigurationError('You seem to have provided wrong connection information in '\'the %s file. Resolve this first (error: %s).'%(config.sources_file(),str(ex).strip()))init_repository(config,drop=self.config.drop)classGrantUserOnInstanceCommand(Command):"""Grant a database user on a repository system database. <instance> the identifier of the instance <user> the database's user requiring grant access """name='db-grant-user'arguments='<instance> <user>'min_args=max_args=2options=(('set-owner',{'short':'o','type':'yn','metavar':'<yes or no>','default':False,'help':'Set the user as tables owner if yes (no by default).'}),)defrun(self,args):"""run the command with its specific arguments"""fromcubicweb.server.sqlutilsimportsqlexec,sqlgrantsappid,user=argsconfig=ServerConfiguration.config_for(appid)source=config.sources()['system']set_owner=self.config.set_ownercnx=system_source_cnx(source,special_privs='GRANT')cursor=cnx.cursor()schema=config.load_schema()try:sqlexec(sqlgrants(schema,source['db-driver'],user,set_owner=set_owner),cursor)exceptException,ex:cnx.rollback()importtracebacktraceback.print_exc()print'-> an error occurred:',exelse:cnx.commit()print'-> rights granted to %s on instance %s.'%(appid,user)classResetAdminPasswordCommand(Command):"""Reset the administrator password. <instance> the identifier of the instance """name='reset-admin-pwd'arguments='<instance>'defrun(self,args):"""run the command with its specific arguments"""fromcubicweb.server.utilsimportcrypt_password,manager_userpasswdappid=args[0]config=ServerConfiguration.config_for(appid)sourcescfg=config.read_sources_file()try:adminlogin=sourcescfg['admin']['login']exceptKeyError:print'-> Error: could not get cubicweb administrator login.'sys.exit(1)cnx=source_cnx(sourcescfg['system'])driver=sourcescfg['system']['db-driver']fromlogilab.databaseimportget_db_helperdbhelper=get_db_helper(driver)cursor=cnx.cursor()# check admin existscursor.execute("SELECT * FROM cw_CWUser WHERE cw_login=%(l)s",{'l':adminlogin})ifnotcursor.fetchall():print("-> error: admin user %r specified in sources doesn't exist ""in the database"%adminlogin)print" fix your sources file before running this command"cnx.close()sys.exit(1)# ask for a new password_,passwd=manager_userpasswd(adminlogin,confirm=True,passwdmsg='new password for %s'%adminlogin)try:cursor.execute("UPDATE cw_CWUser SET cw_upassword=%(p)s WHERE cw_login=%(l)s",{'p':dbhelper.binary_value(crypt_password(passwd)),'l':adminlogin})sconfig=Configuration(options=USER_OPTIONS)sconfig['login']=adminloginsconfig['password']=passwdsourcescfg['admin']=sconfigconfig.write_sources_file(sourcescfg)exceptException,ex:cnx.rollback()importtracebacktraceback.print_exc()print'-> an error occurred:',exelse:cnx.commit()print'-> password reset, sources file regenerated.'cnx.close()classStartRepositoryCommand(Command):"""Start an CubicWeb RQL server for a given instance. The server will be accessible through pyro <instance> the identifier of the instance to initialize. """name='start-repository'arguments='<instance>'min_args=max_args=1options=(('debug',{'short':'D','action':'store_true','help':'start server in debug mode.'}),('loglevel',{'short':'l','type':'choice','metavar':'<log level>','default':None,'choices':('debug','info','warning','error'),'help':'debug if -D is set, error otherwise',}),)defrun(self,args):fromlogilab.common.daemonimportdaemonizefromcubicweb.cwctlimportinit_cmdline_log_thresholdfromcubicweb.server.serverimportRepositoryServerappid=args[0]debug=self['debug']ifsys.platform=='win32'andnotdebug:fromloggingimportgetLoggerlogger=getLogger('cubicweb.ctl')logger.info('Forcing debug mode on win32 platform')debug=Trueconfig=ServerConfiguration.config_for(appid,debugmode=debug)init_cmdline_log_threshold(config,self['loglevel'])# create the serverserver=RepositoryServer(config)# ensure the directory where the pid-file should be set exists (for# instance /var/run/cubicweb may be deleted on computer restart)pidfile=config['pid-file']piddir=os.path.dirname(pidfile)# go ! (don't daemonize in debug mode)ifnotos.path.exists(piddir):os.makedirs(piddir)ifnotdebuganddaemonize(pidfile):returnuid=config['uid']ifuidisnotNone:try:uid=int(uid)exceptValueError:frompwdimportgetpwnamuid=getpwnam(uid).pw_uidos.setuid(uid)server.install_sig_handlers()server.connect(config['host'],0)server.run()def_remote_dump(host,appid,output,sudo=False):# XXX generate unique/portable file namefromdatetimeimportdatefilename='%s-%s.tgz'%(appid,date.today().strftime('%Y-%m-%d'))dmpcmd='cubicweb-ctl db-dump -o /tmp/%s%s'%(filename,appid)ifsudo:dmpcmd='sudo %s'%(dmpcmd)dmpcmd='ssh -t %s "%s"'%(host,dmpcmd)printdmpcmdifos.system(dmpcmd):raiseExecutionError('Error while dumping the database')ifoutputisNone:output=filenamecmd='scp %s:/tmp/%s%s'%(host,filename,output)printcmdifos.system(cmd):raiseExecutionError('Error while retrieving the dump at /tmp/%s'%filename)rmcmd='ssh -t %s "rm -f /tmp/%s"'%(host,filename)printrmcmdifos.system(rmcmd)andnotASK.confirm('An error occurred while deleting remote dump at /tmp/%s. ''Continue anyway?'%filename):raiseExecutionError('Error while deleting remote dump at /tmp/%s'%filename)def_local_dump(appid,output):config=ServerConfiguration.config_for(appid)config.quick_start=Truemih=config.migration_handler(connect=False,verbosity=1)mih.backup_database(output,askconfirm=False)mih.shutdown()def_local_restore(appid,backupfile,drop,systemonly=True):config=ServerConfiguration.config_for(appid)config.verbosity=1# else we won't be asked for confirmation on problemsconfig.quick_start=Truemih=config.migration_handler(connect=False,verbosity=1)mih.restore_database(backupfile,drop,systemonly,askconfirm=False)repo=mih.repo_connect()# version of the databasedbversions=repo.get_versions()mih.shutdown()ifnotdbversions:print"bad or missing version information in the database, don't upgrade file system"return# version of installed softwareeversion=dbversions['cubicweb']status=instance_status(config,eversion,dbversions)# * database version > installed softwareifstatus=='needsoftupgrade':print"** The database of %s is more recent than the installed software!"%config.appidprint"** Upgrade your software, then migrate the database by running the command"print"** 'cubicweb-ctl upgrade %s'"%config.appidreturn# * database version < installed software, an upgrade will be necessary# anyway, just rewrite vc.conf and warn user he has to upgradeelifstatus=='needapplupgrade':print"** The database of %s is older than the installed software."%config.appidprint"** Migrate the database by running the command"print"** 'cubicweb-ctl upgrade %s'"%config.appidreturn# * database version = installed software, database version = instance fs version# ok!definstance_status(config,cubicwebapplversion,vcconf):cubicwebversion=config.cubicweb_version()ifcubicwebapplversion>cubicwebversion:return'needsoftupgrade'ifcubicwebapplversion<cubicwebversion:return'needapplupgrade'forcubeinconfig.cubes():try:softversion=config.cube_version(cube)exceptConfigurationError:print'-> Error: no cube version information for %s, please check that the cube is installed.'%cubecontinuetry:applversion=vcconf[cube]exceptKeyError:print'-> Error: no cube version information for %s in version configuration.'%cubecontinueifsoftversion==applversion:continueifsoftversion>applversion:return'needsoftupgrade'elifsoftversion<applversion:return'needapplupgrade'returnNoneclassDBDumpCommand(Command):"""Backup the system database of an instance. <instance> the identifier of the instance to backup format [[user@]host:]appname """name='db-dump'arguments='<instance>'min_args=max_args=1options=(('output',{'short':'o','type':'string','metavar':'<file>','default':None,'help':'Specify the backup file where the backup will be stored.'}),('sudo',{'short':'s','action':'store_true','default':False,'help':'Use sudo on the remote host.'}),)defrun(self,args):appid=args[0]if':'inappid:host,appid=appid.split(':')_remote_dump(host,appid,self.config.output,self.config.sudo)else:_local_dump(appid,self.config.output)classDBRestoreCommand(Command):"""Restore the system database of an instance. <instance> the identifier of the instance to restore """name='db-restore'arguments='<instance> <backupfile>'min_args=max_args=2options=(('no-drop',{'short':'n','action':'store_true','default':False,'help':'for some reason the database doesn\'t exist and so ''should not be dropped.'}),('restore-all',{'short':'r','action':'store_true','default':False,'help':'restore everything, eg not only the system source database ''but also data for all sources supporting backup/restore and custom ''instance data. In that case, <backupfile> is expected to be the ''timestamp of the backup to restore, not a file'}),)defrun(self,args):appid,backupfile=args_local_restore(appid,backupfile,drop=notself.config.no_drop,systemonly=notself.config.restore_all)classDBCopyCommand(Command):"""Copy the system database of an instance (backup and restore). <src-instance> the identifier of the instance to backup format [[user@]host:]appname <dest-instance> the identifier of the instance to restore """name='db-copy'arguments='<src-instance> <dest-instance>'min_args=max_args=2options=(('no-drop',{'short':'n','action':'store_true','default':False,'help':'For some reason the database doesn\'t exist and so ''should not be dropped.'}),('keep-dump',{'short':'k','action':'store_true','default':False,'help':'Specify that the dump file should not be automatically removed.'}),('sudo',{'short':'s','action':'store_true','default':False,'help':'Use sudo on the remote host.'}),)defrun(self,args):importtempfilesrcappid,destappid=argsfd,output=tempfile.mkstemp()os.close(fd)if':'insrcappid:host,srcappid=srcappid.split(':')_remote_dump(host,srcappid,output,self.config.sudo)else:_local_dump(srcappid,output)_local_restore(destappid,output,notself.config.no_drop)ifself.config.keep_dump:print'-> you can get the dump file at',outputelse:os.remove(output)classCheckRepositoryCommand(Command):"""Check integrity of the system database of an instance. <instance> the identifier of the instance to check """name='db-check'arguments='<instance>'min_args=max_args=1options=(('checks',{'short':'c','type':'csv','metavar':'<check list>','default':('entities','relations','metadata','schema','text_index'),'help':'Comma separated list of check to run. By default run all \checks, i.e. entities, relations, text_index and metadata.'}),('autofix',{'short':'a','type':'yn','metavar':'<yes or no>','default':False,'help':'Automatically correct integrity problems if this option \is set to "y" or "yes", else only display them'}),('reindex',{'short':'r','type':'yn','metavar':'<yes or no>','default':False,'help':'re-indexes the database for full text search if this \option is set to "y" or "yes" (may be long for large database).'}),('force',{'short':'f','action':'store_true','default':False,'help':'don\'t check instance is up to date.'}),)defrun(self,args):fromcubicweb.server.checkintegrityimportcheckappid=args[0]config=ServerConfiguration.config_for(appid)config.repairing=self.config.forcerepo,cnx=repo_cnx(config)check(repo,cnx,self.config.checks,self.config.reindex,self.config.autofix)classRebuildFTICommand(Command):"""Rebuild the full-text index of the system database of an instance. <instance> the identifier of the instance to rebuild """name='db-rebuild-fti'arguments='<instance>'min_args=max_args=1defrun(self,args):fromcubicweb.server.checkintegrityimportreindex_entitiesappid=args[0]config=ServerConfiguration.config_for(appid)repo,cnx=repo_cnx(config)session=repo._get_session(cnx.sessionid,setpool=True)reindex_entities(repo.schema,session)cnx.commit()classSynchronizeInstanceSchemaCommand(Command):"""Synchronize persistent schema with cube schema. Will synchronize common stuff between the cube schema and the actual persistent schema, but will not add/remove any entity or relation. <instance> the identifier of the instance to synchronize. """name='schema-sync'arguments='<instance>'min_args=max_args=1defrun(self,args):appid=args[0]config=ServerConfiguration.config_for(appid)mih=config.migration_handler()mih.cmd_synchronize_schema()classCheckMappingCommand(Command):"""Check content of the mapping file of an external source. The mapping is checked against the instance's schema, searching for inconsistencies or stuff you may have forgotten. It's higly recommanded to run it when you setup a multi-sources instance. <instance> the identifier of the instance. <mapping file> the mapping file to check. """name='check-mapping'arguments='<instance> <mapping file>'min_args=max_args=2defrun(self,args):fromcubicweb.server.checkintegrityimportcheck_mappingfromcubicweb.server.sources.pyrorqlimportload_mapping_fileappid,mappingfile=argsconfig=ServerConfiguration.config_for(appid)config.quick_start=Truemih=config.migration_handler(connect=False,verbosity=1)repo=mih.repo_connect()# necessary to get cubescheck_mapping(config.load_schema(),load_mapping_file(mappingfile))forcmdclassin(CreateInstanceDBCommand,InitInstanceCommand,GrantUserOnInstanceCommand,ResetAdminPasswordCommand,StartRepositoryCommand,DBDumpCommand,DBRestoreCommand,DBCopyCommand,CheckRepositoryCommand,RebuildFTICommand,SynchronizeInstanceSchemaCommand,CheckMappingCommand,):CWCTL.register(cmdclass)