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")
215 print("[alias]\nme: %s <%s>" % (name, email), file=f)
218 def _UpdateDefaults(parser, config):
219 """Update the given OptionParser defaults based on config.
221 We'll walk through all of the settings from the parser
222 For each setting we'll look for a default in the option parser.
223 If it's found we'll update the option parser default.
225 The idea here is that the .patman file should be able to update
226 defaults but that command line flags should still have the final
230 parser: An instance of an OptionParser whose defaults will be
232 config: An instance of _ProjectConfigParser that we will query
235 defaults = parser.get_default_values()
236 for name, val in config.items('settings'):
237 if hasattr(defaults, name):
238 default_val = getattr(defaults, name)
239 if isinstance(default_val, bool):
240 val = config.getboolean('settings', name)
241 elif isinstance(default_val, int):
242 val = config.getint('settings', name)
243 parser.set_default(name, val)
245 print("WARNING: Unknown setting %s" % name)
247 def _ReadAliasFile(fname):
248 """Read in the U-Boot git alias file if it exists.
251 fname: Filename to read.
253 if os.path.exists(fname):
255 with open(fname) as fd:
260 if not line or line.startswith('#'):
262 words = line.split(' ', 2)
263 if len(words) < 3 or words[0] != 'alias':
265 bad_line = "%s:%d:Invalid line '%s'" % (fname, linenum,
268 alias[words[1]] = [s.strip() for s in words[2].split(',')]
272 def Setup(parser, project_name, config_fname=''):
273 """Set up the settings module by reading config files.
276 parser: The parser to update
277 project_name: Name of project that we're working on; we'll look
278 for sections named "project_section" as well.
279 config_fname: Config filename to read ('' for default)
281 # First read the git alias file if available
282 _ReadAliasFile('doc/git-mailrc')
283 config = _ProjectConfigParser(project_name)
284 if config_fname == '':
285 config_fname = '%s/.patman' % os.getenv('HOME')
287 if not os.path.exists(config_fname):
288 print("No config file found ~/.patman\nCreating one...\n")
289 CreatePatmanConfigFile(config_fname)
291 config.read(config_fname)
293 for name, value in config.items('alias'):
294 alias[name] = value.split(',')
296 _UpdateDefaults(parser, config)
298 # These are the aliases we understand, indexed by alias. Each member is a list.
301 if __name__ == "__main__":