# copyright 2003-2011 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/>."""server.serverconfig definition"""__docformat__="restructuredtext en"importsysfromos.pathimportjoin,existsfromStringIOimportStringIOimportlogilab.common.configurationaslgconfigfromlogilab.common.decoratorsimportwproperty,cachedfromcubicweb.toolsutilsimportread_config,restrict_perms_to_userfromcubicweb.cwconfigimportCONFIGURATIONS,CubicWebConfiguration,merge_optionsfromcubicweb.serverimportSOURCE_TYPESUSER_OPTIONS=(('login',{'type':'string','default':'admin','help':"cubicweb manager account's login "'(this user will be created)','level':0,}),('password',{'type':'password','default':lgconfig.REQUIRED,'help':"cubicweb manager account's password",'level':0,}),)classSourceConfiguration(lgconfig.Configuration):def__init__(self,appconfig,options):self.appconfig=appconfig# has to be done before super callsuper(SourceConfiguration,self).__init__(options=options)# make Method('default_instance_id') usable in db option defs (in native.py)defdefault_instance_id(self):returnself.appconfig.appiddefinput_option(self,option,optdict,inputlevel):try:dbdriver=self['db-driver']exceptlgconfig.OptionError:passelse:ifdbdriver=='sqlite':ifoptionin('db-user','db-password'):returnifoption=='db-name':optdict=optdict.copy()optdict['help']='path to the sqlite database'optdict['default']=join(self.appconfig.appdatahome,self.appconfig.appid+'.sqlite')super(SourceConfiguration,self).input_option(option,optdict,inputlevel)defask_source_config(appconfig,type,inputlevel=0):options=SOURCE_TYPES[type].optionssconfig=SourceConfiguration(appconfig,options=options)sconfig.input_config(inputlevel=inputlevel)returnsconfigdefgenerate_source_config(sconfig,encoding=sys.stdin.encoding):"""serialize a repository source configuration as text"""stream=StringIO()optsbysect=list(sconfig.options_by_section())assertlen(optsbysect)==1,'all options for a source should be in the same group'lgconfig.ini_format(stream,optsbysect[0][1],encoding)returnstream.getvalue()classServerConfiguration(CubicWebConfiguration):"""standalone RQL server"""name='repository'cubicweb_appobject_path=CubicWebConfiguration.cubicweb_appobject_path|set(['sobjects','hooks'])cube_appobject_path=CubicWebConfiguration.cube_appobject_path|set(['sobjects','hooks'])options=merge_options((# ctl configuration('host',{'type':'string','default':None,'help':'host name if not correctly detectable through gethostname','group':'main','level':1,}),('pid-file',{'type':'string','default':lgconfig.Method('default_pid_file'),'help':'repository\'s pid file','group':'main','level':2,}),('uid',{'type':'string','default':None,'help':'if this option is set, use the specified user to start \the repository rather than the user running the command','group':'main','level':(CubicWebConfiguration.mode=='installed')and0or1,}),('cleanup-session-time',{'type':'time','default':'24h','help':'duration of inactivity after which a session ''will be closed, to limit memory consumption (avoid sessions that ''never expire and cause memory leak when http-session-time is 0, or ''because of bad client that never closes their connection). ''So notice that even if http-session-time is 0 and the user don\'t ''close his browser, he will have to reauthenticate after this time ''of inactivity. Default to 24h.','group':'main','level':3,}),('connections-pool-size',{'type':'int','default':4,'help':'size of the connections pool. Each source supporting multiple \connections will have this number of opened connections.','group':'main','level':3,}),('rql-cache-size',{'type':'int','default':300,'help':'size of the parsed rql cache size.','group':'main','level':3,}),('undo-support',{'type':'string','default':'','help':'string defining actions that will have undo support: \[C]reate [U]pdate [D]elete entities / [A]dd [R]emove relation. Leave it empty \for no undo support, set it to CUDAR for full undo support, or to DR for \support undoing of deletion only.','group':'main','level':3,}),('keep-transaction-lifetime',{'type':'int','default':7,'help':'number of days during which transaction records should be \kept (hence undoable).','group':'main','level':3,}),('multi-sources-etypes',{'type':'csv','default':(),'help':'defines which entity types from this repository are used \by some other instances. You should set this properly for these instances to \detect updates / deletions.','group':'main','level':3,}),('delay-full-text-indexation',{'type':'yn','default':False,'help':'When full text indexation of entity has a too important cost'' to be done when entity are added/modified by users, activate this ''option and setup a job using cubicweb-ctl db-rebuild-fti on your ''system (using cron for instance).','group':'main','level':3,}),# email configuration('default-recipients-mode',{'type':'choice','choices':('default-dest-addrs','users','none'),'default':'default-dest-addrs','help':'when a notification should be sent with no specific rules \to find recipients, recipients will be found according to this mode. Available \modes are "default-dest-addrs" (emails specified in the configuration \variable with the same name), "users" (every users which has activated \account with an email set), "none" (no notification).','group':'email','level':2,}),('default-dest-addrs',{'type':'csv','default':(),'help':'comma separated list of email addresses that will be used \as default recipient when an email is sent and the notification has no \specific recipient rules.','group':'email','level':2,}),('supervising-addrs',{'type':'csv','default':(),'help':'comma separated list of email addresses that will be \notified of every changes.','group':'email','level':2,}),# pyro server.serverconfig('pyro-host',{'type':'string','default':None,'help':'Pyro server host, if not detectable correctly through \gethostname(). It may contains port information using <host>:<port> notation, \and if not set, it will be choosen randomly','group':'pyro','level':3,}),)+CubicWebConfiguration.options)# should we init the connections pool (eg connect to sources). This is# usually necessary...init_cnxset_pool=True# read the schema from the databaseread_instance_schema=True# set this to true to get a minimal repository, for instance to get cubes# information on commands such as i18ninstance, db-restore, etc...quick_start=False# check user's state at login timeconsider_user_state=True# should some hooks be deactivated during [pre|post]create script executionfree_wheel=False# list of enables sources when sources restriction is necessary# (eg repository initialization at least)enabled_sources=Nonedefbootstrap_cubes(self):fromlogilab.common.textutilsimportsplitstripforlineinfile(join(self.apphome,'bootstrap_cubes')):line=line.strip()ifnotlineorline.startswith('#'):continueself.init_cubes(self.expand_cubes(splitstrip(line)))breakelse:# no cubesself.init_cubes(())defwrite_bootstrap_cubes_file(self,cubes):stream=file(join(self.apphome,'bootstrap_cubes'),'w')stream.write('# this is a generated file only used for bootstraping\n')stream.write('# you should not have to edit this\n')stream.write('%s\n'%','.join(cubes))stream.close()defsources_file(self):returnjoin(self.apphome,'sources')# this method has to be cached since when the server is running using a# restricted user, this user usually don't have access to the sources# configuration file (#16102)@cacheddefread_sources_file(self):returnread_config(self.sources_file(),raise_if_unreadable=True)defsources(self):"""return a dictionnaries containing sources definitions indexed by sources'uri """returnself.read_sources_file()defsource_enabled(self,source):ifself.sources_modeisnotNone:if'migration'inself.sources_mode:assertlen(self.sources_mode)==1ifsource.connect_for_migration:returnTrueprint'not connecting to source',source.uri,'during migration'returnFalseif'all'inself.sources_mode:assertlen(self.sources_mode)==1returnTruereturnsource.uriinself.sources_modeifself.quick_start:returnFalsereturn(notsource.disabledand(notself.enabled_sourcesorsource.uriinself.enabled_sources))defwrite_sources_file(self,sourcescfg):"""serialize repository'sources configuration into a INI like file"""sourcesfile=self.sources_file()ifexists(sourcesfile):importshutilshutil.copy(sourcesfile,sourcesfile+'.bak')stream=open(sourcesfile,'w')forsectionin('admin','system'):sconfig=sourcescfg[section]ifisinstance(sconfig,dict):# get a Configuration objectassertsection=='system'_sconfig=SourceConfiguration(self,options=SOURCE_TYPES['native'].options)forattr,valinsconfig.items():try:_sconfig.set_option(attr,val)exceptlgconfig.OptionError:# skip adapter, may be present on pre 3.10 instancesifattr!='adapter':self.error('skip unknown option %s in sources file')sconfig=_sconfigprint>>stream,'[%s]'%sectionprint>>stream,generate_source_config(sconfig)print>>streamrestrict_perms_to_user(sourcesfile)defpyro_enabled(self):"""pyro is always enabled in standalone repository configuration"""returnTruedefload_schema(self,expand_cubes=False,**kwargs):fromcubicweb.schemaimportCubicWebSchemaLoaderifexpand_cubes:# in case some new dependencies have been introduced, we have to# reinitialize cubes so the full filesystem schema is readorigcubes=self.cubes()self._cubes=Noneself.init_cubes(self.expand_cubes(origcubes))schema=CubicWebSchemaLoader().load(self,**kwargs)ifexpand_cubes:# restaure original valueself._cubes=origcubesreturnschemadefload_bootstrap_schema(self):fromcubicweb.schemaimportBootstrapSchemaLoaderschema=BootstrapSchemaLoader().load(self)schema.name='bootstrap'returnschemasources_mode=Nonedefset_sources_mode(self,sources):self.sources_mode=sourcesdefmigration_handler(self,schema=None,interactive=True,cnx=None,repo=None,connect=True,verbosity=None):"""return a migration handler instance"""fromcubicweb.server.migractionsimportServerMigrationHelperifverbosityisNone:verbosity=getattr(self,'verbosity',0)returnServerMigrationHelper(self,schema,interactive=interactive,cnx=cnx,repo=repo,connect=connect,verbosity=verbosity)CONFIGURATIONS.append(ServerConfiguration)