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