1 # Copyright (c) 2011 The Chromium OS Authors.
3 # SPDX-License-Identifier: GPL-2.0+
6 from __future__ import print_function
15 """Default settings per-project.
17 These are used by _ProjectConfigParser. Settings names should match
18 the "dest" of the option parser from patman.py.
23 "process_tags": "False",
27 class _ProjectConfigParser(ConfigParser.SafeConfigParser):
28 """ConfigParser that handles projects.
30 There are two main goals of this class:
31 - Load project-specific default settings.
32 - Merge general default settings/aliases with project-specific ones.
34 # Sample config used for tests below...
36 >>> sample_config = '''
38 ... me: Peter P. <likesspiders@example.com>
39 ... enemies: Evil <evil@example.com>
42 ... enemies: Green G. <ugly@example.com>
45 ... enemies: Doc O. <pus@example.com>
51 # Check to make sure that bogus project gets general alias.
52 >>> config = _ProjectConfigParser("zzz")
53 >>> config.readfp(StringIO.StringIO(sample_config))
54 >>> config.get("alias", "enemies")
55 'Evil <evil@example.com>'
57 # Check to make sure that alias gets overridden by project.
58 >>> config = _ProjectConfigParser("sm")
59 >>> config.readfp(StringIO.StringIO(sample_config))
60 >>> config.get("alias", "enemies")
61 'Green G. <ugly@example.com>'
63 # Check to make sure that settings get merged with project.
64 >>> config = _ProjectConfigParser("linux")
65 >>> config.readfp(StringIO.StringIO(sample_config))
66 >>> sorted(config.items("settings"))
67 [('am_hero', 'True'), ('process_tags', 'False')]
69 # Check to make sure that settings works with unknown project.
70 >>> config = _ProjectConfigParser("unknown")
71 >>> config.readfp(StringIO.StringIO(sample_config))
72 >>> sorted(config.items("settings"))
75 def __init__(self, project_name):
76 """Construct _ProjectConfigParser.
78 In addition to standard SafeConfigParser initialization, this also loads
82 project_name: The name of the project.
84 self._project_name = project_name
85 ConfigParser.SafeConfigParser.__init__(self)
87 # Update the project settings in the config based on
88 # the _default_settings global.
89 project_settings = "%s_settings" % project_name
90 if not self.has_section(project_settings):
91 self.add_section(project_settings)
92 project_defaults = _default_settings.get(project_name, {})
93 for setting_name, setting_value in project_defaults.iteritems():
94 self.set(project_settings, setting_name, setting_value)
96 def get(self, section, option, *args, **kwargs):
97 """Extend SafeConfigParser to try project_section before section.
100 See SafeConfigParser.
102 See SafeConfigParser.
105 return ConfigParser.SafeConfigParser.get(
106 self, "%s_%s" % (self._project_name, section), option,
109 except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
110 return ConfigParser.SafeConfigParser.get(
111 self, section, option, *args, **kwargs
114 def items(self, section, *args, **kwargs):
115 """Extend SafeConfigParser to add project_section to section.
118 See SafeConfigParser.
120 See SafeConfigParser.
123 has_project_section = False
126 # Get items from the project section
128 project_items = ConfigParser.SafeConfigParser.items(
129 self, "%s_%s" % (self._project_name, section), *args, **kwargs
131 has_project_section = True
132 except ConfigParser.NoSectionError:
135 # Get top-level items
137 top_items = ConfigParser.SafeConfigParser.items(
138 self, section, *args, **kwargs
140 except ConfigParser.NoSectionError:
141 # If neither section exists raise the error on...
142 if not has_project_section:
145 item_dict = dict(top_items)
146 item_dict.update(project_items)
147 return item_dict.items()
149 def ReadGitAliases(fname):
150 """Read a git alias file. This is in the form used by git:
152 alias uboot u-boot@lists.denx.de
153 alias wd Wolfgang Denk <wd@denx.de>
156 fname: Filename to read
159 fd = open(fname, 'r')
161 print("Warning: Cannot find alias file '%s'" % fname)
164 re_line = re.compile('alias\s+(\S+)\s+(.*)')
165 for line in fd.readlines():
167 if not line or line[0] == '#':
170 m = re_line.match(line)
172 print("Warning: Alias file line '%s' not understood" % line)
175 list = alias.get(m.group(1), [])
176 for item in m.group(2).split(','):
180 alias[m.group(1)] = list
184 def CreatePatmanConfigFile(config_fname):
185 """Creates a config file under $(HOME)/.patman if it can't find one.
188 config_fname: Default config filename i.e., $(HOME)/.patman
193 name = gitutil.GetDefaultUserName()
195 name = raw_input("Enter name: ")
197 email = gitutil.GetDefaultUserEmail()
200 email = raw_input("Enter email: ")
203 f = open(config_fname, 'w')
205 print("Couldn't create patman config file\n")
208 print("[alias]\nme: %s <%s>" % (name, email), file=f)
211 def _UpdateDefaults(parser, config):
212 """Update the given OptionParser defaults based on config.
214 We'll walk through all of the settings from the parser
215 For each setting we'll look for a default in the option parser.
216 If it's found we'll update the option parser default.
218 The idea here is that the .patman file should be able to update
219 defaults but that command line flags should still have the final
223 parser: An instance of an OptionParser whose defaults will be
225 config: An instance of _ProjectConfigParser that we will query
228 defaults = parser.get_default_values()
229 for name, val in config.items('settings'):
230 if hasattr(defaults, name):
231 default_val = getattr(defaults, name)
232 if isinstance(default_val, bool):
233 val = config.getboolean('settings', name)
234 elif isinstance(default_val, int):
235 val = config.getint('settings', name)
236 parser.set_default(name, val)
238 print("WARNING: Unknown setting %s" % name)
240 def _ReadAliasFile(fname):
241 """Read in the U-Boot git alias file if it exists.
244 fname: Filename to read.
246 if os.path.exists(fname):
248 with open(fname) as fd:
253 if not line or line.startswith('#'):
255 words = line.split(' ', 2)
256 if len(words) < 3 or words[0] != 'alias':
258 bad_line = "%s:%d:Invalid line '%s'" % (fname, linenum,
261 alias[words[1]] = [s.strip() for s in words[2].split(',')]
265 def Setup(parser, project_name, config_fname=''):
266 """Set up the settings module by reading config files.
269 parser: The parser to update
270 project_name: Name of project that we're working on; we'll look
271 for sections named "project_section" as well.
272 config_fname: Config filename to read ('' for default)
274 # First read the git alias file if available
275 _ReadAliasFile('doc/git-mailrc')
276 config = _ProjectConfigParser(project_name)
277 if config_fname == '':
278 config_fname = '%s/.patman' % os.getenv('HOME')
280 if not os.path.exists(config_fname):
281 print("No config file found ~/.patman\nCreating one...\n")
282 CreatePatmanConfigFile(config_fname)
284 config.read(config_fname)
286 for name, value in config.items('alias'):
287 alias[name] = value.split(',')
289 _UpdateDefaults(parser, config)
291 # These are the aliases we understand, indexed by alias. Each member is a list.
294 if __name__ == "__main__":