[2.28] add raptor, used by tracker (GNOME #582754)
[jhbuild.git] / jhbuild / config.py
blobfdd1e9440a7b10840c32e76442fff1608355d2be
1 # jhbuild - a build script for GNOME 1.x and 2.x
2 # Copyright (C) 2001-2006 James Henstridge
3 # Copyright (C) 2007-2008 Frederic Peters
5 # config.py: configuration file parser
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 import os
22 import sys
23 import traceback
24 import types
25 import logging
27 from jhbuild.errors import UsageError, FatalError, CommandError
28 from jhbuild.utils.cmds import get_output
30 __all__ = [ 'Config' ]
32 _defaults_file = os.path.join(os.path.dirname(__file__), 'defaults.jhbuildrc')
33 _default_jhbuildrc = os.path.join(os.environ['HOME'], '.jhbuildrc')
35 _known_keys = [ 'moduleset', 'modules', 'skip', 'tags', 'prefix',
36 'checkoutroot', 'buildroot', 'autogenargs', 'makeargs',
37 'installprog', 'repos', 'branches', 'noxvfb', 'xvfbargs',
38 'builddir_pattern', 'module_autogenargs', 'module_makeargs',
39 'interact', 'buildscript', 'nonetwork',
40 'alwaysautogen', 'nobuild', 'makeclean', 'makecheck', 'module_makecheck',
41 'use_lib64', 'tinderbox_outputdir', 'sticky_date',
42 'tarballdir', 'pretty_print', 'svn_program', 'makedist',
43 'makedistcheck', 'nonotify', 'cvs_program',
44 'checkout_mode', 'copy_dir', 'module_checkout_mode',
45 'build_policy', 'trycheckout', 'min_time',
46 'nopoison', 'forcecheck', 'makecheck_advisory',
47 'quiet_mode', 'progress_bar', 'module_extra_env',
48 'jhbuildbot_master', 'jhbuildbot_slavename', 'jhbuildbot_password',
49 'jhbuildbot_svn_commits_box',
50 'use_local_modulesets', 'ignore_suggests', 'modulesets_dir',
51 'mirror_policy', 'module_mirror_policy', 'dvcs_mirror_dir',
54 env_prepends = {}
55 def prependpath(envvar, path):
56 env_prepends.setdefault(envvar, []).append(path)
58 def addpath(envvar, path):
59 '''Adds a path to an environment variable.'''
60 # special case ACLOCAL_FLAGS
61 if envvar in [ 'ACLOCAL_FLAGS' ]:
62 envval = os.environ.get(envvar, '-I %s' % path)
63 parts = ['-I', path] + envval.split()
64 i = 2
65 while i < len(parts)-1:
66 if parts[i] == '-I':
67 # check if "-I parts[i]" comes earlier
68 for j in range(0, i-1):
69 if parts[j] == '-I' and parts[j+1] == parts[i+1]:
70 del parts[i:i+2]
71 break
72 else:
73 i += 2
74 else:
75 i += 1
76 envval = ' '.join(parts)
77 elif envvar in [ 'LDFLAGS', 'CFLAGS', 'CXXFLAGS' ]:
78 envval = os.environ.get(envvar)
79 if envval:
80 envval = path + ' ' + envval
81 else:
82 envval = path
83 else:
84 envval = os.environ.get(envvar, path)
85 parts = envval.split(':')
86 parts.insert(0, path)
87 # remove duplicate entries:
88 i = 1
89 while i < len(parts):
90 if parts[i] in parts[:i]:
91 del parts[i]
92 elif envvar == 'PYTHONPATH' and parts[i] == "":
93 del parts[i]
94 else:
95 i += 1
96 envval = ':'.join(parts)
98 os.environ[envvar] = envval
100 class Config:
101 _orig_environ = None
103 def __init__(self, filename=_default_jhbuildrc):
104 self._config = {
105 '__file__': _defaults_file,
106 'addpath': addpath,
107 'prependpath': prependpath
110 if not self._orig_environ:
111 self.__dict__['_orig_environ'] = os.environ.copy()
113 try:
114 SRCDIR
115 except NameError:
116 raise FatalError(_('Obsolete jhbuild start script, do run \'make install\''))
118 env_prepends.clear()
119 try:
120 execfile(_defaults_file, self._config)
121 except:
122 traceback.print_exc()
123 raise FatalError(_('could not load config defaults'))
124 self._config['__file__'] = filename
125 self.filename = filename
126 if not os.path.exists(filename):
127 raise FatalError(_('could not load config file, %s is missing') % filename)
129 self.load()
130 self.setup_env()
132 def reload(self):
133 os.environ = self._orig_environ.copy()
134 self.__init__(filename=self._config.get('__file__'))
136 def load(self):
137 config = self._config
138 try:
139 execfile(self.filename, config)
140 except Exception:
141 traceback.print_exc()
142 raise FatalError(_('could not load config file'))
144 if not config.get('quiet_mode'):
145 unknown_keys = []
146 for k in config.keys():
147 if k in _known_keys + ['cvsroots', 'svnroots', 'cflags']:
148 continue
149 if k[0] == '_':
150 continue
151 if type(config[k]) in (types.ModuleType, types.FunctionType):
152 continue
153 unknown_keys.append(k)
154 if unknown_keys:
155 logging.info(
156 _('unknown keys defined in configuration file: %s') % \
157 ', '.join(unknown_keys))
159 # backward compatibility, from the days when jhbuild only
160 # supported Gnome.org CVS.
161 if config.get('cvsroot'):
162 logging.warning(
163 _('the "%s" configuration variable is deprecated, '
164 'you should use "repos[\'gnome.org\']".') % 'cvsroot')
165 config['repos'].update({'gnome.org': config['cvsroot']})
166 if config.get('cvsroots'):
167 logging.warning(
168 _('the "%s" configuration variable is deprecated, '
169 'you should use "repos".') % 'cvsroots')
170 config['repos'].update(config['cvsroots'])
171 if config.get('svnroots'):
172 logging.warning(
173 _('the "%s" configuration variable is deprecated, '
174 'you should use "repos".') % 'svnroots')
175 config['repos'].update(config['svnroots'])
177 # environment variables
178 if config.has_key('cflags') and config['cflags']:
179 os.environ['CFLAGS'] = config['cflags']
180 if config.get('installprog') and os.path.exists(config['installprog']):
181 os.environ['INSTALL'] = config['installprog']
183 # copy known config keys to attributes on the instance
184 for name in _known_keys:
185 setattr(self, name, config[name])
187 # default tarballdir to checkoutroot
188 if not self.tarballdir: self.tarballdir = self.checkoutroot
190 # check possible checkout_mode values
191 seen_copy_mode = (self.checkout_mode == 'copy')
192 possible_checkout_modes = ('update', 'clobber', 'export', 'copy')
193 if self.checkout_mode not in possible_checkout_modes:
194 raise FatalError(_('invalid checkout mode'))
195 for module, checkout_mode in self.module_checkout_mode.items():
196 seen_copy_mode = seen_copy_mode or (checkout_mode == 'copy')
197 if checkout_mode not in possible_checkout_modes:
198 raise FatalError(_('invalid checkout mode (module: %s)') % module)
199 if seen_copy_mode and not self.copy_dir:
200 raise FatalError(_('copy mode requires copy_dir to be set'))
202 if not os.path.exists(self.modulesets_dir):
203 if self.use_local_modulesets:
204 logging.warning(
205 _('modulesets directory (%s) not found, '
206 'disabling use_local_modulesets') % self.modulesets_dir)
207 self.use_local_modulesets = False
208 self.modulesets_dir = None
210 def setup_env(self):
211 '''set environment variables for using prefix'''
213 if not os.path.exists(self.prefix):
214 try:
215 os.makedirs(self.prefix)
216 except:
217 raise FatalError(_('install prefix (%s) can not be created') % self.prefix)
219 os.environ['UNMANGLED_LD_LIBRARY_PATH'] = os.environ.get('LD_LIBRARY_PATH', '')
221 # LD_LIBRARY_PATH
222 if self.use_lib64:
223 libdir = os.path.join(self.prefix, 'lib64')
224 else:
225 libdir = os.path.join(self.prefix, 'lib')
226 addpath('LD_LIBRARY_PATH', libdir)
228 # LDFLAGS and C_INCLUDE_PATH are required for autoconf configure
229 # scripts to find modules that do not use pkg-config (such as guile
230 # looking for gmp, or wireless-tools for NetworkManager)
231 # (see bug #377724 and bug #545018)
232 os.environ['LDFLAGS'] = ('-L%s ' % libdir) + os.environ.get('LDFLAGS', '')
233 includedir = os.path.join(self.prefix, 'include')
234 addpath('C_INCLUDE_PATH', includedir)
235 addpath('CPLUS_INCLUDE_PATH', includedir)
237 # On Mac OS X, we use DYLD_FALLBACK_LIBRARY_PATH
238 addpath('DYLD_FALLBACK_LIBRARY_PATH', libdir)
240 # PATH
241 bindir = os.path.join(self.prefix, 'bin')
242 addpath('PATH', bindir)
244 # MANPATH
245 manpathdir = os.path.join(self.prefix, 'share', 'man')
246 addpath('MANPATH', manpathdir)
248 # PKG_CONFIG_PATH
249 if os.environ.get('PKG_CONFIG_PATH') is None:
250 # add system pkgconfig lookup-directories by default, as pkg-config
251 # usage spread and is now used by libraries that are out of jhbuild
252 # realm; this also helps when building a single module with
253 # jhbuild. It is possible to avoid this by setting PKG_CONFIG_PATH
254 # to the empty string.
255 for dirname in ('share', 'lib', 'lib64'):
256 full_name = '/usr/%s/pkgconfig' % dirname
257 if os.path.exists(full_name):
258 addpath('PKG_CONFIG_PATH', full_name)
259 pkgconfigdatadir = os.path.join(self.prefix, 'share', 'pkgconfig')
260 pkgconfigdir = os.path.join(libdir, 'pkgconfig')
261 addpath('PKG_CONFIG_PATH', pkgconfigdatadir)
262 addpath('PKG_CONFIG_PATH', pkgconfigdir)
264 # XDG_DATA_DIRS
265 xdgdatadir = os.path.join(self.prefix, 'share')
266 addpath('XDG_DATA_DIRS', xdgdatadir)
268 # XDG_CONFIG_DIRS
269 xdgconfigdir = os.path.join(self.prefix, 'etc', 'xdg')
270 addpath('XDG_CONFIG_DIRS', xdgconfigdir)
272 # ACLOCAL_FLAGS
273 aclocaldir = os.path.join(self.prefix, 'share', 'aclocal')
274 if not os.path.exists(aclocaldir):
275 try:
276 os.makedirs(aclocaldir)
277 except:
278 raise FatalError(_("Can't create %s directory") % aclocaldir)
279 addpath('ACLOCAL_FLAGS', aclocaldir)
281 # PERL5LIB
282 perl5lib = os.path.join(self.prefix, 'lib', 'perl5')
283 addpath('PERL5LIB', perl5lib)
285 os.environ['CERTIFIED_GNOMIE'] = 'yes'
287 # PYTHONPATH
288 # Python inside jhbuild may be different than Python executing jhbuild,
289 # so it is executed to get its version number (fallback to local
290 # version number should never happen)
291 python_bin = os.environ.get('PYTHON', 'python')
292 try:
293 pythonversion = 'python' + get_output([python_bin, '-c',
294 'import sys; print ".".join([str(x) for x in sys.version_info[:2]])'],
295 get_stderr = False).strip()
296 except CommandError:
297 pythonversion = 'python' + str(sys.version_info[0]) + '.' + str(sys.version_info[1])
299 # In Python 2.6, site-packages got replaced by dist-packages, get the
300 # actual value by asking distutils
301 # <http://bugzilla.gnome.org/show_bug.cgi?id=575426>
302 try:
303 python_packages_dir = get_output([python_bin, 'c',
304 'import os, distutils.sysconfig; '\
305 'print distutils.sysconfig.get_python_lib(prefix="").split(os.path.sep)[-1]'],
306 get_stderr=False).strip()
307 except CommandError:
308 python_packages_dir = 'site-packages'
310 if self.use_lib64:
311 pythonpath = os.path.join(self.prefix, 'lib64', pythonversion, python_packages_dir)
312 addpath('PYTHONPATH', pythonpath)
313 if not os.path.exists(pythonpath):
314 os.makedirs(pythonpath)
316 pythonpath = os.path.join(self.prefix, 'lib', pythonversion, python_packages_dir)
317 addpath('PYTHONPATH', pythonpath)
318 if not os.path.exists(pythonpath):
319 os.makedirs(pythonpath)
321 # if there is a Python installed in JHBuild prefix, set it in PYTHON
322 # environment variable, so it gets picked up by configure scripts
323 # <http://bugzilla.gnome.org/show_bug.cgi?id=560872>
324 if os.path.exists(os.path.join(self.prefix, 'bin', 'python')):
325 os.environ['PYTHON'] = os.path.join(self.prefix, 'bin', 'python')
327 # Mono Prefixes
328 os.environ['MONO_PREFIX'] = self.prefix
329 os.environ['MONO_GAC_PREFIX'] = self.prefix
331 # handle environment prepends ...
332 for envvar in env_prepends.keys():
333 for path in env_prepends[envvar]:
334 addpath(envvar, path)
337 # get rid of gdkxft from the env -- it will cause problems.
338 if os.environ.has_key('LD_PRELOAD'):
339 valarr = os.environ['LD_PRELOAD'].split(' ')
340 for x in valarr[:]:
341 if x.find('libgdkxft.so') >= 0:
342 valarr.remove(x)
343 os.environ['LD_PRELOAD'] = ' '.join(valarr)
345 def __setattr__(self, k, v):
346 '''Override __setattr__ for additional checks on some options.'''
347 if k == 'quiet_mode' and v:
348 try:
349 import curses
350 except ImportError:
351 logging.warning(
352 _('quiet mode has been disabled because the Python curses module is missing.'))
353 v = False
355 self.__dict__[k] = v