This file is indexed.

/usr/lib/python3/dist-packages/DistUtilsExtra/auto.py is in python3-distutils-extra 2.38-1build1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
'''DistUtilsExtra.auto

This provides a setup() method for distutils and DistUtilsExtra which infers as
many setup() arguments as possible. The idea is that your setup.py only needs
to have the metadata and some tweaks for unusual files/paths, in a "convention
over configuration" paradigm.

This currently supports:

 * Python modules (./*.py, only in root directory)
 * Python packages (all directories with __init__.py)
 * Docbook-XML GNOME help files (help/<language>/{*.xml,*.omf,figures})
 * GtkBuilder and Qt4 user interfaces (*.ui) [installed into
   prefix/share/<projectname>/]
 * D-Bus (*.conf and *.service)
 * GSettings schemas (*.gschema.xml)
 * polkit (*.policy.in)
 * Desktop files (*.desktop.in) [into prefix/share/applications, or
   prefix/share/autostart if they have "autostart" anywhere in the path]
 * KDE4 notifications (*.notifyrc.in)
 * Apport hooks (apport/*) [installed into /usr/share/apport/package-hooks]
 * scripts (all in bin/, and ./<projectname>
 * Auxiliary data files (in data/*) [into prefix/share/<projectname>/]
 * automatic po/POTFILES.in (with all source files which contain _())
 * automatic MANIFEST (everything except swap and backup files, *.pyc, and
   revision control)
 * manpages (*.[0-9])
 * icons (data/icons/<size>/<category>/*.{svg,png})
 * files which should go into /etc (./etc/*, copied verbatim)
 * determining "requires" from import statements in source code
 * determining "provides" from shipped packages and modules

If you follow above conventions, then you don't need any po/POTFILES.in,
./setup.cfg, or ./MANIFEST.in, and just need the project metadata (name,
author, license, etc.) in ./setup.py.
'''

# (c) 2009 Canonical Ltd.
# Author: Martin Pitt <martin.pitt@ubuntu.com>

import os, os.path, fnmatch, stat, sys, subprocess
import ast, locale
import distutils.core
from functools import reduce

from DistUtilsExtra import __version__ as __pkgversion
from DistUtilsExtra.command import *
import distutils.dir_util
import distutils.command.clean
import distutils.command.sdist
import distutils.command.install
import distutils.filelist

__version__ = __pkgversion

# FIXME: global variable, to share with build_i18n_auto
src = {}
src_all = {}

def setup(**attrs):
    '''Auto-inferring extension of standard distutils.core.setup()'''
    global src
    global src_all
    src_all = src_find(attrs)
    src = src_all.copy()

    # src_find() removes explicit scripts, but we need them for automatic
    # POTFILE.in building and requires
    src_all.update(set(attrs.get('scripts', [])))

    src_mark(src, 'setup.py')
    src_markglob(src, 'setup.cfg')

    # mark files in etc/*, handled by install_auto
    # don't install DistUtilsExtra if bundled with a source tarball
    # ignore packaging
    ignore_dirs = ['etc', 'DistUtilsExtra', 'debian']
    
    for f in src.copy():
        for d in ignore_dirs:
            if f.startswith(d + os.path.sep):
                src.remove(f)

    __cmdclass(attrs)
    __modules(attrs, src)
    __packages(attrs, src)
    __provides(attrs, src)
    __dbus(attrs, src)
    __gschema(attrs, src)
    __apport_hooks(attrs, src)
    __data(attrs, src)
    __scripts(attrs, src)
    __stdfiles(attrs, src)
    __ui(attrs, src)
    __manpages(attrs, src)

    if 'clean' not in sys.argv:
        __requires(attrs, src_all)

    distutils.core.setup(**attrs)

    if src:
        print('WARNING: the following files are not recognized by DistUtilsExtra.auto:')
        enc = locale.getpreferredencoding()
        for f in sorted(src):
            # ensure that we can always print the file name
            if(sys.version_info[0] < 3):
                # hack to make this work with Python 2
                f_loc = f.decode('ascii', 'ignore')
            else:
                f_loc = f.encode(enc, errors='replace').decode(enc, errors='replace')
            print ('  ' + f_loc)

#
# parts of setup()
#

class clean_build_tree(distutils.command.clean.clean):

    description = 'clean up build/ directory'

    def run(self):
        # clean build/mo
        if os.path.isdir('build'):
            distutils.dir_util.remove_tree('build')
        distutils.command.clean.clean.run(self)

def __cmdclass(attrs):
    '''Default cmdclass for DistUtilsExtra'''

    v = attrs.setdefault('cmdclass', {})
    v.setdefault('build', build_extra.build_extra)
    v.setdefault('build_help', build_help_auto)
    v.setdefault('build_i18n', build_i18n_auto)
    v.setdefault('build_icons', build_icons.build_icons)
    v.setdefault('install', install_auto)
    v.setdefault('clean', clean_build_tree)
    v.setdefault('sdist', sdist_auto)
    v.setdefault('pylint', pylint.pylint)

def __modules(attrs, src):
    '''Default modules'''

    if 'py_modules' in attrs:
        for mod in attrs['py_modules']:
            print(mod)
            src_markglob(src, os.path.join(mod, '*.py'))
        return

    mods = attrs.setdefault('py_modules', [])

    for f in src_fileglob(src, '*.py'):
        if os.path.sep not in f:
            mods.append(os.path.splitext(f)[0])
            src_markglob(src, f)

def __packages(attrs, src):
    '''Default packages'''

    if 'packages' in attrs:
        for pkg in attrs['packages']:
            src_markglob(src, os.path.join(pkg, '*.py'))
        return

    packages = attrs.setdefault('packages', [])

    for f in src_fileglob(src, '__init__.py'):
        if f.startswith('data' + os.path.sep):
            continue
        pkg = os.path.dirname(f)
        packages.append(pkg)
        src_markglob(src, os.path.join(pkg, '*.py'))

def __dbus(attrs, src):
    '''D-Bus configuration and services'''

    v = attrs.setdefault('data_files', [])

    # /etc/dbus-1/system.d/*.conf
    dbus_conf = []
    for f in src_fileglob(src, '*.conf'):
        if '-//freedesktop//DTD D-BUS Bus Configuration' in open(f).read():
            src_mark(src, f)
            dbus_conf.append(f)
    if dbus_conf:
        v.append(('/etc/dbus-1/system.d/', dbus_conf))

    session_service = []
    system_service = []
    # dbus services
    for f in src_fileglob(src, '*.service'):
        lines = [l.strip() for l in open(f).readlines()]
        if '[D-BUS Service]' not in lines:
            continue
        for l in lines:
            if l.startswith('User='):
                src_mark(src, f)
                system_service.append(f)
                break
        else:
            src_mark(src, f)
            session_service.append(f)
    if system_service:
        v.append(('share/dbus-1/system-services', system_service))
    if session_service:
        v.append(('share/dbus-1/services', session_service))

def __gschema(attrs, src):
    '''Install GSettings schema files'''
    
    v = attrs.setdefault('data_files', [])
    schema_glob = '*.gschema.xml'
    schemas = src_fileglob(src, schema_glob)
    if schemas:
        src_markglob(src, schema_glob)
        src_markglob(src, '*gschemas.compiled')
        v.append(('share/glib-2.0/schemas/', schemas))

def __apport_hooks(attrs, src):      
    '''Apport hooks'''  
    v = attrs.setdefault('data_files', [])

    # files will be copied to /usr/share/apport/package-hooks/
    hooks = []
    assert 'name' in attrs, 'You need to set the "name" property in setup.py'
    for f in src_fileglob(src, '*.py'):
        if f.startswith('apport/'):
            hooks.append(f)
            src_mark(src, f)
    if hooks:
        v.append(('share/apport/package-hooks/', hooks))

def __data(attrs, src):
    '''Install auxiliary data files.

    This installs everything from data/ except data/icons/ and *.in files (which
    are handled differently) into prefix/share/<projectname>/.
    '''
    v = attrs.setdefault('data_files', [])

    assert 'name' in attrs, 'You need to set the "name" property in setup.py'

    data_files = []
    for f in src.copy():
        if f.startswith('data/') and not f.startswith('data/icons/') and \
                not f.endswith('.desktop.in') and not f.endswith('.notifyrc.in'):
            if not os.path.islink(f):
                # symlinks are handled in install_auto
                v.append((os.path.join('share', attrs['name'], os.path.dirname(f[5:])), [f]))
            src_mark(src, f)

def __scripts(attrs, src):
    '''Install scripts.

    This picks executable scripts in bin/*, and an executable ./<projectname>.
    Other scripts have to be added manually; this is to avoid automatically
    installing test suites, build scripts, etc.
    '''
    assert 'name' in attrs, 'You need to set the "name" property in setup.py'

    scripts = []
    for f in src.copy():
        if f.startswith('bin/') or f == attrs['name']:
            st = os.lstat(f)
            if stat.S_ISREG(st.st_mode) and st.st_mode & stat.S_IEXEC:
                scripts.append(f)
                src_mark(src, f)
            elif stat.S_ISLNK(st.st_mode):
                # symlinks are handled in install_auto
                src_mark(src, f)

    if scripts:
        v = attrs.setdefault('scripts', [])
        v += scripts

def __stdfiles(attrs, src):
    '''Install/mark standard files.

    This covers COPYING, AUTHORS, README, etc.
    '''
    src_markglob(src, 'COPYING*')
    src_markglob(src, 'LICENSE*')
    src_markglob(src, 'AUTHORS')
    src_markglob(src, 'MANIFEST.in')
    src_markglob(src, 'MANIFEST')
    src_markglob(src, 'TODO')

    # install all README* from the root directory
    readme = []
    for f in src_fileglob(src, 'README*').union(src_fileglob(src, 'NEWS')):
        if os.path.sep not in f:
            readme.append(f)
            src_mark(src, f)
    if readme:
        assert 'name' in attrs, 'You need to set the "name" property in setup.py'

        attrs.setdefault('data_files', []).append((os.path.join('share', 'doc',
            attrs['name']), readme))

def __ui(attrs, src):
    '''Install GtkBuilder/Qt *.ui files'''

    ui = []
    for f in src_fileglob(src, '*.ui'):
        fd = open(f, 'rb')
        firstlines = fd.readline()
        firstlines += b'\n' + fd.readline()
        fd.close()
        if b'<interface' in firstlines or b'<ui version=' in firstlines:
            src_mark(src, f)
            ui.append(f)
    if ui:
        assert 'name' in attrs, 'You need to set the "name" property in setup.py'

        attrs.setdefault('data_files', []).append((os.path.join('share', 
            attrs['name']), ui))

def __manpages(attrs, src):
    '''Install manpages'''

    mans = {}
    for f in src_fileglob(src, '*.[0123456789]'):
        with open(f) as fd:
            for line in fd:
                if line.startswith('.\"'):
                    continue
                if line.startswith('.TH '):
                    src_mark(src, f)
                    mans.setdefault(f[-1], []).append(f)
                break

    v = attrs.setdefault('data_files', [])
    for section, files in mans.items():
        v.append((os.path.join('share', 'man', 'man' + section), files))

def __external_mod(cur_module, module, attrs):
    '''Check if given Python module is not included in Python or locally'''

    # filter out locally provided modules early, to avoid importing them (which
    # might raise an exception, or parse argv, etc.)
    if module in attrs['provides']:
        return False
    for m in _module_parents(module):
        if m in attrs['provides']:
            return False

    try:
        mod = __import__(module)
    except ImportError:
        # try relative import
        try:
            if cur_module:
                mod = __import__(cur_module + '.' + module)
            else:
                raise ImportError
        except ImportError:
            sys.stderr.write('ERROR: Python module %s not found\n' % module)
            return False
        except ValueError: # weird ctypes case with wintypes
            return False 
        except RuntimeError: # When Gdk can't be initialized
            return False
    except ValueError: # weird ctypes case with wintypes
        return False 
    except RuntimeError: # When Gdk can't be initialized
        return False

    if not hasattr(mod, '__file__'):
        # builtin module
        return False

    # filter out locally provided modules
    if mod.__name__ in attrs['provides']:
        return False

    return 'dist-packages' in mod.__file__ or 'site-packages' in mod.__file__ or \
            not mod.__file__.startswith(os.path.dirname(os.__file__))

def __add_imports(imports, file, attrs):
    '''Add all imported modules from file to imports set.

    This filters out modules which are shipped with Python itself.
    '''
    if os.path.exists(os.path.join(os.path.dirname(file), '__init__.py')):
        cur_module = '.'.join(file.split(os.path.sep)[:-1])
    else:
        # this might happen for paths like bin/<script> which we do not want to
        # treat as module for checking relative imports
        cur_module = None

    try:
        with open(file, 'rb') as f:
            # send binary blob for python2, otherwise sending an unicode object with
            # "encoding" directive makes ast triggering an exception in python2
            if(sys.version_info[0] < 3):
                file_content = f.read()
            else:
                file_content = f.read().decode('UTF-8')
            tree = ast.parse(file_content, file)

        for node in ast.walk(tree):
            if isinstance(node, ast.Import):
                for alias in node.names:
                    if alias.name and __external_mod(cur_module, alias.name, attrs):
                        imports.add(alias.name)
            if isinstance(node, ast.ImportFrom):
                if node.module == 'gi.repository':
                    for name in node.names:
                        imports.add('gi.repository.%s' % name.name)

                elif node.module and __external_mod(cur_module, node.module, attrs):
                    imports.add(node.module)
    except SyntaxError as e:
        sys.stderr.write('WARNING: syntax errors in %s: %s\n' % (file, str(e)))

def _module_parents(mod):
    '''Iterate over all parents of a module'''

    hierarchy = mod.split('.')
    hierarchy.pop()
    while hierarchy:
        yield '.'.join(hierarchy)
        hierarchy.pop()

def __filter_namespace(modules):
    '''Filter out modules which are already covered by a parent module
    
    E. g. this transforms ['os.path', 'os', 'foo.bar.baz', 'foo.bar'] to
    ['os', 'foo.bar'].
    '''
    result = set()

    for m in modules:
        if m.startswith('gi.repository.'):
            result.add(m)
            continue
        for p in _module_parents(m):
            if p in modules:
                break
        else:
            result.add(m)

    return sorted(result)

def __requires(attrs, src_all):
    '''Determine requires (if not set explicitly)'''

    if 'requires' in attrs:
        return

    imports = set()

    # iterate over all *.py and scripts which are Python
    for s in src_all:
        if s == 'setup.py':
            continue
        if s.startswith('data' + os.path.sep):
            continue
        ext = os.path.splitext(s)[1]
        if ext == '':
            try:
                with open(s) as f:
                    line = f.readline()
            except (UnicodeDecodeError, IOError):
                continue
            if not line.startswith('#!') or 'python' not in line:
                continue
        elif ext != '.py':
            continue
        __add_imports(imports, s, attrs)

    attrs['requires'] = __filter_namespace(imports)

def __provides(attrs, src_all):
    '''Determine provides (if not set explicitly)'''

    if 'provides' in attrs:
        return

    provides = list(attrs.get('py_modules', [])) # we need a copy here
    for p in attrs.get('packages', []):
        provides.append(p.replace(os.path.sep, '.'))
    attrs['provides'] = __filter_namespace(provides)
 
#
# helper functions
#

def src_find(attrs):
    '''Find source files.
    
    This ignores all source files which are explicitly specified as setup()
    arguments.
    '''
    src = set()

    # files explicitly covered in setup() call
    explicit = set(attrs.get('scripts', []))
    for (destdir, files) in attrs.get('data_files', []):
        explicit.update(files)

    for (root, dirs, files) in os.walk('.'):
        if root.startswith('./'):
            root = root[2:]
        if root == '.':
            root = ''
        if root.startswith('.') or \
                root.split(os.path.sep, 1)[0] in ('build', 'test', 'tests'):
            continue
        # data/icons is handled by build_icons
        if root.startswith(os.path.join('data', 'icons')):
            continue
        for f in files:
            ext = os.path.splitext(f)[1]
            if f.startswith('.') or ext in ('.pyc', '~', '.mo'):
                continue
            # po/*.po is taken care of by build_i18n
            if root == 'po' and (ext == '.po' or f == 'POTFILES.in'):
                continue
            
            path = os.path.join(root, f)
            if path not in explicit:
                src.add(path)

    return src

def src_fileglob(src, fnameglob):
    '''Return set of files which match fnameglob.'''

    result = set()
    for f in src:
        if fnmatch.fnmatch(os.path.basename(f), fnameglob):
            result.add(f)
    return result

def src_mark(src, path):
    '''Remove path from src.'''

    src.remove(path)

def src_markglob(src, pathglob):
    '''Remove all paths from src which match pathglob.'''

    for f in src.copy():
        if fnmatch.fnmatch(f, pathglob):
            src.remove(f)

#
# Automatic setup.cfg
#

class build_help_auto(build_help.build_help):
    def finalize_options(self):
        build_help.build_help.finalize_options(self)
        global src
        
        for data_set in self.get_data_files():
            for filepath in data_set[1]:
                src.remove(filepath)

class build_i18n_auto(build_i18n.build_i18n):
    def finalize_options(self):
        build_i18n.build_i18n.finalize_options(self)
        global src
        global src_all

        # add polkit files
        policy_files = []
        for f in src_fileglob(src, '*.policy.in'):
            src_mark(src, f)
            policy_files.append(f)
        if policy_files:
            try:
                xf = eval(self.xml_files)
            except TypeError:
                xf = []
            xf.append((os.path.join('share', 'polkit-1', 'actions'), policy_files))
            self.xml_files = repr(xf)

        # add desktop files
        desktop_files = []
        autostart_files = []
        notify_files = []
        for f in src_fileglob(src, '*.desktop.in'):
            src_mark(src, f)
            if 'autostart' in f:
                autostart_files.append(f)
            else:
                desktop_files.append(f)
        for f in src_fileglob(src, '*.notifyrc.in'):
            src_mark(src, f)
            notify_files.append(f)
        try:
            df = eval(self.desktop_files)
        except TypeError:
            df = []
        if desktop_files:
            df.append(('share/applications', desktop_files))
        if autostart_files:
            df.append(('share/autostart', autostart_files))
        if notify_files:
            df.append(('share/kde4/apps/' + self.distribution.get_name(), notify_files))
        self.desktop_files = repr(df)
        
        # mark PO template as known to handle
        try:
            src_mark(src, os.path.join(self.po_dir, self.distribution.get_name() + '.pot'))
        except KeyError:
            pass

    def run(self):
        '''Build a default POTFILES.in'''

        auto_potfiles_in = False
        exe_symlinks = []
        global src_all
        try:
            if not os.path.exists(os.path.join('po', 'POTFILES.in')):
                files = src_fileglob(src_all, '*.py')
                files.update(src_fileglob(src_all, '*.desktop.in'))
                files.update(src_fileglob(src_all, '*.notifyrc.in'))
                files.update(src_fileglob(src_all, '*.policy.in'))

                for f in src_fileglob(src_all, '*.ui'):
                    contents = open(f, 'rb').read()
                    if (b'<interface>\n' in contents or b'<interface ' in contents) and b'class="Gtk' in contents:
                        files.add('[type: gettext/glade]' + f)

                # find extensionless executable scripts which are Python files, and
                # generate a temporary *.py alias, so that they get caught by
                # intltool
                for f in reduce(lambda x, y: x.union(y[1]), self.distribution.data_files, src_all):
                    f_py = f + '.py'
                    if os.access(f, os.X_OK) and os.path.splitext(f)[1] == '' and \
                            not os.path.exists(f_py):
                        line = open(f, 'rb').readline()
                        if line.startswith(b'#!') and b'python' in line:
                            os.symlink(os.path.basename(f), f_py)
                            files.add(f_py)
                            exe_symlinks.append(f_py)

                if files:
                    if not os.path.isdir('po'):
                        os.mkdir('po')
                    potfiles_in = open('po/POTFILES.in', 'w')
                    potfiles_in.write('[encoding: UTF-8]\n')
                    for f in files:
                        potfiles_in.write(f + '\n')
                    potfiles_in.close()

                    auto_potfiles_in = True

            build_i18n.build_i18n.run(self)
        finally:
            for f in exe_symlinks:
                os.unlink(f)

        if auto_potfiles_in:
            os.unlink('po/POTFILES.in')
            try:
                os.rmdir('po')
            except:
                pass

#
# Automatic sdist
#

class sdist_auto(distutils.command.sdist.sdist):
    '''Default values for the 'sdist' command.
    
    Replace the manually maintained MANIFEST.in file by providing information
    about what the source tarball created using the 'sdist' command should
    contain in normal cases.
    
    It prevents the 'build' directory, version control related files, as well as
    compiled Python and gettext files and temporary files from being included in
    the source tarball.
    
    It's possible for subclasses to extend the 'filter_prefix' and
    'filter_suffix' properties.
    '''
    filter_prefix = ['build', '.git', '.svn', '.CVS', '.bzr', '.shelf']
    filter_suffix = ['.pyc', '.mo', '~', '.swp']
    
    def add_defaults(self):
        distutils.command.sdist.sdist.add_defaults(self)
        
        if os.path.exists('MANIFEST.in'):
            return

        self.filter_prefix.append(os.path.join('dist',
            self.distribution.get_name()))
        
        for f in distutils.filelist.findall():
            if f in self.filelist.files or \
                any(map(f.startswith, self.filter_prefix)) or \
                any(map(f.endswith, self.filter_suffix)):
                continue
            
            self.filelist.append(f)

#
# Automatic installation of ./etc/ and symlinks
#

class install_auto(distutils.command.install.install):
    def run(self):
        # install files from etc/
        if os.path.isdir('etc'):
            # work around a bug in copy_tree() which fails with "File exists" on
            # previously existing symlinks
            for f in distutils.filelist.findall('etc'):
                if not f.startswith('etc' + os.path.sep) or not os.path.islink(f):
                    continue
                try:
                    os.unlink(os.path.join(self.root, f))
                except OSError:
                    pass
            if not self.root:
                self.root = ''
            distutils.dir_util.copy_tree('etc', os.path.join(self.root, 'etc'),
                    preserve_times=0, preserve_symlinks=1, verbose=1)

        # install data/scripts symlinks
        for (path, dirs, files) in os.walk('.'):
            for f in files:
                f = os.path.join(path, f)
                if not os.path.islink(f):
                    continue

                if f.startswith('./bin/') or f.startswith('./data/'):
                    if f.startswith('./bin'):
                        dir = self.install_scripts
                        dest = os.path.join(dir, os.path.sep.join(f.split(os.path.sep)[2:]))
                    elif f.startswith('./data/icons'):
                        dir = os.path.join(self.install_data, 'share', 'icons', 'hicolor')
                        dest = os.path.join(dir, os.path.sep.join(f.split(os.path.sep)[3:]))
                    else:
                        dir = os.path.join(self.install_data, 'share', self.distribution.get_name())
                        dest = os.path.join(dir, os.path.sep.join(f.split(os.path.sep)[2:]))

                    d = os.path.dirname(dest)
                    if not os.path.isdir(d):
                        os.makedirs(d)
                    if os.path.exists(dest):
                        os.unlink(dest)
                    os.symlink(os.readlink(f), dest)

        distutils.command.install.install.run(self)