--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/settings.py Fri May 16 19:46:16 2008 +0000
@@ -0,0 +1,164 @@
+#!/usr/bin/python2.5
+#
+# Copyright 2008 the Melange authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Custom optparse OptionParser and functions for reading Python settings files.
+
+ Option: class derived from optparse.Option that adds a 'required' parameter
+ OptionParser: class derived from optparse.OptionParser for use with Option
+
+ readPythonSettings(): interprets a valid Python file as a settings file
+"""
+
+__authors__ = [
+ # alphabetical order by last name, please
+ '"Todd Larsen" <tlarsen@google.com>',
+]
+
+
+import os
+import optparse
+import sys
+
+
+DEF_SETTINGS_FILE_DIR = "~"
+DEF_SETTINGS_FILE_NAME = '.soc_scripts_settings'
+
+
+class Error(Exception):
+ """Base exception class for all exceptions in the settings module."""
+ pass
+
+
+class Option(optparse.Option):
+ """Class derived from optparse.Option that adds a 'required' parameter."""
+
+ ATTRS = optparse.Option.ATTRS + ['required']
+
+ def _check_required(self):
+ """Insures that 'required' option can accept a value."""
+ if self.required and (not self.takes_value()):
+ raise optparse.OptionError(
+ "'required' parameter set for option that does not take a value",
+ self)
+
+ # Make sure _check_required() is called from the constructor!
+ CHECK_METHODS = optparse.Option.CHECK_METHODS + [_check_required]
+
+ def process(self, opt, value, values, parser):
+ optparse.Option.process(self, opt, value, values, parser)
+ parser.option_seen[self] = 1
+
+
+class OptionParser(optparse.OptionParser):
+ """Class derived from optparse.OptionParser for use with Option."""
+
+ def _init_parsing_state(self):
+ """Sets up dict to track options seen so far."""
+ optparse.OptionParser._init_parsing_state(self)
+ self.option_seen = {}
+
+ def error(self, *args):
+ """Convert errors reported by optparse.OptionParser to Error exceptions.
+
+ Args:
+ *args: passed through to the Error exception __init__() constructor,
+ usually a list of strings
+
+ Raises:
+ Error with the supplied *args
+ """
+ raise Error(*args)
+
+ def check_values(self, values, args):
+ """Checks to make sure all required=True options were supplied.
+
+ Args:
+ values, args: passed through unchanged (see Returns:)
+
+ Returns:
+ (values, args) unchanged.
+
+ Raises:
+ Error if an option was not supplied that had required=True; exception
+ positional arguments are the error message strings.
+ """
+ errors = []
+
+ for option in self.option_list:
+ if (isinstance(option, Option)
+ and option.required
+ and (not self.option_seen.has_key(option))):
+ errors.append(
+ 'required %s option not supplied' % option)
+
+ if errors:
+ self.error(*errors)
+
+ return values, args
+
+
+def readPythonSettings(defaults={}, # {} OK since defaults is always copied
+ settings_dir=DEF_SETTINGS_FILE_DIR,
+ settings_file=DEF_SETTINGS_FILE_NAME):
+ """Executes a Python-syntax settings file and returns the local variables.
+
+ Args:
+ defaults: dict of default values to use when settings are not present
+ in the settings file (or if no settings file is present at all); this
+ dict is *copied* and is not altered at all
+ settings_dir: optional directory containing settings_file
+ settings_file: optional settings file name found in settings_dir
+
+ Returns:
+ dict of setting name/value pairs (possibly including some values from the
+ defaults parameter). Since the settings file is full-fledged Python
+ source, the values could be any valid Python object.
+
+ Raises:
+ Error if some error occurred parsing the present settings file; exception
+ positional arguments are the error message strings.
+ """
+ # do not let the original defaults be altered
+ defaults = defaults.copy()
+
+ # form absolute path to the settings file, expanding any environment
+ # variables and "~", then removing excess . and .. path elements
+ path = os.path.abspath(
+ os.path.normpath(
+ os.path.expanduser(
+ os.path.expandvars(
+ os.path.join(settings_dir, settings_file)))))
+
+ # empty dict to capture the local variables in the settings file
+ settings_locals = {}
+
+ try:
+ # execute the Python source file and recover the local variables as settings
+ execfile(path, {}, settings_locals)
+ except IOError:
+ # If the settings file is not present, there are no defaults.
+ pass
+ except Exception, error:
+ # Other exceptions usually mean a faulty settings file.
+ raise Error(
+ 'faulty settings file:',
+ (' %s: %s' % (error.__class__.__name__, str(error))),
+ (' %s' % path))
+
+ # overwrite defaults copy with values from the (possibly empty) settings file
+ defaults.update(settings_locals)
+
+ return defaults