aboutsummaryrefslogtreecommitdiffstats
path: root/setuptools/command/sdist.py
blob: cdbc5248fdca175306b5145b2e5012bee7a50b23 (plain)
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
from distutils.command.sdist import sdist as _sdist
from distutils.util import convert_path
import os,re

entities = [
    ("&lt;","<"), ("&gt;", ">"), ("&quot;", '"'), ("&apos;", "'"),
    ("&amp;", "&")
]

def unescape(data):
    for old,new in entities:
        data = data.replace(old,new)
    return data

def re_finder(pattern, postproc=None):
    def find(dirname, filename):
        f = open(filename,'rU')
        data = f.read()
        f.close()
        for match in pattern.finditer(data):
            path = match.group(1)
            if postproc:
                path = postproc(path)
            yield joinpath(dirname,path)
    return find

def joinpath(prefix,suffix):
    if not prefix:
        return suffix
    return os.path.join(prefix,suffix)











def walk_revctrl(dirname='', memo=None):
    """Find all files under revision control"""
    if memo is None:
        memo = {}
    if dirname in memo:
        # Don't rescan a scanned directory
        return
    for path, finder in finders:
        path = joinpath(dirname,path)
        if os.path.isfile(path):
            for path in finder(dirname,path):
                if os.path.isfile(path):
                    yield path
                elif os.path.isdir(path):
                    for item in walk_revctrl(path, memo):
                        yield item

def externals_finder(dirname, filename):
    """Find any 'svn:externals' directories"""
    found = False
    f = open(filename,'rb')
    for line in iter(f.readline, ''):    # can't use direct iter!
        parts = line.split()
        if len(parts)==2:
            kind,length = parts
            data = f.read(int(length))
            if kind=='K' and data=='svn:externals':
                found = True
            elif kind=='V' and found:
                f.close()
                break
    else:
        f.close()
        return

    for line in data.splitlines():
        parts = line.split()
        if parts:
            yield joinpath(dirname, parts[0])


finders = [
    (convert_path('CVS/Entries'),
        re_finder(re.compile(r"^\w?/([^/]+)/", re.M))),
    (convert_path('.svn/entries'),
        re_finder(
            re.compile(r'name="([^"]+)"(?![^>]+deleted="true")', re.I),
            unescape
        )
    ),
    (convert_path('.svn/dir-props'), externals_finder),
]


class sdist(_sdist):
    """Smart sdist that finds anything supported by revision control"""

    def run(self):
        self.run_command('egg_info')
        _sdist.run(self)
        dist_files = getattr(self.distribution,'dist_files',[])
        for file in self.archive_files:
            data = ('sdist', '', file)
            if data not in dist_files:
                dist_files.append(data)

    def finalize_options(self):
        _sdist.finalize_options(self)
        if not os.path.isfile(self.template):
            self.force_manifest = 1     # always regen if no template

    def add_defaults(self):
        _sdist.add_defaults(self)
        self.filelist.extend(walk_revctrl())