i2c: muxes: pca954x: Add support for GPIO reset line
[platform/kernel/u-boot.git] / 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     >>> try:
40     ...     from StringIO import StringIO
41     ... except ImportError:
42     ...     from io import StringIO
43     >>> sample_config = '''
44     ... [alias]
45     ... me: Peter P. <likesspiders@example.com>
46     ... enemies: Evil <evil@example.com>
47     ...
48     ... [sm_alias]
49     ... enemies: Green G. <ugly@example.com>
50     ...
51     ... [sm2_alias]
52     ... enemies: Doc O. <pus@example.com>
53     ...
54     ... [settings]
55     ... am_hero: True
56     ... '''
57
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>'
63
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>'
69
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')]
75
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"))
80     [('am_hero', 'True')]
81     """
82     def __init__(self, project_name):
83         """Construct _ProjectConfigParser.
84
85         In addition to standard SafeConfigParser initialization, this also loads
86         project defaults.
87
88         Args:
89             project_name: The name of the project.
90         """
91         self._project_name = project_name
92         ConfigParser.SafeConfigParser.__init__(self)
93
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)
102
103     def get(self, section, option, *args, **kwargs):
104         """Extend SafeConfigParser to try project_section before section.
105
106         Args:
107             See SafeConfigParser.
108         Returns:
109             See SafeConfigParser.
110         """
111         try:
112             return ConfigParser.SafeConfigParser.get(
113                 self, "%s_%s" % (self._project_name, section), option,
114                 *args, **kwargs
115             )
116         except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
117             return ConfigParser.SafeConfigParser.get(
118                 self, section, option, *args, **kwargs
119             )
120
121     def items(self, section, *args, **kwargs):
122         """Extend SafeConfigParser to add project_section to section.
123
124         Args:
125             See SafeConfigParser.
126         Returns:
127             See SafeConfigParser.
128         """
129         project_items = []
130         has_project_section = False
131         top_items = []
132
133         # Get items from the project section
134         try:
135             project_items = ConfigParser.SafeConfigParser.items(
136                 self, "%s_%s" % (self._project_name, section), *args, **kwargs
137             )
138             has_project_section = True
139         except ConfigParser.NoSectionError:
140             pass
141
142         # Get top-level items
143         try:
144             top_items = ConfigParser.SafeConfigParser.items(
145                 self, section, *args, **kwargs
146             )
147         except ConfigParser.NoSectionError:
148             # If neither section exists raise the error on...
149             if not has_project_section:
150                 raise
151
152         item_dict = dict(top_items)
153         item_dict.update(project_items)
154         return item_dict.items()
155
156 def ReadGitAliases(fname):
157     """Read a git alias file. This is in the form used by git:
158
159     alias uboot  u-boot@lists.denx.de
160     alias wd     Wolfgang Denk <wd@denx.de>
161
162     Args:
163         fname: Filename to read
164     """
165     try:
166         fd = open(fname, 'r')
167     except IOError:
168         print("Warning: Cannot find alias file '%s'" % fname)
169         return
170
171     re_line = re.compile('alias\s+(\S+)\s+(.*)')
172     for line in fd.readlines():
173         line = line.strip()
174         if not line or line[0] == '#':
175             continue
176
177         m = re_line.match(line)
178         if not m:
179             print("Warning: Alias file line '%s' not understood" % line)
180             continue
181
182         list = alias.get(m.group(1), [])
183         for item in m.group(2).split(','):
184             item = item.strip()
185             if item:
186                 list.append(item)
187         alias[m.group(1)] = list
188
189     fd.close()
190
191 def CreatePatmanConfigFile(config_fname):
192     """Creates a config file under $(HOME)/.patman if it can't find one.
193
194     Args:
195         config_fname: Default config filename i.e., $(HOME)/.patman
196
197     Returns:
198         None
199     """
200     name = gitutil.GetDefaultUserName()
201     if name == None:
202         name = raw_input("Enter name: ")
203
204     email = gitutil.GetDefaultUserEmail()
205
206     if email == None:
207         email = raw_input("Enter email: ")
208
209     try:
210         f = open(config_fname, 'w')
211     except IOError:
212         print("Couldn't create patman config file\n")
213         raise
214
215     print("[alias]\nme: %s <%s>" % (name, email), file=f)
216     f.close();
217
218 def _UpdateDefaults(parser, config):
219     """Update the given OptionParser defaults based on config.
220
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.
224
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
227     say.
228
229     Args:
230         parser: An instance of an OptionParser whose defaults will be
231             updated.
232         config: An instance of _ProjectConfigParser that we will query
233             for settings.
234     """
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)
244         else:
245             print("WARNING: Unknown setting %s" % name)
246
247 def _ReadAliasFile(fname):
248     """Read in the U-Boot git alias file if it exists.
249
250     Args:
251         fname: Filename to read.
252     """
253     if os.path.exists(fname):
254         bad_line = None
255         with open(fname) as fd:
256             linenum = 0
257             for line in fd:
258                 linenum += 1
259                 line = line.strip()
260                 if not line or line.startswith('#'):
261                     continue
262                 words = line.split(' ', 2)
263                 if len(words) < 3 or words[0] != 'alias':
264                     if not bad_line:
265                         bad_line = "%s:%d:Invalid line '%s'" % (fname, linenum,
266                                                                 line)
267                     continue
268                 alias[words[1]] = [s.strip() for s in words[2].split(',')]
269         if bad_line:
270             print(bad_line)
271
272 def _ReadBouncesFile(fname):
273     """Read in the bounces file if it exists
274
275     Args:
276         fname: Filename to read.
277     """
278     if os.path.exists(fname):
279         with open(fname) as fd:
280             for line in fd:
281                 if line.startswith('#'):
282                     continue
283                 bounces.add(line.strip())
284
285 def Setup(parser, project_name, config_fname=''):
286     """Set up the settings module by reading config files.
287
288     Args:
289         parser:         The parser to update
290         project_name:   Name of project that we're working on; we'll look
291             for sections named "project_section" as well.
292         config_fname:   Config filename to read ('' for default)
293     """
294     # First read the git alias file if available
295     _ReadAliasFile('doc/git-mailrc')
296     config = _ProjectConfigParser(project_name)
297     if config_fname == '':
298         config_fname = '%s/.patman' % os.getenv('HOME')
299
300     if not os.path.exists(config_fname):
301         print("No config file found ~/.patman\nCreating one...\n")
302         CreatePatmanConfigFile(config_fname)
303
304     config.read(config_fname)
305
306     for name, value in config.items('alias'):
307         alias[name] = value.split(',')
308
309     _ReadBouncesFile('doc/bounces')
310     for name, value in config.items('bounces'):
311         bounces.add(value)
312
313     _UpdateDefaults(parser, config)
314
315 # These are the aliases we understand, indexed by alias. Each member is a list.
316 alias = {}
317 bounces = set()
318
319 if __name__ == "__main__":
320     import doctest
321
322     doctest.testmod()