From a1dcee84c993232a6c5a1f3b4e54952b587cf1d1 Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Mon, 3 Dec 2012 14:43:18 +0000 Subject: patman: Add the concept of multiple projects There are cases that we want to support different settings (or maybe even different aliases) for different projects. Add support for this by: * Adding detection for two big projects: U-Boot and Linux. * Adding default settings for Linux (U-Boot is already good with the standard patman defaults). * Extend the new "settings" feature in .patman to specify per-project settings. Signed-off-by: Doug Anderson Acked-by: Simon Glass --- tools/patman/settings.py | 147 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 144 insertions(+), 3 deletions(-) (limited to 'tools/patman/settings.py') diff --git a/tools/patman/settings.py b/tools/patman/settings.py index 5208f7d..084d1b8 100644 --- a/tools/patman/settings.py +++ b/tools/patman/settings.py @@ -26,6 +26,140 @@ import re import command import gitutil +"""Default settings per-project. + +These are used by _ProjectConfigParser. Settings names should match +the "dest" of the option parser from patman.py. +""" +_default_settings = { + "u-boot": {}, + "linux": { + "process_tags": "False", + } +} + +class _ProjectConfigParser(ConfigParser.SafeConfigParser): + """ConfigParser that handles projects. + + There are two main goals of this class: + - Load project-specific default settings. + - Merge general default settings/aliases with project-specific ones. + + # Sample config used for tests below... + >>> import StringIO + >>> sample_config = ''' + ... [alias] + ... me: Peter P. + ... enemies: Evil + ... + ... [sm_alias] + ... enemies: Green G. + ... + ... [sm2_alias] + ... enemies: Doc O. + ... + ... [settings] + ... am_hero: True + ... ''' + + # Check to make sure that bogus project gets general alias. + >>> config = _ProjectConfigParser("zzz") + >>> config.readfp(StringIO.StringIO(sample_config)) + >>> config.get("alias", "enemies") + 'Evil ' + + # Check to make sure that alias gets overridden by project. + >>> config = _ProjectConfigParser("sm") + >>> config.readfp(StringIO.StringIO(sample_config)) + >>> config.get("alias", "enemies") + 'Green G. ' + + # Check to make sure that settings get merged with project. + >>> config = _ProjectConfigParser("linux") + >>> config.readfp(StringIO.StringIO(sample_config)) + >>> sorted(config.items("settings")) + [('am_hero', 'True'), ('process_tags', 'False')] + + # Check to make sure that settings works with unknown project. + >>> config = _ProjectConfigParser("unknown") + >>> config.readfp(StringIO.StringIO(sample_config)) + >>> sorted(config.items("settings")) + [('am_hero', 'True')] + """ + def __init__(self, project_name): + """Construct _ProjectConfigParser. + + In addition to standard SafeConfigParser initialization, this also loads + project defaults. + + Args: + project_name: The name of the project. + """ + self._project_name = project_name + ConfigParser.SafeConfigParser.__init__(self) + + # Update the project settings in the config based on + # the _default_settings global. + project_settings = "%s_settings" % project_name + if not self.has_section(project_settings): + self.add_section(project_settings) + project_defaults = _default_settings.get(project_name, {}) + for setting_name, setting_value in project_defaults.iteritems(): + self.set(project_settings, setting_name, setting_value) + + def get(self, section, option, *args, **kwargs): + """Extend SafeConfigParser to try project_section before section. + + Args: + See SafeConfigParser. + Returns: + See SafeConfigParser. + """ + try: + return ConfigParser.SafeConfigParser.get( + self, "%s_%s" % (self._project_name, section), option, + *args, **kwargs + ) + except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): + return ConfigParser.SafeConfigParser.get( + self, section, option, *args, **kwargs + ) + + def items(self, section, *args, **kwargs): + """Extend SafeConfigParser to add project_section to section. + + Args: + See SafeConfigParser. + Returns: + See SafeConfigParser. + """ + project_items = [] + has_project_section = False + top_items = [] + + # Get items from the project section + try: + project_items = ConfigParser.SafeConfigParser.items( + self, "%s_%s" % (self._project_name, section), *args, **kwargs + ) + has_project_section = True + except ConfigParser.NoSectionError: + pass + + # Get top-level items + try: + top_items = ConfigParser.SafeConfigParser.items( + self, section, *args, **kwargs + ) + except ConfigParser.NoSectionError: + # If neither section exists raise the error on... + if not has_project_section: + raise + + item_dict = dict(top_items) + item_dict.update(project_items) + return item_dict.items() + def ReadGitAliases(fname): """Read a git alias file. This is in the form used by git: @@ -102,7 +236,7 @@ def _UpdateDefaults(parser, config): Args: parser: An instance of an OptionParser whose defaults will be updated. - config: An instance of SafeConfigParser that we will query + config: An instance of _ProjectConfigParser that we will query for settings. """ defaults = parser.get_default_values() @@ -117,14 +251,16 @@ def _UpdateDefaults(parser, config): else: print "WARNING: Unknown setting %s" % name -def Setup(parser, config_fname=''): +def Setup(parser, project_name, config_fname=''): """Set up the settings module by reading config files. Args: parser: The parser to update + project_name: Name of project that we're working on; we'll look + for sections named "project_section" as well. config_fname: Config filename to read ('' for default) """ - config = ConfigParser.SafeConfigParser() + config = _ProjectConfigParser(project_name) if config_fname == '': config_fname = '%s/.patman' % os.getenv('HOME') @@ -141,3 +277,8 @@ def Setup(parser, config_fname=''): # These are the aliases we understand, indexed by alias. Each member is a list. alias = {} + +if __name__ == "__main__": + import doctest + + doctest.testmod() -- cgit v1.1