1# This Source Code Form is subject to the terms of the Mozilla Public
2# License, v. 2.0. If a copy of the MPL was not distributed with this file,
3# You can obtain one at http://mozilla.org/MPL/2.0/.
4
5# This file contains utility functions for reading .properties files, like
6# region.properties.
7
8from __future__ import absolute_import, unicode_literals
9
10import codecs
11import re
12import sys
13
14if sys.version_info[0] == 3:
15    str_type = str
16else:
17    str_type = basestring
18
19class DotProperties:
20    r'''A thin representation of a key=value .properties file.'''
21
22    def __init__(self, file=None):
23        self._properties = {}
24        if file:
25            self.update(file)
26
27    def update(self, file):
28        '''Updates properties from a file name or file-like object.
29
30        Ignores empty lines and comment lines.'''
31
32        if isinstance(file, str_type):
33            f = codecs.open(file, 'r', 'utf-8')
34        else:
35            f = file
36
37        for l in f.readlines():
38            line = l.strip()
39            if not line or line.startswith('#'):
40                continue
41            (k, v) = re.split('\s*=\s*', line, 1)
42            self._properties[k] = v
43
44    def get(self, key, default=None):
45        return self._properties.get(key, default)
46
47    def get_list(self, prefix):
48        '''Turns {'list.0':'foo', 'list.1':'bar'} into ['foo', 'bar'].
49
50        Returns [] to indicate an empty or missing list.'''
51
52        if not prefix.endswith('.'):
53            prefix = prefix + '.'
54        indexes = []
55        for k, v in self._properties.iteritems():
56            if not k.startswith(prefix):
57                continue
58            key = k[len(prefix):]
59            if '.' in key:
60                # We have something like list.sublist.0.
61                continue
62            indexes.append(int(key))
63        return [self._properties[prefix + str(index)] for index in sorted(indexes)]
64
65    def get_dict(self, prefix, required_keys=[]):
66        '''Turns {'foo.title':'title', ...} into {'title':'title', ...}.
67
68        If |required_keys| is present, it must be an iterable of required key
69        names.  If a required key is not present, ValueError is thrown.
70
71        Returns {} to indicate an empty or missing dict.'''
72
73        if not prefix.endswith('.'):
74            prefix = prefix + '.'
75
76        D = dict((k[len(prefix):], v) for k, v in self._properties.iteritems()
77                 if k.startswith(prefix) and '.' not in k[len(prefix):])
78
79        for required_key in required_keys:
80            if not required_key in D:
81                raise ValueError('Required key %s not present' % required_key)
82
83        return D
84