]> git.sur5r.net Git - u-boot/blob - tools/patman/settings.py
patman: Import 'configparser' lower case to be python 3.x safe
[u-boot] / tools / patman / settings.py
1 # Copyright (c) 2011 The Chromium OS Authors.
2 #
3 # SPDX-License-Identifier:      GPL-2.0+
4 #
5
6 from __future__ import print_function
7
8 try:
9     import configparser as ConfigParser
10 except:
11     import ConfigParser
12
13 import os
14 import re
15
16 import command
17 import gitutil
18
19 """Default settings per-project.
20
21 These are used by _ProjectConfigParser.  Settings names should match
22 the "dest" of the option parser from patman.py.
23 """
24 _default_settings = {
25     "u-boot": {},
26     "linux": {
27         "process_tags": "False",
28     }
29 }
30
31 class _ProjectConfigParser(ConfigParser.SafeConfigParser):
32     """ConfigParser that handles projects.
33
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.
37
38     # Sample config used for tests below...
39     >>> import StringIO
40     >>> sample_config = '''
41     ... [alias]
42     ... me: Peter P. <likesspiders@example.com>
43     ... enemies: Evil <evil@example.com>
44     ...
45     ... [sm_alias]
46     ... enemies: Green G. <ugly@example.com>
47     ...
48     ... [sm2_alias]
49     ... enemies: Doc O. <pus@example.com>
50     ...
51     ... [settings]
52     ... am_hero: True
53     ... '''
54
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>'
60
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>'
66
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')]
72
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"))
77     [('am_hero', 'True')]
78     """
79     def __init__(self, project_name):
80         """Construct _ProjectConfigParser.
81
82         In addition to standard SafeConfigParser initialization, this also loads
83         project defaults.
84
85         Args:
86             project_name: The name of the project.
87         """
88         self._project_name = project_name
89         ConfigParser.SafeConfigParser.__init__(self)
90
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)
99
100     def get(self, section, option, *args, **kwargs):
101         """Extend SafeConfigParser to try project_section before section.
102
103         Args:
104             See SafeConfigParser.
105         Returns:
106             See SafeConfigParser.
107         """
108         try:
109             return ConfigParser.SafeConfigParser.get(
110                 self, "%s_%s" % (self._project_name, section), option,
111                 *args, **kwargs
112             )
113         except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
114             return ConfigParser.SafeConfigParser.get(
115                 self, section, option, *args, **kwargs
116             )
117
118     def items(self, section, *args, **kwargs):
119         """Extend SafeConfigParser to add project_section to section.
120
121         Args:
122             See SafeConfigParser.
123         Returns:
124             See SafeConfigParser.
125         """
126         project_items = []
127         has_project_section = False
128         top_items = []
129
130         # Get items from the project section
131         try:
132             project_items = ConfigParser.SafeConfigParser.items(
133                 self, "%s_%s" % (self._project_name, section), *args, **kwargs
134             )
135             has_project_section = True
136         except ConfigParser.NoSectionError:
137             pass
138
139         # Get top-level items
140         try:
141             top_items = ConfigParser.SafeConfigParser.items(
142                 self, section, *args, **kwargs
143             )
144         except ConfigParser.NoSectionError:
145             # If neither section exists raise the error on...
146             if not has_project_section:
147                 raise
148
149         item_dict = dict(top_items)
150         item_dict.update(project_items)
151         return item_dict.items()
152
153 def ReadGitAliases(fname):
154     """Read a git alias file. This is in the form used by git:
155
156     alias uboot  u-boot@lists.denx.de
157     alias wd     Wolfgang Denk <wd@denx.de>
158
159     Args:
160         fname: Filename to read
161     """
162     try:
163         fd = open(fname, 'r')
164     except IOError:
165         print("Warning: Cannot find alias file '%s'" % fname)
166         return
167
168     re_line = re.compile('alias\s+(\S+)\s+(.*)')
169     for line in fd.readlines():
170         line = line.strip()
171         if not line or line[0] == '#':
172             continue
173
174         m = re_line.match(line)
175         if not m:
176             print("Warning: Alias file line '%s' not understood" % line)
177             continue
178
179         list = alias.get(m.group(1), [])
180         for item in m.group(2).split(','):
181             item = item.strip()
182             if item:
183                 list.append(item)
184         alias[m.group(1)] = list
185
186     fd.close()
187
188 def CreatePatmanConfigFile(config_fname):
189     """Creates a config file under $(HOME)/.patman if it can't find one.
190
191     Args:
192         config_fname: Default config filename i.e., $(HOME)/.patman
193
194     Returns:
195         None
196     """
197     name = gitutil.GetDefaultUserName()
198     if name == None:
199         name = raw_input("Enter name: ")
200
201     email = gitutil.GetDefaultUserEmail()
202
203     if email == None:
204         email = raw_input("Enter email: ")
205
206     try:
207         f = open(config_fname, 'w')
208     except IOError:
209         print("Couldn't create patman config file\n")
210         raise
211
212     print("[alias]\nme: %s <%s>" % (name, email), file=f)
213     f.close();
214
215 def _UpdateDefaults(parser, config):
216     """Update the given OptionParser defaults based on config.
217
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.
221
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
224     say.
225
226     Args:
227         parser: An instance of an OptionParser whose defaults will be
228             updated.
229         config: An instance of _ProjectConfigParser that we will query
230             for settings.
231     """
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)
241         else:
242             print("WARNING: Unknown setting %s" % name)
243
244 def _ReadAliasFile(fname):
245     """Read in the U-Boot git alias file if it exists.
246
247     Args:
248         fname: Filename to read.
249     """
250     if os.path.exists(fname):
251         bad_line = None
252         with open(fname) as fd:
253             linenum = 0
254             for line in fd:
255                 linenum += 1
256                 line = line.strip()
257                 if not line or line.startswith('#'):
258                     continue
259                 words = line.split(' ', 2)
260                 if len(words) < 3 or words[0] != 'alias':
261                     if not bad_line:
262                         bad_line = "%s:%d:Invalid line '%s'" % (fname, linenum,
263                                                                 line)
264                     continue
265                 alias[words[1]] = [s.strip() for s in words[2].split(',')]
266         if bad_line:
267             print(bad_line)
268
269 def Setup(parser, project_name, config_fname=''):
270     """Set up the settings module by reading config files.
271
272     Args:
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)
277     """
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')
283
284     if not os.path.exists(config_fname):
285         print("No config file found ~/.patman\nCreating one...\n")
286         CreatePatmanConfigFile(config_fname)
287
288     config.read(config_fname)
289
290     for name, value in config.items('alias'):
291         alias[name] = value.split(',')
292
293     _UpdateDefaults(parser, config)
294
295 # These are the aliases we understand, indexed by alias. Each member is a list.
296 alias = {}
297
298 if __name__ == "__main__":
299     import doctest
300
301     doctest.testmod()