aboutsummaryrefslogtreecommitdiffstats
path: root/setuptools/command/egg_info.py
blob: 7d0a1473b8c3f51872cd082c2db0908b2f234879 (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
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
"""setuptools.command.egg_info

Create a distribution's .egg-info directory and contents"""

# This module should be kept compatible with Python 2.3
import os
from setuptools import Command
from distutils.errors import *
from distutils import log
from pkg_resources import parse_requirements, safe_name, \
    safe_version, yield_lines, EntryPoint

class egg_info(Command):

    description = "create a distribution's .egg-info directory"

    user_options = [
        ('egg-base=', 'e', "directory containing .egg-info directories"
                           " (default: top of the source tree)"),
        ('tag-svn-revision', 'r',
            "Add subversion revision ID to version number"),
        ('tag-date', 'd', "Add date stamp (e.g. 20050528) to version number"),
        ('tag-build=', 'b', "Specify explicit tag to add to version number"),
    ]

    boolean_options = ['tag-date','tag-svn-revision']


    def initialize_options (self):
        self.egg_name = None
        self.egg_version = None
        self.egg_base = None
        self.egg_info = None
        self.tag_build = None
        self.tag_svn_revision = 0
        self.tag_date = 0





    def finalize_options (self):
        self.egg_name = safe_name(self.distribution.get_name())
        self.egg_version = self.tagged_version()

        try:
            list(
                parse_requirements('%s==%s' % (self.egg_name,self.egg_version))
            )
        except ValueError:
            raise DistutilsOptionError(
                "Invalid distribution name or version syntax: %s-%s" %
                (self.egg_name,self.egg_version)
            )

        if self.egg_base is None:
            dirs = self.distribution.package_dir
            self.egg_base = (dirs or {}).get('',os.curdir)

        self.ensure_dirname('egg_base')
        self.egg_info = os.path.join(self.egg_base, self.egg_name+'.egg-info')

        # Set package version and name for the benefit of dumber commands
        # (e.g. sdist, bdist_wininst, etc.)  We escape '-' so filenames will
        # be more machine-parseable.
        #
        metadata = self.distribution.metadata
        metadata.version = self.egg_version.replace('-','_')
        metadata.name    = self.egg_name.replace('-','_')













    def run(self):
        # Make the .egg-info directory, then write PKG-INFO and requires.txt
        self.mkpath(self.egg_info)
        log.info("writing %s" % os.path.join(self.egg_info,'PKG-INFO'))

        if not self.dry_run:
            metadata = self.distribution.metadata
            metadata.version, oldver = self.egg_version, metadata.version
            metadata.name, oldname   = self.egg_name, metadata.name
            try:
                # write unescaped data to PKG-INFO, so older pkg_resources
                # can still parse it
                metadata.write_pkg_info(self.egg_info)
            finally:
                metadata.name, metadata.version = oldname, oldver
        self.write_entry_points()
        self.write_requirements()
        self.write_toplevel_names()
        self.write_or_delete_dist_arg('namespace_packages')
        self.write_or_delete_dist_arg('eager_resources')
        if os.path.exists(os.path.join(self.egg_info,'depends.txt')):
            log.warn(
                "WARNING: 'depends.txt' is not used by setuptools 0.6!\n"
                "Use the install_requires/extras_require setup() args instead."
            )

    def write_requirements(self):
        dist = self.distribution
        if not getattr(dist,'install_requires',None) and \
           not getattr(dist,'extras_require',None): return

        requires = os.path.join(self.egg_info,"requires.txt")
        log.info("writing %s", requires)

        if not self.dry_run:
            f = open(requires, 'wt')
            f.write('\n'.join(yield_lines(dist.install_requires)))
            for extra,reqs in dist.extras_require.items():
                f.write('\n\n[%s]\n%s' % (extra, '\n'.join(yield_lines(reqs))))
            f.close()

    def tagged_version(self):
        version = self.distribution.get_version()
        if self.tag_build:
            version+=self.tag_build
        if self.tag_svn_revision and os.path.exists('.svn'):
            version += '-r%s' % self.get_svn_revision()
        if self.tag_date:
            import time
            version += time.strftime("-%Y%m%d")
        return safe_version(version)


    def get_svn_revision(self):
        stdin, stdout = os.popen4("svn info -R"); stdin.close()
        result = stdout.read(); stdout.close()
        import re
        revisions = [
            int(match.group(1))
                for match in re.finditer(r'Last Changed Rev: (\d+)', result)
        ]
        if not revisions:
            raise DistutilsError("svn info error: %s" % result.strip())
        return str(max(revisions))


    def write_toplevel_names(self):
        pkgs = dict.fromkeys(
            [k.split('.',1)[0]
                for k in self.distribution.iter_distribution_names()
            ]
        )
        toplevel = os.path.join(self.egg_info, "top_level.txt")
        log.info("writing list of top-level names to %s" % toplevel)
        if not self.dry_run:
            f = open(toplevel, 'wt')
            f.write('\n'.join(pkgs))
            f.write('\n')
            f.close()



    def write_or_delete_dist_arg(self, argname, filename=None):
        value = getattr(self.distribution, argname, None)
        filename = filename or argname+'.txt'
        filename = os.path.join(self.egg_info,filename)
        if value:
            log.info("writing %s", filename)
            if not self.dry_run:
                f = open(filename, 'wt')
                f.write('\n'.join(value))
                f.write('\n')
                f.close()
        elif os.path.exists(filename):
            if value is None:
                log.warn(
                    "%s not set in setup(), but %s exists", argname, filename
                )
            return
            log.info("deleting %s", filename)
            if not self.dry_run:
                os.unlink(filename)

    def write_entry_points(self):
        ep = getattr(self.distribution,'entry_points',None)
        if ep is None:
            return

        epname = os.path.join(self.egg_info,"entry_points.txt")
        log.info("writing %s", epname)

        if not self.dry_run:
            f = open(epname, 'wt')
            if isinstance(ep,basestring):
                f.write(ep)
            else:
                for section, contents in ep.items():
                    if not isinstance(contents,basestring):
                        contents = EntryPoint.parse_list(section, contents)
                        contents = '\n'.join(map(str,contents.values()))
                    f.write('[%s]\n%s\n\n' % (section,contents))
            f.close()