Project

General

Profile

Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (68.5 KB)

1
#!python
2
"""\
3
Easy Install
4
------------
5

6
A tool for doing automatic download/extract/build of distutils-based Python
7
packages.  For detailed documentation, see the accompanying EasyInstall.txt
8
file, or visit the `EasyInstall home page`__.
9

10
__ http://packages.python.org/distribute/easy_install.html
11

12
"""
13
import sys, os.path, zipimport, shutil, tempfile, zipfile, re, stat, random
14
from glob import glob
15
from setuptools import Command, _dont_write_bytecode
16
from setuptools.sandbox import run_setup
17
from distutils import log, dir_util
18
from distutils.util import get_platform
19
from distutils.util import convert_path, subst_vars
20
from distutils.sysconfig import get_python_lib, get_config_vars
21
from distutils.errors import DistutilsArgError, DistutilsOptionError, \
22
    DistutilsError, DistutilsPlatformError
23
from distutils.command.install import INSTALL_SCHEMES, SCHEME_KEYS
24
from setuptools.archive_util import unpack_archive
25
from setuptools.package_index import PackageIndex
26
from setuptools.package_index import URL_SCHEME
27
from setuptools.command import bdist_egg, egg_info
28
from pkg_resources import yield_lines, normalize_path, resource_string, \
29
        ensure_directory, get_distribution, find_distributions, \
30
        Environment, Requirement, Distribution, \
31
        PathMetadata, EggMetadata, WorkingSet, \
32
         DistributionNotFound, VersionConflict, \
33
        DEVELOP_DIST
34

    
35
sys_executable = os.path.normpath(sys.executable)
36

    
37
__all__ = [
38
    'samefile', 'easy_install', 'PthDistributions', 'extract_wininst_cfg',
39
    'main', 'get_exe_prefixes',
40
]
41

    
42
import site
43
HAS_USER_SITE = not sys.version < "2.6" and site.ENABLE_USER_SITE
44

    
45
def samefile(p1,p2):
46
    if hasattr(os.path,'samefile') and (
47
        os.path.exists(p1) and os.path.exists(p2)
48
    ):
49
        return os.path.samefile(p1,p2)
50
    return (
51
        os.path.normpath(os.path.normcase(p1)) ==
52
        os.path.normpath(os.path.normcase(p2))
53
    )
54

    
55
if sys.version_info <= (3,):
56
    def _to_ascii(s):
57
        return s
58
    def isascii(s):
59
        try:
60
            unicode(s, 'ascii')
61
            return True
62
        except UnicodeError:
63
            return False
64
else:
65
    def _to_ascii(s):
66
        return s.encode('ascii')
67
    def isascii(s):
68
        try:
69
            s.encode('ascii')
70
            return True
71
        except UnicodeError:
72
            return False
73

    
74
class easy_install(Command):
75
    """Manage a download/build/install process"""
76
    description = "Find/get/install Python packages"
77
    command_consumes_arguments = True
78

    
79
    user_options = [
80
        ('prefix=', None, "installation prefix"),
81
        ("zip-ok", "z", "install package as a zipfile"),
82
        ("multi-version", "m", "make apps have to require() a version"),
83
        ("upgrade", "U", "force upgrade (searches PyPI for latest versions)"),
84
        ("install-dir=", "d", "install package to DIR"),
85
        ("script-dir=", "s", "install scripts to DIR"),
86
        ("exclude-scripts", "x", "Don't install scripts"),
87
        ("always-copy", "a", "Copy all needed packages to install dir"),
88
        ("index-url=", "i", "base URL of Python Package Index"),
89
        ("find-links=", "f", "additional URL(s) to search for packages"),
90
        ("delete-conflicting", "D", "no longer needed; don't use this"),
91
        ("ignore-conflicts-at-my-risk", None,
92
            "no longer needed; don't use this"),
93
        ("build-directory=", "b",
94
            "download/extract/build in DIR; keep the results"),
95
        ('optimize=', 'O',
96
         "also compile with optimization: -O1 for \"python -O\", "
97
         "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"),
98
        ('record=', None,
99
         "filename in which to record list of installed files"),
100
        ('always-unzip', 'Z', "don't install as a zipfile, no matter what"),
101
        ('site-dirs=','S',"list of directories where .pth files work"),
102
        ('editable', 'e', "Install specified packages in editable form"),
103
        ('no-deps', 'N', "don't install dependencies"),
104
        ('allow-hosts=', 'H', "pattern(s) that hostnames must match"),
105
        ('local-snapshots-ok', 'l', "allow building eggs from local checkouts"),
106
        ('version', None, "print version information and exit"),
107
        ('no-find-links', None,
108
         "Don't load find-links defined in packages being installed")
109
    ]
110
    boolean_options = [
111
        'zip-ok', 'multi-version', 'exclude-scripts', 'upgrade', 'always-copy',
112
        'delete-conflicting', 'ignore-conflicts-at-my-risk', 'editable',
113
        'no-deps', 'local-snapshots-ok', 'version'
114
    ]
115

    
116
    if HAS_USER_SITE:
117
        user_options.append(('user', None,
118
                             "install in user site-package '%s'" % site.USER_SITE))
119
        boolean_options.append('user')
120

    
121

    
122
    negative_opt = {'always-unzip': 'zip-ok'}
123
    create_index = PackageIndex
124

    
125
    def initialize_options(self):
126
        if HAS_USER_SITE:
127
            whereami = os.path.abspath(__file__)
128
            self.user = whereami.startswith(site.USER_SITE)
129
        else:
130
            self.user = 0
131

    
132
        self.zip_ok = self.local_snapshots_ok = None
133
        self.install_dir = self.script_dir = self.exclude_scripts = None
134
        self.index_url = None
135
        self.find_links = None
136
        self.build_directory = None
137
        self.args = None
138
        self.optimize = self.record = None
139
        self.upgrade = self.always_copy = self.multi_version = None
140
        self.editable = self.no_deps = self.allow_hosts = None
141
        self.root = self.prefix = self.no_report = None
142
        self.version = None
143
        self.install_purelib = None     # for pure module distributions
144
        self.install_platlib = None     # non-pure (dists w/ extensions)
145
        self.install_headers = None     # for C/C++ headers
146
        self.install_lib = None         # set to either purelib or platlib
147
        self.install_scripts = None
148
        self.install_data = None
149
        self.install_base = None
150
        self.install_platbase = None
151
        if HAS_USER_SITE:
152
            self.install_userbase = site.USER_BASE
153
            self.install_usersite = site.USER_SITE
154
        else:
155
            self.install_userbase = None
156
            self.install_usersite = None
157
        self.no_find_links = None
158

    
159
        # Options not specifiable via command line
160
        self.package_index = None
161
        self.pth_file = self.always_copy_from = None
162
        self.delete_conflicting = None
163
        self.ignore_conflicts_at_my_risk = None
164
        self.site_dirs = None
165
        self.installed_projects = {}
166
        self.sitepy_installed = False
167
        # Always read easy_install options, even if we are subclassed, or have
168
        # an independent instance created.  This ensures that defaults will
169
        # always come from the standard configuration file(s)' "easy_install"
170
        # section, even if this is a "develop" or "install" command, or some
171
        # other embedding.
172
        self._dry_run = None
173
        self.verbose = self.distribution.verbose
174
        self.distribution._set_command_options(
175
            self, self.distribution.get_option_dict('easy_install')
176
        )
177

    
178
    def delete_blockers(self, blockers):
179
        for filename in blockers:
180
            if os.path.exists(filename) or os.path.islink(filename):
181
                log.info("Deleting %s", filename)
182
                if not self.dry_run:
183
                    if os.path.isdir(filename) and not os.path.islink(filename):
184
                        rmtree(filename)
185
                    else:
186
                        os.unlink(filename)
187

    
188
    def finalize_options(self):
189
        if self.version:
190
            print 'distribute %s' % get_distribution('distribute').version
191
            sys.exit()
192

    
193
        py_version = sys.version.split()[0]
194
        prefix, exec_prefix = get_config_vars('prefix', 'exec_prefix')
195

    
196
        self.config_vars = {'dist_name': self.distribution.get_name(),
197
                            'dist_version': self.distribution.get_version(),
198
                            'dist_fullname': self.distribution.get_fullname(),
199
                            'py_version': py_version,
200
                            'py_version_short': py_version[0:3],
201
                            'py_version_nodot': py_version[0] + py_version[2],
202
                            'sys_prefix': prefix,
203
                            'prefix': prefix,
204
                            'sys_exec_prefix': exec_prefix,
205
                            'exec_prefix': exec_prefix,
206
                            # Only python 3.2+ has abiflags
207
                            'abiflags': getattr(sys, 'abiflags', ''),
208
                           }
209

    
210
        if HAS_USER_SITE:
211
            self.config_vars['userbase'] = self.install_userbase
212
            self.config_vars['usersite'] = self.install_usersite
213

    
214
        # fix the install_dir if "--user" was used
215
        #XXX: duplicate of the code in the setup command
216
        if self.user and HAS_USER_SITE:
217
            self.create_home_path()
218
            if self.install_userbase is None:
219
                raise DistutilsPlatformError(
220
                    "User base directory is not specified")
221
            self.install_base = self.install_platbase = self.install_userbase
222
            if os.name == 'posix':
223
                self.select_scheme("unix_user")
224
            else:
225
                self.select_scheme(os.name + "_user")
226

    
227
        self.expand_basedirs()
228
        self.expand_dirs()
229

    
230
        self._expand('install_dir','script_dir','build_directory','site_dirs')
231
        # If a non-default installation directory was specified, default the
232
        # script directory to match it.
233
        if self.script_dir is None:
234
            self.script_dir = self.install_dir
235

    
236
        if self.no_find_links is None:
237
            self.no_find_links = False
238

    
239
        # Let install_dir get set by install_lib command, which in turn
240
        # gets its info from the install command, and takes into account
241
        # --prefix and --home and all that other crud.
242
        self.set_undefined_options('install_lib',
243
            ('install_dir','install_dir')
244
        )
245
        # Likewise, set default script_dir from 'install_scripts.install_dir'
246
        self.set_undefined_options('install_scripts',
247
            ('install_dir', 'script_dir')
248
        )
249

    
250
        if self.user and self.install_purelib:
251
            self.install_dir = self.install_purelib
252
            self.script_dir = self.install_scripts
253
        # default --record from the install command
254
        self.set_undefined_options('install', ('record', 'record'))
255
        normpath = map(normalize_path, sys.path)
256
        self.all_site_dirs = get_site_dirs()
257
        if self.site_dirs is not None:
258
            site_dirs = [
259
                os.path.expanduser(s.strip()) for s in self.site_dirs.split(',')
260
            ]
261
            for d in site_dirs:
262
                if not os.path.isdir(d):
263
                    log.warn("%s (in --site-dirs) does not exist", d)
264
                elif normalize_path(d) not in normpath:
265
                    raise DistutilsOptionError(
266
                        d+" (in --site-dirs) is not on sys.path"
267
                    )
268
                else:
269
                    self.all_site_dirs.append(normalize_path(d))
270
        if not self.editable: self.check_site_dir()
271
        self.index_url = self.index_url or "http://pypi.python.org/simple"
272
        self.shadow_path = self.all_site_dirs[:]
273
        for path_item in self.install_dir, normalize_path(self.script_dir):
274
            if path_item not in self.shadow_path:
275
                self.shadow_path.insert(0, path_item)
276

    
277
        if self.allow_hosts is not None:
278
            hosts = [s.strip() for s in self.allow_hosts.split(',')]
279
        else:
280
            hosts = ['*']
281
        if self.package_index is None:
282
            self.package_index = self.create_index(
283
                self.index_url, search_path = self.shadow_path, hosts=hosts,
284
            )
285
        self.local_index = Environment(self.shadow_path+sys.path)
286

    
287
        if self.find_links is not None:
288
            if isinstance(self.find_links, basestring):
289
                self.find_links = self.find_links.split()
290
        else:
291
            self.find_links = []
292
        if self.local_snapshots_ok:
293
            self.package_index.scan_egg_links(self.shadow_path+sys.path)
294
        if not self.no_find_links:
295
            self.package_index.add_find_links(self.find_links)
296
        self.set_undefined_options('install_lib', ('optimize','optimize'))
297
        if not isinstance(self.optimize,int):
298
            try:
299
                self.optimize = int(self.optimize)
300
                if not (0 <= self.optimize <= 2): raise ValueError
301
            except ValueError:
302
                raise DistutilsOptionError("--optimize must be 0, 1, or 2")
303

    
304
        if self.delete_conflicting and self.ignore_conflicts_at_my_risk:
305
            raise DistutilsOptionError(
306
                "Can't use both --delete-conflicting and "
307
                "--ignore-conflicts-at-my-risk at the same time"
308
            )
309
        if self.editable and not self.build_directory:
310
            raise DistutilsArgError(
311
                "Must specify a build directory (-b) when using --editable"
312
            )
313
        if not self.args:
314
            raise DistutilsArgError(
315
                "No urls, filenames, or requirements specified (see --help)")
316

    
317
        self.outputs = []
318

    
319

    
320
    def _expand_attrs(self, attrs):
321
        for attr in attrs:
322
            val = getattr(self, attr)
323
            if val is not None:
324
                if os.name == 'posix' or os.name == 'nt':
325
                    val = os.path.expanduser(val)
326
                val = subst_vars(val, self.config_vars)
327
                setattr(self, attr, val)
328

    
329
    def expand_basedirs(self):
330
        """Calls `os.path.expanduser` on install_base, install_platbase and
331
        root."""
332
        self._expand_attrs(['install_base', 'install_platbase', 'root'])
333

    
334
    def expand_dirs(self):
335
        """Calls `os.path.expanduser` on install dirs."""
336
        self._expand_attrs(['install_purelib', 'install_platlib',
337
                            'install_lib', 'install_headers',
338
                            'install_scripts', 'install_data',])
339

    
340
    def run(self):
341
        if self.verbose != self.distribution.verbose:
342
            log.set_verbosity(self.verbose)
343
        try:
344
            for spec in self.args:
345
                self.easy_install(spec, not self.no_deps)
346
            if self.record:
347
                outputs = self.outputs
348
                if self.root:               # strip any package prefix
349
                    root_len = len(self.root)
350
                    for counter in xrange(len(outputs)):
351
                        outputs[counter] = outputs[counter][root_len:]
352
                from distutils import file_util
353
                self.execute(
354
                    file_util.write_file, (self.record, outputs),
355
                    "writing list of installed files to '%s'" %
356
                    self.record
357
                )
358
            self.warn_deprecated_options()
359
        finally:
360
            log.set_verbosity(self.distribution.verbose)
361

    
362
    def pseudo_tempname(self):
363
        """Return a pseudo-tempname base in the install directory.
364
        This code is intentionally naive; if a malicious party can write to
365
        the target directory you're already in deep doodoo.
366
        """
367
        try:
368
            pid = os.getpid()
369
        except:
370
            pid = random.randint(0,sys.maxint)
371
        return os.path.join(self.install_dir, "test-easy-install-%s" % pid)
372

    
373
    def warn_deprecated_options(self):
374
        if self.delete_conflicting or self.ignore_conflicts_at_my_risk:
375
            log.warn(
376
                "Note: The -D, --delete-conflicting and"
377
                " --ignore-conflicts-at-my-risk no longer have any purpose"
378
                " and should not be used."
379
            )
380

    
381
    def check_site_dir(self):
382
        """Verify that self.install_dir is .pth-capable dir, if needed"""
383

    
384
        instdir = normalize_path(self.install_dir)
385
        pth_file = os.path.join(instdir,'easy-install.pth')
386

    
387
        # Is it a configured, PYTHONPATH, implicit, or explicit site dir?
388
        is_site_dir = instdir in self.all_site_dirs
389

    
390
        if not is_site_dir:
391
            # No?  Then directly test whether it does .pth file processing
392
            is_site_dir = self.check_pth_processing()
393
        else:
394
            # make sure we can write to target dir
395
            testfile = self.pseudo_tempname()+'.write-test'
396
            test_exists = os.path.exists(testfile)
397
            try:
398
                if test_exists: os.unlink(testfile)
399
                open(testfile,'w').close()
400
                os.unlink(testfile)
401
            except (OSError,IOError):
402
                self.cant_write_to_target()
403

    
404
        if not is_site_dir and not self.multi_version:
405
            # Can't install non-multi to non-site dir
406
            raise DistutilsError(self.no_default_version_msg())
407

    
408
        if is_site_dir:
409
            if self.pth_file is None:
410
                self.pth_file = PthDistributions(pth_file, self.all_site_dirs)
411
        else:
412
            self.pth_file = None
413

    
414
        PYTHONPATH = os.environ.get('PYTHONPATH','').split(os.pathsep)
415
        if instdir not in map(normalize_path, filter(None,PYTHONPATH)):
416
            # only PYTHONPATH dirs need a site.py, so pretend it's there
417
            self.sitepy_installed = True
418
        elif self.multi_version and not os.path.exists(pth_file):
419
            self.sitepy_installed = True    # don't need site.py in this case
420
            self.pth_file = None            # and don't create a .pth file
421
        self.install_dir = instdir
422

    
423
    def cant_write_to_target(self):
424
        msg = """can't create or remove files in install directory
425

426
The following error occurred while trying to add or remove files in the
427
installation directory:
428

429
    %s
430

431
The installation directory you specified (via --install-dir, --prefix, or
432
the distutils default setting) was:
433

434
    %s
435
"""     % (sys.exc_info()[1], self.install_dir,)
436

    
437
        if not os.path.exists(self.install_dir):
438
            msg += """
439
This directory does not currently exist.  Please create it and try again, or
440
choose a different installation directory (using the -d or --install-dir
441
option).
442
"""
443
        else:
444
            msg += """
445
Perhaps your account does not have write access to this directory?  If the
446
installation directory is a system-owned directory, you may need to sign in
447
as the administrator or "root" account.  If you do not have administrative
448
access to this machine, you may wish to choose a different installation
449
directory, preferably one that is listed in your PYTHONPATH environment
450
variable.
451

452
For information on other options, you may wish to consult the
453
documentation at:
454

455
  http://packages.python.org/distribute/easy_install.html
456

457
Please make the appropriate changes for your system and try again.
458
"""
459
        raise DistutilsError(msg)
460

    
461

    
462

    
463

    
464
    def check_pth_processing(self):
465
        """Empirically verify whether .pth files are supported in inst. dir"""
466
        instdir = self.install_dir
467
        log.info("Checking .pth file support in %s", instdir)
468
        pth_file = self.pseudo_tempname()+".pth"
469
        ok_file = pth_file+'.ok'
470
        ok_exists = os.path.exists(ok_file)
471
        try:
472
            if ok_exists: os.unlink(ok_file)
473
            dirname = os.path.dirname(ok_file)
474
            if not os.path.exists(dirname):
475
                os.makedirs(dirname)
476
            f = open(pth_file,'w')
477
        except (OSError,IOError):
478
            self.cant_write_to_target()
479
        else:
480
            try:
481
                f.write("import os;open(%r,'w').write('OK')\n" % (ok_file,))
482
                f.close(); f=None
483
                executable = sys.executable
484
                if os.name=='nt':
485
                    dirname,basename = os.path.split(executable)
486
                    alt = os.path.join(dirname,'pythonw.exe')
487
                    if basename.lower()=='python.exe' and os.path.exists(alt):
488
                        # use pythonw.exe to avoid opening a console window
489
                        executable = alt
490

    
491
                from distutils.spawn import spawn
492
                spawn([executable,'-E','-c','pass'],0)
493

    
494
                if os.path.exists(ok_file):
495
                    log.info(
496
                        "TEST PASSED: %s appears to support .pth files",
497
                        instdir
498
                    )
499
                    return True
500
            finally:
501
                if f: f.close()
502
                if os.path.exists(ok_file): os.unlink(ok_file)
503
                if os.path.exists(pth_file): os.unlink(pth_file)
504
        if not self.multi_version:
505
            log.warn("TEST FAILED: %s does NOT support .pth files", instdir)
506
        return False
507

    
508
    def install_egg_scripts(self, dist):
509
        """Write all the scripts for `dist`, unless scripts are excluded"""
510
        if not self.exclude_scripts and dist.metadata_isdir('scripts'):
511
            for script_name in dist.metadata_listdir('scripts'):
512
                self.install_script(
513
                    dist, script_name,
514
                    dist.get_metadata('scripts/'+script_name)
515
                )
516
        self.install_wrapper_scripts(dist)
517

    
518
    def add_output(self, path):
519
        if os.path.isdir(path):
520
            for base, dirs, files in os.walk(path):
521
                for filename in files:
522
                    self.outputs.append(os.path.join(base,filename))
523
        else:
524
            self.outputs.append(path)
525

    
526
    def not_editable(self, spec):
527
        if self.editable:
528
            raise DistutilsArgError(
529
                "Invalid argument %r: you can't use filenames or URLs "
530
                "with --editable (except via the --find-links option)."
531
                % (spec,)
532
            )
533

    
534
    def check_editable(self,spec):
535
        if not self.editable:
536
            return
537

    
538
        if os.path.exists(os.path.join(self.build_directory, spec.key)):
539
            raise DistutilsArgError(
540
                "%r already exists in %s; can't do a checkout there" %
541
                (spec.key, self.build_directory)
542
            )
543

    
544

    
545

    
546

    
547

    
548

    
549
    def easy_install(self, spec, deps=False):
550
        tmpdir = tempfile.mkdtemp(prefix="easy_install-")
551
        download = None
552
        if not self.editable: self.install_site_py()
553

    
554
        try:
555
            if not isinstance(spec,Requirement):
556
                if URL_SCHEME(spec):
557
                    # It's a url, download it to tmpdir and process
558
                    self.not_editable(spec)
559
                    download = self.package_index.download(spec, tmpdir)
560
                    return self.install_item(None, download, tmpdir, deps, True)
561

    
562
                elif os.path.exists(spec):
563
                    # Existing file or directory, just process it directly
564
                    self.not_editable(spec)
565
                    return self.install_item(None, spec, tmpdir, deps, True)
566
                else:
567
                    spec = parse_requirement_arg(spec)
568

    
569
            self.check_editable(spec)
570
            dist = self.package_index.fetch_distribution(
571
                spec, tmpdir, self.upgrade, self.editable, not self.always_copy,
572
                self.local_index
573
            )
574

    
575
            if dist is None:
576
                msg = "Could not find suitable distribution for %r" % spec
577
                if self.always_copy:
578
                    msg+=" (--always-copy skips system and development eggs)"
579
                raise DistutilsError(msg)
580
            elif dist.precedence==DEVELOP_DIST:
581
                # .egg-info dists don't need installing, just process deps
582
                self.process_distribution(spec, dist, deps, "Using")
583
                return dist
584
            else:
585
                return self.install_item(spec, dist.location, tmpdir, deps)
586

    
587
        finally:
588
            if os.path.exists(tmpdir):
589
                rmtree(tmpdir)
590

    
591
    def install_item(self, spec, download, tmpdir, deps, install_needed=False):
592

    
593
        # Installation is also needed if file in tmpdir or is not an egg
594
        install_needed = install_needed or self.always_copy
595
        install_needed = install_needed or os.path.dirname(download) == tmpdir
596
        install_needed = install_needed or not download.endswith('.egg')
597
        install_needed = install_needed or (
598
            self.always_copy_from is not None and
599
            os.path.dirname(normalize_path(download)) ==
600
            normalize_path(self.always_copy_from)
601
        )
602

    
603
        if spec and not install_needed:
604
            # at this point, we know it's a local .egg, we just don't know if
605
            # it's already installed.
606
            for dist in self.local_index[spec.project_name]:
607
                if dist.location==download:
608
                    break
609
            else:
610
                install_needed = True   # it's not in the local index
611

    
612
        log.info("Processing %s", os.path.basename(download))
613

    
614
        if install_needed:
615
            dists = self.install_eggs(spec, download, tmpdir)
616
            for dist in dists:
617
                self.process_distribution(spec, dist, deps)
618
        else:
619
            dists = [self.check_conflicts(self.egg_distribution(download))]
620
            self.process_distribution(spec, dists[0], deps, "Using")
621

    
622
        if spec is not None:
623
            for dist in dists:
624
                if dist in spec:
625
                    return dist
626

    
627

    
628

    
629
    def select_scheme(self, name):
630
        """Sets the install directories by applying the install schemes."""
631
        # it's the caller's problem if they supply a bad name!
632
        scheme = INSTALL_SCHEMES[name]
633
        for key in SCHEME_KEYS:
634
            attrname = 'install_' + key
635
            if getattr(self, attrname) is None:
636
                setattr(self, attrname, scheme[key])
637

    
638

    
639

    
640

    
641
    def process_distribution(self, requirement, dist, deps=True, *info):
642
        self.update_pth(dist)
643
        self.package_index.add(dist)
644
        self.local_index.add(dist)
645
        if not self.editable:
646
            self.install_egg_scripts(dist)
647
        self.installed_projects[dist.key] = dist
648
        log.info(self.installation_report(requirement, dist, *info))
649
        if (dist.has_metadata('dependency_links.txt') and
650
            not self.no_find_links):
651
            self.package_index.add_find_links(
652
                dist.get_metadata_lines('dependency_links.txt')
653
            )
654
        if not deps and not self.always_copy:
655
            return
656
        elif requirement is not None and dist.key != requirement.key:
657
            log.warn("Skipping dependencies for %s", dist)
658
            return  # XXX this is not the distribution we were looking for
659
        elif requirement is None or dist not in requirement:
660
            # if we wound up with a different version, resolve what we've got
661
            distreq = dist.as_requirement()
662
            requirement = requirement or distreq
663
            requirement = Requirement(
664
                distreq.project_name, distreq.specs, requirement.extras
665
            )
666
        log.info("Processing dependencies for %s", requirement)
667
        try:
668
            distros = WorkingSet([]).resolve(
669
                [requirement], self.local_index, self.easy_install
670
            )
671
        except DistributionNotFound, e:
672
            raise DistutilsError(
673
                "Could not find required distribution %s" % e.args
674
            )
675
        except VersionConflict, e:
676
            raise DistutilsError(
677
                "Installed distribution %s conflicts with requirement %s"
678
                % e.args
679
            )
680
        if self.always_copy or self.always_copy_from:
681
            # Force all the relevant distros to be copied or activated
682
            for dist in distros:
683
                if dist.key not in self.installed_projects:
684
                    self.easy_install(dist.as_requirement())
685
        log.info("Finished processing dependencies for %s", requirement)
686

    
687
    def should_unzip(self, dist):
688
        if self.zip_ok is not None:
689
            return not self.zip_ok
690
        if dist.has_metadata('not-zip-safe'):
691
            return True
692
        if not dist.has_metadata('zip-safe'):
693
            return True
694
        return True
695

    
696
    def maybe_move(self, spec, dist_filename, setup_base):
697
        dst = os.path.join(self.build_directory, spec.key)
698
        if os.path.exists(dst):
699
            log.warn(
700
               "%r already exists in %s; build directory %s will not be kept",
701
               spec.key, self.build_directory, setup_base
702
            )
703
            return setup_base
704
        if os.path.isdir(dist_filename):
705
            setup_base = dist_filename
706
        else:
707
            if os.path.dirname(dist_filename)==setup_base:
708
                os.unlink(dist_filename)   # get it out of the tmp dir
709
            contents = os.listdir(setup_base)
710
            if len(contents)==1:
711
                dist_filename = os.path.join(setup_base,contents[0])
712
                if os.path.isdir(dist_filename):
713
                    # if the only thing there is a directory, move it instead
714
                    setup_base = dist_filename
715
        ensure_directory(dst); shutil.move(setup_base, dst)
716
        return dst
717

    
718
    def install_wrapper_scripts(self, dist):
719
        if not self.exclude_scripts:
720
            for args in get_script_args(dist):
721
                self.write_script(*args)
722

    
723

    
724

    
725
    def install_script(self, dist, script_name, script_text, dev_path=None):
726
        """Generate a legacy script wrapper and install it"""
727
        spec = str(dist.as_requirement())
728
        is_script = is_python_script(script_text, script_name)
729

    
730
        if is_script and dev_path:
731
            script_text = get_script_header(script_text) + (
732
                "# EASY-INSTALL-DEV-SCRIPT: %(spec)r,%(script_name)r\n"
733
                "__requires__ = %(spec)r\n"
734
                "from pkg_resources import require; require(%(spec)r)\n"
735
                "del require\n"
736
                "__file__ = %(dev_path)r\n"
737
                "execfile(__file__)\n"
738
            ) % locals()
739
        elif is_script:
740
            script_text = get_script_header(script_text) + (
741
                "# EASY-INSTALL-SCRIPT: %(spec)r,%(script_name)r\n"
742
                "__requires__ = %(spec)r\n"
743
                "import pkg_resources\n"
744
                "pkg_resources.run_script(%(spec)r, %(script_name)r)\n"
745
            ) % locals()
746
        self.write_script(script_name, _to_ascii(script_text), 'b')
747

    
748
    def write_script(self, script_name, contents, mode="t", blockers=()):
749
        """Write an executable file to the scripts directory"""
750
        self.delete_blockers(   # clean up old .py/.pyw w/o a script
751
            [os.path.join(self.script_dir,x) for x in blockers])
752
        log.info("Installing %s script to %s", script_name, self.script_dir)
753
        target = os.path.join(self.script_dir, script_name)
754
        self.add_output(target)
755

    
756
        if not self.dry_run:
757
            ensure_directory(target)
758
            f = open(target,"w"+mode)
759
            f.write(contents)
760
            f.close()
761
            chmod(target,0755)
762

    
763

    
764

    
765

    
766
    def install_eggs(self, spec, dist_filename, tmpdir):
767
        # .egg dirs or files are already built, so just return them
768
        if dist_filename.lower().endswith('.egg'):
769
            return [self.install_egg(dist_filename, tmpdir)]
770
        elif dist_filename.lower().endswith('.exe'):
771
            return [self.install_exe(dist_filename, tmpdir)]
772

    
773
        # Anything else, try to extract and build
774
        setup_base = tmpdir
775
        if os.path.isfile(dist_filename) and not dist_filename.endswith('.py'):
776
            unpack_archive(dist_filename, tmpdir, self.unpack_progress)
777
        elif os.path.isdir(dist_filename):
778
            setup_base = os.path.abspath(dist_filename)
779

    
780
        if (setup_base.startswith(tmpdir)   # something we downloaded
781
            and self.build_directory and spec is not None
782
        ):
783
            setup_base = self.maybe_move(spec, dist_filename, setup_base)
784

    
785
        # Find the setup.py file
786
        setup_script = os.path.join(setup_base, 'setup.py')
787

    
788
        if not os.path.exists(setup_script):
789
            setups = glob(os.path.join(setup_base, '*', 'setup.py'))
790
            if not setups:
791
                raise DistutilsError(
792
                    "Couldn't find a setup script in %s" % os.path.abspath(dist_filename)
793
                )
794
            if len(setups)>1:
795
                raise DistutilsError(
796
                    "Multiple setup scripts in %s" % os.path.abspath(dist_filename)
797
                )
798
            setup_script = setups[0]
799

    
800
        # Now run it, and return the result
801
        if self.editable:
802
            log.info(self.report_editable(spec, setup_script))
803
            return []
804
        else:
805
            return self.build_and_install(setup_script, setup_base)
806

    
807
    def egg_distribution(self, egg_path):
808
        if os.path.isdir(egg_path):
809
            metadata = PathMetadata(egg_path,os.path.join(egg_path,'EGG-INFO'))
810
        else:
811
            metadata = EggMetadata(zipimport.zipimporter(egg_path))
812
        return Distribution.from_filename(egg_path,metadata=metadata)
813

    
814
    def install_egg(self, egg_path, tmpdir):
815
        destination = os.path.join(self.install_dir,os.path.basename(egg_path))
816
        destination = os.path.abspath(destination)
817
        if not self.dry_run:
818
            ensure_directory(destination)
819

    
820
        dist = self.egg_distribution(egg_path)
821
        self.check_conflicts(dist)
822
        if not samefile(egg_path, destination):
823
            if os.path.isdir(destination) and not os.path.islink(destination):
824
                dir_util.remove_tree(destination, dry_run=self.dry_run)
825
            elif os.path.exists(destination):
826
                self.execute(os.unlink,(destination,),"Removing "+destination)
827
            uncache_zipdir(destination)
828
            if os.path.isdir(egg_path):
829
                if egg_path.startswith(tmpdir):
830
                    f,m = shutil.move, "Moving"
831
                else:
832
                    f,m = shutil.copytree, "Copying"
833
            elif self.should_unzip(dist):
834
                self.mkpath(destination)
835
                f,m = self.unpack_and_compile, "Extracting"
836
            elif egg_path.startswith(tmpdir):
837
                f,m = shutil.move, "Moving"
838
            else:
839
                f,m = shutil.copy2, "Copying"
840

    
841
            self.execute(f, (egg_path, destination),
842
                (m+" %s to %s") %
843
                (os.path.basename(egg_path),os.path.dirname(destination)))
844

    
845
        self.add_output(destination)
846
        return self.egg_distribution(destination)
847

    
848
    def install_exe(self, dist_filename, tmpdir):
849
        # See if it's valid, get data
850
        cfg = extract_wininst_cfg(dist_filename)
851
        if cfg is None:
852
            raise DistutilsError(
853
                "%s is not a valid distutils Windows .exe" % dist_filename
854
            )
855
        # Create a dummy distribution object until we build the real distro
856
        dist = Distribution(None,
857
            project_name=cfg.get('metadata','name'),
858
            version=cfg.get('metadata','version'), platform=get_platform()
859
        )
860

    
861
        # Convert the .exe to an unpacked egg
862
        egg_path = dist.location = os.path.join(tmpdir, dist.egg_name()+'.egg')
863
        egg_tmp  = egg_path+'.tmp'
864
        egg_info = os.path.join(egg_tmp, 'EGG-INFO')
865
        pkg_inf = os.path.join(egg_info, 'PKG-INFO')
866
        ensure_directory(pkg_inf)   # make sure EGG-INFO dir exists
867
        dist._provider = PathMetadata(egg_tmp, egg_info)    # XXX
868
        self.exe_to_egg(dist_filename, egg_tmp)
869

    
870
        # Write EGG-INFO/PKG-INFO
871
        if not os.path.exists(pkg_inf):
872
            f = open(pkg_inf,'w')
873
            f.write('Metadata-Version: 1.0\n')
874
            for k,v in cfg.items('metadata'):
875
                if k<>'target_version':
876
                    f.write('%s: %s\n' % (k.replace('_','-').title(), v))
877
            f.close()
878
        script_dir = os.path.join(egg_info,'scripts')
879
        self.delete_blockers(   # delete entry-point scripts to avoid duping
880
            [os.path.join(script_dir,args[0]) for args in get_script_args(dist)]
881
        )
882
        # Build .egg file from tmpdir
883
        bdist_egg.make_zipfile(
884
            egg_path, egg_tmp, verbose=self.verbose, dry_run=self.dry_run
885
        )
886
        # install the .egg
887
        return self.install_egg(egg_path, tmpdir)
888

    
889
    def exe_to_egg(self, dist_filename, egg_tmp):
890
        """Extract a bdist_wininst to the directories an egg would use"""
891
        # Check for .pth file and set up prefix translations
892
        prefixes = get_exe_prefixes(dist_filename)
893
        to_compile = []
894
        native_libs = []
895
        top_level = {}
896
        def process(src,dst):
897
            s = src.lower()
898
            for old,new in prefixes:
899
                if s.startswith(old):
900
                    src = new+src[len(old):]
901
                    parts = src.split('/')
902
                    dst = os.path.join(egg_tmp, *parts)
903
                    dl = dst.lower()
904
                    if dl.endswith('.pyd') or dl.endswith('.dll'):
905
                        parts[-1] = bdist_egg.strip_module(parts[-1])
906
                        top_level[os.path.splitext(parts[0])[0]] = 1
907
                        native_libs.append(src)
908
                    elif dl.endswith('.py') and old!='SCRIPTS/':
909
                        top_level[os.path.splitext(parts[0])[0]] = 1
910
                        to_compile.append(dst)
911
                    return dst
912
            if not src.endswith('.pth'):
913
                log.warn("WARNING: can't process %s", src)
914
            return None
915
        # extract, tracking .pyd/.dll->native_libs and .py -> to_compile
916
        unpack_archive(dist_filename, egg_tmp, process)
917
        stubs = []
918
        for res in native_libs:
919
            if res.lower().endswith('.pyd'):    # create stubs for .pyd's
920
                parts = res.split('/')
921
                resource = parts[-1]
922
                parts[-1] = bdist_egg.strip_module(parts[-1])+'.py'
923
                pyfile = os.path.join(egg_tmp, *parts)
924
                to_compile.append(pyfile); stubs.append(pyfile)
925
                bdist_egg.write_stub(resource, pyfile)
926
        self.byte_compile(to_compile)   # compile .py's
927
        bdist_egg.write_safety_flag(os.path.join(egg_tmp,'EGG-INFO'),
928
            bdist_egg.analyze_egg(egg_tmp, stubs))  # write zip-safety flag
929

    
930
        for name in 'top_level','native_libs':
931
            if locals()[name]:
932
                txt = os.path.join(egg_tmp, 'EGG-INFO', name+'.txt')
933
                if not os.path.exists(txt):
934
                    f = open(txt,'w')
935
                    f.write('\n'.join(locals()[name])+'\n')
936
                    f.close()
937

    
938
    def check_conflicts(self, dist):
939
        """Verify that there are no conflicting "old-style" packages"""
940

    
941
        return dist     # XXX temporarily disable until new strategy is stable
942
        from imp import find_module, get_suffixes
943
        from glob import glob
944

    
945
        blockers = []
946
        names = dict.fromkeys(dist._get_metadata('top_level.txt')) # XXX private attr
947

    
948
        exts = {'.pyc':1, '.pyo':1}     # get_suffixes() might leave one out
949
        for ext,mode,typ in get_suffixes():
950
            exts[ext] = 1
951

    
952
        for path,files in expand_paths([self.install_dir]+self.all_site_dirs):
953
            for filename in files:
954
                base,ext = os.path.splitext(filename)
955
                if base in names:
956
                    if not ext:
957
                        # no extension, check for package
958
                        try:
959
                            f, filename, descr = find_module(base, [path])
960
                        except ImportError:
961
                            continue
962
                        else:
963
                            if f: f.close()
964
                            if filename not in blockers:
965
                                blockers.append(filename)
966
                    elif ext in exts and base!='site':  # XXX ugh
967
                        blockers.append(os.path.join(path,filename))
968
        if blockers:
969
            self.found_conflicts(dist, blockers)
970

    
971
        return dist
972

    
973
    def found_conflicts(self, dist, blockers):
974
        if self.delete_conflicting:
975
            log.warn("Attempting to delete conflicting packages:")
976
            return self.delete_blockers(blockers)
977

    
978
        msg = """\
979
-------------------------------------------------------------------------
980
CONFLICT WARNING:
981

982
The following modules or packages have the same names as modules or
983
packages being installed, and will be *before* the installed packages in
984
Python's search path.  You MUST remove all of the relevant files and
985
directories before you will be able to use the package(s) you are
986
installing:
987

988
   %s
989

990
""" % '\n   '.join(blockers)
991

    
992
        if self.ignore_conflicts_at_my_risk:
993
            msg += """\
994
(Note: you can run EasyInstall on '%s' with the
995
--delete-conflicting option to attempt deletion of the above files
996
and/or directories.)
997
""" % dist.project_name
998
        else:
999
            msg += """\
1000
Note: you can attempt this installation again with EasyInstall, and use
1001
either the --delete-conflicting (-D) option or the
1002
--ignore-conflicts-at-my-risk option, to either delete the above files
1003
and directories, or to ignore the conflicts, respectively.  Note that if
1004
you ignore the conflicts, the installed package(s) may not work.
1005
"""
1006
        msg += """\
1007
-------------------------------------------------------------------------
1008
"""
1009
        sys.stderr.write(msg)
1010
        sys.stderr.flush()
1011
        if not self.ignore_conflicts_at_my_risk:
1012
            raise DistutilsError("Installation aborted due to conflicts")
1013

    
1014
    def installation_report(self, req, dist, what="Installed"):
1015
        """Helpful installation message for display to package users"""
1016
        msg = "\n%(what)s %(eggloc)s%(extras)s"
1017
        if self.multi_version and not self.no_report:
1018
            msg += """
1019

1020
Because this distribution was installed --multi-version, before you can
1021
import modules from this package in an application, you will need to
1022
'import pkg_resources' and then use a 'require()' call similar to one of
1023
these examples, in order to select the desired version:
1024

1025
    pkg_resources.require("%(name)s")  # latest installed version
1026
    pkg_resources.require("%(name)s==%(version)s")  # this exact version
1027
    pkg_resources.require("%(name)s>=%(version)s")  # this version or higher
1028
"""
1029
            if self.install_dir not in map(normalize_path,sys.path):
1030
                msg += """
1031

1032
Note also that the installation directory must be on sys.path at runtime for
1033
this to work.  (e.g. by being the application's script directory, by being on
1034
PYTHONPATH, or by being added to sys.path by your code.)
1035
"""
1036
        eggloc = dist.location
1037
        name = dist.project_name
1038
        version = dist.version
1039
        extras = '' # TODO: self.report_extras(req, dist)
1040
        return msg % locals()
1041

    
1042
    def report_editable(self, spec, setup_script):
1043
        dirname = os.path.dirname(setup_script)
1044
        python = sys.executable
1045
        return """\nExtracted editable version of %(spec)s to %(dirname)s
1046

1047
If it uses setuptools in its setup script, you can activate it in
1048
"development" mode by going to that directory and running::
1049

1050
    %(python)s setup.py develop
1051

1052
See the setuptools documentation for the "develop" command for more info.
1053
""" % locals()
1054

    
1055
    def run_setup(self, setup_script, setup_base, args):
1056
        sys.modules.setdefault('distutils.command.bdist_egg', bdist_egg)
1057
        sys.modules.setdefault('distutils.command.egg_info', egg_info)
1058

    
1059
        args = list(args)
1060
        if self.verbose>2:
1061
            v = 'v' * (self.verbose - 1)
1062
            args.insert(0,'-'+v)
1063
        elif self.verbose<2:
1064
            args.insert(0,'-q')
1065
        if self.dry_run:
1066
            args.insert(0,'-n')
1067
        log.info(
1068
            "Running %s %s", setup_script[len(setup_base)+1:], ' '.join(args)
1069
        )
1070
        try:
1071
            run_setup(setup_script, args)
1072
        except SystemExit, v:
1073
            raise DistutilsError("Setup script exited with %s" % (v.args[0],))
1074

    
1075
    def build_and_install(self, setup_script, setup_base):
1076
        args = ['bdist_egg', '--dist-dir']
1077
        dist_dir = tempfile.mkdtemp(
1078
            prefix='egg-dist-tmp-', dir=os.path.dirname(setup_script)
1079
        )
1080
        try:
1081
            args.append(dist_dir)
1082
            self.run_setup(setup_script, setup_base, args)
1083
            all_eggs = Environment([dist_dir])
1084
            eggs = []
1085
            for key in all_eggs:
1086
                for dist in all_eggs[key]:
1087
                    eggs.append(self.install_egg(dist.location, setup_base))
1088
            if not eggs and not self.dry_run:
1089
                log.warn("No eggs found in %s (setup script problem?)",
1090
                    dist_dir)
1091
            return eggs
1092
        finally:
1093
            rmtree(dist_dir)
1094
            log.set_verbosity(self.verbose) # restore our log verbosity
1095

    
1096
    def update_pth(self,dist):
1097
        if self.pth_file is None:
1098
            return
1099

    
1100
        for d in self.pth_file[dist.key]:    # drop old entries
1101
            if self.multi_version or d.location != dist.location:
1102
                log.info("Removing %s from easy-install.pth file", d)
1103
                self.pth_file.remove(d)
1104
                if d.location in self.shadow_path:
1105
                    self.shadow_path.remove(d.location)
1106

    
1107
        if not self.multi_version:
1108
            if dist.location in self.pth_file.paths:
1109
                log.info(
1110
                    "%s is already the active version in easy-install.pth",
1111
                    dist
1112
                )
1113
            else:
1114
                log.info("Adding %s to easy-install.pth file", dist)
1115
                self.pth_file.add(dist) # add new entry
1116
                if dist.location not in self.shadow_path:
1117
                    self.shadow_path.append(dist.location)
1118

    
1119
        if not self.dry_run:
1120

    
1121
            self.pth_file.save()
1122
            if dist.key=='distribute':
1123
                # Ensure that setuptools itself never becomes unavailable!
1124
                # XXX should this check for latest version?
1125
                filename = os.path.join(self.install_dir,'setuptools.pth')
1126
                if os.path.islink(filename): os.unlink(filename)
1127
                f = open(filename, 'wt')
1128
                f.write(self.pth_file.make_relative(dist.location)+'\n')
1129
                f.close()
1130

    
1131
    def unpack_progress(self, src, dst):
1132
        # Progress filter for unpacking
1133
        log.debug("Unpacking %s to %s", src, dst)
1134
        return dst     # only unpack-and-compile skips files for dry run
1135

    
1136
    def unpack_and_compile(self, egg_path, destination):
1137
        to_compile = []; to_chmod = []
1138

    
1139
        def pf(src,dst):
1140
            if dst.endswith('.py') and not src.startswith('EGG-INFO/'):
1141
                to_compile.append(dst)
1142
                to_chmod.append(dst)
1143
            elif dst.endswith('.dll') or dst.endswith('.so'):
1144
                to_chmod.append(dst)
1145
            self.unpack_progress(src,dst)
1146
            return not self.dry_run and dst or None
1147

    
1148
        unpack_archive(egg_path, destination, pf)
1149
        self.byte_compile(to_compile)
1150
        if not self.dry_run:
1151
            for f in to_chmod:
1152
                mode = ((os.stat(f)[stat.ST_MODE]) | 0555) & 07755
1153
                chmod(f, mode)
1154

    
1155
    def byte_compile(self, to_compile):
1156
        if _dont_write_bytecode:
1157
            self.warn('byte-compiling is disabled, skipping.')
1158
            return
1159

    
1160
        from distutils.util import byte_compile
1161
        try:
1162
            # try to make the byte compile messages quieter
1163
            log.set_verbosity(self.verbose - 1)
1164

    
1165
            byte_compile(to_compile, optimize=0, force=1, dry_run=self.dry_run)
1166
            if self.optimize:
1167
                byte_compile(
1168
                    to_compile, optimize=self.optimize, force=1,
1169
                    dry_run=self.dry_run
1170
                )
1171
        finally:
1172
            log.set_verbosity(self.verbose)     # restore original verbosity
1173

    
1174

    
1175

    
1176

    
1177

    
1178

    
1179

    
1180

    
1181
    def no_default_version_msg(self):
1182
        return """bad install directory or PYTHONPATH
1183

1184
You are attempting to install a package to a directory that is not
1185
on PYTHONPATH and which Python does not read ".pth" files from.  The
1186
installation directory you specified (via --install-dir, --prefix, or
1187
the distutils default setting) was:
1188

1189
    %s
1190

1191
and your PYTHONPATH environment variable currently contains:
1192

1193
    %r
1194

1195
Here are some of your options for correcting the problem:
1196

1197
* You can choose a different installation directory, i.e., one that is
1198
  on PYTHONPATH or supports .pth files
1199

1200
* You can add the installation directory to the PYTHONPATH environment
1201
  variable.  (It must then also be on PYTHONPATH whenever you run
1202
  Python and want to use the package(s) you are installing.)
1203

1204
* You can set up the installation directory to support ".pth" files by
1205
  using one of the approaches described here:
1206

1207
  http://packages.python.org/distribute/easy_install.html#custom-installation-locations
1208

1209
Please make the appropriate changes for your system and try again.""" % (
1210
        self.install_dir, os.environ.get('PYTHONPATH','')
1211
    )
1212

    
1213

    
1214

    
1215

    
1216

    
1217

    
1218

    
1219

    
1220

    
1221

    
1222
    def install_site_py(self):
1223
        """Make sure there's a site.py in the target dir, if needed"""
1224

    
1225
        if self.sitepy_installed:
1226
            return  # already did it, or don't need to
1227

    
1228
        sitepy = os.path.join(self.install_dir, "site.py")
1229
        source = resource_string(Requirement.parse("distribute"), "site.py")
1230
        current = ""
1231

    
1232
        if os.path.exists(sitepy):
1233
            log.debug("Checking existing site.py in %s", self.install_dir)
1234
            f = open(sitepy,'rb')
1235
            current = f.read()
1236
            # we want str, not bytes
1237
            if sys.version_info >= (3,):
1238
                current = current.decode()
1239

    
1240
            f.close()
1241
            if not current.startswith('def __boot():'):
1242
                raise DistutilsError(
1243
                    "%s is not a setuptools-generated site.py; please"
1244
                    " remove it." % sitepy
1245
                )
1246

    
1247
        if current != source:
1248
            log.info("Creating %s", sitepy)
1249
            if not self.dry_run:
1250
                ensure_directory(sitepy)
1251
                f = open(sitepy,'wb')
1252
                f.write(source)
1253
                f.close()
1254
            self.byte_compile([sitepy])
1255

    
1256
        self.sitepy_installed = True
1257

    
1258

    
1259

    
1260

    
1261
    def create_home_path(self):
1262
        """Create directories under ~."""
1263
        if not self.user:
1264
            return
1265
        home = convert_path(os.path.expanduser("~"))
1266
        for name, path in self.config_vars.iteritems():
1267
            if path.startswith(home) and not os.path.isdir(path):
1268
                self.debug_print("os.makedirs('%s', 0700)" % path)
1269
                os.makedirs(path, 0700)
1270

    
1271

    
1272

    
1273

    
1274

    
1275

    
1276

    
1277
    INSTALL_SCHEMES = dict(
1278
        posix = dict(
1279
            install_dir = '$base/lib/python$py_version_short/site-packages',
1280
            script_dir  = '$base/bin',
1281
        ),
1282
    )
1283

    
1284
    DEFAULT_SCHEME = dict(
1285
        install_dir = '$base/Lib/site-packages',
1286
        script_dir  = '$base/Scripts',
1287
    )
1288

    
1289
    def _expand(self, *attrs):
1290
        config_vars = self.get_finalized_command('install').config_vars
1291

    
1292
        if self.prefix:
1293
            # Set default install_dir/scripts from --prefix
1294
            config_vars = config_vars.copy()
1295
            config_vars['base'] = self.prefix
1296
            scheme = self.INSTALL_SCHEMES.get(os.name,self.DEFAULT_SCHEME)
1297
            for attr,val in scheme.items():
1298
                if getattr(self,attr,None) is None:
1299
                    setattr(self,attr,val)
1300

    
1301
        from distutils.util import subst_vars
1302
        for attr in attrs:
1303
            val = getattr(self, attr)
1304
            if val is not None:
1305
                val = subst_vars(val, config_vars)
1306
                if os.name == 'posix':
1307
                    val = os.path.expanduser(val)
1308
                setattr(self, attr, val)
1309

    
1310

    
1311

    
1312

    
1313

    
1314

    
1315

    
1316

    
1317

    
1318
def get_site_dirs():
1319
    # return a list of 'site' dirs
1320
    sitedirs = filter(None,os.environ.get('PYTHONPATH','').split(os.pathsep))
1321
    prefixes = [sys.prefix]
1322
    if sys.exec_prefix != sys.prefix:
1323
        prefixes.append(sys.exec_prefix)
1324
    for prefix in prefixes:
1325
        if prefix:
1326
            if sys.platform in ('os2emx', 'riscos'):
1327
                sitedirs.append(os.path.join(prefix, "Lib", "site-packages"))
1328
            elif os.sep == '/':
1329
                sitedirs.extend([os.path.join(prefix,
1330
                                         "lib",
1331
                                         "python" + sys.version[:3],
1332
                                         "site-packages"),
1333
                            os.path.join(prefix, "lib", "site-python")])
1334
            else:
1335
                sitedirs.extend(
1336
                    [prefix, os.path.join(prefix, "lib", "site-packages")]
1337
                )
1338
            if sys.platform == 'darwin':
1339
                # for framework builds *only* we add the standard Apple
1340
                # locations. Currently only per-user, but /Library and
1341
                # /Network/Library could be added too
1342
                if 'Python.framework' in prefix:
1343
                    home = os.environ.get('HOME')
1344
                    if home:
1345
                        sitedirs.append(
1346
                            os.path.join(home,
1347
                                         'Library',
1348
                                         'Python',
1349
                                         sys.version[:3],
1350
                                         'site-packages'))
1351
    for plat_specific in (0,1):
1352
        site_lib = get_python_lib(plat_specific)
1353
        if site_lib not in sitedirs: sitedirs.append(site_lib)
1354

    
1355
    if HAS_USER_SITE:
1356
        sitedirs.append(site.USER_SITE)
1357

    
1358
    sitedirs = map(normalize_path, sitedirs)
1359

    
1360
    return sitedirs
1361

    
1362

    
1363
def expand_paths(inputs):
1364
    """Yield sys.path directories that might contain "old-style" packages"""
1365

    
1366
    seen = {}
1367

    
1368
    for dirname in inputs:
1369
        dirname = normalize_path(dirname)
1370
        if dirname in seen:
1371
            continue
1372

    
1373
        seen[dirname] = 1
1374
        if not os.path.isdir(dirname):
1375
            continue
1376

    
1377
        files = os.listdir(dirname)
1378
        yield dirname, files
1379

    
1380
        for name in files:
1381
            if not name.endswith('.pth'):
1382
                # We only care about the .pth files
1383
                continue
1384
            if name in ('easy-install.pth','setuptools.pth'):
1385
                # Ignore .pth files that we control
1386
                continue
1387

    
1388
            # Read the .pth file
1389
            f = open(os.path.join(dirname,name))
1390
            lines = list(yield_lines(f))
1391
            f.close()
1392

    
1393
            # Yield existing non-dupe, non-import directory lines from it
1394
            for line in lines:
1395
                if not line.startswith("import"):
1396
                    line = normalize_path(line.rstrip())
1397
                    if line not in seen:
1398
                        seen[line] = 1
1399
                        if not os.path.isdir(line):
1400
                            continue
1401
                        yield line, os.listdir(line)
1402

    
1403

    
1404
def extract_wininst_cfg(dist_filename):
1405
    """Extract configuration data from a bdist_wininst .exe
1406

1407
    Returns a ConfigParser.RawConfigParser, or None
1408
    """
1409
    f = open(dist_filename,'rb')
1410
    try:
1411
        endrec = zipfile._EndRecData(f)
1412
        if endrec is None:
1413
            return None
1414

    
1415
        prepended = (endrec[9] - endrec[5]) - endrec[6]
1416
        if prepended < 12:  # no wininst data here
1417
            return None
1418
        f.seek(prepended-12)
1419

    
1420
        import struct, StringIO, ConfigParser
1421
        tag, cfglen, bmlen = struct.unpack("<iii",f.read(12))
1422
        if tag not in (0x1234567A, 0x1234567B):
1423
            return None     # not a valid tag
1424

    
1425
        f.seek(prepended-(12+cfglen))
1426
        cfg = ConfigParser.RawConfigParser({'version':'','target_version':''})
1427
        try:
1428
            cfg.readfp(StringIO.StringIO(f.read(cfglen).split(chr(0),1)[0]))
1429
        except ConfigParser.Error:
1430
            return None
1431
        if not cfg.has_section('metadata') or not cfg.has_section('Setup'):
1432
            return None
1433
        return cfg
1434

    
1435
    finally:
1436
        f.close()
1437

    
1438

    
1439

    
1440

    
1441

    
1442

    
1443

    
1444

    
1445
def get_exe_prefixes(exe_filename):
1446
    """Get exe->egg path translations for a given .exe file"""
1447

    
1448
    prefixes = [
1449
        ('PURELIB/', ''), ('PLATLIB/pywin32_system32', ''),
1450
        ('PLATLIB/', ''),
1451
        ('SCRIPTS/', 'EGG-INFO/scripts/'),
1452
        ('DATA/LIB/site-packages', ''),
1453
    ]
1454
    z = zipfile.ZipFile(exe_filename)
1455
    try:
1456
        for info in z.infolist():
1457
            name = info.filename
1458
            parts = name.split('/')
1459
            if len(parts)==3 and parts[2]=='PKG-INFO':
1460
                if parts[1].endswith('.egg-info'):
1461
                    prefixes.insert(0,('/'.join(parts[:2]), 'EGG-INFO/'))
1462
                    break
1463
            if len(parts)<>2 or not name.endswith('.pth'):
1464
                continue
1465
            if name.endswith('-nspkg.pth'):
1466
                continue
1467
            if parts[0].upper() in ('PURELIB','PLATLIB'):
1468
                for pth in yield_lines(z.read(name)):
1469
                    pth = pth.strip().replace('\\','/')
1470
                    if not pth.startswith('import'):
1471
                        prefixes.append((('%s/%s/' % (parts[0],pth)), ''))
1472
    finally:
1473
        z.close()
1474
    prefixes = [(x.lower(),y) for x, y in prefixes]
1475
    prefixes.sort(); prefixes.reverse()
1476
    return prefixes
1477

    
1478

    
1479
def parse_requirement_arg(spec):
1480
    try:
1481
        return Requirement.parse(spec)
1482
    except ValueError:
1483
        raise DistutilsError(
1484
            "Not a URL, existing file, or requirement spec: %r" % (spec,)
1485
        )
1486

    
1487
class PthDistributions(Environment):
1488
    """A .pth file with Distribution paths in it"""
1489

    
1490
    dirty = False
1491

    
1492
    def __init__(self, filename, sitedirs=()):
1493
        self.filename = filename; self.sitedirs=map(normalize_path, sitedirs)
1494
        self.basedir = normalize_path(os.path.dirname(self.filename))
1495
        self._load(); Environment.__init__(self, [], None, None)
1496
        for path in yield_lines(self.paths):
1497
            map(self.add, find_distributions(path, True))
1498

    
1499
    def _load(self):
1500
        self.paths = []
1501
        saw_import = False
1502
        seen = dict.fromkeys(self.sitedirs)
1503
        if os.path.isfile(self.filename):
1504
            f = open(self.filename,'rt')
1505
            for line in f:
1506
                if line.startswith('import'):
1507
                    saw_import = True
1508
                    continue
1509
                path = line.rstrip()
1510
                self.paths.append(path)
1511
                if not path.strip() or path.strip().startswith('#'):
1512
                    continue
1513
                # skip non-existent paths, in case somebody deleted a package
1514
                # manually, and duplicate paths as well
1515
                path = self.paths[-1] = normalize_path(
1516
                    os.path.join(self.basedir,path)
1517
                )
1518
                if not os.path.exists(path) or path in seen:
1519
                    self.paths.pop()    # skip it
1520
                    self.dirty = True   # we cleaned up, so we're dirty now :)
1521
                    continue
1522
                seen[path] = 1
1523
            f.close()
1524

    
1525
        if self.paths and not saw_import:
1526
            self.dirty = True   # ensure anything we touch has import wrappers
1527
        while self.paths and not self.paths[-1].strip():
1528
            self.paths.pop()
1529

    
1530
    def save(self):
1531
        """Write changed .pth file back to disk"""
1532
        if not self.dirty:
1533
            return
1534

    
1535
        data = '\n'.join(map(self.make_relative,self.paths))
1536
        if data:
1537
            log.debug("Saving %s", self.filename)
1538
            data = (
1539
                "import sys; sys.__plen = len(sys.path)\n"
1540
                "%s\n"
1541
                "import sys; new=sys.path[sys.__plen:];"
1542
                " del sys.path[sys.__plen:];"
1543
                " p=getattr(sys,'__egginsert',0); sys.path[p:p]=new;"
1544
                " sys.__egginsert = p+len(new)\n"
1545
            ) % data
1546

    
1547
            if os.path.islink(self.filename):
1548
                os.unlink(self.filename)
1549
            f = open(self.filename,'wt')
1550
            f.write(data); f.close()
1551

    
1552
        elif os.path.exists(self.filename):
1553
            log.debug("Deleting empty %s", self.filename)
1554
            os.unlink(self.filename)
1555

    
1556
        self.dirty = False
1557

    
1558
    def add(self,dist):
1559
        """Add `dist` to the distribution map"""
1560
        if (dist.location not in self.paths and (
1561
                dist.location not in self.sitedirs or
1562
                dist.location == os.getcwd() #account for '.' being in PYTHONPATH
1563
                )):
1564
            self.paths.append(dist.location)
1565
            self.dirty = True
1566
        Environment.add(self,dist)
1567

    
1568
    def remove(self,dist):
1569
        """Remove `dist` from the distribution map"""
1570
        while dist.location in self.paths:
1571
            self.paths.remove(dist.location); self.dirty = True
1572
        Environment.remove(self,dist)
1573

    
1574

    
1575
    def make_relative(self,path):
1576
        npath, last = os.path.split(normalize_path(path))
1577
        baselen = len(self.basedir)
1578
        parts = [last]
1579
        sep = os.altsep=='/' and '/' or os.sep
1580
        while len(npath)>=baselen:
1581
            if npath==self.basedir:
1582
                parts.append(os.curdir)
1583
                parts.reverse()
1584
                return sep.join(parts)
1585
            npath, last = os.path.split(npath)
1586
            parts.append(last)
1587
        else:
1588
            return path
1589

    
1590
def get_script_header(script_text, executable=sys_executable, wininst=False):
1591
    """Create a #! line, getting options (if any) from script_text"""
1592
    from distutils.command.build_scripts import first_line_re
1593

    
1594
    # first_line_re in Python >=3.1.4 and >=3.2.1 is a bytes pattern.
1595
    if not isinstance(first_line_re.pattern, str):
1596
        first_line_re = re.compile(first_line_re.pattern.decode())
1597

    
1598
    first = (script_text+'\n').splitlines()[0]
1599
    match = first_line_re.match(first)
1600
    options = ''
1601
    if match:
1602
        options = match.group(1) or ''
1603
        if options: options = ' '+options
1604
    if wininst:
1605
        executable = "python.exe"
1606
    else:
1607
        executable = nt_quote_arg(executable)
1608
    hdr = "#!%(executable)s%(options)s\n" % locals()
1609
    if not isascii(hdr):
1610
        # Non-ascii path to sys.executable, use -x to prevent warnings
1611
        if options:
1612
            if options.strip().startswith('-'):
1613
                options = ' -x'+options.strip()[1:]
1614
            # else: punt, we can't do it, let the warning happen anyway
1615
        else:
1616
            options = ' -x'
1617
    executable = fix_jython_executable(executable, options)
1618
    hdr = "#!%(executable)s%(options)s\n" % locals()
1619
    return hdr
1620

    
1621
def auto_chmod(func, arg, exc):
1622
    if func is os.remove and os.name=='nt':
1623
        chmod(arg, stat.S_IWRITE)
1624
        return func(arg)
1625
    exc = sys.exc_info()
1626
    raise exc[0], (exc[1][0], exc[1][1] + (" %s %s" % (func,arg)))
1627

    
1628
def uncache_zipdir(path):
1629
    """Ensure that the importer caches dont have stale info for `path`"""
1630
    from zipimport import _zip_directory_cache as zdc
1631
    _uncache(path, zdc)
1632
    _uncache(path, sys.path_importer_cache)
1633

    
1634
def _uncache(path, cache):
1635
    if path in cache:
1636
        del cache[path]
1637
    else:
1638
        path = normalize_path(path)
1639
        for p in cache:
1640
            if normalize_path(p)==path:
1641
                del cache[p]
1642
                return
1643

    
1644
def is_python(text, filename='<string>'):
1645
    "Is this string a valid Python script?"
1646
    try:
1647
        compile(text, filename, 'exec')
1648
    except (SyntaxError, TypeError):
1649
        return False
1650
    else:
1651
        return True
1652

    
1653
def is_sh(executable):
1654
    """Determine if the specified executable is a .sh (contains a #! line)"""
1655
    try:
1656
        fp = open(executable)
1657
        magic = fp.read(2)
1658
        fp.close()
1659
    except (OSError,IOError): return executable
1660
    return magic == '#!'
1661

    
1662
def nt_quote_arg(arg):
1663
    """Quote a command line argument according to Windows parsing rules"""
1664

    
1665
    result = []
1666
    needquote = False
1667
    nb = 0
1668

    
1669
    needquote = (" " in arg) or ("\t" in arg)
1670
    if needquote:
1671
        result.append('"')
1672

    
1673
    for c in arg:
1674
        if c == '\\':
1675
            nb += 1
1676
        elif c == '"':
1677
            # double preceding backslashes, then add a \"
1678
            result.append('\\' * (nb*2) + '\\"')
1679
            nb = 0
1680
        else:
1681
            if nb:
1682
                result.append('\\' * nb)
1683
                nb = 0
1684
            result.append(c)
1685

    
1686
    if nb:
1687
        result.append('\\' * nb)
1688

    
1689
    if needquote:
1690
        result.append('\\' * nb)    # double the trailing backslashes
1691
        result.append('"')
1692

    
1693
    return ''.join(result)
1694

    
1695

    
1696

    
1697

    
1698

    
1699

    
1700

    
1701

    
1702

    
1703
def is_python_script(script_text, filename):
1704
    """Is this text, as a whole, a Python script? (as opposed to shell/bat/etc.
1705
    """
1706
    if filename.endswith('.py') or filename.endswith('.pyw'):
1707
        return True     # extension says it's Python
1708
    if is_python(script_text, filename):
1709
        return True     # it's syntactically valid Python
1710
    if script_text.startswith('#!'):
1711
        # It begins with a '#!' line, so check if 'python' is in it somewhere
1712
        return 'python' in script_text.splitlines()[0].lower()
1713

    
1714
    return False    # Not any Python I can recognize
1715

    
1716
try:
1717
    from os import chmod as _chmod
1718
except ImportError:
1719
    # Jython compatibility
1720
    def _chmod(*args): pass
1721

    
1722
def chmod(path, mode):
1723
    log.debug("changing mode of %s to %o", path, mode)
1724
    try:
1725
        _chmod(path, mode)
1726
    except os.error, e:
1727
        log.debug("chmod failed: %s", e)
1728

    
1729
def fix_jython_executable(executable, options):
1730
    if sys.platform.startswith('java') and is_sh(executable):
1731
        # Workaround Jython's sys.executable being a .sh (an invalid
1732
        # shebang line interpreter)
1733
        if options:
1734
            # Can't apply the workaround, leave it broken
1735
            log.warn("WARNING: Unable to adapt shebang line for Jython,"
1736
                             " the following script is NOT executable\n"
1737
                     "         see http://bugs.jython.org/issue1112 for"
1738
                             " more information.")
1739
        else:
1740
            return '/usr/bin/env %s' % executable
1741
    return executable
1742

    
1743

    
1744
def get_script_args(dist, executable=sys_executable, wininst=False):
1745
    """Yield write_script() argument tuples for a distribution's entrypoints"""
1746
    spec = str(dist.as_requirement())
1747
    header = get_script_header("", executable, wininst)
1748
    for group in 'console_scripts', 'gui_scripts':
1749
        for name, ep in dist.get_entry_map(group).items():
1750
            script_text = (
1751
                "# EASY-INSTALL-ENTRY-SCRIPT: %(spec)r,%(group)r,%(name)r\n"
1752
                "__requires__ = %(spec)r\n"
1753
                "import sys\n"
1754
                "from pkg_resources import load_entry_point\n"
1755
                "\n"
1756
                "if __name__ == '__main__':"
1757
                "\n"
1758
                "    sys.exit(\n"
1759
                "        load_entry_point(%(spec)r, %(group)r, %(name)r)()\n"
1760
                "    )\n"
1761
            ) % locals()
1762
            if sys.platform=='win32' or wininst:
1763
                # On Windows/wininst, add a .py extension and an .exe launcher
1764
                if group=='gui_scripts':
1765
                    ext, launcher = '-script.pyw', 'gui.exe'
1766
                    old = ['.pyw']
1767
                    new_header = re.sub('(?i)python.exe','pythonw.exe',header)
1768
                else:
1769
                    ext, launcher = '-script.py', 'cli.exe'
1770
                    old = ['.py','.pyc','.pyo']
1771
                    new_header = re.sub('(?i)pythonw.exe','python.exe',header)
1772

    
1773
                if os.path.exists(new_header[2:-1]) or sys.platform!='win32':
1774
                    hdr = new_header
1775
                else:
1776
                    hdr = header
1777
                yield (name+ext, hdr+script_text, 't', [name+x for x in old])
1778
                yield (
1779
                    name+'.exe', resource_string('setuptools', launcher),
1780
                    'b' # write in binary mode
1781
                )
1782
            else:
1783
                # On other platforms, we assume the right thing to do is to
1784
                # just write the stub with no extension.
1785
                yield (name, header+script_text)
1786

    
1787
def rmtree(path, ignore_errors=False, onerror=auto_chmod):
1788
    """Recursively delete a directory tree.
1789

1790
    This code is taken from the Python 2.4 version of 'shutil', because
1791
    the 2.3 version doesn't really work right.
1792
    """
1793
    if ignore_errors:
1794
        def onerror(*args):
1795
            pass
1796
    elif onerror is None:
1797
        def onerror(*args):
1798
            raise
1799
    names = []
1800
    try:
1801
        names = os.listdir(path)
1802
    except os.error, err:
1803
        onerror(os.listdir, path, sys.exc_info())
1804
    for name in names:
1805
        fullname = os.path.join(path, name)
1806
        try:
1807
            mode = os.lstat(fullname).st_mode
1808
        except os.error:
1809
            mode = 0
1810
        if stat.S_ISDIR(mode):
1811
            rmtree(fullname, ignore_errors, onerror)
1812
        else:
1813
            try:
1814
                os.remove(fullname)
1815
            except os.error, err:
1816
                onerror(os.remove, fullname, sys.exc_info())
1817
    try:
1818
        os.rmdir(path)
1819
    except os.error:
1820
        onerror(os.rmdir, path, sys.exc_info())
1821

    
1822
def bootstrap():
1823
    # This function is called when setuptools*.egg is run using /bin/sh
1824
    import setuptools; argv0 = os.path.dirname(setuptools.__path__[0])
1825
    sys.argv[0] = argv0; sys.argv.append(argv0); main()
1826

    
1827
def main(argv=None, **kw):
1828
    from setuptools import setup
1829
    from setuptools.dist import Distribution
1830
    import distutils.core
1831

    
1832
    USAGE = """\
1833
usage: %(script)s [options] requirement_or_url ...
1834
   or: %(script)s --help
1835
"""
1836

    
1837
    def gen_usage (script_name):
1838
        script = os.path.basename(script_name)
1839
        return USAGE % vars()
1840

    
1841
    def with_ei_usage(f):
1842
        old_gen_usage = distutils.core.gen_usage
1843
        try:
1844
            distutils.core.gen_usage = gen_usage
1845
            return f()
1846
        finally:
1847
            distutils.core.gen_usage = old_gen_usage
1848

    
1849
    class DistributionWithoutHelpCommands(Distribution):
1850
        common_usage = ""
1851

    
1852
        def _show_help(self,*args,**kw):
1853
            with_ei_usage(lambda: Distribution._show_help(self,*args,**kw))
1854

    
1855
        def find_config_files(self):
1856
            files = Distribution.find_config_files(self)
1857
            if 'setup.cfg' in files:
1858
                files.remove('setup.cfg')
1859
            return files
1860

    
1861
    if argv is None:
1862
        argv = sys.argv[1:]
1863

    
1864
    with_ei_usage(lambda:
1865
        setup(
1866
            script_args = ['-q','easy_install', '-v']+argv,
1867
            script_name = sys.argv[0] or 'easy_install',
1868
            distclass=DistributionWithoutHelpCommands, **kw
1869
        )
1870
    )
1871

    
1872

    
1873

    
1874