Statistics
| Branch: | Revision:

root / env / lib / python2.7 / site-packages / distribute-0.6.19-py2.7.egg / setuptools / command / egg_info.py @ 1a305335

History | View | Annotate | Download (14 KB)

1
"""setuptools.command.egg_info
2

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

    
5
# This module should be kept compatible with Python 2.3
6
import os, re, sys
7
from setuptools import Command
8
from distutils.errors import *
9
from distutils import log
10
from setuptools.command.sdist import sdist
11
from distutils.util import convert_path
12
from distutils.filelist import FileList
13
from pkg_resources import parse_requirements, safe_name, parse_version, \
14
    safe_version, yield_lines, EntryPoint, iter_entry_points, to_filename
15
from sdist import walk_revctrl
16

    
17
class egg_info(Command):
18
    description = "create a distribution's .egg-info directory"
19

    
20
    user_options = [
21
        ('egg-base=', 'e', "directory containing .egg-info directories"
22
                           " (default: top of the source tree)"),
23
        ('tag-svn-revision', 'r',
24
            "Add subversion revision ID to version number"),
25
        ('tag-date', 'd', "Add date stamp (e.g. 20050528) to version number"),
26
        ('tag-build=', 'b', "Specify explicit tag to add to version number"),
27
        ('no-svn-revision', 'R',
28
            "Don't add subversion revision ID [default]"),
29
        ('no-date', 'D', "Don't include date stamp [default]"),
30
    ]
31

    
32
    boolean_options = ['tag-date', 'tag-svn-revision']
33
    negative_opt = {'no-svn-revision': 'tag-svn-revision',
34
                    'no-date': 'tag-date'}
35

    
36

    
37

    
38

    
39

    
40

    
41

    
42
    def initialize_options(self):
43
        self.egg_name = None
44
        self.egg_version = None
45
        self.egg_base = None
46
        self.egg_info = None
47
        self.tag_build = None
48
        self.tag_svn_revision = 0
49
        self.tag_date = 0
50
        self.broken_egg_info = False
51
        self.vtags = None
52

    
53
    def save_version_info(self, filename):
54
        from setopt import edit_config
55
        edit_config(
56
            filename,
57
            {'egg_info':
58
                {'tag_svn_revision':0, 'tag_date': 0, 'tag_build': self.tags()}
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
    def finalize_options (self):
84
        self.egg_name = safe_name(self.distribution.get_name())
85
        self.vtags = self.tags()
86
        self.egg_version = self.tagged_version()
87

    
88
        try:
89
            list(
90
                parse_requirements('%s==%s' % (self.egg_name,self.egg_version))
91
            )
92
        except ValueError:
93
            raise DistutilsOptionError(
94
                "Invalid distribution name or version syntax: %s-%s" %
95
                (self.egg_name,self.egg_version)
96
            )
97

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

    
102
        self.ensure_dirname('egg_base')
103
        self.egg_info = to_filename(self.egg_name)+'.egg-info'
104
        if self.egg_base != os.curdir:
105
            self.egg_info = os.path.join(self.egg_base, self.egg_info)
106
        if '-' in self.egg_name: self.check_broken_egg_info()
107

    
108
        # Set package version for the benefit of dumber commands
109
        # (e.g. sdist, bdist_wininst, etc.)
110
        #
111
        self.distribution.metadata.version = self.egg_version
112

    
113
        # If we bootstrapped around the lack of a PKG-INFO, as might be the
114
        # case in a fresh checkout, make sure that any special tags get added
115
        # to the version info
116
        #
117
        pd = self.distribution._patched_dist
118
        if pd is not None and pd.key==self.egg_name.lower():
119
            pd._version = self.egg_version
120
            pd._parsed_version = parse_version(self.egg_version)
121
            self.distribution._patched_dist = None
122

    
123

    
124
    def write_or_delete_file(self, what, filename, data, force=False):
125
        """Write `data` to `filename` or delete if empty
126

127
        If `data` is non-empty, this routine is the same as ``write_file()``.
128
        If `data` is empty but not ``None``, this is the same as calling
129
        ``delete_file(filename)`.  If `data` is ``None``, then this is a no-op
130
        unless `filename` exists, in which case a warning is issued about the
131
        orphaned file (if `force` is false), or deleted (if `force` is true).
132
        """
133
        if data:
134
            self.write_file(what, filename, data)
135
        elif os.path.exists(filename):
136
            if data is None and not force:
137
                log.warn(
138
                    "%s not set in setup(), but %s exists", what, filename
139
                )
140
                return
141
            else:
142
                self.delete_file(filename)
143

    
144
    def write_file(self, what, filename, data):
145
        """Write `data` to `filename` (if not a dry run) after announcing it
146

147
        `what` is used in a log message to identify what is being written
148
        to the file.
149
        """
150
        log.info("writing %s to %s", what, filename)
151
        if sys.version_info >= (3,):
152
            data = data.encode("utf-8")
153
        if not self.dry_run:
154
            f = open(filename, 'wb')
155
            f.write(data)
156
            f.close()
157

    
158
    def delete_file(self, filename):
159
        """Delete `filename` (if not a dry run) after announcing it"""
160
        log.info("deleting %s", filename)
161
        if not self.dry_run:
162
            os.unlink(filename)
163

    
164
    def tagged_version(self):
165
        return safe_version(self.distribution.get_version() + self.vtags)
166

    
167
    def run(self):
168
        self.mkpath(self.egg_info)
169
        installer = self.distribution.fetch_build_egg
170
        for ep in iter_entry_points('egg_info.writers'):
171
            writer = ep.load(installer=installer)
172
            writer(self, ep.name, os.path.join(self.egg_info,ep.name))
173

    
174
        # Get rid of native_libs.txt if it was put there by older bdist_egg
175
        nl = os.path.join(self.egg_info, "native_libs.txt")
176
        if os.path.exists(nl):
177
            self.delete_file(nl)
178

    
179
        self.find_sources()
180

    
181
    def tags(self):
182
        version = ''
183
        if self.tag_build:
184
            version+=self.tag_build
185
        if self.tag_svn_revision and (
186
            os.path.exists('.svn') or os.path.exists('PKG-INFO')
187
        ):  version += '-r%s' % self.get_svn_revision()
188
        if self.tag_date:
189
            import time; version += time.strftime("-%Y%m%d")
190
        return version
191

    
192

    
193

    
194

    
195

    
196

    
197

    
198

    
199

    
200

    
201

    
202

    
203

    
204

    
205

    
206

    
207

    
208
    def get_svn_revision(self):
209
        revision = 0
210
        urlre = re.compile('url="([^"]+)"')
211
        revre = re.compile('committed-rev="(\d+)"')
212

    
213
        for base,dirs,files in os.walk(os.curdir):
214
            if '.svn' not in dirs:
215
                dirs[:] = []
216
                continue    # no sense walking uncontrolled subdirs
217
            dirs.remove('.svn')
218
            f = open(os.path.join(base,'.svn','entries'))
219
            data = f.read()
220
            f.close()
221

    
222
            if data.startswith('10') or data.startswith('9') or data.startswith('8'):
223
                data = map(str.splitlines,data.split('\n\x0c\n'))
224
                del data[0][0]  # get rid of the '8' or '9' or '10'
225
                dirurl = data[0][3]
226
                localrev = max([int(d[9]) for d in data if len(d)>9 and d[9]]+[0])
227
            elif data.startswith('<?xml'):
228
                dirurl = urlre.search(data).group(1)    # get repository URL
229
                localrev = max([int(m.group(1)) for m in revre.finditer(data)]+[0])
230
            else:
231
                log.warn("unrecognized .svn/entries format; skipping %s", base)
232
                dirs[:] = []
233
                continue
234
            if base==os.curdir:
235
                base_url = dirurl+'/'   # save the root url
236
            elif not dirurl.startswith(base_url):
237
                dirs[:] = []
238
                continue    # not part of the same svn tree, skip it
239
            revision = max(revision, localrev)
240

    
241
        return str(revision or get_pkg_info_revision())
242

    
243

    
244

    
245

    
246

    
247

    
248

    
249
    def find_sources(self):
250
        """Generate SOURCES.txt manifest file"""
251
        manifest_filename = os.path.join(self.egg_info,"SOURCES.txt")
252
        mm = manifest_maker(self.distribution)
253
        mm.manifest = manifest_filename
254
        mm.run()
255
        self.filelist = mm.filelist
256

    
257
    def check_broken_egg_info(self):
258
        bei = self.egg_name+'.egg-info'
259
        if self.egg_base != os.curdir:
260
            bei = os.path.join(self.egg_base, bei)
261
        if os.path.exists(bei):
262
            log.warn(
263
                "-"*78+'\n'
264
                "Note: Your current .egg-info directory has a '-' in its name;"
265
                '\nthis will not work correctly with "setup.py develop".\n\n'
266
                'Please rename %s to %s to correct this problem.\n'+'-'*78,
267
                bei, self.egg_info
268
            )
269
            self.broken_egg_info = self.egg_info
270
            self.egg_info = bei     # make it work for now
271

    
272
class FileList(FileList):
273
    """File list that accepts only existing, platform-independent paths"""
274

    
275
    def append(self, item):
276
        if item.endswith('\r'):     # Fix older sdists built on Windows
277
            item = item[:-1]
278
        path = convert_path(item)
279
        if os.path.exists(path):
280
            self.files.append(path)
281

    
282

    
283

    
284

    
285

    
286

    
287

    
288

    
289

    
290
class manifest_maker(sdist):
291

    
292
    template = "MANIFEST.in"
293

    
294
    def initialize_options (self):
295
        self.use_defaults = 1
296
        self.prune = 1
297
        self.manifest_only = 1
298
        self.force_manifest = 1
299

    
300
    def finalize_options(self):
301
        pass
302

    
303
    def run(self):
304
        self.filelist = FileList()
305
        if not os.path.exists(self.manifest):
306
            self.write_manifest()   # it must exist so it'll get in the list
307
        self.filelist.findall()
308
        self.add_defaults()
309
        if os.path.exists(self.template):
310
            self.read_template()
311
        self.prune_file_list()
312
        self.filelist.sort()
313
        self.filelist.remove_duplicates()
314
        self.write_manifest()
315

    
316
    def write_manifest (self):
317
        """Write the file list in 'self.filelist' (presumably as filled in
318
        by 'add_defaults()' and 'read_template()') to the manifest file
319
        named by 'self.manifest'.
320
        """
321
        files = self.filelist.files
322
        if os.sep!='/':
323
            files = [f.replace(os.sep,'/') for f in files]
324
        self.execute(write_file, (self.manifest, files),
325
                     "writing manifest file '%s'" % self.manifest)
326

    
327
    def warn(self, msg):    # suppress missing-file warnings from sdist
328
        if not msg.startswith("standard file not found:"):
329
            sdist.warn(self, msg)
330

    
331
    def add_defaults(self):
332
        sdist.add_defaults(self)
333
        self.filelist.append(self.template)
334
        self.filelist.append(self.manifest)
335
        rcfiles = list(walk_revctrl())
336
        if rcfiles:
337
            self.filelist.extend(rcfiles)
338
        elif os.path.exists(self.manifest):
339
            self.read_manifest()
340
        ei_cmd = self.get_finalized_command('egg_info')
341
        self.filelist.include_pattern("*", prefix=ei_cmd.egg_info)
342

    
343
    def prune_file_list (self):
344
        build = self.get_finalized_command('build')
345
        base_dir = self.distribution.get_fullname()
346
        self.filelist.exclude_pattern(None, prefix=build.build_base)
347
        self.filelist.exclude_pattern(None, prefix=base_dir)
348
        sep = re.escape(os.sep)
349
        self.filelist.exclude_pattern(sep+r'(RCS|CVS|\.svn)'+sep, is_regex=1)
350

    
351

    
352
def write_file (filename, contents):
353
    """Create a file with the specified name and write 'contents' (a
354
    sequence of strings without line terminators) to it.
355
    """
356
    contents = "\n".join(contents)
357
    if sys.version_info >= (3,):
358
        contents = contents.encode("utf-8")
359
    f = open(filename, "wb")        # always write POSIX-style manifest
360
    f.write(contents)
361
    f.close()
362

    
363

    
364

    
365

    
366

    
367

    
368

    
369

    
370

    
371

    
372

    
373

    
374

    
375
def write_pkg_info(cmd, basename, filename):
376
    log.info("writing %s", filename)
377
    if not cmd.dry_run:
378
        metadata = cmd.distribution.metadata
379
        metadata.version, oldver = cmd.egg_version, metadata.version
380
        metadata.name, oldname   = cmd.egg_name, metadata.name
381
        try:
382
            # write unescaped data to PKG-INFO, so older pkg_resources
383
            # can still parse it
384
            metadata.write_pkg_info(cmd.egg_info)
385
        finally:
386
            metadata.name, metadata.version = oldname, oldver
387

    
388
        safe = getattr(cmd.distribution,'zip_safe',None)
389
        import bdist_egg; bdist_egg.write_safety_flag(cmd.egg_info, safe)
390

    
391
def warn_depends_obsolete(cmd, basename, filename):
392
    if os.path.exists(filename):
393
        log.warn(
394
            "WARNING: 'depends.txt' is not used by setuptools 0.6!\n"
395
            "Use the install_requires/extras_require setup() args instead."
396
        )
397

    
398

    
399
def write_requirements(cmd, basename, filename):
400
    dist = cmd.distribution
401
    data = ['\n'.join(yield_lines(dist.install_requires or ()))]
402
    for extra,reqs in (dist.extras_require or {}).items():
403
        data.append('\n\n[%s]\n%s' % (extra, '\n'.join(yield_lines(reqs))))
404
    cmd.write_or_delete_file("requirements", filename, ''.join(data))
405

    
406
def write_toplevel_names(cmd, basename, filename):
407
    pkgs = dict.fromkeys(
408
        [k.split('.',1)[0]
409
            for k in cmd.distribution.iter_distribution_names()
410
        ]
411
    )
412
    cmd.write_file("top-level names", filename, '\n'.join(pkgs)+'\n')
413

    
414

    
415

    
416
def overwrite_arg(cmd, basename, filename):
417
    write_arg(cmd, basename, filename, True)
418

    
419
def write_arg(cmd, basename, filename, force=False):
420
    argname = os.path.splitext(basename)[0]
421
    value = getattr(cmd.distribution, argname, None)
422
    if value is not None:
423
        value = '\n'.join(value)+'\n'
424
    cmd.write_or_delete_file(argname, filename, value, force)
425

    
426
def write_entries(cmd, basename, filename):
427
    ep = cmd.distribution.entry_points
428

    
429
    if isinstance(ep,basestring) or ep is None:
430
        data = ep
431
    elif ep is not None:
432
        data = []
433
        for section, contents in ep.items():
434
            if not isinstance(contents,basestring):
435
                contents = EntryPoint.parse_group(section, contents)
436
                contents = '\n'.join(map(str,contents.values()))
437
            data.append('[%s]\n%s\n\n' % (section,contents))
438
        data = ''.join(data)
439

    
440
    cmd.write_or_delete_file('entry points', filename, data, True)
441

    
442
def get_pkg_info_revision():
443
    # See if we can get a -r### off of PKG-INFO, in case this is an sdist of
444
    # a subversion revision
445
    #
446
    if os.path.exists('PKG-INFO'):
447
        f = open('PKG-INFO','rU')
448
        for line in f:
449
            match = re.match(r"Version:.*-r(\d+)\s*$", line)
450
            if match:
451
                return int(match.group(1))
452
        f.close()
453
    return 0
454

    
455

    
456

    
457
#