1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
6 # Copyright (C) 2010-2012 OpenERP s.a. (<http://openerp.com>).
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU Affero General Public License as
10 # published by the Free Software Foundation, either version 3 of the
11 # License, or (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU Affero General Public License for more details.
18 # You should have received a copy of the GNU Affero General Public License
19 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 ##############################################################################
29 import openerp.loglevels as loglevels
31 import openerp.release as release
33 class MyOption (optparse.Option, object):
34 """ optparse Option with two additional attributes.
36 The list of command line options (getopt.Option) is used to create the
37 list of the configuration file options. When reading the file, and then
38 reading the command line arguments, we don't want optparse.parse results
39 to override the configuration file values. But if we provide default
40 values to optparse, optparse will return them and we can't know if they
41 were really provided by the user or not. A solution is to not use
42 optparse's default attribute, but use a custom one (that will be copied
43 to create the default values of the configuration file).
46 def __init__(self, *opts, **attrs):
47 self.my_default = attrs.pop('my_default', None)
48 super(MyOption, self).__init__(*opts, **attrs)
50 #.apidoc title: Server Configuration Loader
54 from OpenSSL import SSL
57 return hasattr(socket, 'ssl') and hasattr(SSL, "Connection")
61 class configmanager(object):
62 def __init__(self, fname=None):
63 # Options not exposed on the command line. Command line options will be added
64 # from optparse's parser.
66 'admin_passwd': 'admin',
67 'csv_internal_sep': ',',
68 'login_message': False,
69 'publisher_warranty_url': 'http://services.openerp.com/publisher-warranty/',
74 # Not exposed in the configuration file.
75 self.blacklist_for_save = set(
76 ['publisher_warranty_url', 'load_language', 'root_path',
77 'init', 'save', 'config', 'update', 'stop_after_init'])
79 # dictionary mapping option destination (keys in self.options) to MyOptions.
83 self.config_file = fname
84 self.has_ssl = check_ssl()
86 self._LOGLEVELS = dict([(getattr(loglevels, 'LOG_%s' % x), getattr(logging, x)) for x in ('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'TEST', 'DEBUG', 'NOTSET')])
88 version = "%s %s" % (release.description, release.version)
89 self.parser = parser = optparse.OptionParser(version=version, option_class=MyOption)
91 # Server startup config
92 group = optparse.OptionGroup(parser, "Common options")
93 group.add_option("-c", "--config", dest="config", help="specify alternate config file")
94 group.add_option("-s", "--save", action="store_true", dest="save", default=False,
95 help="save configuration to ~/.openerp_serverrc")
96 group.add_option("-i", "--init", dest="init", help="install one or more modules (comma-separated list, use \"all\" for all modules), requires -d")
97 group.add_option("-u", "--update", dest="update",
98 help="update one or more modules (comma-separated list, use \"all\" for all modules). Requires -d.")
99 group.add_option("--without-demo", dest="without_demo",
100 help="disable loading demo data for modules to be installed (comma-separated, use \"all\" for all modules). Requires -d and -i. Default is %default",
102 group.add_option("-P", "--import-partial", dest="import_partial", my_default='',
103 help="Use this for big data importation, if it crashes you will be able to continue at the current state. Provide a filename to store intermediate importation states.")
104 group.add_option("--pidfile", dest="pidfile", help="file where the server pid will be stored")
105 group.add_option("--addons-path", dest="addons_path",
106 help="specify additional addons paths (separated by commas).",
107 action="callback", callback=self._check_addons_path, nargs=1, type="string")
108 group.add_option("--load", dest="server_wide_modules", help="Comma-separated list of server-wide modules default=web")
109 parser.add_option_group(group)
112 group = optparse.OptionGroup(parser, "XML-RPC Configuration")
113 group.add_option("--xmlrpc-interface", dest="xmlrpc_interface", my_default='',
114 help="Specify the TCP IP address for the XML-RPC protocol. The empty string binds to all interfaces.")
115 group.add_option("--xmlrpc-port", dest="xmlrpc_port", my_default=8069,
116 help="specify the TCP port for the XML-RPC protocol", type="int")
117 group.add_option("--no-xmlrpc", dest="xmlrpc", action="store_false", my_default=True,
118 help="disable the XML-RPC protocol")
119 group.add_option("--proxy-mode", dest="proxy_mode", action="store_true", my_default=False,
120 help="Enable correct behavior when behind a reverse proxy")
121 parser.add_option_group(group)
124 title = "XML-RPC Secure Configuration"
126 title += " (disabled as ssl is unavailable)"
128 group = optparse.OptionGroup(parser, title)
129 group.add_option("--xmlrpcs-interface", dest="xmlrpcs_interface", my_default='',
130 help="Specify the TCP IP address for the XML-RPC Secure protocol. The empty string binds to all interfaces.")
131 group.add_option("--xmlrpcs-port", dest="xmlrpcs_port", my_default=8071,
132 help="specify the TCP port for the XML-RPC Secure protocol", type="int")
133 group.add_option("--no-xmlrpcs", dest="xmlrpcs", action="store_false", my_default=True,
134 help="disable the XML-RPC Secure protocol")
135 group.add_option("--cert-file", dest="secure_cert_file", my_default='server.cert',
136 help="specify the certificate file for the SSL connection")
137 group.add_option("--pkey-file", dest="secure_pkey_file", my_default='server.pkey',
138 help="specify the private key file for the SSL connection")
139 parser.add_option_group(group)
142 group = optparse.OptionGroup(parser, "NET-RPC Configuration")
143 group.add_option("--netrpc-interface", dest="netrpc_interface", my_default='',
144 help="specify the TCP IP address for the NETRPC protocol")
145 group.add_option("--netrpc-port", dest="netrpc_port", my_default=8070,
146 help="specify the TCP port for the NETRPC protocol", type="int")
147 group.add_option("--no-netrpc", dest="netrpc", action="store_false", my_default=True,
148 help="disable the NETRPC protocol")
149 parser.add_option_group(group)
152 # TODO move to web addons after MetaOption merge
153 group = optparse.OptionGroup(parser, "Web interface Configuration")
154 group.add_option("--db-filter", dest="dbfilter", default='.*',
155 help="Filter listed database", metavar="REGEXP")
156 parser.add_option_group(group)
159 group = optparse.OptionGroup(parser, "Static HTTP service")
160 group.add_option("--static-http-enable", dest="static_http_enable", action="store_true", my_default=False, help="enable static HTTP service for serving plain HTML files")
161 group.add_option("--static-http-document-root", dest="static_http_document_root", help="specify the directory containing your static HTML files (e.g '/var/www/')")
162 group.add_option("--static-http-url-prefix", dest="static_http_url_prefix", help="specify the URL root prefix where you want web browsers to access your static HTML files (e.g '/')")
163 parser.add_option_group(group)
166 group = optparse.OptionGroup(parser, "Testing Configuration")
167 group.add_option("--test-file", dest="test_file", my_default=False,
168 help="Launch a YML test file.")
169 group.add_option("--test-report-directory", dest="test_report_directory", my_default=False,
170 help="If set, will save sample of all reports in this directory.")
171 group.add_option("--test-enable", action="store_true", dest="test_enable",
172 my_default=False, help="Enable YAML and unit tests.")
173 group.add_option("--test-commit", action="store_true", dest="test_commit",
174 my_default=False, help="Commit database changes performed by YAML or XML tests.")
175 parser.add_option_group(group)
178 group = optparse.OptionGroup(parser, "Logging Configuration")
179 group.add_option("--logfile", dest="logfile", help="file where the server log will be stored")
180 group.add_option("--no-logrotate", dest="logrotate", action="store_false", my_default=True, help="do not rotate the logfile")
181 group.add_option("--syslog", action="store_true", dest="syslog", my_default=False, help="Send the log to the syslog server")
182 group.add_option('--log-handler', action="append", default=[':INFO'], my_default=[':INFO'], metavar="PREFIX:LEVEL", help='setup a handler at LEVEL for a given PREFIX. An empty PREFIX indicates the root logger. This option can be repeated. Example: "openerp.orm:DEBUG" or "werkzeug:CRITICAL" (default: ":INFO")')
183 group.add_option('--log-request', action="append_const", dest="log_handler", const="openerp.netsvc.rpc.request:DEBUG", help='shortcut for --log-handler=openerp.netsvc.rpc.request:DEBUG')
184 group.add_option('--log-response', action="append_const", dest="log_handler", const="openerp.netsvc.rpc.response:DEBUG", help='shortcut for --log-handler=openerp.netsvc.rpc.response:DEBUG')
185 group.add_option('--log-web', action="append_const", dest="log_handler", const="openerp.addons.web.http:DEBUG", help='shortcut for --log-handler=openerp.addons.web.http:DEBUG')
186 group.add_option('--log-sql', action="append_const", dest="log_handler", const="openerp.sql_db:DEBUG", help='shortcut for --log-handler=openerp.sql_db:DEBUG')
187 # For backward-compatibility, map the old log levels to something
189 levels = ['info', 'debug_rpc', 'warn', 'test', 'critical',
190 'debug_sql', 'error', 'debug', 'debug_rpc_answer', 'notset']
191 group.add_option('--log-level', dest='log_level', type='choice', choices=levels,
192 my_default='info', help='specify the level of the logging. Accepted values: ' + str(levels) + ' (deprecated option).')
194 parser.add_option_group(group)
197 group = optparse.OptionGroup(parser, "SMTP Configuration")
198 group.add_option('--email-from', dest='email_from', my_default=False,
199 help='specify the SMTP email address for sending email')
200 group.add_option('--smtp', dest='smtp_server', my_default='localhost',
201 help='specify the SMTP server for sending email')
202 group.add_option('--smtp-port', dest='smtp_port', my_default=25,
203 help='specify the SMTP port', type="int")
204 group.add_option('--smtp-ssl', dest='smtp_ssl', action='store_true', my_default=False,
205 help='specify the SMTP server support SSL or not')
206 group.add_option('--smtp-user', dest='smtp_user', my_default=False,
207 help='specify the SMTP username for sending email')
208 group.add_option('--smtp-password', dest='smtp_password', my_default=False,
209 help='specify the SMTP password for sending email')
210 parser.add_option_group(group)
212 group = optparse.OptionGroup(parser, "Database related options")
213 group.add_option("-d", "--database", dest="db_name", my_default=False,
214 help="specify the database name")
215 group.add_option("-r", "--db_user", dest="db_user", my_default=False,
216 help="specify the database user name")
217 group.add_option("-w", "--db_password", dest="db_password", my_default=False,
218 help="specify the database password")
219 group.add_option("--pg_path", dest="pg_path", help="specify the pg executable path")
220 group.add_option("--db_host", dest="db_host", my_default=False,
221 help="specify the database host")
222 group.add_option("--db_port", dest="db_port", my_default=False,
223 help="specify the database port", type="int")
224 group.add_option("--db_maxconn", dest="db_maxconn", type='int', my_default=64,
225 help="specify the the maximum number of physical connections to posgresql")
226 group.add_option("--db-template", dest="db_template", my_default="template1",
227 help="specify a custom database template to create a new database")
228 parser.add_option_group(group)
230 group = optparse.OptionGroup(parser, "Internationalisation options",
231 "Use these options to translate OpenERP to another language."
232 "See i18n section of the user manual. Option '-d' is mandatory."
233 "Option '-l' is mandatory in case of importation"
235 group.add_option('--load-language', dest="load_language",
236 help="specifies the languages for the translations you want to be loaded")
237 group.add_option('-l', "--language", dest="language",
238 help="specify the language of the translation file. Use it with --i18n-export or --i18n-import")
239 group.add_option("--i18n-export", dest="translate_out",
240 help="export all sentences to be translated to a CSV file, a PO file or a TGZ archive and exit")
241 group.add_option("--i18n-import", dest="translate_in",
242 help="import a CSV or a PO file with translations and exit. The '-l' option is required.")
243 group.add_option("--i18n-overwrite", dest="overwrite_existing_translations", action="store_true", my_default=False,
244 help="overwrites existing translation terms on updating a module or importing a CSV or a PO file.")
245 group.add_option("--modules", dest="translate_modules",
246 help="specify modules to export. Use in combination with --i18n-export")
247 parser.add_option_group(group)
249 security = optparse.OptionGroup(parser, 'Security-related options')
250 security.add_option('--no-database-list', action="store_false", dest='list_db', my_default=True,
251 help="disable the ability to return the list of databases")
252 parser.add_option_group(security)
255 group = optparse.OptionGroup(parser, "Advanced options")
256 group.add_option('--debug', dest='debug_mode', action='store_true', my_default=False, help='enable debug mode')
257 group.add_option("--stop-after-init", action="store_true", dest="stop_after_init", my_default=False,
258 help="stop the server after its initialization")
259 group.add_option("-t", "--timezone", dest="timezone", my_default=False,
260 help="specify reference timezone for the server (e.g. Europe/Brussels")
261 group.add_option("--osv-memory-count-limit", dest="osv_memory_count_limit", my_default=False,
262 help="Force a limit on the maximum number of records kept in the virtual "
263 "osv_memory tables. The default is False, which means no count-based limit.",
265 group.add_option("--osv-memory-age-limit", dest="osv_memory_age_limit", my_default=1.0,
266 help="Force a limit on the maximum age of records kept in the virtual "
267 "osv_memory tables. This is a decimal value expressed in hours, "
268 "and the default is 1 hour.",
270 group.add_option("--max-cron-threads", dest="max_cron_threads", my_default=4,
271 help="Maximum number of threads processing concurrently cron jobs.",
273 group.add_option("--unaccent", dest="unaccent", my_default=False, action="store_true",
274 help="Use the unaccent function provided by the database when available.")
275 parser.add_option_group(group)
277 group = optparse.OptionGroup(parser, "Multiprocessing options")
278 # TODO sensible default for the three following limits.
279 group.add_option("--workers", dest="workers", my_default=0,
280 help="Specify the number of workers, 0 disable prefork mode.",
282 group.add_option("--limit-memory-soft", dest="limit_memory_soft", my_default=640 * 1024 * 1024,
283 help="Maximum allowed virtual memory per worker, when reached the worker be reset after the current request.",
285 group.add_option("--limit-memory-hard", dest="limit_memory_hard", my_default=768 * 1024 * 1024,
286 help="Maximum allowed virtual memory per worker, when reached, any memory allocation will fail.",
288 group.add_option("--limit-time-cpu", dest="limit_time_cpu", my_default=60,
289 help="Maximum allowed CPU time per request.",
291 group.add_option("--limit-time-real", dest="limit_time_real", my_default=60,
292 help="Maximum allowed Real time per request. ",
294 group.add_option("--limit-request", dest="limit_request", my_default=8192,
295 help="Maximum number of request to be processed per worker.",
297 parser.add_option_group(group)
299 # Copy all optparse options (i.e. MyOption) into self.options.
300 for group in parser.option_groups:
301 for option in group.option_list:
302 self.options[option.dest] = option.my_default
303 self.casts[option.dest] = option
305 self.parse_config(None, False)
307 def parse_config(self, args=None, complete=True):
308 """ Parse the configuration file (if any) and the command-line
311 This method initializes openerp.tools.config and openerp.conf (the
312 former should be removed in the furture) with library-wide
313 configuration values.
315 This method must be called before proper usage of this library can be
318 Typical usage of this method:
320 openerp.tools.config.parse_config(sys.argv[1:])
322 :param complete: this is a hack used in __init__(), leave it to True.
327 opt, args = self.parser.parse_args(args)
331 self.parser.error(msg)
333 # Ensures no illegitimate argument is silently discarded (avoids insidious "hyphen to dash" problem)
334 die(args, "unrecognized parameters: '%s'" % " ".join(args))
336 die(bool(opt.syslog) and bool(opt.logfile),
337 "the syslog and logfile options are exclusive")
339 die(opt.translate_in and (not opt.language or not opt.db_name),
340 "the i18n-import option cannot be used without the language (-l) and the database (-d) options")
342 die(opt.overwrite_existing_translations and not (opt.translate_in or opt.update),
343 "the i18n-overwrite option cannot be used without the i18n-import option or without the update option")
345 die(opt.translate_out and (not opt.db_name),
346 "the i18n-export option cannot be used without the database (-d) option")
348 # Check if the config file exists (-c used, but not -s)
349 die(not opt.save and opt.config and not os.path.exists(opt.config),
350 "The config file '%s' selected with -c/--config doesn't exist, "\
351 "use -s/--save if you want to generate it"%(opt.config))
353 # place/search the config file on Win32 near the server installation
354 # (../etc from the server)
355 # if the server is run by an unprivileged user, he has to specify location of a config file where he has the rights to write,
356 # else he won't be able to save the configurations, or even to start the server...
358 rcfilepath = os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), 'openerp-server.conf')
360 rcfilepath = os.path.expanduser('~/.openerp_serverrc')
362 self.rcfile = os.path.abspath(
363 self.config_file or opt.config \
364 or os.environ.get('OPENERP_SERVER') or rcfilepath)
368 # Verify that we want to log or not, if not the output will go to stdout
369 if self.options['logfile'] in ('None', 'False'):
370 self.options['logfile'] = False
371 # the same for the pidfile
372 if self.options['pidfile'] in ('None', 'False'):
373 self.options['pidfile'] = False
375 # if defined dont take the configfile value even if the defined value is None
376 keys = ['xmlrpc_interface', 'xmlrpc_port', 'db_name', 'db_user', 'db_password', 'db_host',
377 'db_port', 'db_template', 'logfile', 'pidfile', 'smtp_port',
378 'email_from', 'smtp_server', 'smtp_user', 'smtp_password',
379 'netrpc_interface', 'netrpc_port', 'db_maxconn', 'import_partial', 'addons_path',
380 'netrpc', 'xmlrpc', 'syslog', 'without_demo', 'timezone',
381 'xmlrpcs_interface', 'xmlrpcs_port', 'xmlrpcs',
382 'static_http_enable', 'static_http_document_root', 'static_http_url_prefix',
383 'secure_cert_file', 'secure_pkey_file', 'dbfilter', 'log_handler', 'log_level'
387 # Copy the command-line argument...
388 if getattr(opt, arg):
389 self.options[arg] = getattr(opt, arg)
390 # ... or keep, but cast, the config file value.
391 elif isinstance(self.options[arg], basestring) and self.casts[arg].type in optparse.Option.TYPE_CHECKER:
392 self.options[arg] = optparse.Option.TYPE_CHECKER[self.casts[arg].type](self.casts[arg], arg, self.options[arg])
394 # if defined but None take the configfile value
396 'language', 'translate_out', 'translate_in', 'overwrite_existing_translations',
397 'debug_mode', 'smtp_ssl', 'load_language',
398 'stop_after_init', 'logrotate', 'without_demo', 'netrpc', 'xmlrpc', 'syslog',
399 'list_db', 'xmlrpcs', 'proxy_mode',
400 'test_file', 'test_enable', 'test_commit', 'test_report_directory',
401 'osv_memory_count_limit', 'osv_memory_age_limit', 'max_cron_threads', 'unaccent',
402 'workers', 'limit_memory_hard', 'limit_memory_soft', 'limit_time_cpu', 'limit_time_real', 'limit_request'
406 # Copy the command-line argument...
407 if getattr(opt, arg) is not None:
408 self.options[arg] = getattr(opt, arg)
409 # ... or keep, but cast, the config file value.
410 elif isinstance(self.options[arg], basestring) and self.casts[arg].type in optparse.Option.TYPE_CHECKER:
411 self.options[arg] = optparse.Option.TYPE_CHECKER[self.casts[arg].type](self.casts[arg], arg, self.options[arg])
413 self.options['root_path'] = os.path.abspath(os.path.expanduser(os.path.expandvars(os.path.dirname(openerp.__file__))))
414 if not self.options['addons_path'] or self.options['addons_path']=='None':
415 self.options['addons_path'] = os.path.join(self.options['root_path'], 'addons')
417 self.options['addons_path'] = ",".join(
418 os.path.abspath(os.path.expanduser(os.path.expandvars(x)))
419 for x in self.options['addons_path'].split(','))
421 self.options['init'] = opt.init and dict.fromkeys(opt.init.split(','), 1) or {}
422 self.options["demo"] = not opt.without_demo and self.options['init'] or {}
423 self.options['update'] = opt.update and dict.fromkeys(opt.update.split(','), 1) or {}
424 self.options['translate_modules'] = opt.translate_modules and map(lambda m: m.strip(), opt.translate_modules.split(',')) or ['all']
425 self.options['translate_modules'].sort()
427 # TODO checking the type of the parameters should be done for every
428 # parameters, not just the timezone.
429 # The call to get_server_timezone() sets the timezone; this should
430 # probably done here.
431 if self.options['timezone']:
432 # Prevent the timezone to be True. (The config file parsing changes
433 # the string 'True' to the boolean value True. It would be probably
434 # be better to remove that conversion.)
435 die(not isinstance(self.options['timezone'], basestring),
436 "Invalid timezone value in configuration or environment: %r.\n"
437 "Please fix this in your configuration." %(self.options['timezone']))
439 # If an explicit TZ was provided in the config, make sure it is known
442 pytz.timezone(self.options['timezone'])
443 except pytz.UnknownTimeZoneError:
444 die(True, "The specified timezone (%s) is invalid" % self.options['timezone'])
446 # If pytz is missing, don't check the provided TZ, it will be ignored anyway.
450 self.options['pg_path'] = opt.pg_path
452 if self.options.get('language', False):
453 if len(self.options['language']) > 5:
454 raise Exception('ERROR: The Lang name must take max 5 chars, Eg: -lfr_BE')
456 if not self.options['db_user']:
459 self.options['db_user'] = getpass.getuser()
461 self.options['db_user'] = None
463 die(not self.options['db_user'], 'ERROR: No user specified for the connection to the database')
465 if self.options['db_password']:
466 if sys.platform == 'win32' and not self.options['db_host']:
467 self.options['db_host'] = 'localhost'
468 #if self.options['db_host']:
469 # self._generate_pgpassfile()
474 openerp.conf.max_cron_threads = self.options['max_cron_threads']
476 openerp.conf.addons_paths = self.options['addons_path'].split(',')
477 if opt.server_wide_modules:
478 openerp.conf.server_wide_modules = map(lambda m: m.strip(), opt.server_wide_modules.split(','))
480 openerp.conf.server_wide_modules = ['web']
482 openerp.modules.module.initialize_sys_path()
483 openerp.modules.loading.open_openerp_namespace()
485 def _generate_pgpassfile(self):
487 Generate the pgpass file with the parameters from the command line (db_host, db_user,
490 Used because pg_dump and pg_restore can not accept the password on the command line.
492 is_win32 = sys.platform == 'win32'
494 filename = os.path.join(os.environ['APPDATA'], 'pgpass.conf')
496 filename = os.path.join(os.environ['HOME'], '.pgpass')
498 text_to_add = "%(db_host)s:*:*:%(db_user)s:%(db_password)s" % self.options
500 if os.path.exists(filename):
501 content = [x.strip() for x in file(filename, 'r').readlines()]
502 if text_to_add in content:
505 fp = file(filename, 'a+')
506 fp.write(text_to_add + "\n")
514 x=_winreg.ConnectRegistry(None,_winreg.HKEY_LOCAL_MACHINE)
515 y = _winreg.OpenKey(x, r"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", 0,_winreg.KEY_ALL_ACCESS)
516 _winreg.SetValueEx(y,"PGPASSFILE", 0, _winreg.REG_EXPAND_SZ, filename )
521 os.chmod(filename, stat.S_IRUSR + stat.S_IWUSR)
523 def _is_addons_path(self, path):
524 for f in os.listdir(path):
525 modpath = os.path.join(path, f)
526 if os.path.isdir(modpath):
527 def hasfile(filename):
528 return os.path.isfile(os.path.join(modpath, filename))
529 if hasfile('__init__.py') and (hasfile('__openerp__.py') or hasfile('__terp__.py')):
533 def _check_addons_path(self, option, opt, value, parser):
535 for path in value.split(','):
537 res = os.path.abspath(os.path.expanduser(path))
538 if not os.path.isdir(res):
539 raise optparse.OptionValueError("option %s: no such directory: %r" % (opt, path))
540 if not self._is_addons_path(res):
541 raise optparse.OptionValueError("option %s: The addons-path %r does not seem to a be a valid Addons Directory!" % (opt, path))
544 setattr(parser.values, option.dest, ",".join(ad_paths))
547 p = ConfigParser.ConfigParser()
549 p.read([self.rcfile])
550 for (name,value) in p.items('options'):
551 if value=='True' or value=='true':
553 if value=='False' or value=='false':
555 self.options[name] = value
556 #parse the other sections, as well
557 for sec in p.sections():
560 if not self.misc.has_key(sec):
562 for (name, value) in p.items(sec):
563 if value=='True' or value=='true':
565 if value=='False' or value=='false':
567 self.misc[sec][name] = value
570 except ConfigParser.NoSectionError:
574 p = ConfigParser.ConfigParser()
575 loglevelnames = dict(zip(self._LOGLEVELS.values(), self._LOGLEVELS.keys()))
576 p.add_section('options')
577 for opt in sorted(self.options.keys()):
578 if opt in ('version', 'language', 'translate_out', 'translate_in', 'overwrite_existing_translations', 'init', 'update'):
580 if opt in self.blacklist_for_save:
582 if opt in ('log_level',):
583 p.set('options', opt, loglevelnames.get(self.options[opt], self.options[opt]))
585 p.set('options', opt, self.options[opt])
587 for sec in sorted(self.misc.keys()):
589 for opt in sorted(self.misc[sec].keys()):
590 p.set(sec,opt,self.misc[sec][opt])
592 # try to create the directories and write the file
594 rc_exists = os.path.exists(self.rcfile)
595 if not rc_exists and not os.path.exists(os.path.dirname(self.rcfile)):
596 os.makedirs(os.path.dirname(self.rcfile))
598 p.write(file(self.rcfile, 'w'))
600 os.chmod(self.rcfile, 0600)
602 sys.stderr.write("ERROR: couldn't write the config file\n")
605 # what to do if impossible?
606 sys.stderr.write("ERROR: couldn't create the config directory\n")
608 def get(self, key, default=None):
609 return self.options.get(key, default)
611 def get_misc(self, sect, key, default=None):
612 return self.misc.get(sect,{}).get(key, default)
614 def __setitem__(self, key, value):
615 self.options[key] = value
617 def __getitem__(self, key):
618 return self.options[key]
620 config = configmanager()
623 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: