moduleset.dtd svn layout template tags
[jhbuild.git] / jhbuild / monkeypatch.py
blob12ad8ba5f0963805d60c699625a9559556fb6fa3
1 # jhbuild - a build script for GNOME 1.x and 2.x
2 # Copyright (C) 2001-2006 James Henstridge
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 2 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 # extras not found in old versions of Python
20 import sys
21 import __builtin__
23 # Windows lacks all sorts of subprocess features that we need to kludge around
24 if sys.platform.startswith('win'):
25 from jhbuild.utils import subprocess_win32
26 sys.modules['subprocess'] = subprocess_win32
28 # Python < 2.4 lacks reversed() builtin
29 if not hasattr(__builtin__, 'reversed'):
30 def reversed(l):
31 l = list(l)
32 l.reverse()
33 return iter(l)
34 __builtin__.reversed = reversed
36 # Python < 2.4 lacks string.Template class
37 import string
38 if not hasattr(string, 'Template'):
39 import re as _re
41 class _multimap:
42 """Helper class for combining multiple mappings.
44 Used by .{safe_,}substitute() to combine the mapping and keyword
45 arguments.
46 """
47 def __init__(self, primary, secondary):
48 self._primary = primary
49 self._secondary = secondary
51 def __getitem__(self, key):
52 try:
53 return self._primary[key]
54 except KeyError:
55 return self._secondary[key]
58 class _TemplateMetaclass(type):
59 pattern = r"""
60 %(delim)s(?:
61 (?P<escaped>%(delim)s) | # Escape sequence of two delimiters
62 (?P<named>%(id)s) | # delimiter and a Python identifier
63 {(?P<braced>%(id)s)} | # delimiter and a braced identifier
64 (?P<invalid>) # Other ill-formed delimiter exprs
66 """
68 def __init__(cls, name, bases, dct):
69 super(_TemplateMetaclass, cls).__init__(name, bases, dct)
70 if 'pattern' in dct:
71 pattern = cls.pattern
72 else:
73 pattern = _TemplateMetaclass.pattern % {
74 'delim' : _re.escape(cls.delimiter),
75 'id' : cls.idpattern,
77 cls.pattern = _re.compile(pattern, _re.IGNORECASE | _re.VERBOSE)
80 class Template:
81 """A string class for supporting $-substitutions."""
82 __metaclass__ = _TemplateMetaclass
83 __module__ = 'string'
85 delimiter = '$'
86 idpattern = r'[_a-z][_a-z0-9]*'
88 def __init__(self, template):
89 self.template = template
91 # Search for $$, $identifier, ${identifier}, and any bare $'s
93 def _invalid(self, mo):
94 i = mo.start('invalid')
95 lines = self.template[:i].splitlines(True)
96 if not lines:
97 colno = 1
98 lineno = 1
99 else:
100 colno = i - len(''.join(lines[:-1]))
101 lineno = len(lines)
102 raise ValueError(_('Invalid placeholder in string: line %d, col %d') %
103 (lineno, colno))
105 def substitute(self, *args, **kws):
106 if len(args) > 1:
107 raise TypeError(_('Too many positional arguments'))
108 if not args:
109 mapping = kws
110 elif kws:
111 mapping = _multimap(kws, args[0])
112 else:
113 mapping = args[0]
114 # Helper function for .sub()
115 def convert(mo):
116 # Check the most common path first.
117 named = mo.group('named') or mo.group('braced')
118 if named is not None:
119 val = mapping[named]
120 # We use this idiom instead of str() because the latter will
121 # fail if val is a Unicode containing non-ASCII characters.
122 return '%s' % val
123 if mo.group('escaped') is not None:
124 return self.delimiter
125 if mo.group('invalid') is not None:
126 self._invalid(mo)
127 raise ValueError(_('Unrecognized named group in pattern'),
128 self.pattern)
129 return self.pattern.sub(convert, self.template)
131 def safe_substitute(self, *args, **kws):
132 if len(args) > 1:
133 raise TypeError(_('Too many positional arguments'))
134 if not args:
135 mapping = kws
136 elif kws:
137 mapping = _multimap(kws, args[0])
138 else:
139 mapping = args[0]
140 # Helper function for .sub()
141 def convert(mo):
142 named = mo.group('named')
143 if named is not None:
144 try:
145 # We use this idiom instead of str() because the latter
146 # will fail if val is a Unicode containing non-ASCII
147 return '%s' % mapping[named]
148 except KeyError:
149 return self.delimiter + named
150 braced = mo.group('braced')
151 if braced is not None:
152 try:
153 return '%s' % mapping[braced]
154 except KeyError:
155 return self.delimiter + '{' + braced + '}'
156 if mo.group('escaped') is not None:
157 return self.delimiter
158 if mo.group('invalid') is not None:
159 return self.delimiter
160 raise ValueError(_('Unrecognized named group in pattern'),
161 self.pattern)
162 return self.pattern.sub(convert, self.template)
164 string.Template = Template
166 # Python < 2.4 lacks subprocess module
167 try:
168 import subprocess
169 except ImportError:
170 from jhbuild.cut_n_paste import subprocess
171 sys.modules['subprocess'] = subprocess