1 # Copyright (c) 2011 The Chromium OS Authors.
3 # SPDX-License-Identifier: GPL-2.0+
6 from __future__ import print_function
9 import configparser as ConfigParser
19 """Default settings per-project.
21 These are used by _ProjectConfigParser. Settings names should match
22 the "dest" of the option parser from patman.py.
27 "process_tags": "False",
31 class _ProjectConfigParser(ConfigParser.SafeConfigParser):
32 """ConfigParser that handles projects.
34 There are two main goals of this class:
35 - Load project-specific default settings.
36 - Merge general default settings/aliases with project-specific ones.
38 # Sample config used for tests below...
40 >>> sample_config = '''
42 ... me: Peter P. <likesspiders@example.com>
43 ... enemies: Evil <evil@example.com>
46 ... enemies: Green G. <ugly@example.com>
49 ... enemies: Doc O. <pus@example.com>
55 # Check to make sure that bogus project gets general alias.
56 >>> config = _ProjectConfigParser("zzz")
57 >>> config.readfp(StringIO.StringIO(sample_config))
58 >>> config.get("alias", "enemies")
59 'Evil <evil@example.com>'
61 # Check to make sure that alias gets overridden by project.
62 >>> config = _ProjectConfigParser("sm")
63 >>> config.readfp(StringIO.StringIO(sample_config))
64 >>> config.get("alias", "enemies")
65 'Green G. <ugly@example.com>'
67 # Check to make sure that settings get merged with project.
68 >>> config = _ProjectConfigParser("linux")
69 >>> config.readfp(StringIO.StringIO(sample_config))
70 >>> sorted(config.items("settings"))
71 [('am_hero', 'True'), ('process_tags', 'False')]
73 # Check to make sure that settings works with unknown project.
74 >>> config = _ProjectConfigParser("unknown")
75 >>> config.readfp(StringIO.StringIO(sample_config))
76 >>> sorted(config.items("settings"))
79 def __init__(self, project_name):
80 """Construct _ProjectConfigParser.
82 In addition to standard SafeConfigParser initialization, this also loads
86 project_name: The name of the project.
88 self._project_name = project_name
89 ConfigParser.SafeConfigParser.__init__(self)
91 # Update the project settings in the config based on
92 # the _default_settings global.
93 project_settings = "%s_settings" % project_name
94 if not self.has_section(project_settings):
95 self.add_section(project_settings)
96 project_defaults = _default_settings.get(project_name, {})
97 for setting_name, setting_value in project_defaults.iteritems():
98 self.set(project_settings, setting_name, setting_value)
100 def get(self, section, option, *args, **kwargs):
101 """Extend SafeConfigParser to try project_section before section.
104 See SafeConfigParser.
106 See SafeConfigParser.
109 return ConfigParser.SafeConfigParser.get(
110 self, "%s_%s" % (self._project_name, section), option,
113 except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
114 return ConfigParser.SafeConfigParser.get(
115 self, section, option, *args, **kwargs
118 def items(self, section, *args, **kwargs):
119 """Extend SafeConfigParser to add project_section to section.
122 See SafeConfigParser.
124 See SafeConfigParser.
127 has_project_section = False
130 # Get items from the project section
132 project_items = ConfigParser.SafeConfigParser.items(
133 self, "%s_%s" % (self._project_name, section), *args, **kwargs
135 has_project_section = True
136 except ConfigParser.NoSectionError:
139 # Get top-level items
141 top_items = ConfigParser.SafeConfigParser.items(
142 self, section, *args, **kwargs
144 except ConfigParser.NoSectionError:
145 # If neither section exists raise the error on...
146 if not has_project_section:
149 item_dict = dict(top_items)
150 item_dict.update(project_items)
151 return item_dict.items()
153 def ReadGitAliases(fname):
154 """Read a git alias file. This is in the form used by git:
156 alias uboot u-boot@lists.denx.de
157 alias wd Wolfgang Denk <wd@denx.de>
160 fname: Filename to read
163 fd = open(fname, 'r')
165 print("Warning: Cannot find alias file '%s'" % fname)
168 re_line = re.compile('alias\s+(\S+)\s+(.*)')
169 for line in fd.readlines():
171 if not line or line[0] == '#':
174 m = re_line.match(line)
176 print("Warning: Alias file line '%s' not understood" % line)
179 list = alias.get(m.group(1), [])
180 for item in m.group(2).split(','):
184 alias[m.group(1)] = list
188 def CreatePatmanConfigFile(config_fname):
189 """Creates a config file under $(HOME)/.patman if it can't find one.
192 config_fname: Default config filename i.e., $(HOME)/.patman
197 name = gitutil.GetDefaultUserName()
199 name = raw_input("Enter name: ")
201 email = gitutil.GetDefaultUserEmail()
204 email = raw_input("Enter email: ")
207 f = open(config_fname, 'w')
209 print("Couldn't create patman config file\n")
212 print("[alias]\nme: %s <%s>" % (name, email), file=f)
215 def _UpdateDefaults(parser, config):
216 """Update the given OptionParser defaults based on config.
218 We'll walk through all of the settings from the parser
219 For each setting we'll look for a default in the option parser.
220 If it's found we'll update the option parser default.
222 The idea here is that the .patman file should be able to update
223 defaults but that command line flags should still have the final
227 parser: An instance of an OptionParser whose defaults will be
229 config: An instance of _ProjectConfigParser that we will query
232 defaults = parser.get_default_values()
233 for name, val in config.items('settings'):
234 if hasattr(defaults, name):
235 default_val = getattr(defaults, name)
236 if isinstance(default_val, bool):
237 val = config.getboolean('settings', name)
238 elif isinstance(default_val, int):
239 val = config.getint('settings', name)
240 parser.set_default(name, val)
242 print("WARNING: Unknown setting %s" % name)
244 def _ReadAliasFile(fname):
245 """Read in the U-Boot git alias file if it exists.
248 fname: Filename to read.
250 if os.path.exists(fname):
252 with open(fname) as fd:
257 if not line or line.startswith('#'):
259 words = line.split(' ', 2)
260 if len(words) < 3 or words[0] != 'alias':
262 bad_line = "%s:%d:Invalid line '%s'" % (fname, linenum,
265 alias[words[1]] = [s.strip() for s in words[2].split(',')]
269 def Setup(parser, project_name, config_fname=''):
270 """Set up the settings module by reading config files.
273 parser: The parser to update
274 project_name: Name of project that we're working on; we'll look
275 for sections named "project_section" as well.
276 config_fname: Config filename to read ('' for default)
278 # First read the git alias file if available
279 _ReadAliasFile('doc/git-mailrc')
280 config = _ProjectConfigParser(project_name)
281 if config_fname == '':
282 config_fname = '%s/.patman' % os.getenv('HOME')
284 if not os.path.exists(config_fname):
285 print("No config file found ~/.patman\nCreating one...\n")
286 CreatePatmanConfigFile(config_fname)
288 config.read(config_fname)
290 for name, value in config.items('alias'):
291 alias[name] = value.split(',')
293 _UpdateDefaults(parser, config)
295 # These are the aliases we understand, indexed by alias. Each member is a list.
298 if __name__ == "__main__":