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