fix proxy support
[straw.git] / tools / straw_distutils.py
blob63757d5a04f989952d7fca2384b17f9f12e34285
1 # -*- python -*- -*- encoding: Latin-1 -*-
3 __copyright__ = "Copyright (c) 2003 Terje Røsten <terjeros@phys.ntnu.no>"
5 # Extention of distutils for straw.
7 import sys
8 import os
9 import os.path
10 import re
11 import glob
12 import types
13 import commands
15 from distutils.core import Command
16 from distutils.command.build import build
17 from distutils.command.install import install
18 from distutils.command.install_lib import install_lib
19 from distutils.command.install_data import install_data
20 from distutils.dep_util import newer
21 from distutils.util import subst_vars
22 from distutils.dist import Distribution
23 from distutils.core import setup
25 class straw_build(build):
26 def has_po_files(self):
27 return self.distribution.has_po_files()
29 def has_desktop_file(self):
30 return self.distribution.has_desktop_file()
32 sub_commands = []
33 sub_commands.extend(build.sub_commands)
34 sub_commands.append(('build_mo', has_po_files))
35 sub_commands.append(('build_desktop', has_desktop_file))
37 class build_mo(Command):
38 description = 'build binary message catalog'
39 user_options = [('build-base=', 'b', 'directory to build to')]
40 def initialize_options(self):
41 self.build_base = None
42 self.force = None
44 def finalize_options(self):
45 self.set_undefined_options('build',
46 ('build_base', 'build_base'),
47 ('force', 'force'))
49 def run(self):
50 self.announce('Building binary message catalog')
51 if self.distribution.has_po_files():
52 for mo, po in self.distribution.translations:
53 dest = os.path.normpath(self.build_base + '/' + mo)
54 self.mkpath(os.path.dirname(dest))
55 if not self.force and not newer(po, dest):
56 self.warn("not building %s (up-to-date)" % dest)
57 else:
58 import msgfmt
59 msgfmt.make(po, dest)
61 class build_desktop(Command):
62 description = 'builds the straw.desktop file'
63 user_options = [('build-base=', 'b', 'directory to build to')]
64 def initialize_options(self):
65 self.build_base = None
66 self.intl_merge = None
68 def finalize_options(self):
69 if self.intl_merge is None:
70 self.intl_merge = commands.getoutput('which intltool-merge')
71 if not os.path.exists(self.intl_merge):
72 sys.exit('intltool-merge does not exist in your PATH. ' + \
73 'Make sure it exists in your PATH..')
74 self.set_undefined_options('build',
75 ('build_base', 'build_base'))
77 def run(self):
78 self.announce("Building straw.desktop file....")
79 if self.distribution.has_desktop_file():
80 for desktop in self.distribution.desktop_file:
81 dest = os.path.normpath(os.path.join(self.build_base, 'share/applications'))
82 self.mkpath(dest, 1)
83 fname = '.'.join(desktop.split('.')[:2]) # straw.desktop.in -> straw.desktop
84 cmd = '%s -d -u po %s %s/%s' % (self.intl_merge, desktop,
85 dest, fname)
86 err, val = commands.getstatusoutput(cmd)
87 if err:
88 sys.exit('Unable to translate straw.desktop. %s' % err)
90 class straw_install(install):
91 user_options = []
92 _user_options = [
93 ('sysconfdir=', None, 'specify SYSCONFDIR [default=PREFIX/etc]'),
94 ('disable-modules-check', None,
95 'do not check that necessary modules is installed'),
96 ('enable-modules-check', None,
97 'check that necessary modules is installed [default]'),
98 ('disable-schemas-install', None,
99 'do not install schema files. Setting the variable '
100 'GCONF_DISABLE_MAKEFILE_SCHEMA_INSTALL will prevent this too.'),
101 ('enable-schemas-install', None,
102 'install schema files. [default]'),
103 ('with-gconftool=', None,
104 'specify path to the gconftool executable. Can also be set by'
105 'the variable GCONFTOOL. [default=gconftool-2]' ),
106 ('with-gconf-source=', None,
107 'Config database for installing schema files. Can also be set by '
108 'the variable GCONF_SCHEMA_CONFIG_SOURCE. Setting to `auto\' is '
109 'short for `$(gconftool-2 --get-default-source)\'. '),
110 ('with-gconf-schema-file-dir=', None,
111 'Directory for installing schema files. Can also be set by the '
112 'variable GCONF_SCHEMA_FILE_DIR. [default=SYSCONFDIR/gconf/schemas]'),
113 ('with-desktop-file-dir=', None,
114 'specify directory for the straw.desktop file [default=PREFIX/share/applications')]
115 user_options.extend(install.user_options)
116 user_options.extend(_user_options)
117 boolean_options = []
118 boolean_options.extend(install.boolean_options)
119 boolean_options.extend([
120 'disable-schemas-install', 'disable-modules-check' ])
122 negative_opt = {}
123 try:
124 negative_opt.update(install.negative_opt)
125 except AttributeError:
126 pass
127 negative_opt.update({'enable-schemas-install' : 'disable-schemas-install',
128 'enable-modules-check' : 'disable-modules-check'})
130 def initialize_options(self):
131 install.initialize_options(self)
132 #self.prefix = '/usr/local'
133 # if self.sysconfdir is not a absolute path it will
134 # be prefixed by self.prefix
135 self.sysconfdir = 'etc'
136 self.disable_modules_check = 0
137 self.disable_schemas_install = os.environ.get(
138 'GCONF_DISABLE_MAKEFILE_SCHEMA_INSTALL', 0)
139 self.with_gconftool = os.environ.get(
140 'GCONFTOOL', commands.getoutput('which gconftool-2'))
141 self.with_gconf_source = os.environ.get(
142 'GCONF_SCHEMA_CONFIG_SOURCE', 'auto')
143 self.with_gconf_schema_file_dir = os.environ.get(
144 'GCONF_SCHEMA_FILE_DIR', None)
145 self.with_desktop_file_dir = 'share/applications'
147 def finalize_options(self):
148 if self.prefix == 'auto':
149 cmd = 'pkg-config --variable=prefix libgnome2.0'
150 err, val = commands.getstatusoutput(cmd)
151 if not err:
152 self.prefix = val
153 else:
154 sys.exit('Cannot find prefix: %s. pkgconfig not installed?'
155 % val)
157 self.sysconfdir = os.path.join(self.prefix, self.sysconfdir)
158 if self.root:
159 self.sysconfdir = os.path.normpath(self.root + '/' + self.sysconfdir)
161 self.announce(self.sysconfdir)
162 if self.root and self.with_gconf_schema_file_dir:
163 self.with_gconf_schema_file_dir = os.path.normpath(
164 self.root + '/' + self.with_gconf_schema_file_dir)
166 if not self.disable_schemas_install:
167 # Sanity check
168 if not os.path.exists(self.with_gconftool):
169 sys.exit('gconftool-2 executable not found in your path ' + \
170 '- should be installed with GConf')
172 if self.with_gconf_source == 'auto':
173 cmd = '%s --get-default-source' % self.with_gconftool
174 self.with_gconf_source = commands.getoutput(cmd)
176 if self.with_gconf_source != 'auto' and self.root:
177 self.with_gconf_source = self.with_gconf_source.replace(
178 'xml::','xml::%s' % self.root)
179 elif not self.with_gconf_source:
180 fmt = 'xml::%s/gconf/gconf.xml.defaults'
181 self.with_gconf_source = fmt % self.sysconfdir
183 # Run this after we (possibly) have changed prefix.
184 install.finalize_options(self)
186 def has_modules_check(self):
187 return self.distribution.has_modules_check()
189 def has_config_files(self):
190 return self.distribution.has_config_files()
192 def has_po_files(self):
193 return self.distribution.has_po_files()
195 def has_desktop_file(self):
196 return self.distribution.has_desktop_file()
198 def has_constants(self):
199 return self.distribution.has_constants()
201 sub_commands = []
202 # Check modules before we start to install files
203 sub_commands.append(('install_modules_check', has_modules_check))
204 sub_commands.extend(install.sub_commands)
205 sub_commands.append(('install_mo', has_po_files))
206 sub_commands.append(('install_gconf', has_config_files))
207 sub_commands.append(('install_desktop', has_desktop_file))
208 sub_commands.append(('install_constants', has_constants))
210 class install_mo(install_data):
211 description = 'install generated binary message catalog'
212 def initialize_options(self):
213 self.translations = self.distribution.translations
214 self.has_po_files = self.distribution.has_po_files
215 self.install_dir = None
216 self.build_dir = None
217 self.skip_build = None
218 self.outfiles = []
220 def finalize_options(self):
221 self.set_undefined_options('build_mo', ('build_base', 'build_dir'))
222 self.set_undefined_options('install',
223 ('install_data', 'install_dir'),
224 ('skip_build', 'skip_build'))
225 def run(self):
226 if not self.skip_build:
227 self.run_command('build_mo')
228 if self.has_po_files():
229 for mo, po in self.translations:
230 src = os.path.normpath(self.build_dir + '/' + mo)
231 if not os.path.isabs(mo):
232 dest = os.path.normpath(self.install_dir + '/' + mo)
233 elif self.root:
234 dest = self.root + mo
235 else:
236 dest = mo
237 self.mkpath(os.path.dirname(dest))
238 (out, _) = self.copy_file(src, dest)
239 self.outfiles.append(out)
241 def get_outputs (self): return self.outfiles
242 def get_inputs (self): return [ po for mo, po in self.translations ]
244 class install_gconf(install_data):
246 Same as install_data but using <sysconfdir> instead of
247 <prefix>. If <sysconfdir> is not absolute, <prefix> is prefixed
248 <sysconfdir>. If the tuple has length 3 and the option in the last
249 element is known, the value of the option is used as dest
250 directory. On the other hand if option is None, the value of the
251 option is set to value of the first element in the tuple.
253 description = 'install generated gconf files'
254 user_options = [
255 ('sysconfdir', None,
256 'specify SYSCONFDIR [default=PREFIX/etc]')]
258 def initialize_options(self):
259 self.disable_schemas_install = None
260 self.sysconfdir = None
261 self.with_gconftool = None
262 self.with_gconf_source = None
263 self.with_gconf_schema_file_dir = None
264 self.config_files = self.distribution.config_files
265 install_data.initialize_options(self)
267 def finalize_options(self):
268 install_data.finalize_options(self)
269 self.set_undefined_options(
270 'install',
271 ('disable_schemas_install', 'disable_schemas_install'),
272 ('with_gconftool', 'with_gconftool'),
273 ('with_gconf_source', 'with_gconf_source'),
274 ('sysconfdir','sysconfdir'),
275 ('with_gconf_schema_file_dir', 'with_gconf_schema_file_dir'))
276 self.option_to_dir()
278 def install_schema(self):
279 schemas_dir, schemas_file = self.config_files[0]
280 schemas_idir = os.path.normpath(self.sysconfdir+'/'+schemas_dir)
281 self.mkpath(schemas_idir)
282 os.environ['GCONF_CONFIG_SOURCE'] = self.with_gconf_source
283 for filepath in schemas_file:
284 sfile = filepath.split('/')[-1]
285 ofile = os.path.normpath(os.path.join(schemas_idir,sfile))
286 self.copy_file(filepath,ofile)
287 cmd = '%s --makefile-install-rule %s'\
288 % (self.with_gconftool, ofile)
289 err, out = commands.getstatusoutput(cmd)
290 if out:
291 self.announce(out)
292 if err:
293 self.warn('Error: installation of gconf schema files failed: %s' % out)
295 def run(self):
296 if not self.disable_schemas_install:
297 self.install_schema()
299 def option_to_dir(self):
300 data_files = []
301 for tup in self.config_files:
302 if len(tup) == 2:
303 data_files.append(tup)
304 elif len(tup) == 3:
305 option = tup[2].replace('-','_')
306 dest = getattr(self, option, None)
307 if dest:
308 data_files.append((dest, tup[1]))
309 else:
310 data_files.append((tup[0], tup[1]))
311 dest = os.path.normpath(self.sysconfdir + '/' + tup[0])
312 setattr(self, option, dest)
313 self.config_files = data_files
315 def get_outputs(self): return []
316 def get_inputs(self): return []
318 class install_modules_check(Command):
319 description = 'check that all necessary Python modules are installed'
320 user_options = [
321 ('disable-modules-check', None,
322 'do not check that necessary modules is installed'),
323 ('enable-modules-check', None,
324 'check that necessary modules is installed [default]')]
325 boolean_options = []
326 boolean_options.append('disable-modules-check')
327 negative_opt = {'enable-modules-check' : 'disable-modules-check'}
329 def initialize_options(self):
330 self.disable_modules_check = None
331 self.modules_check = self.distribution.modules_check
333 def finalize_options(self):
334 self.set_undefined_options(
335 'install',
336 ('disable_modules_check', 'disable_modules_check'))
338 def run(self):
339 if self.disable_modules_check:
340 self.announce('Modules not checked')
341 elif self.modules_check:
342 self.modules_check()
343 self.announce('All nescessary modules installed')
345 def get_outputs(self): return []
346 def get_inputs(self): return []
348 class install_desktop(install_data):
349 description = 'Installs generated desktop file'
350 user_options = [
351 ('with-desktop-file-dir=', None,
352 'specify directory for the straw.desktop file [default=PREFIX/share/applications]')]
354 def initialize_options(self):
355 self.outfiles = []
356 self.build_dir = None
357 self.install_dir = None
358 self.skip_build = None
359 self.with_desktop_file_dir = None
361 def finalize_options(self):
362 self.set_undefined_options('build_desktop', ('build_base', 'build_dir'))
363 self.set_undefined_options('install',('install_data','install_dir'),
364 ('skip_build', 'skip_build'),
365 ('with_desktop_file_dir','with_desktop_file_dir'))
367 def run(self):
368 if not self.skip_build: self.run_command('build_desktop')
369 src = os.path.normpath(os.path.join(
370 self.build_dir, 'share/applications/straw.desktop'))
371 dest = os.path.normpath(self.install_dir + '/' + self.with_desktop_file_dir)
372 self.mkpath(dest)
373 (out, _) = self.copy_file(src, dest)
374 self.outfiles.append(out)
376 def get_outputs (self): return self.outfiles
377 def get_inputs (self):
378 return (os.path.join(self.build_dir, 'share/applications/straw.desktop'))
380 class translate(Command):
381 description = 'update .pot file and merge po files'
382 user_options = [('pot', 'p', 'only update the pot file (no merge)')]
383 user_options.extend([('dist=', 'd','Merge LANGCODE.po with existing PO template.')])
384 boolean_options = ['pot']
386 def initialize_options(self):
387 self.intl_update = None
388 self.pot = 0
389 self.dist = None
390 self.pot_file = None
392 def finalize_options(self):
393 if not self.intl_update:
394 self.intl_update = commands.getoutput('which intltool-update')
395 if not os.path.exists(self.intl_update):
396 sys.exit('intltool-update does not exist in your PATH. ' + \
397 'Make sure it exists in your PATH..')
399 if not self.pot_file:
400 self.distribution.pot_file
401 if self.pot and self.dist:
402 sys.exit('You can only specify one option at time...\n' + \
403 "'python setup.py translate --help' for more info")
405 def run(self):
406 # intltool-update needs to be run inside po/
407 if os.path.exists('./po/'):
408 os.chdir('./po/')
409 else:
410 sys.exit('po/ directory not found.. not continuing...')
412 if self.pot:
413 cmd = '%s --pot' % self.intl_update
414 err, val = commands.getstatusoutput(cmd)
415 if err:
416 os.chdir('../')
417 sys.exit('Error generating template file %s' % self.pot_file)
419 if self.dist:
420 cmd = '%s %s' % (self.intl_update, self.dist)
421 err, val = commands.getstatusoutput(cmd)
422 if err:
423 os.chdir('../')
424 sys.exit('Error merging %s.po with %s' % (self.dist,self.pot_file))
425 os.chdir('../')
427 class install_constants(install_lib):
428 description = "Installs and substitutes file paths and other constants in constants.py.in"
429 def initialize_options(self):
430 self.build_dir = None
431 self.install_lib = None
432 self.prefix = None
433 self.build_dict = None
434 install_lib.initialize_options(self)
436 def finalize_options(self):
437 install_lib.finalize_options(self)
438 self.set_undefined_options('install',
439 ('install_lib','install_lib'),
440 ('prefix','prefix'),)
441 self.build_dict = {'libdir': os.path.normpath(os.path.join(self.install_lib,'straw')),
442 'datadir': os.path.normpath(os.path.join(self.prefix,'share'))}
444 def run(self):
445 self.announce("building constants.py...")
446 self.fix_constants()
447 install_lib.run(self)
449 def fix_constants(self):
450 if self.distribution.has_constants():
451 for fname,vars_dict in self.distribution.constants:
452 vars_dict.update(self.build_dict)
453 f = open(fname,'r')
454 cdata = f.read()
455 f.close()
456 sfname = '.'.join(fname.split('.')[:2]) # foo.py.in -> foo.py
457 f = open(os.path.normpath(os.path.join(self.build_dir, 'straw', sfname)),'w')
458 f.write(subst_vars(cdata, vars_dict))
459 f.close()
460 self.announce("... done.")
462 class StrawDistribution(Distribution):
463 def __init__(self, attrs = None):
464 self.modules_check = 0
465 self.msg_sources = None
466 self.pot_file = None
467 self.translations = []
468 self.config_files = []
469 self.desktop_file = []
470 self.constants = []
471 self.ext_modules = []
472 Distribution.__init__(self, attrs)
473 self.cmdclass = {
474 'install_modules_check' : install_modules_check,
475 'build' : straw_build,
476 'build_mo' : build_mo,
477 'translate' : translate,
478 'build_desktop': build_desktop,
479 'install' : straw_install,
480 'install_mo' : install_mo,
481 'install_desktop' : install_desktop,
482 'install_constants': install_constants,
483 'install_gconf' : install_gconf}
485 def has_po_files(self): return len(self.translations) > 0
486 def has_modules_check(self): return isinstance(self.modules_check, types.FunctionType)
487 def has_config_files(self): return len(self.config_files) > 0
488 def has_desktop_file(self): return len(self.desktop_file) > 0
489 def has_constants(self): return len(self.constants) > 0
491 def setup(**kwds):
492 from distutils.core import setup
493 kwds['distclass'] = StrawDistribution
494 setup(**kwds)