]> git.sur5r.net Git - u-boot/blob - tools/patman/settings.py
SPDX: Convert a few files that were missed before
[u-boot] / tools / patman / settings.py
1 # SPDX-License-Identifier: GPL-2.0+
2 # Copyright (c) 2011 The Chromium OS Authors.
3 #
4
5 from __future__ import print_function
6
7 try:
8     import configparser as ConfigParser
9 except:
10     import ConfigParser
11
12 import os
13 import re
14
15 import command
16 import gitutil
17
18 """Default settings per-project.
19
20 These are used by _ProjectConfigParser.  Settings names should match
21 the "dest" of the option parser from patman.py.
22 """
23 _default_settings = {
24     "u-boot": {},
25     "linux": {
26         "process_tags": "False",
27     }
28 }
29
30 class _ProjectConfigParser(ConfigParser.SafeConfigParser):
31     """ConfigParser that handles projects.
32
33     There are two main goals of this class:
34     - Load project-specific default settings.
35     - Merge general default settings/aliases with project-specific ones.
36
37     # Sample config used for tests below...
38     >>> try:
39     ...     from StringIO import StringIO
40     ... except ImportError:
41     ...     from io import StringIO
42     >>> sample_config = '''
43     ... [alias]
44     ... me: Peter P. <likesspiders@example.com>
45     ... enemies: Evil <evil@example.com>
46     ...
47     ... [sm_alias]
48     ... enemies: Green G. <ugly@example.com>
49     ...
50     ... [sm2_alias]
51     ... enemies: Doc O. <pus@example.com>
52     ...
53     ... [settings]
54     ... am_hero: True
55     ... '''
56
57     # Check to make sure that bogus project gets general alias.
58     >>> config = _ProjectConfigParser("zzz")
59     >>> config.readfp(StringIO(sample_config))
60     >>> config.get("alias", "enemies")
61     'Evil <evil@example.com>'
62
63     # Check to make sure that alias gets overridden by project.
64     >>> config = _ProjectConfigParser("sm")
65     >>> config.readfp(StringIO(sample_config))
66     >>> config.get("alias", "enemies")
67     'Green G. <ugly@example.com>'
68
69     # Check to make sure that settings get merged with project.
70     >>> config = _ProjectConfigParser("linux")
71     >>> config.readfp(StringIO(sample_config))
72     >>> sorted(config.items("settings"))
73     [('am_hero', 'True'), ('process_tags', 'False')]
74
75     # Check to make sure that settings works with unknown project.
76     >>> config = _ProjectConfigParser("unknown")
77     >>> config.readfp(StringIO(sample_config))
78     >>> sorted(config.items("settings"))
79     [('am_hero', 'True')]
80     """
81     def __init__(self, project_name):
82         """Construct _ProjectConfigParser.
83
84         In addition to standard SafeConfigParser initialization, this also loads
85         project defaults.
86
87         Args:
88             project_name: The name of the project.
89         """
90         self._project_name = project_name
91         ConfigParser.SafeConfigParser.__init__(self)
92
93         # Update the project settings in the config based on
94         # the _default_settings global.
95         project_settings = "%s_settings" % project_name
96         if not self.has_section(project_settings):
97             self.add_section(project_settings)
98         project_defaults = _default_settings.get(project_name, {})
99         for setting_name, setting_value in project_defaults.items():
100             self.set(project_settings, setting_name, setting_value)
101
102     def get(self, section, option, *args, **kwargs):
103         """Extend SafeConfigParser to try project_section before section.
104
105         Args:
106             See SafeConfigParser.
107         Returns:
108             See SafeConfigParser.
109         """
110         try:
111             return ConfigParser.SafeConfigParser.get(
112                 self, "%s_%s" % (self._project_name, section), option,
113                 *args, **kwargs
114             )
115         except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
116             return ConfigParser.SafeConfigParser.get(
117                 self, section, option, *args, **kwargs
118             )
119
120     def items(self, section, *args, **kwargs):
121         """Extend SafeConfigParser to add project_section to section.
122
123         Args:
124             See SafeConfigParser.
125         Returns:
126             See SafeConfigParser.
127         """
128         project_items = []
129         has_project_section = False
130         top_items = []
131
132         # Get items from the project section
133         try:
134             project_items = ConfigParser.SafeConfigParser.items(
135                 self, "%s_%s" % (self._project_name, section), *args, **kwargs
136             )
137             has_project_section = True
138         except ConfigParser.NoSectionError:
139             pass
140
141         # Get top-level items
142         try:
143             top_items = ConfigParser.SafeConfigParser.items(
144                 self, section, *args, **kwargs
145             )
146         except ConfigParser.NoSectionError:
147             # If neither section exists raise the error on...
148             if not has_project_section:
149                 raise
150
151         item_dict = dict(top_items)
152         item_dict.update(project_items)
153         return item_dict.items()
154
155 def ReadGitAliases(fname):
156     """Read a git alias file. This is in the form used by git:
157
158     alias uboot  u-boot@lists.denx.de
159     alias wd     Wolfgang Denk <wd@denx.de>
160
161     Args:
162         fname: Filename to read
163     """
164     try:
165         fd = open(fname, 'r')
166     except IOError:
167         print("Warning: Cannot find alias file '%s'" % fname)
168         return
169
170     re_line = re.compile('alias\s+(\S+)\s+(.*)')
171     for line in fd.readlines():
172         line = line.strip()
173         if not line or line[0] == '#':
174             continue
175
176         m = re_line.match(line)
177         if not m:
178             print("Warning: Alias file line '%s' not understood" % line)
179             continue
180
181         list = alias.get(m.group(1), [])
182         for item in m.group(2).split(','):
183             item = item.strip()
184             if item:
185                 list.append(item)
186         alias[m.group(1)] = list
187
188     fd.close()
189
190 def CreatePatmanConfigFile(config_fname):
191     """Creates a config file under $(HOME)/.patman if it can't find one.
192
193     Args:
194         config_fname: Default config filename i.e., $(HOME)/.patman
195
196     Returns:
197         None
198     """
199     name = gitutil.GetDefaultUserName()
200     if name == None:
201         name = raw_input("Enter name: ")
202
203     email = gitutil.GetDefaultUserEmail()
204
205     if email == None:
206         email = raw_input("Enter email: ")
207
208     try:
209         f = open(config_fname, 'w')
210     except IOError:
211         print("Couldn't create patman config file\n")
212         raise
213
214     print('''[alias]
215 me: %s <%s>
216
217 [bounces]
218 nxp = Zhikang Zhang <zhikang.zhang@nxp.com>
219 ''' % (name, email), file=f)
220     f.close();
221
222 def _UpdateDefaults(parser, config):
223     """Update the given OptionParser defaults based on config.
224
225     We'll walk through all of the settings from the parser
226     For each setting we'll look for a default in the option parser.
227     If it's found we'll update the option parser default.
228
229     The idea here is that the .patman file should be able to update
230     defaults but that command line flags should still have the final
231     say.
232
233     Args:
234         parser: An instance of an OptionParser whose defaults will be
235             updated.
236         config: An instance of _ProjectConfigParser that we will query
237             for settings.
238     """
239     defaults = parser.get_default_values()
240     for name, val in config.items('settings'):
241         if hasattr(defaults, name):
242             default_val = getattr(defaults, name)
243             if isinstance(default_val, bool):
244                 val = config.getboolean('settings', name)
245             elif isinstance(default_val, int):
246                 val = config.getint('settings', name)
247             parser.set_default(name, val)
248         else:
249             print("WARNING: Unknown setting %s" % name)
250
251 def _ReadAliasFile(fname):
252     """Read in the U-Boot git alias file if it exists.
253
254     Args:
255         fname: Filename to read.
256     """
257     if os.path.exists(fname):
258         bad_line = None
259         with open(fname) as fd:
260             linenum = 0
261             for line in fd:
262                 linenum += 1
263                 line = line.strip()
264                 if not line or line.startswith('#'):
265                     continue
266                 words = line.split(' ', 2)
267                 if len(words) < 3 or words[0] != 'alias':
268                     if not bad_line:
269                         bad_line = "%s:%d:Invalid line '%s'" % (fname, linenum,
270                                                                 line)
271                     continue
272                 alias[words[1]] = [s.strip() for s in words[2].split(',')]
273         if bad_line:
274             print(bad_line)
275
276 def _ReadBouncesFile(fname):
277     """Read in the bounces file if it exists
278
279     Args:
280         fname: Filename to read.
281     """
282     if os.path.exists(fname):
283         with open(fname) as fd:
284             for line in fd:
285                 if line.startswith('#'):
286                     continue
287                 bounces.add(line.strip())
288
289 def GetItems(config, section):
290     """Get the items from a section of the config.
291
292     Args:
293         config: _ProjectConfigParser object containing settings
294         section: name of section to retrieve
295
296     Returns:
297         List of (name, value) tuples for the section
298     """
299     try:
300         return config.items(section)
301     except ConfigParser.NoSectionError as e:
302         return []
303     except:
304         raise
305
306 def Setup(parser, project_name, config_fname=''):
307     """Set up the settings module by reading config files.
308
309     Args:
310         parser:         The parser to update
311         project_name:   Name of project that we're working on; we'll look
312             for sections named "project_section" as well.
313         config_fname:   Config filename to read ('' for default)
314     """
315     # First read the git alias file if available
316     _ReadAliasFile('doc/git-mailrc')
317     config = _ProjectConfigParser(project_name)
318     if config_fname == '':
319         config_fname = '%s/.patman' % os.getenv('HOME')
320
321     if not os.path.exists(config_fname):
322         print("No config file found ~/.patman\nCreating one...\n")
323         CreatePatmanConfigFile(config_fname)
324
325     config.read(config_fname)
326
327     for name, value in GetItems(config, 'alias'):
328         alias[name] = value.split(',')
329
330     _ReadBouncesFile('doc/bounces')
331     for name, value in GetItems(config, 'bounces'):
332         bounces.add(value)
333
334     _UpdateDefaults(parser, config)
335
336 # These are the aliases we understand, indexed by alias. Each member is a list.
337 alias = {}
338 bounces = set()
339
340 if __name__ == "__main__":
341     import doctest
342
343     doctest.testmod()