Left: | ||
Right: |
OLD | NEW |
---|---|
(Empty) | |
1 # coding: utf-8 | |
2 | |
3 # This file is part of the Adblock Plus build tools, | |
4 # Copyright (C) 2006-2012 Eyeo GmbH | |
5 # | |
6 # Adblock Plus is free software: you can redistribute it and/or modify | |
7 # it under the terms of the GNU General Public License version 3 as | |
8 # published by the Free Software Foundation. | |
9 # | |
10 # Adblock Plus is distributed in the hope that it will be useful, | |
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 # GNU General Public License for more details. | |
14 # | |
15 # You should have received a copy of the GNU General Public License | |
16 # along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. | |
17 | |
18 # Note: These are the base functions common to all packagers, the actual | |
19 # packagers are implemented in packagerGecko and packagerChrome. | |
20 | |
21 import os, codecs, ConfigParser | |
22 | |
23 class ChainedConfigParser: | |
Sebastian Noack
2013/11/05 12:19:38
I find this approach slightly overkill. I would pr
Wladimir Palant
2013/11/05 12:45:38
That was a consideration of course. However, we ne
Sebastian Noack
2013/11/05 13:13:25
Fair enough, LGTM.
| |
24 """ | |
25 This class provides essentially the same interfaces as SafeConfigParser but | |
26 allows chaining configuration files so that one config file provides the | |
27 default values for the other. To specify the config file to inherit from | |
28 a config file needs to contain the following option: | |
29 | |
30 [default] | |
31 inherit = foo/bar.config | |
32 | |
33 The value of the inherit option has to be a relative path with forward | |
34 slashes as delimiters. Up to 5 configuration files can be chained this way, | |
35 longer chains are disallowed to deal with circular references. | |
36 | |
37 A main API difference to SafeConfigParser is the way a class instance is | |
38 constructed: a file path has to be passed, this file is assumed to be | |
39 encoded as UTF-8. Also, ChainedConfigParser data is read-only and the | |
40 options are case-sensitive. | |
41 """ | |
42 | |
43 def __init__(self, path): | |
44 self.chain = [] | |
45 self.read_path(path) | |
46 | |
47 def read_path(self, path): | |
48 if len(self.chain) >= 5: | |
49 raise Exception('Too much inheritance in config files') | |
50 | |
51 config = ConfigParser.SafeConfigParser() | |
52 config.optionxform = str | |
53 handle = codecs.open(path, 'rb', encoding='utf-8') | |
54 config.readfp(handle) | |
55 handle.close() | |
56 self.chain.append(config) | |
57 | |
58 if config.has_section('default') and config.has_option('default', 'inherit') : | |
59 parts = config.get('default', 'inherit').split('/') | |
60 defaults_path = os.path.join(os.path.dirname(path), *parts) | |
61 self.read_path(defaults_path) | |
62 | |
63 def defaults(self): | |
64 result = {} | |
65 for config in reverse(self.chain): | |
66 for key, value in config.defaults().iteritems(): | |
67 result[key] = value | |
68 return result | |
69 | |
70 def sections(self): | |
71 result = set() | |
72 for config in self.chain: | |
73 for section in config.sections(): | |
74 result.add(section) | |
75 return list(result) | |
76 | |
77 def has_section(self, section): | |
78 for config in self.chain: | |
79 if config.has_section(section): | |
80 return True | |
81 return False | |
82 | |
83 def options(self, section): | |
84 result = set() | |
85 for config in self.chain: | |
86 if config.has_section(section): | |
87 for option in config.options(section): | |
88 result.add(option) | |
89 return list(result) | |
90 | |
91 def has_option(self, section, option): | |
92 for config in self.chain: | |
93 if config.has_section(section) and config.has_option(section, option): | |
94 return True | |
95 return False | |
96 | |
97 def get(self, section, option): | |
98 for config in self.chain: | |
99 if config.has_section(section) and config.has_option(section, option): | |
100 return config.get(section, option) | |
101 raise ConfigParser.NoOptionError(option, section) | |
102 | |
103 def items(self, section): | |
104 seen = set() | |
105 result = [] | |
106 for config in self.chain: | |
107 if config.has_section(section): | |
108 for name, value in config.items(section): | |
109 if name not in seen: | |
110 seen.add(name) | |
111 result.append((name, value)) | |
112 return result | |
OLD | NEW |