1 # Copyright (c) 2011 The Chromium OS Authors.
3 # SPDX-License-Identifier: GPL-2.0+
13 """Default settings per-project.
15 These are used by _ProjectConfigParser. Settings names should match
16 the "dest" of the option parser from patman.py.
21 "process_tags": "False",
25 class _ProjectConfigParser(ConfigParser.SafeConfigParser):
26 """ConfigParser that handles projects.
28 There are two main goals of this class:
29 - Load project-specific default settings.
30 - Merge general default settings/aliases with project-specific ones.
32 # Sample config used for tests below...
34 >>> sample_config = '''
36 ... me: Peter P. <likesspiders@example.com>
37 ... enemies: Evil <evil@example.com>
40 ... enemies: Green G. <ugly@example.com>
43 ... enemies: Doc O. <pus@example.com>
49 # Check to make sure that bogus project gets general alias.
50 >>> config = _ProjectConfigParser("zzz")
51 >>> config.readfp(StringIO.StringIO(sample_config))
52 >>> config.get("alias", "enemies")
53 'Evil <evil@example.com>'
55 # Check to make sure that alias gets overridden by project.
56 >>> config = _ProjectConfigParser("sm")
57 >>> config.readfp(StringIO.StringIO(sample_config))
58 >>> config.get("alias", "enemies")
59 'Green G. <ugly@example.com>'
61 # Check to make sure that settings get merged with project.
62 >>> config = _ProjectConfigParser("linux")
63 >>> config.readfp(StringIO.StringIO(sample_config))
64 >>> sorted(config.items("settings"))
65 [('am_hero', 'True'), ('process_tags', 'False')]
67 # Check to make sure that settings works with unknown project.
68 >>> config = _ProjectConfigParser("unknown")
69 >>> config.readfp(StringIO.StringIO(sample_config))
70 >>> sorted(config.items("settings"))
73 def __init__(self, project_name):
74 """Construct _ProjectConfigParser.
76 In addition to standard SafeConfigParser initialization, this also loads
80 project_name: The name of the project.
82 self._project_name = project_name
83 ConfigParser.SafeConfigParser.__init__(self)
85 # Update the project settings in the config based on
86 # the _default_settings global.
87 project_settings = "%s_settings" % project_name
88 if not self.has_section(project_settings):
89 self.add_section(project_settings)
90 project_defaults = _default_settings.get(project_name, {})
91 for setting_name, setting_value in project_defaults.iteritems():
92 self.set(project_settings, setting_name, setting_value)
94 def get(self, section, option, *args, **kwargs):
95 """Extend SafeConfigParser to try project_section before section.
100 See SafeConfigParser.
103 return ConfigParser.SafeConfigParser.get(
104 self, "%s_%s" % (self._project_name, section), option,
107 except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
108 return ConfigParser.SafeConfigParser.get(
109 self, section, option, *args, **kwargs
112 def items(self, section, *args, **kwargs):
113 """Extend SafeConfigParser to add project_section to section.
116 See SafeConfigParser.
118 See SafeConfigParser.
121 has_project_section = False
124 # Get items from the project section
126 project_items = ConfigParser.SafeConfigParser.items(
127 self, "%s_%s" % (self._project_name, section), *args, **kwargs
129 has_project_section = True
130 except ConfigParser.NoSectionError:
133 # Get top-level items
135 top_items = ConfigParser.SafeConfigParser.items(
136 self, section, *args, **kwargs
138 except ConfigParser.NoSectionError:
139 # If neither section exists raise the error on...
140 if not has_project_section:
143 item_dict = dict(top_items)
144 item_dict.update(project_items)
145 return item_dict.items()
147 def ReadGitAliases(fname):
148 """Read a git alias file. This is in the form used by git:
150 alias uboot u-boot@lists.denx.de
151 alias wd Wolfgang Denk <wd@denx.de>
154 fname: Filename to read
157 fd = open(fname, 'r')
159 print "Warning: Cannot find alias file '%s'" % fname
162 re_line = re.compile('alias\s+(\S+)\s+(.*)')
163 for line in fd.readlines():
165 if not line or line[0] == '#':
168 m = re_line.match(line)
170 print "Warning: Alias file line '%s' not understood" % line
173 list = alias.get(m.group(1), [])
174 for item in m.group(2).split(','):
178 alias[m.group(1)] = list
182 def CreatePatmanConfigFile(config_fname):
183 """Creates a config file under $(HOME)/.patman if it can't find one.
186 config_fname: Default config filename i.e., $(HOME)/.patman
191 name = gitutil.GetDefaultUserName()
193 name = raw_input("Enter name: ")
195 email = gitutil.GetDefaultUserEmail()
198 email = raw_input("Enter email: ")
201 f = open(config_fname, 'w')
203 print "Couldn't create patman config file\n"
206 print >>f, "[alias]\nme: %s <%s>" % (name, email)
209 def _UpdateDefaults(parser, config):
210 """Update the given OptionParser defaults based on config.
212 We'll walk through all of the settings from the parser
213 For each setting we'll look for a default in the option parser.
214 If it's found we'll update the option parser default.
216 The idea here is that the .patman file should be able to update
217 defaults but that command line flags should still have the final
221 parser: An instance of an OptionParser whose defaults will be
223 config: An instance of _ProjectConfigParser that we will query
226 defaults = parser.get_default_values()
227 for name, val in config.items('settings'):
228 if hasattr(defaults, name):
229 default_val = getattr(defaults, name)
230 if isinstance(default_val, bool):
231 val = config.getboolean('settings', name)
232 elif isinstance(default_val, int):
233 val = config.getint('settings', name)
234 parser.set_default(name, val)
236 print "WARNING: Unknown setting %s" % name
238 def _ReadAliasFile(fname):
239 """Read in the U-Boot git alias file if it exists.
242 fname: Filename to read.
244 if os.path.exists(fname):
246 with open(fname) as fd:
251 if not line or line.startswith('#'):
253 words = line.split(' ', 2)
254 if len(words) < 3 or words[0] != 'alias':
256 bad_line = "%s:%d:Invalid line '%s'" % (fname, linenum,
259 alias[words[1]] = [s.strip() for s in words[2].split(',')]
263 def Setup(parser, project_name, config_fname=''):
264 """Set up the settings module by reading config files.
267 parser: The parser to update
268 project_name: Name of project that we're working on; we'll look
269 for sections named "project_section" as well.
270 config_fname: Config filename to read ('' for default)
272 # First read the git alias file if available
273 _ReadAliasFile('doc/git-mailrc')
274 config = _ProjectConfigParser(project_name)
275 if config_fname == '':
276 config_fname = '%s/.patman' % os.getenv('HOME')
278 if not os.path.exists(config_fname):
279 print "No config file found ~/.patman\nCreating one...\n"
280 CreatePatmanConfigFile(config_fname)
282 config.read(config_fname)
284 for name, value in config.items('alias'):
285 alias[name] = value.split(',')
287 _UpdateDefaults(parser, config)
289 # These are the aliases we understand, indexed by alias. Each member is a list.
292 if __name__ == "__main__":