Mercurial > p > roundup > code
changeset 2770:cdf6787ffeda
implement getopt().
support config file paths as well as directory paths for loading.
UserConfig: defaults were added to all config sections. filter them out.
| author | Alexander Smishlajev <a1s@users.sourceforge.net> |
|---|---|
| date | Sun, 17 Oct 2004 17:35:32 +0000 |
| parents | b4fb224300b1 |
| children | d385f6c1d4ed |
| files | roundup/configuration.py |
| diffstat | 1 files changed, 110 insertions(+), 47 deletions(-) [+] |
line wrap: on
line diff
--- a/roundup/configuration.py Sat Oct 16 14:57:23 2004 +0000 +++ b/roundup/configuration.py Sun Oct 17 17:35:32 2004 +0000 @@ -1,9 +1,10 @@ # Roundup Issue Tracker configuration support # -# $Id: configuration.py,v 1.16 2004-07-28 09:46:58 a1s Exp $ +# $Id: configuration.py,v 1.17 2004-10-17 17:35:32 a1s Exp $ # __docformat__ = "restructuredtext" +import getopt import imp import os import time @@ -303,7 +304,7 @@ """ class_description = "The path may be either absolute or relative\n" \ - " to the directory containig this config file." + "to the directory containig this config file." def get(self): _val = Option.get(self) @@ -588,15 +589,18 @@ section_options = None # mapping from option names and aliases to Option instances options = None + # actual name of the config file. set on load. + filepath = os.path.join(HOME, INI_FILE) - def __init__(self, home_dir=None, layout=None): + def __init__(self, config_path=None, layout=None): """Initialize confing instance Parameters: - home_dir: - optional configuration directory. - If passed, load the config from that directory - after processing config layout (if any). + config_path: + optional directory or file name of the config file. + If passed, load the config after processing layout (if any). + If config_path is a directory name, use default base name + of the config file. layout: optional configuration layout, a sequence of section definitions suitable for .add_section() @@ -611,8 +615,8 @@ if layout: for section in layout: self.add_section(*section) - if home_dir is not None: - self.load(home_dir) + if config_path is not None: + self.load(config_path) def add_section(self, section, options, description=None): """Define new config section @@ -698,16 +702,30 @@ for _option in self.items(): _option.reset() - # This is a placeholder. TBD. # Meant for commandline tools. # Allows automatic creation of configuration files like this: # roundup-server -p 8017 -u roundup --save-config - def getopt(self, args, **options): + def getopt(self, args, short_options="", long_options=(), + config_load_options=("C", "config"), **options + ): """Apply options specified in command line arguments. Parameters: args: command line to parse (sys.argv[1:]) + short_options: + optional string of letters for command line options + that are not config options + long_options: + optional list of names for long options + that are not config options + config_load_options: + two-element sequence (letter, long_option) defining + the options for config file. If unset, don't load + config file; otherwise config file is read prior + to applying other options. Short option letter + must not have a colon and long_option name must + not have an equal sign or '--' prefix. options: mapping from option names to command line option specs. e.g. server_port="p:", server_user="u:" @@ -720,6 +738,53 @@ processed options are removed from returned option list. """ + # take a copy of long_options + long_options = list(long_options) + # build option lists + cfg_names = {} + booleans = [] + for (name, letter) in options.items(): + cfg_name = name.upper() + short_opt = "-" + letter[0] + name = name.lower().replace("_", "-") + cfg_names.update({short_opt: cfg_name, "--" + name: cfg_name}) + + short_options += letter + if letter[-1] == ":": + long_options.append(name + "=") + else: + booleans.append(short_opt) + long_options.append(name) + + if config_load_options: + short_options += config_load_options[0] + ":" + long_options.append(config_load_options[1] + "=") + # compute names that will be searched in getopt return value + config_load_options = ( + "-" + config_load_options[0], + "--" + config_load_options[1], + ) + # parse command line arguments + optlist, args = getopt.getopt(args, short_options, long_options) + # load config file if requested + if config_load_options: + for option in optlist: + if option[0] in config_load_options: + self.load_ini(option[1]) + optlist.remove(option) + break + # apply options + extra_options = [] + for (opt, arg) in optlist: + if (opt in booleans): # and not arg + arg = "yes" + try: + name = cfg_names[opt] + except KeyError: + extra_options.append((opt, arg)) + else: + self[name] = arg + return (extra_options, args) # option and section locators (used in option access methods) @@ -746,14 +811,24 @@ need_set.setdefault(option.section, []).append(option.setting) return need_set + def _adjust_options(self, config): + """Load ad-hoc option definitions from ConfigParser instance.""" + pass + + def _get_name(self): + """Return the service name for config file heading""" + return "" + # file operations - def load_ini(self, home_dir, defaults=None): + def load_ini(self, config_path, defaults=None): """Set options from config.ini file in given home_dir Parameters: - home_dir: - config home directory + config_path: + directory or file name of the config file. + If config_path is a directory name, use default + base name of the config file defaults: optional dictionary of defaults for ConfigParser @@ -761,15 +836,23 @@ no error is raised. Config will be reset to defaults. """ + if os.path.isdir(config_path): + home_dir = config_path + config_path = os.path.join(config_path, self.INI_FILE) + else: + home_dir = os.path.dirname(config_path) # parse the file config_defaults = {"HOME": home_dir} if defaults: config_defaults.update(defaults) config = ConfigParser.ConfigParser(config_defaults) config.read([os.path.join(home_dir, self.INI_FILE)]) - # .ini file loaded ok. set the options, starting from HOME + # .ini file loaded ok. + self.HOME = home_dir + self.filepath = config_path + self._adjust_options(config) + # set the options, starting from HOME self.reset() - self.HOME = home_dir for option in self.items(): option.load_ini(config) @@ -789,12 +872,12 @@ """ if ini_file is None: - ini_file = os.path.join(self.HOME, self.INI_FILE) + ini_file = self.filepath _tmp_file = os.path.splitext(ini_file)[0] _bak_file = _tmp_file + ".bak" _tmp_file = _tmp_file + ".tmp" _fp = file(_tmp_file, "wt") - _fp.write("# %s configuration file\n" % self["TRACKER_NAME"]) + _fp.write("# %s configuration file\n" % self._get_name()) _fp.write("# Autogenerated at %s\n" % time.asctime()) need_set = self._get_unset_options() if need_set: @@ -891,40 +974,17 @@ """ - def load_ini(self, home_dir, defaults=None): - """Load options from config.ini file in given home_dir - - Parameters: - home_dir: - config home directory - defaults: - optional dictionary of defaults for ConfigParser - - Options are automatically created as they are read - from the config file. - - Note: if home_dir does not contain config.ini file, - no error is raised. Config will be reset to defaults. - - """ - # parse the file - config_defaults = {"HOME": home_dir} - if defaults: - config_defaults.update(defaults) - config = ConfigParser.ConfigParser(defaults) - config.read([os.path.join(home_dir, self.INI_FILE)]) - # .ini file loaded ok. - self.HOME = home_dir + def _adjust_options(self, config): + # config defaults appear in all sections. + # we'll need to filter them out. + defaults = config.defaults().keys() # see what options are already defined and add missing ones preset = [(option.section, option.setting) for option in self.items()] for section in config.sections(): for name in config.options(section): - if (section, name) not in preset: + if ((section, name) not in preset) \ + and (name not in defaults): self.add_option(Option(self, section, name)) - # set the options - self.reset() - for option in self.items(): - option.load_ini(config) class CoreConfig(Config): @@ -968,6 +1028,9 @@ del need_set["mail"] return need_set + def _get_name(self): + return self["TRACKER_NAME"] + def reset(self): Config.reset(self) if self.ext:
