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