"""server.serverconfig definition:organization: Logilab:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses"""__docformat__="restructuredtext en"importosfromos.pathimportjoin,existsfromlogilab.common.configurationimportREQUIRED,Method,Configuration, \ini_format_sectionfromlogilab.common.decoratorsimportwproperty,cached,clear_cachefromcubicwebimportCW_SOFTWARE_ROOT,RegistryNotFoundfromcubicweb.toolsutilsimportenv_path,read_config,restrict_perms_to_userfromcubicweb.cwconfigimportCubicWebConfiguration,merge_optionsfromcubicweb.serverimportSOURCE_TYPESUSER_OPTIONS=(('login',{'type':'string','default':REQUIRED,'help':"cubicweb manager account's login "'(this user will be created)','inputlevel':0,}),('password',{'type':'password','help':"cubicweb manager account's password",'inputlevel':0,}),)defgenerate_sources_file(sourcesfile,sourcescfg,keys=None):"""serialize repository'sources configuration into a INI like file the `keys` parameter may be used to sort sections """ifkeysisNone:keys=sourcescfg.keys()else:forkeyinsourcescfg:ifnotkeyinkeys:keys.append(key)stream=open(sourcesfile,'w')foruriinkeys:sconfig=sourcescfg[uri]ifisinstance(sconfig,dict):# get a Configuration objectifuri=='admin':options=USER_OPTIONSelse:options=SOURCE_TYPES[sconfig['adapter']].options_sconfig=Configuration(options=options)forattr,valinsconfig.items():ifattr=='uri':continueifattr=='adapter':_sconfig.adapter=valelse:_sconfig.set_option(attr,val)sconfig=_sconfigoptsbysect=list(sconfig.options_by_section())assertlen(optsbysect)==1,'all options for a source should be in the same group'ini_format_section(stream,uri,optsbysect[0][1])ifhasattr(sconfig,'adapter'):print>>streamprint>>stream,'# adapter for this source (YOU SHOULD NOT CHANGE THIS)'print>>stream,'adapter=%s'%sconfig.adapterprint>>streamclassServerConfiguration(CubicWebConfiguration):"""standalone RQL server"""name='repository'ifos.environ.get('APYCOT_ROOT'):root=os.environ['APYCOT_ROOT']SCHEMAS_LIB_DIR='%s/local/share/cubicweb/schemas/'%rootelifCubicWebConfiguration.mode=='dev':SCHEMAS_LIB_DIR=join(CW_SOFTWARE_ROOT,'schemas')BACKUP_DIR=CubicWebConfiguration.RUNTIME_DIRelse:SCHEMAS_LIB_DIR='/usr/share/cubicweb/schemas/'BACKUP_DIR='/var/lib/cubicweb/backup/'cubicweb_vobject_path=CubicWebConfiguration.cubicweb_vobject_path|set(['sobjects'])cube_vobject_path=CubicWebConfiguration.cube_vobject_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','inputlevel':1,}),('pid-file',{'type':'string','default':Method('default_pid_file'),'help':'repository\'s pid file','group':'main','inputlevel':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','inputlevel':(CubicWebConfiguration.mode=='installed')and0or1,}),('session-time',{'type':'int','default':30*60,'help':'session expiration time, default to 30 minutes','group':'main','inputlevel':1,}),('connections-pool-size',{'type':'int','default':4,'help':'size of the connections pools. Each source supporting multiple \connections will have this number of opened connections.','group':'main','inputlevel':1,}),('rql-cache-size',{'type':'int','default':300,'help':'size of the parsed rql cache size.','group':'main','inputlevel':1,}),('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','inputlevel':1,}),# 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','inputlevel':1,}),('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','inputlevel':1,}),('supervising-addrs',{'type':'csv','default':(),'help':'comma separated list of email addresses that will be \notified of every changes.','group':'email','inputlevel':2,}),# pyro server.serverconfig('pyro-port',{'type':'int','default':None,'help':'Pyro server port. If not set, it will be choosen randomly','group':'pyro-server','inputlevel':2,}),('pyro-id',# XXX reuse pyro-application-id{'type':'string','default':None,'help':'identifier of the repository in the pyro name server','group':'pyro-server','inputlevel':2,}),)+CubicWebConfiguration.options)# read the schema from the databaseread_application_schema=Truebootstrap_schema=True# check user's state at login timeconsider_user_state=True# hooks registration configuration# all hooks should be activated during normal executioncore_hooks=Trueusergroup_hooks=Trueschema_hooks=Truenotification_hooks=Truesecurity_hooks=Trueapplication_hooks=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=None@wpropertydefenabled_sources(self,sourceuris=None):self._enabled_sources=sourceurisclear_cache(self,'sources')@classmethoddefschemas_lib_dir(cls):"""application schema directory"""returnenv_path('CW_SCHEMA_LIB',cls.SCHEMAS_LIB_DIR,'schemas')@classmethoddefbackup_dir(cls):"""backup directory where a stored db backups before migration"""returnenv_path('CW_BACKUP',cls.BACKUP_DIR,'run time')defbootstrap_cubes(self):fromlogilab.common.textutilsimportget_csvforlineinfile(join(self.apphome,'bootstrap_cubes')):line=line.strip()ifnotlineorline.startswith('#'):continueself.init_cubes(self.expand_cubes(get_csv(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())defsources(self):"""return a dictionnaries containing sources definitions indexed by sources'uri """allsources=self.read_sources_file()ifself._enabled_sourcesisNone:returnallsourcesreturndict((uri,config)foruri,configinallsources.items()ifuriinself._enabled_sourcesoruri=='admin')defwrite_sources_file(self,sourcescfg):sourcesfile=self.sources_file()ifexists(sourcesfile):importshutilshutil.copy(sourcesfile,sourcesfile+'.bak')generate_sources_file(sourcesfile,sourcescfg,['admin','system'])restrict_perms_to_user(sourcesfile)defpyro_enabled(self):"""pyro is always enabled in standalone repository configuration"""returnTruedefload_hooks(self,vreg):hooks={}forpathinreversed([self.apphome]+self.cubes_path()):hooksfile=join(path,'application_hooks.py')ifexists(hooksfile):self.warning('application_hooks.py is deprecated, use dynamic ''objects to register hooks (%s)',hooksfile)context={}# Use execfile rather than `load_module_from_name` because# the latter gets fooled by the `sys.modules` cache when# loading different configurations one after the other# (another fix would have been to do :# sys.modules.pop('applications_hooks')# or to modify load_module_from_name so that it provides# a use_cache optional parameterexecfile(hooksfile,context,context)forevent,hooksdefincontext['HOOKS'].items():forertype,hookcbsinhooksdef.items():hooks.setdefault(event,{}).setdefault(ertype,[]).extend(hookcbs)try:apphookdefs=vreg.registry_objects('hooks')exceptRegistryNotFound:returnhooksforhookdefinapphookdefs:forevent,ertypeinhookdef.register_to():ifertype=='Any':ertype=''cb=hookdef.make_callback(event)hooks.setdefault(event,{}).setdefault(ertype,[]).append(cb)returnhooksdefload_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'returnschemadefset_sources_mode(self,sources):if'migration'insources:fromcubicweb.server.sourcesimportsource_adapterassertlen(sources)==1enabled_sources=[]foruri,configinself.sources().iteritems():ifuri=='admin':continueifsource_adapter(config).connect_for_migration:enabled_sources.append(uri)else:print'not connecting to source',uri,'during migration'elif'all'insources:assertlen(sources)==1enabled_sources=Noneelse:known_sources=self.sources()foruriinsources:asserturiinknown_sources,urienabled_sources=sourcesself._enabled_sources=enabled_sourcesclear_cache(self,'sources')defmigration_handler(self,schema=None,interactive=True,cnx=None,repo=None,connect=True):"""return a migration handler instance"""fromcubicweb.server.migractionsimportServerMigrationHelperreturnServerMigrationHelper(self,schema,interactive=interactive,cnx=cnx,repo=repo,connect=connect,verbosity=getattr(self,'verbosity',0))