Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: chainedconfigparser.py

Issue 9190147: Allow metadata file to inherit values from another configuration file (Closed)
Patch Set: Created Jan. 18, 2013, 11:40 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | packager.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« no previous file with comments | « no previous file | packager.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld