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 ... from StringIO import StringIO
41 ... except ImportError:
42 ... from io import StringIO
43 >>> sample_config = '''
45 ... me: Peter P. <likesspiders@example.com>
46 ... enemies: Evil <evil@example.com>
49 ... enemies: Green G. <ugly@example.com>
52 ... enemies: Doc O. <pus@example.com>
58 # Check to make sure that bogus project gets general alias.
59 >>> config = _ProjectConfigParser("zzz")
60 >>> config.readfp(StringIO(sample_config))
61 >>> config.get("alias", "enemies")
62 'Evil <evil@example.com>'
64 # Check to make sure that alias gets overridden by project.
65 >>> config = _ProjectConfigParser("sm")
66 >>> config.readfp(StringIO(sample_config))
67 >>> config.get("alias", "enemies")
68 'Green G. <ugly@example.com>'
70 # Check to make sure that settings get merged with project.
71 >>> config = _ProjectConfigParser("linux")
72 >>> config.readfp(StringIO(sample_config))
73 >>> sorted(config.items("settings"))
74 [('am_hero', 'True'), ('process_tags', 'False')]
76 # Check to make sure that settings works with unknown project.
77 >>> config = _ProjectConfigParser("unknown")
78 >>> config.readfp(StringIO(sample_config))
79 >>> sorted(config.items("settings"))
82 def __init__(self, project_name):
83 """Construct _ProjectConfigParser.
85 In addition to standard SafeConfigParser initialization, this also loads
89 project_name: The name of the project.
91 self._project_name = project_name
92 ConfigParser.SafeConfigParser.__init__(self)
94 # Update the project settings in the config based on
95 # the _default_settings global.
96 project_settings = "%s_settings" % project_name
97 if not self.has_section(project_settings):
98 self.add_section(project_settings)
99 project_defaults = _default_settings.get(project_name, {})
100 for setting_name, setting_value in project_defaults.items():
101 self.set(project_settings, setting_name, setting_value)
103 def get(self, section, option, *args, **kwargs):
104 """Extend SafeConfigParser to try project_section before section.
107 See SafeConfigParser.
109 See SafeConfigParser.
112 return ConfigParser.SafeConfigParser.get(
113 self, "%s_%s" % (self._project_name, section), option,
116 except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
117 return ConfigParser.SafeConfigParser.get(
118 self, section, option, *args, **kwargs
121 def items(self, section, *args, **kwargs):
122 """Extend SafeConfigParser to add project_section to section.
125 See SafeConfigParser.
127 See SafeConfigParser.
130 has_project_section = False
133 # Get items from the project section
135 project_items = ConfigParser.SafeConfigParser.items(
136 self, "%s_%s" % (self._project_name, section), *args, **kwargs
138 has_project_section = True
139 except ConfigParser.NoSectionError:
142 # Get top-level items
144 top_items = ConfigParser.SafeConfigParser.items(
145 self, section, *args, **kwargs
147 except ConfigParser.NoSectionError:
148 # If neither section exists raise the error on...
149 if not has_project_section:
152 item_dict = dict(top_items)
153 item_dict.update(project_items)
154 return item_dict.items()
156 def ReadGitAliases(fname):
157 """Read a git alias file. This is in the form used by git:
159 alias uboot u-boot@lists.denx.de
160 alias wd Wolfgang Denk <wd@denx.de>
163 fname: Filename to read
166 fd = open(fname, 'r')
168 print("Warning: Cannot find alias file '%s'" % fname)
171 re_line = re.compile('alias\s+(\S+)\s+(.*)')
172 for line in fd.readlines():
174 if not line or line[0] == '#':
177 m = re_line.match(line)
179 print("Warning: Alias file line '%s' not understood" % line)
182 list = alias.get(m.group(1), [])
183 for item in m.group(2).split(','):
187 alias[m.group(1)] = list
191 def CreatePatmanConfigFile(config_fname):
192 """Creates a config file under $(HOME)/.patman if it can't find one.
195 config_fname: Default config filename i.e., $(HOME)/.patman
200 name = gitutil.GetDefaultUserName()
202 name = raw_input("Enter name: ")
204 email = gitutil.GetDefaultUserEmail()
207 email = raw_input("Enter email: ")
210 f = open(config_fname, 'w')
212 print("Couldn't create patman config file\n")
219 nxp = Zhikang Zhang <zhikang.zhang@nxp.com>
220 ''' % (name, email), file=f)
223 def _UpdateDefaults(parser, config):
224 """Update the given OptionParser defaults based on config.
226 We'll walk through all of the settings from the parser
227 For each setting we'll look for a default in the option parser.
228 If it's found we'll update the option parser default.
230 The idea here is that the .patman file should be able to update
231 defaults but that command line flags should still have the final
235 parser: An instance of an OptionParser whose defaults will be
237 config: An instance of _ProjectConfigParser that we will query
240 defaults = parser.get_default_values()
241 for name, val in config.items('settings'):
242 if hasattr(defaults, name):
243 default_val = getattr(defaults, name)
244 if isinstance(default_val, bool):
245 val = config.getboolean('settings', name)
246 elif isinstance(default_val, int):
247 val = config.getint('settings', name)
248 parser.set_default(name, val)
250 print("WARNING: Unknown setting %s" % name)
252 def _ReadAliasFile(fname):
253 """Read in the U-Boot git alias file if it exists.
256 fname: Filename to read.
258 if os.path.exists(fname):
260 with open(fname) as fd:
265 if not line or line.startswith('#'):
267 words = line.split(' ', 2)
268 if len(words) < 3 or words[0] != 'alias':
270 bad_line = "%s:%d:Invalid line '%s'" % (fname, linenum,
273 alias[words[1]] = [s.strip() for s in words[2].split(',')]
277 def _ReadBouncesFile(fname):
278 """Read in the bounces file if it exists
281 fname: Filename to read.
283 if os.path.exists(fname):
284 with open(fname) as fd:
286 if line.startswith('#'):
288 bounces.add(line.strip())
290 def GetItems(config, section):
291 """Get the items from a section of the config.
294 config: _ProjectConfigParser object containing settings
295 section: name of section to retrieve
298 List of (name, value) tuples for the section
301 return config.items(section)
302 except ConfigParser.NoSectionError as e:
307 def Setup(parser, project_name, config_fname=''):
308 """Set up the settings module by reading config files.
311 parser: The parser to update
312 project_name: Name of project that we're working on; we'll look
313 for sections named "project_section" as well.
314 config_fname: Config filename to read ('' for default)
316 # First read the git alias file if available
317 _ReadAliasFile('doc/git-mailrc')
318 config = _ProjectConfigParser(project_name)
319 if config_fname == '':
320 config_fname = '%s/.patman' % os.getenv('HOME')
322 if not os.path.exists(config_fname):
323 print("No config file found ~/.patman\nCreating one...\n")
324 CreatePatmanConfigFile(config_fname)
326 config.read(config_fname)
328 for name, value in GetItems(config, 'alias'):
329 alias[name] = value.split(',')
331 _ReadBouncesFile('doc/bounces')
332 for name, value in GetItems(config, 'bounces'):
335 _UpdateDefaults(parser, config)
337 # These are the aliases we understand, indexed by alias. Each member is a list.
341 if __name__ == "__main__":