~ubuntu-branches/ubuntu/natty/python-distutils-extra/natty-updates

« back to all changes in this revision

Viewing changes to .pc/debian-changes-2.22-3/DistUtilsExtra/auto.py

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt, Didier Roche
  • Date: 2010-11-18 11:39:08 UTC
  • mfrom: (18.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20101118113908-djxv5m9au6fv5tk7
Tags: 2.23-1
[ Didier Roche ]
* debian/local/python-mkdebian: (LP: #625581)
  - add --force-rules to force the rules file to be recreated
  - add --prefix to force a prefix other than /usr for installing your python
    modules
* debian/local/python-mkdebian.1:
  - add man for --force-copyright
  - add man for --force-rules and --prefix

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
'''DistUtilsExtra.auto
2
 
 
3
 
This provides a setup() method for distutils and DistUtilsExtra which infers as
4
 
many setup() arguments as possible. The idea is that your setup.py only needs
5
 
to have the metadata and some tweaks for unusual files/paths, in a "convention
6
 
over configuration" paradigm.
7
 
 
8
 
This currently supports:
9
 
 
10
 
 * Python modules (./*.py, only in root directory)
11
 
 * Python packages (all directories with __init__.py)
12
 
 * Docbook-XML GNOME help files (help/<language>/{*.xml,*.omf,figures})
13
 
 * GtkBuilder (*.ui) [installed into prefix/share/<projectname>/]
14
 
 * Qt4 user interfaces (*.ui) [compiled with pykdeuic into Python modules]
15
 
 * D-Bus (*.conf and *.service)
16
 
 * PolicyKit (*.policy.in)
17
 
 * Desktop files (*.desktop.in) [into prefix/share/applications, or
18
 
   prefix/share/autostart if they have "autostart" anywhere in the path]
19
 
 * KDE4 notifications (*.notifyrc.in)
20
 
 * Apport hooks (apport/*) [installed into /usr/share/apport/package-hooks]
21
 
 * scripts (all in bin/, and ./<projectname>
22
 
 * Auxiliary data files (in data/*) [into prefix/share/<projectname>/]
23
 
 * automatic po/POTFILES.in (with all source files which contain _())
24
 
 * automatic MANIFEST (everything except swap and backup files, *.pyc, and
25
 
   revision control)
26
 
 * manpages (*.[0-9])
27
 
 * icons (data/icons/<size>/<category>/*.{svg,png})
28
 
 * files which should go into /etc (./etc/*, copied verbatim)
29
 
 * determining "requires" from import statements in source code
30
 
 * determining "provides" from shipped packages and modules
31
 
 
32
 
If you follow above conventions, then you don't need any po/POTFILES.in,
33
 
./setup.cfg, or ./MANIFEST.in, and just need the project metadata (name,
34
 
author, license, etc.) in ./setup.py.
35
 
'''
36
 
 
37
 
# (c) 2009 Canonical Ltd.
38
 
# Author: Martin Pitt <martin.pitt@ubuntu.com>
39
 
 
40
 
import os, os.path, fnmatch, stat, sys, subprocess
41
 
import ast
42
 
import distutils.core
43
 
 
44
 
from DistUtilsExtra import __version__ as __pkgversion
45
 
from DistUtilsExtra.command import *
46
 
import distutils.dir_util
47
 
import distutils.command.clean
48
 
import distutils.command.sdist
49
 
import distutils.command.install
50
 
import distutils.filelist
51
 
 
52
 
__version__ = __pkgversion
53
 
 
54
 
# FIXME: global variable, to share with build_i18n_auto
55
 
src = {}
56
 
src_all = {}
57
 
 
58
 
def setup(**attrs):
59
 
    '''Auto-inferring extension of standard distutils.core.setup()'''
60
 
    global src
61
 
    global src_all
62
 
    src_all = src_find(attrs)
63
 
    src = src_all.copy()
64
 
 
65
 
    # src_find() removes explicit scripts, but we need them for automatic
66
 
    # POTFILE.in building and requires
67
 
    src_all.update(set(attrs.get('scripts', [])))
68
 
 
69
 
    src_mark(src, 'setup.py')
70
 
    src_markglob(src, 'setup.cfg')
71
 
 
72
 
    # mark files in etc/*, handled by install_auto
73
 
    # don't install DistUtilsExtra if bundled with a source tarball
74
 
    # ignore packaging
75
 
    ignore_dirs = ['etc', 'DistUtilsExtra', 'debian']
76
 
    
77
 
    for f in src.copy():
78
 
        for d in ignore_dirs:
79
 
            if f.startswith(d + os.path.sep):
80
 
                src.remove(f)
81
 
 
82
 
    __cmdclass(attrs)
83
 
    __modules(attrs, src)
84
 
    __packages(attrs, src)
85
 
    __provides(attrs, src)
86
 
    __dbus(attrs, src)
87
 
    __apport_hooks(attrs, src)
88
 
    __data(attrs, src)
89
 
    __scripts(attrs, src)
90
 
    __stdfiles(attrs, src)
91
 
    __gtkbuilder(attrs, src)
92
 
    __manpages(attrs, src)
93
 
 
94
 
    if 'clean' not in sys.argv:
95
 
        __requires(attrs, src_all)
96
 
 
97
 
    distutils.core.setup(**attrs)
98
 
 
99
 
    if src:
100
 
        print 'WARNING: the following files are not recognized by DistUtilsExtra.auto:'
101
 
        for f in sorted(src):
102
 
            print ' ', f
103
 
 
104
 
#
105
 
# parts of setup()
106
 
#
107
 
 
108
 
class clean_build_tree(distutils.command.clean.clean):
109
 
 
110
 
    description = 'clean up build/ directory'
111
 
 
112
 
    def run(self):
113
 
        # clean build/mo
114
 
        if os.path.isdir('build'):
115
 
            distutils.dir_util.remove_tree('build')
116
 
        distutils.command.clean.clean.run(self)
117
 
 
118
 
def __cmdclass(attrs):
119
 
    '''Default cmdclass for DistUtilsExtra'''
120
 
 
121
 
    v = attrs.setdefault('cmdclass', {})
122
 
    v.setdefault('build', build_extra.build_extra)
123
 
    v.setdefault('build_help', build_help_auto)
124
 
    v.setdefault('build_i18n', build_i18n_auto)
125
 
    v.setdefault('build_icons', build_icons.build_icons)
126
 
    v.setdefault('build_kdeui', build_kdeui_auto)
127
 
    v.setdefault('install', install_auto)
128
 
    v.setdefault('clean', clean_build_tree)
129
 
    v.setdefault('sdist', sdist_auto)
130
 
 
131
 
def __modules(attrs, src):
132
 
    '''Default modules'''
133
 
 
134
 
    if 'py_modules' in attrs:
135
 
        for mod in attrs['py_modules']:
136
 
            src_markglob(src, os.path.join(mod, '*.py'))
137
 
        return
138
 
 
139
 
    mods = attrs.setdefault('py_modules', [])
140
 
 
141
 
    for f in src_fileglob(src, '*.py'):
142
 
        if os.path.sep not in f:
143
 
            mods.append(os.path.splitext(f)[0])
144
 
            src_markglob(src, f)
145
 
 
146
 
def __packages(attrs, src):
147
 
    '''Default packages'''
148
 
 
149
 
    if 'packages' in attrs:
150
 
        for pkg in attrs['packages']:
151
 
            src_markglob(src, os.path.join(pkg, '*.py'))
152
 
        return
153
 
 
154
 
    packages = attrs.setdefault('packages', [])
155
 
 
156
 
    for f in src_fileglob(src, '__init__.py'):
157
 
        if f.startswith('data' + os.path.sep):
158
 
            continue
159
 
        pkg = os.path.dirname(f)
160
 
        packages.append(pkg)
161
 
        src_markglob(src, os.path.join(pkg, '*.py'))
162
 
 
163
 
def __dbus(attrs, src):
164
 
    '''D-Bus configuration and services'''
165
 
 
166
 
    v = attrs.setdefault('data_files', [])
167
 
 
168
 
    # /etc/dbus-1/system.d/*.conf
169
 
    dbus_conf = []
170
 
    for f in src_fileglob(src, '*.conf'):
171
 
        if '-//freedesktop//DTD D-BUS Bus Configuration' in open(f).read():
172
 
            src_mark(src, f)
173
 
            dbus_conf.append(f)
174
 
    if dbus_conf:
175
 
        v.append(('/etc/dbus-1/system.d/', dbus_conf))
176
 
 
177
 
    session_service = []
178
 
    system_service = []
179
 
    # dbus services
180
 
    for f in src_fileglob(src, '*.service'):
181
 
        lines = [l.strip() for l in open(f).readlines()]
182
 
        if '[D-BUS Service]' not in lines:
183
 
            continue
184
 
        for l in lines:
185
 
            if l.startswith('User='):
186
 
                src_mark(src, f)
187
 
                system_service.append(f)
188
 
                break
189
 
        else:
190
 
            src_mark(src, f)
191
 
            session_service.append(f)
192
 
    if system_service:
193
 
        v.append(('share/dbus-1/system-services', system_service))
194
 
    if session_service:
195
 
        v.append(('share/dbus-1/services', session_service))
196
 
 
197
 
def __apport_hooks(attrs, src):      
198
 
    '''Apport hooks'''  
199
 
    v = attrs.setdefault('data_files', [])
200
 
 
201
 
    # files will be copied to /usr/share/apport/package-hooks/
202
 
    hooks = []
203
 
    assert 'name' in attrs, 'You need to set the "name" property in setup.py'
204
 
    for f in src_fileglob(src, '*.py'):
205
 
        if f.startswith('apport/'):
206
 
            hooks.append(f)
207
 
            src_mark(src, f)
208
 
    if hooks:
209
 
        v.append(('share/apport/package-hooks/', hooks))
210
 
 
211
 
def __data(attrs, src):
212
 
    '''Install auxiliary data files.
213
 
 
214
 
    This installs everything from data/ except data/icons/ and *.in files (which
215
 
    are handled differently) into prefix/share/<projectname>/.
216
 
    '''
217
 
    v = attrs.setdefault('data_files', [])
218
 
 
219
 
    assert 'name' in attrs, 'You need to set the "name" property in setup.py'
220
 
 
221
 
    data_files = []
222
 
    for f in src.copy():
223
 
        if f.startswith('data/') and not f.startswith('data/icons/') and \
224
 
                not f.endswith('.desktop.in') and not f.endswith('*.notifyrc.in'):
225
 
            if not os.path.islink(f):
226
 
                # symlinks are handled in install_auto
227
 
                v.append((os.path.join('share', attrs['name'], os.path.dirname(f[5:])), [f]))
228
 
            src_mark(src, f)
229
 
 
230
 
def __scripts(attrs, src):
231
 
    '''Install scripts.
232
 
 
233
 
    This picks executable scripts in bin/*, and an executable ./<projectname>.
234
 
    Other scripts have to be added manually; this is to avoid automatically
235
 
    installing test suites, build scripts, etc.
236
 
    '''
237
 
    assert 'name' in attrs, 'You need to set the "name" property in setup.py'
238
 
 
239
 
    scripts = []
240
 
    for f in src.copy():
241
 
        if f.startswith('bin/') or f == attrs['name']:
242
 
            st = os.lstat(f)
243
 
            if stat.S_ISREG(st.st_mode) and st.st_mode & stat.S_IEXEC:
244
 
                scripts.append(f)
245
 
                src_mark(src, f)
246
 
            elif stat.S_ISLNK(st.st_mode):
247
 
                # symlinks are handled in install_auto
248
 
                src_mark(src, f)
249
 
 
250
 
    if scripts:
251
 
        v = attrs.setdefault('scripts', [])
252
 
        v += scripts
253
 
 
254
 
def __stdfiles(attrs, src):
255
 
    '''Install/mark standard files.
256
 
 
257
 
    This covers COPYING, AUTHORS, README, etc.
258
 
    '''
259
 
    src_markglob(src, 'COPYING*')
260
 
    src_markglob(src, 'LICENSE*')
261
 
    src_markglob(src, 'AUTHORS')
262
 
    src_markglob(src, 'MANIFEST.in')
263
 
    src_markglob(src, 'MANIFEST')
264
 
    src_markglob(src, 'TODO')
265
 
 
266
 
    # install all README* from the root directory
267
 
    readme = []
268
 
    for f in src_fileglob(src, 'README*').union(src_fileglob(src, 'NEWS')):
269
 
        if os.path.sep not in f:
270
 
            readme.append(f)
271
 
            src_mark(src, f)
272
 
    if readme:
273
 
        assert 'name' in attrs, 'You need to set the "name" property in setup.py'
274
 
 
275
 
        attrs.setdefault('data_files', []).append((os.path.join('share', 'doc',
276
 
            attrs['name']), readme))
277
 
 
278
 
def __gtkbuilder(attrs, src):
279
 
    '''Install GtkBuilder *.ui files'''
280
 
 
281
 
    ui = []
282
 
    for f in src_fileglob(src, '*.ui'):
283
 
        contents = open(f).read()
284
 
        if ('<interface>\n' in contents or '<interface ' in contents) and 'class="Gtk' in contents:
285
 
            src_mark(src, f)
286
 
            ui.append(f)
287
 
    if ui:
288
 
        assert 'name' in attrs, 'You need to set the "name" property in setup.py'
289
 
 
290
 
        attrs.setdefault('data_files', []).append((os.path.join('share', 
291
 
            attrs['name']), ui))
292
 
 
293
 
def __manpages(attrs, src):
294
 
    '''Install manpages'''
295
 
 
296
 
    mans = {}
297
 
    for f in src_fileglob(src, '*.[0123456789]'):
298
 
        line = open(f).readline()
299
 
        if line.startswith('.TH '):
300
 
            src_mark(src, f)
301
 
            mans.setdefault(f[-1], []).append(f)
302
 
    v = attrs.setdefault('data_files', [])
303
 
    for section, files in mans.iteritems():
304
 
        v.append((os.path.join('share', 'man', 'man' + section), files))
305
 
 
306
 
def __external_mod(module, attrs):
307
 
    '''Check if given Python module is not included in Python or locally'''
308
 
 
309
 
    # filter out locally provided modules
310
 
    if module in attrs['provides']:
311
 
        return False
312
 
    for m in _module_parents(module):
313
 
        if m in attrs['provides']:
314
 
            return False
315
 
 
316
 
    try:
317
 
        path = __import__(module).__file__
318
 
    except ImportError:
319
 
        print >> sys.stderr, 'ERROR: Python module %s not found' % module
320
 
        return False
321
 
    except AttributeError: # builtin modules
322
 
        return False
323
 
 
324
 
    return 'dist-packages' in path or 'site-packages' in path or \
325
 
            not path.startswith(os.path.dirname(os.__file__))
326
 
 
327
 
def __add_imports(imports, file, attrs):
328
 
    '''Add all imported modules from file to imports set.
329
 
 
330
 
    This filters out modules which are shipped with Python itself.
331
 
    '''
332
 
    try:
333
 
        tree = ast.parse(open(file).read(), file)
334
 
 
335
 
        for node in ast.walk(tree):
336
 
            if isinstance(node, ast.Import):
337
 
                for alias in node.names:
338
 
                    if __external_mod(alias.name, attrs):
339
 
                        imports.add(alias.name)
340
 
            if isinstance(node, ast.ImportFrom):
341
 
                if __external_mod(node.module, attrs):
342
 
                    imports.add(node.module)
343
 
    except SyntaxError, e:
344
 
        print >> sys.stderr, 'WARNING: syntax errors in', file, ':', e
345
 
 
346
 
def _module_parents(mod):
347
 
    '''Iterate over all parents of a module'''
348
 
 
349
 
    hierarchy = mod.split('.')
350
 
    hierarchy.pop()
351
 
    while hierarchy:
352
 
        yield '.'.join(hierarchy)
353
 
        hierarchy.pop()
354
 
 
355
 
def __filter_namespace(modules):
356
 
    '''Filter out modules which are already covered by a parent module
357
 
    
358
 
    E. g. this transforms ['os.path', 'os', 'foo.bar.baz', 'foo.bar'] to
359
 
    ['os', 'foo.bar'].
360
 
    '''
361
 
    result = set()
362
 
 
363
 
    for m in modules:
364
 
        for p in _module_parents(m):
365
 
            if p in modules:
366
 
                break
367
 
        else:
368
 
            result.add(m)
369
 
 
370
 
    return sorted(result)
371
 
 
372
 
def __requires(attrs, src_all):
373
 
    '''Determine requires (if not set explicitly)'''
374
 
 
375
 
    if 'requires' in attrs:
376
 
        return
377
 
 
378
 
    imports = set()
379
 
 
380
 
    # iterate over all *.py and scripts which are Python
381
 
    for s in src_all:
382
 
        if s.startswith('data' + os.path.sep):
383
 
            continue
384
 
        ext = os.path.splitext(s)[1]
385
 
        if ext == '':
386
 
            f = open(s)
387
 
            line = f.readline()
388
 
            if not line.startswith('#!') or 'python' not in line:
389
 
                continue
390
 
        elif ext != '.py':
391
 
            continue
392
 
        __add_imports(imports, s, attrs)
393
 
 
394
 
    attrs['requires'] = __filter_namespace(imports)
395
 
 
396
 
def __provides(attrs, src_all):
397
 
    '''Determine provides (if not set explicitly)'''
398
 
 
399
 
    if 'provides' in attrs:
400
 
        return
401
 
 
402
 
    provides = attrs.get('py_modules', [])
403
 
    for p in attrs.get('packages', []):
404
 
        provides.append(p.replace(os.path.sep, '.'))
405
 
    attrs['provides'] = __filter_namespace(provides)
406
 
 
407
 
#
408
 
# helper functions
409
 
#
410
 
 
411
 
def src_find(attrs):
412
 
    '''Find source files.
413
 
    
414
 
    This ignores all source files which are explicitly specified as setup()
415
 
    arguments.
416
 
    '''
417
 
    src = set()
418
 
 
419
 
    # files explicitly covered in setup() call
420
 
    explicit = set(attrs.get('scripts', []))
421
 
    for (destdir, files) in attrs.get('data_files', []):
422
 
        explicit.update(files)
423
 
 
424
 
    for (root, dirs, files) in os.walk('.'):
425
 
        if root.startswith('./'):
426
 
            root = root[2:]
427
 
        if root == '.':
428
 
            root = ''
429
 
        if root.startswith('.') or \
430
 
                root.split(os.path.sep, 1)[0] in ('build', 'test', 'tests'):
431
 
            continue
432
 
        # data/icons is handled by build_icons
433
 
        if root.startswith(os.path.join('data', 'icons')):
434
 
            continue
435
 
        for f in files:
436
 
            ext = os.path.splitext(f)[1]
437
 
            if f.startswith('.') or ext in ('.pyc', '~', '.mo'):
438
 
                continue
439
 
            # po/*.po is taken care of by build_i18n
440
 
            if root == 'po' and (ext == '.po' or f == 'POTFILES.in'):
441
 
                continue
442
 
            
443
 
            path = os.path.join(root, f)
444
 
            if path not in explicit:
445
 
                src.add(path)
446
 
 
447
 
    return src
448
 
 
449
 
def src_fileglob(src, fnameglob):
450
 
    '''Return set of files which match fnameglob.'''
451
 
 
452
 
    result = set()
453
 
    for f in src:
454
 
        if fnmatch.fnmatch(os.path.basename(f), fnameglob):
455
 
            result.add(f)
456
 
    return result
457
 
 
458
 
def src_mark(src, path):
459
 
    '''Remove path from src.'''
460
 
 
461
 
    src.remove(path)
462
 
 
463
 
def src_markglob(src, pathglob):
464
 
    '''Remove all paths from src which match pathglob.'''
465
 
 
466
 
    for f in src.copy():
467
 
        if fnmatch.fnmatch(f, pathglob):
468
 
            src.remove(f)
469
 
 
470
 
#
471
 
# Automatic setup.cfg
472
 
#
473
 
 
474
 
class build_help_auto(build_help.build_help):
475
 
    def finalize_options(self):
476
 
        build_help.build_help.finalize_options(self)
477
 
        global src
478
 
        
479
 
        for data_set in self.get_data_files():
480
 
            for filepath in data_set[1]:
481
 
                src.remove(filepath)
482
 
 
483
 
class build_i18n_auto(build_i18n.build_i18n):
484
 
    def finalize_options(self):
485
 
        build_i18n.build_i18n.finalize_options(self)
486
 
        global src
487
 
        global src_all
488
 
 
489
 
        # add PolicyKit files
490
 
        policy_files = []
491
 
        for f in src_fileglob(src, '*.policy.in'):
492
 
            src_mark(src, f)
493
 
            policy_files.append(f)
494
 
        if policy_files:
495
 
            # check if we have PolicyKit 1 API
496
 
            if subprocess.call(['grep', '-q', 'org\.freedesktop\.PolicyKit1'] +
497
 
                    list(src_fileglob(src_all, '*.py')),
498
 
                    stderr=subprocess.PIPE) == 0:
499
 
                destdir = os.path.join('share', 'polkit-1', 'actions')
500
 
            else:
501
 
                destdir = os.path.join('share', 'PolicyKit', 'policy')
502
 
            try:
503
 
                xf = eval(self.xml_files)
504
 
            except TypeError:
505
 
                xf = []
506
 
            xf.append((destdir, policy_files))
507
 
            self.xml_files = repr(xf)
508
 
 
509
 
        # add desktop files
510
 
        desktop_files = []
511
 
        autostart_files = []
512
 
        notify_files = []
513
 
        for f in src_fileglob(src, '*.desktop.in'):
514
 
            src_mark(src, f)
515
 
            if 'autostart' in f:
516
 
                autostart_files.append(f)
517
 
            else:
518
 
                desktop_files.append(f)
519
 
        for f in src_fileglob(src, '*.notifyrc.in'):
520
 
            src_mark(src, f)
521
 
            notify_files.append(f)
522
 
        try:
523
 
            df = eval(self.desktop_files)
524
 
        except TypeError:
525
 
            df = []
526
 
        if desktop_files:
527
 
            df.append(('share/applications', desktop_files))
528
 
        if autostart_files:
529
 
            df.append(('share/autostart', autostart_files))
530
 
        if notify_files:
531
 
            df.append(('share/kde4/apps/' + self.distribution.get_name(), notify_files))
532
 
        self.desktop_files = repr(df)
533
 
        
534
 
        # mark PO template as known to handle
535
 
        try:
536
 
            src_mark(src, os.path.join(self.po_dir, self.distribution.get_name() + '.pot'))
537
 
        except KeyError:
538
 
            pass
539
 
 
540
 
    def run(self):
541
 
        '''Build a default POTFILES.in'''
542
 
 
543
 
        auto_potfiles_in = False
544
 
        exe_symlinks = []
545
 
        global src_all
546
 
        try:
547
 
            if not os.path.exists(os.path.join('po', 'POTFILES.in')):
548
 
                files = src_fileglob(src_all, '*.py')
549
 
                files.update(src_fileglob(src_all, '*.desktop.in'))
550
 
                files.update(src_fileglob(src_all, '*.notifyrc.in'))
551
 
                files.update(src_fileglob(src_all, '*.policy.in'))
552
 
 
553
 
                for f in src_fileglob(src_all, '*.ui'):
554
 
                    contents = open(f).read()
555
 
                    if ('<interface>\n' in contents or '<interface ' in contents) and 'class="Gtk' in contents:
556
 
                        files.add('[type: gettext/glade]' + f)
557
 
 
558
 
                # find extensionless executable scripts which are Python files, and
559
 
                # generate a temporary *.py alias, so that they get caught by
560
 
                # intltool
561
 
                for f in reduce(lambda x, y: x.union(y[1]), self.distribution.data_files, src_all):
562
 
                    f_py = f + '.py'
563
 
                    if os.access(f, os.X_OK) and os.path.splitext(f)[1] == '' and \
564
 
                            not os.path.exists(f_py):
565
 
                        line = open(f).readline()
566
 
                        if line.startswith('#!') and 'python' in line:
567
 
                            os.symlink(os.path.basename(f), f_py)
568
 
                            files.add(f_py)
569
 
                            exe_symlinks.append(f_py)
570
 
 
571
 
                if files:
572
 
                    if not os.path.isdir('po'):
573
 
                        os.mkdir('po')
574
 
                    potfiles_in = open('po/POTFILES.in', 'w')
575
 
                    print >> potfiles_in, '[encoding: UTF-8]'
576
 
                    for f in files:
577
 
                        print >> potfiles_in, f
578
 
                    potfiles_in.close()
579
 
 
580
 
                    auto_potfiles_in = True
581
 
 
582
 
            build_i18n.build_i18n.run(self)
583
 
        finally:
584
 
            for f in exe_symlinks:
585
 
                os.unlink(f)
586
 
 
587
 
        if auto_potfiles_in:
588
 
            os.unlink('po/POTFILES.in')
589
 
            try:
590
 
                os.rmdir('po')
591
 
            except:
592
 
                pass
593
 
 
594
 
class build_kdeui_auto(build_kdeui.build_kdeui):
595
 
    def finalize_options(self):
596
 
        global src
597
 
 
598
 
        # add *.ui files which belong to KDE4
599
 
        kdeui_files = []
600
 
        for f in src_fileglob(src, '*.ui'):
601
 
            fd = open(f)
602
 
            # might be on the first or second line
603
 
            if fd.readline().startswith('<ui version="') or \
604
 
               fd.readline().startswith('<ui version="'):
605
 
                src_mark(src, f)
606
 
                kdeui_files.append(f)
607
 
            fd.close()
608
 
        if kdeui_files:
609
 
            try:
610
 
                uf = eval(self.ui_files)
611
 
            except TypeError:
612
 
                uf = []
613
 
            uf += kdeui_files
614
 
            self.ui_files = repr(uf)
615
 
 
616
 
        build_kdeui.build_kdeui.finalize_options(self)
617
 
 
618
 
#
619
 
# Automatic sdist
620
 
#
621
 
 
622
 
class sdist_auto(distutils.command.sdist.sdist):
623
 
    '''Default values for the 'sdist' command.
624
 
    
625
 
    Replace the manually maintained MANIFEST.in file by providing information
626
 
    about what the source tarball created using the 'sdist' command should
627
 
    contain in normal cases.
628
 
    
629
 
    It prevents the 'build' directory, version control related files, as well as
630
 
    compiled Python and gettext files and temporary files from being included in
631
 
    the source tarball.
632
 
    
633
 
    It's possible for subclasses to extend the 'filter_prefix' and
634
 
    'filter_suffix' properties.
635
 
    '''
636
 
    filter_prefix = ['build', '.git', '.svn', '.CVS', '.bzr', '.shelf']
637
 
    filter_suffix = ['.pyc', '.mo', '~', '.swp']
638
 
    
639
 
    def add_defaults(self):
640
 
        distutils.command.sdist.sdist.add_defaults(self)
641
 
        
642
 
        if os.path.exists('MANIFEST.in'):
643
 
            return
644
 
 
645
 
        self.filter_prefix.append(os.path.join('dist',
646
 
            self.distribution.get_name()))
647
 
        
648
 
        for f in distutils.filelist.findall():
649
 
            if f in self.filelist.files or \
650
 
                any(map(f.startswith, self.filter_prefix)) or \
651
 
                any(map(f.endswith, self.filter_suffix)):
652
 
                continue
653
 
            
654
 
            self.filelist.append(f)
655
 
 
656
 
#
657
 
# Automatic installation of ./etc/ and symlinks
658
 
#
659
 
 
660
 
class install_auto(distutils.command.install.install):
661
 
    def run(self):
662
 
        # install files from etc/
663
 
        if os.path.isdir('etc'):
664
 
            # work around a bug in copy_tree() which fails with "File exists" on
665
 
            # previously existing symlinks
666
 
            for f in distutils.filelist.findall('etc'):
667
 
                if not f.startswith('etc' + os.path.sep) or not os.path.islink(f):
668
 
                    continue
669
 
                try:
670
 
                    os.unlink(os.path.join(self.root, f))
671
 
                except OSError:
672
 
                    pass
673
 
            if not self.root:
674
 
                self.root = ''
675
 
            distutils.dir_util.copy_tree('etc', os.path.join(self.root, 'etc'),
676
 
                    preserve_times=0, preserve_symlinks=1, verbose=1)
677
 
 
678
 
        # install data/scripts symlinks
679
 
        for f in distutils.filelist.findall():
680
 
            if not os.path.islink(f):
681
 
                continue
682
 
            if f.startswith('bin/') or f.startswith('data/'):
683
 
                if f.startswith('bin'):
684
 
                    dir = self.install_scripts
685
 
                    dest = os.path.join(dir, os.path.sep.join(f.split(os.path.sep)[1:]))
686
 
                elif f.startswith('data/icons'):
687
 
                    dir = os.path.join(self.install_data, 'share', 'icons', 'hicolor')
688
 
                    dest = os.path.join(dir, os.path.sep.join(f.split(os.path.sep)[2:]))
689
 
                else:
690
 
                    dir = os.path.join(self.install_data, 'share', self.distribution.get_name())
691
 
                    dest = os.path.join(dir, os.path.sep.join(f.split(os.path.sep)[1:]))
692
 
 
693
 
                d = os.path.dirname(dest)
694
 
                if not os.path.isdir(d):
695
 
                    os.makedirs(d)
696
 
                if os.path.exists(dest):
697
 
                    os.unlink(dest)
698
 
                os.symlink(os.readlink(f), dest)
699
 
 
700
 
        distutils.command.install.install.run(self)
701