]> git.rkrishnan.org Git - tahoe-lafs/zfec.git/blob - zfec/setuptools-0.6c15dev.egg/setuptools/command/easy_install.py
setup: bundle the latest zetuptoolz as unpacked source egg and change setup.py to...
[tahoe-lafs/zfec.git] / zfec / setuptools-0.6c15dev.egg / setuptools / command / easy_install.py
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://peak.telecommunity.com/DevCenter/EasyInstall
11 """
12 import sys, os.path, zipimport, shutil, tempfile, zipfile, re, stat, random
13 from glob import glob
14 from setuptools import Command
15 from setuptools.sandbox import run_setup
16 from distutils import log, dir_util
17 from distutils.sysconfig import get_python_lib
18 from distutils.errors import DistutilsArgError, DistutilsOptionError, \
19     DistutilsError
20 from setuptools.archive_util import unpack_archive
21 from setuptools.package_index import PackageIndex, parse_bdist_wininst
22 from setuptools.package_index import URL_SCHEME
23 from setuptools.command import bdist_egg, egg_info
24 from pkg_resources import *
25 sys_executable = os.path.normpath(sys.executable)
26
27 __all__ = [
28     'samefile', 'easy_install', 'PthDistributions', 'extract_wininst_cfg',
29     'main', 'get_exe_prefixes',
30 ]
31
32 def samefile(p1,p2):
33     if hasattr(os.path,'samefile') and (
34         os.path.exists(p1) and os.path.exists(p2)
35     ):
36         return os.path.samefile(p1,p2)
37     return (
38         os.path.normpath(os.path.normcase(p1)) ==
39         os.path.normpath(os.path.normcase(p2))
40     )
41
42 class easy_install(Command):
43     """Manage a download/build/install process"""
44     description = "Find/get/install Python packages"
45     command_consumes_arguments = True
46
47     user_options = [
48         ('prefix=', None, "installation prefix"),
49         ("zip-ok", "z", "install package as a zipfile"),
50         ("multi-version", "m", "make apps have to require() a version"),
51         ("upgrade", "U", "force upgrade (searches PyPI for latest versions)"),
52         ("install-dir=", "d", "install package to DIR"),
53         ("script-dir=", "s", "install scripts to DIR"),
54         ("exclude-scripts", "x", "Don't install scripts"),
55         ("always-copy", "a", "Copy all needed packages to install dir"),
56         ("index-url=", "i", "base URL of Python Package Index"),
57         ("find-links=", "f", "additional URL(s) to search for packages"),
58         ("delete-conflicting", "D", "no longer needed; don't use this"),
59         ("ignore-conflicts-at-my-risk", None,
60             "no longer needed; don't use this"),
61         ("build-directory=", "b",
62             "download/extract/build in DIR; keep the results"),
63         ('optimize=', 'O',
64          "also compile with optimization: -O1 for \"python -O\", "
65          "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"),
66         ('record=', None,
67          "filename in which to record list of installed files"),
68         ('always-unzip', 'Z', "don't install as a zipfile, no matter what"),
69         ('site-dirs=','S',"list of directories where .pth files work"),
70         ('editable', 'e', "Install specified packages in editable form"),
71         ('no-deps', 'N', "don't install dependencies"),
72         ('allow-hosts=', 'H', "pattern(s) that hostnames must match"),
73         ('local-snapshots-ok', 'l', "allow building eggs from local checkouts"),
74     ]
75     boolean_options = [
76         'zip-ok', 'multi-version', 'exclude-scripts', 'upgrade', 'always-copy',
77         'delete-conflicting', 'ignore-conflicts-at-my-risk', 'editable',
78         'no-deps', 'local-snapshots-ok',
79     ]
80     negative_opt = {'always-unzip': 'zip-ok'}
81     create_index = PackageIndex
82
83     def initialize_options(self):
84         self.zip_ok = self.local_snapshots_ok = None
85         self.install_dir = self.script_dir = self.exclude_scripts = None
86         self.index_url = None
87         self.find_links = None
88         self.build_directory = None
89         self.args = None
90         self.optimize = self.record = None
91         self.upgrade = self.always_copy = self.multi_version = None
92         self.editable = self.no_deps = self.allow_hosts = None
93         self.root = self.prefix = self.no_report = None
94
95         # Options not specifiable via command line
96         self.package_index = None
97         self.pth_file = self.always_copy_from = None
98         self.delete_conflicting = None
99         self.ignore_conflicts_at_my_risk = None
100         self.site_dirs = None
101         self.installed_projects = {}
102         self.sitepy_installed = False
103         # Always read easy_install options, even if we are subclassed, or have
104         # an independent instance created.  This ensures that defaults will
105         # always come from the standard configuration file(s)' "easy_install"
106         # section, even if this is a "develop" or "install" command, or some
107         # other embedding.
108         self._dry_run = None
109         self.verbose = self.distribution.verbose
110         self.distribution._set_command_options(
111             self, self.distribution.get_option_dict('easy_install')
112         )
113
114     def delete_blockers(self, blockers):
115         for filename in blockers:
116             if os.path.exists(filename) or os.path.islink(filename):
117                 log.info("Deleting %s", filename)
118                 if not self.dry_run:
119                     if os.path.isdir(filename) and not os.path.islink(filename):
120                         rmtree(filename)
121                     else:
122                         os.unlink(filename)
123
124     def finalize_options(self):
125         self._expand('install_dir','script_dir','build_directory','site_dirs')
126         # If a non-default installation directory was specified, default the
127         # script directory to match it.
128         if self.script_dir is None:
129             self.script_dir = self.install_dir
130
131         # Let install_dir get set by install_lib command, which in turn
132         # gets its info from the install command, and takes into account
133         # --prefix and --home and all that other crud.
134         self.set_undefined_options('install_lib',
135             ('install_dir','install_dir')
136         )
137         # Likewise, set default script_dir from 'install_scripts.install_dir'
138         self.set_undefined_options('install_scripts',
139             ('install_dir', 'script_dir')
140         )
141         # default --record from the install command
142         self.set_undefined_options('install', ('record', 'record'))
143         normpath = map(normalize_path, sys.path)
144         self.all_site_dirs = get_site_dirs()
145         if self.site_dirs is not None:
146             site_dirs = [
147                 os.path.expanduser(s.strip()) for s in self.site_dirs.split(',')
148             ]
149             for d in site_dirs:
150                 if not os.path.isdir(d):
151                     log.warn("%s (in --site-dirs) does not exist", d)
152                 elif normalize_path(d) not in normpath:
153                     raise DistutilsOptionError(
154                         d+" (in --site-dirs) is not on sys.path"
155                     )
156                 else:
157                     self.all_site_dirs.append(normalize_path(d))
158         if not self.editable: self.check_site_dir()
159         self.index_url = self.index_url or "http://pypi.python.org/simple"
160         self.shadow_path = self.all_site_dirs[:]
161         for path_item in self.install_dir, normalize_path(self.script_dir):
162             if path_item not in self.shadow_path:
163                 self.shadow_path.insert(0, path_item)
164
165         if self.allow_hosts is not None:
166             hosts = [s.strip() for s in self.allow_hosts.split(',')]
167         else:
168             hosts = ['*']
169         if self.package_index is None:
170             self.package_index = self.create_index(
171                 self.index_url, search_path = self.shadow_path+sys.path, hosts=hosts,
172             )
173         self.local_index = Environment(self.shadow_path+sys.path)
174
175         if self.find_links is not None:
176             if isinstance(self.find_links, basestring):
177                 self.find_links = self.find_links.split()
178         else:
179             self.find_links = []
180         if self.local_snapshots_ok:
181             self.package_index.scan_egg_links(self.shadow_path+sys.path)
182         self.package_index.add_find_links(self.find_links)
183         self.set_undefined_options('install_lib', ('optimize','optimize'))
184         if not isinstance(self.optimize,int):
185             try:
186                 self.optimize = int(self.optimize)
187                 if not (0 <= self.optimize <= 2): raise ValueError
188             except ValueError:
189                 raise DistutilsOptionError("--optimize must be 0, 1, or 2")
190
191         if self.delete_conflicting and self.ignore_conflicts_at_my_risk:
192             raise DistutilsOptionError(
193                 "Can't use both --delete-conflicting and "
194                 "--ignore-conflicts-at-my-risk at the same time"
195             )
196         if self.editable and not self.build_directory:
197             raise DistutilsArgError(
198                 "Must specify a build directory (-b) when using --editable"
199             )
200         if not self.args:
201             raise DistutilsArgError(
202                 "No urls, filenames, or requirements specified (see --help)")
203
204         self.outputs = []
205
206     def run(self):
207         if self.verbose!=self.distribution.verbose:
208             log.set_verbosity(self.verbose)
209         try:
210             for spec in self.args:
211                 self.easy_install(spec, not self.no_deps)
212             if self.record:
213                 outputs = self.outputs
214                 if self.root:               # strip any package prefix
215                     root_len = len(self.root)
216                     for counter in xrange(len(outputs)):
217                         outputs[counter] = outputs[counter][root_len:]
218                 from distutils import file_util
219                 self.execute(
220                     file_util.write_file, (self.record, outputs),
221                     "writing list of installed files to '%s'" %
222                     self.record
223                 )
224             self.warn_deprecated_options()
225         finally:
226             log.set_verbosity(self.distribution.verbose)
227
228     def pseudo_tempname(self):
229         """Return a pseudo-tempname base in the install directory.
230         This code is intentionally naive; if a malicious party can write to
231         the target directory you're already in deep doodoo.
232         """
233         try:
234             pid = os.getpid()
235         except:
236             pid = random.randint(0,sys.maxint)
237         return os.path.join(self.install_dir, "test-easy-install-%s" % pid)
238
239     def warn_deprecated_options(self):
240         if self.delete_conflicting or self.ignore_conflicts_at_my_risk:
241             log.warn(
242                 "Note: The -D, --delete-conflicting and"
243                 " --ignore-conflicts-at-my-risk no longer have any purpose"
244                 " and should not be used."
245             )
246
247     def check_site_dir(self):
248         """Verify that self.install_dir is .pth-capable dir, if needed"""
249         instdir = normalize_path(self.install_dir)
250         pth_file = os.path.join(instdir,'easy-install.pth')
251
252         # mkdir it if necessary
253         try:
254             os.makedirs(instdir)
255         except OSError:
256             # Oh well -- hopefully this error simply means that it is already there.
257             # If not the subsequent write test will identify the problem.
258             pass
259         # add it to site dirs
260         self.all_site_dirs.append(instdir)
261
262         # Is it a configured, PYTHONPATH, implicit, or explicit site dir?
263         is_site_dir = instdir in self.all_site_dirs
264
265         if not is_site_dir and not self.multi_version:
266             # No?  Then directly test whether it does .pth file processing
267             is_site_dir = self.check_pth_processing()
268         else:
269             # make sure we can write to target dir
270             testfile = self.pseudo_tempname()+'.write-test'
271             test_exists = os.path.exists(testfile)
272             try:
273                 if test_exists: os.unlink(testfile)
274                 open(testfile,'w').close()
275                 os.unlink(testfile)
276             except (OSError,IOError):
277                 self.cant_write_to_target()
278
279         if not is_site_dir and not self.multi_version:
280             # Can't install non-multi to non-site dir
281             log.warn(self.no_default_version_msg())
282
283         if is_site_dir:
284             if self.pth_file is None:
285                 self.pth_file = PthDistributions(pth_file, self.all_site_dirs)
286         else:
287             self.pth_file = None
288
289         if self.multi_version and not os.path.exists(pth_file):
290             self.sitepy_installed = True    # don't need site.py in this case
291             self.pth_file = None            # and don't create a .pth file
292         self.install_dir = instdir
293
294     def cant_write_to_target(self):
295         msg = """can't create or remove files in install directory
296
297 The following error occurred while trying to add or remove files in the
298 installation directory:
299
300     %s
301
302 The installation directory you specified (via --install-dir, --prefix, or
303 the distutils default setting) was:
304
305     %s
306 """     % (sys.exc_info()[1], self.install_dir,)
307
308         if not os.path.exists(self.install_dir):
309             msg += """
310 This directory does not currently exist.  Please create it and try again, or
311 choose a different installation directory (using the -d or --install-dir
312 option).
313 """
314         else:
315             msg += """
316 Perhaps your account does not have write access to this directory?  If the
317 installation directory is a system-owned directory, you may need to sign in
318 as the administrator or "root" account.  If you do not have administrative
319 access to this machine, you may wish to choose a different installation
320 directory, preferably one that is listed in your PYTHONPATH environment
321 variable.
322
323 For information on other options, you may wish to consult the
324 documentation at:
325
326   http://peak.telecommunity.com/EasyInstall.html
327
328 Please make the appropriate changes for your system and try again.
329 """
330         raise DistutilsError(msg)
331
332
333
334
335     def check_pth_processing(self):
336         """Empirically verify whether .pth files are supported in inst. dir"""
337         instdir = self.install_dir
338         log.info("Checking .pth file support in %s", instdir)
339         pth_file = self.pseudo_tempname()+".pth"
340         ok_file = pth_file+'.ok'
341         ok_exists = os.path.exists(ok_file)
342         try:
343             if ok_exists: os.unlink(ok_file)
344             f = open(pth_file,'w')
345         except (OSError,IOError):
346             self.cant_write_to_target()
347         else:
348             try:
349                 f.write("import os;open(%r,'w').write('OK')\n" % (ok_file,))
350                 f.close(); f=None
351                 executable = sys.executable
352                 if os.name=='nt':
353                     dirname,basename = os.path.split(executable)
354                     alt = os.path.join(dirname,'pythonw.exe')
355                     if basename.lower()=='python.exe' and os.path.exists(alt):
356                         # use pythonw.exe to avoid opening a console window
357                         executable = alt
358
359                 from distutils.spawn import spawn
360                 spawn([executable,'-E','-c','pass'],0)
361
362                 if os.path.exists(ok_file):
363                     log.info(
364                         "TEST PASSED: %s appears to support .pth files",
365                         instdir
366                     )
367                     return True
368             finally:
369                 if f: f.close()
370                 if os.path.exists(ok_file): os.unlink(ok_file)
371                 if os.path.exists(pth_file): os.unlink(pth_file)
372         if not self.multi_version:
373             log.warn("TEST FAILED: %s does NOT support .pth files", instdir)
374         return False
375
376     def install_egg_scripts(self, dist):
377         """Write all the scripts for `dist`, unless scripts are excluded"""
378         if not self.exclude_scripts and dist.metadata_isdir('scripts'):
379             for script_name in dist.metadata_listdir('scripts'):
380                 self.install_script(
381                     dist, script_name,
382                     dist.get_metadata('scripts/'+script_name)
383                 )
384         self.install_wrapper_scripts(dist)
385
386     def add_output(self, path):
387         if os.path.isdir(path):
388             for base, dirs, files in os.walk(path):
389                 for filename in files:
390                     self.outputs.append(os.path.join(base,filename))
391         else:
392             self.outputs.append(path)
393
394     def not_editable(self, spec):
395         if self.editable:
396             raise DistutilsArgError(
397                 "Invalid argument %r: you can't use filenames or URLs "
398                 "with --editable (except via the --find-links option)."
399                 % (spec,)
400             )
401
402     def check_editable(self,spec):
403         if not self.editable:
404             return
405
406         if os.path.exists(os.path.join(self.build_directory, spec.key)):
407             raise DistutilsArgError(
408                 "%r already exists in %s; can't do a checkout there" %
409                 (spec.key, self.build_directory)
410             )
411
412
413
414
415
416
417     def easy_install(self, spec, deps=False):
418         tmpdir = tempfile.mkdtemp(prefix="easy_install-")
419         download = None
420         if not self.editable: self.install_site_py()
421
422         try:
423             if not isinstance(spec,Requirement):
424                 if URL_SCHEME(spec):
425                     # It's a url, download it to tmpdir and process
426                     self.not_editable(spec)
427                     download = self.package_index.download(spec, tmpdir)
428                     return self.install_item(None, download, tmpdir, deps, True)
429
430                 elif os.path.exists(spec):
431                     # Existing file or directory, just process it directly
432                     self.not_editable(spec)
433                     return self.install_item(None, spec, tmpdir, deps, True)
434                 else:
435                     spec = parse_requirement_arg(spec)
436
437             self.check_editable(spec)
438             dist = self.package_index.fetch_distribution(
439                 spec, tmpdir, self.upgrade, self.editable, not self.always_copy,
440                 self.local_index
441             )
442             if dist is None:
443                 msg = "Could not find suitable distribution for %r" % spec
444                 if self.always_copy:
445                     msg+=" (--always-copy skips system and development eggs)"
446                 raise DistutilsError(msg)
447             elif dist.precedence==DEVELOP_DIST:
448                 # .egg-info dists don't need installing, just process deps
449                 self.process_distribution(spec, dist, deps, "Using")
450                 return dist
451             else:
452                 return self.install_item(spec, dist.location, tmpdir, deps)
453
454         finally:
455             if os.path.exists(tmpdir):
456                 rmtree(tmpdir)
457
458     def install_item(self, spec, download, tmpdir, deps, install_needed=False):
459
460         # Installation is also needed if file in tmpdir or is not an egg
461         install_needed = install_needed or self.always_copy
462         install_needed = install_needed or os.path.dirname(download) == tmpdir
463         install_needed = install_needed or not download.endswith('.egg')
464         install_needed = install_needed or (
465             self.always_copy_from is not None and
466             os.path.dirname(normalize_path(download)) ==
467             normalize_path(self.always_copy_from)
468         )
469
470         if spec and not install_needed:
471             # at this point, we know it's a local .egg, we just don't know if
472             # it's already installed.
473             for dist in self.local_index[spec.project_name]:
474                 if dist.location==download:
475                     break
476             else:
477                 install_needed = True   # it's not in the local index
478
479         log.info("Processing %s", os.path.basename(download))
480
481         if install_needed:
482             dists = self.install_eggs(spec, download, tmpdir)
483             for dist in dists:
484                 self.process_distribution(spec, dist, deps)
485         else:
486             dists = [self.check_conflicts(self.egg_distribution(download))]
487             self.process_distribution(spec, dists[0], deps, "Using")
488
489         if spec is not None:
490             for dist in dists:
491                 if dist in spec:
492                     return dist
493
494
495
496
497
498
499     def process_distribution(self, requirement, dist, deps=True, *info):
500         self.update_pth(dist)
501         self.package_index.add(dist)
502         self.local_index.add(dist)
503         self.install_egg_scripts(dist)
504         self.installed_projects[dist.key] = dist
505         log.info(self.installation_report(requirement, dist, *info))
506         if dist.has_metadata('dependency_links.txt'):
507             self.package_index.add_find_links(
508                 dist.get_metadata_lines('dependency_links.txt')
509             )
510         if not deps and not self.always_copy:
511             return
512         elif requirement is not None and dist.key != requirement.key:
513             log.warn("Skipping dependencies for %s", dist)
514             return  # XXX this is not the distribution we were looking for
515         elif requirement is None or dist not in requirement:
516             # if we wound up with a different version, resolve what we've got
517             distreq = dist.as_requirement()
518             requirement = requirement or distreq
519             requirement = Requirement(
520                 distreq.project_name, distreq.specs, requirement.extras
521             )
522         log.info("Processing dependencies for %s", requirement)
523         try:
524             distros = WorkingSet([]).resolve(
525                 [requirement], self.local_index, self.easy_install
526             )
527         except DistributionNotFound, e:
528             raise DistutilsError(
529                 "Could not find required distribution %s" % e.args
530             )
531         except VersionConflict, e:
532             raise DistutilsError(
533                 "Installed distribution %s conflicts with requirement %s"
534                 % e.args
535             )
536         if self.always_copy or self.always_copy_from:
537             # Force all the relevant distros to be copied or activated
538             for dist in distros:
539                 if dist.key not in self.installed_projects:
540                     self.easy_install(dist.as_requirement())
541         log.info("Finished processing dependencies for %s", requirement)
542
543     def should_unzip(self, dist):
544         if self.zip_ok is not None:
545             return not self.zip_ok
546         if dist.has_metadata('not-zip-safe'):
547             return True
548         if not dist.has_metadata('zip-safe'):
549             return True
550         return False
551
552     def maybe_move(self, spec, dist_filename, setup_base):
553         dst = os.path.join(self.build_directory, spec.key)
554         if os.path.exists(dst):
555             log.warn(
556                "%r already exists in %s; build directory %s will not be kept",
557                spec.key, self.build_directory, setup_base
558             )
559             return setup_base
560         if os.path.isdir(dist_filename):
561             setup_base = dist_filename
562         else:
563             if os.path.dirname(dist_filename)==setup_base:
564                 os.unlink(dist_filename)   # get it out of the tmp dir
565             contents = os.listdir(setup_base)
566             if len(contents)==1:
567                 dist_filename = os.path.join(setup_base,contents[0])
568                 if os.path.isdir(dist_filename):
569                     # if the only thing there is a directory, move it instead
570                     setup_base = dist_filename
571         ensure_directory(dst); shutil.move(setup_base, dst)
572         return dst
573
574     def install_wrapper_scripts(self, dist):
575         if not self.exclude_scripts:
576             for args in get_script_args(dist):
577                 self.write_script(*args)
578
579
580
581     def install_script(self, dist, script_name, script_text, dev_path=None):
582         """Generate a legacy script wrapper and install it"""
583         spec = str(dist.as_requirement())
584         is_script = is_python_script(script_text, script_name)
585
586         if is_script and dev_path:
587             script_text = get_script_header(script_text) + (
588                 "# EASY-INSTALL-DEV-SCRIPT: %(spec)r,%(script_name)r\n"
589                 "__requires__ = %(spec)r\n"
590                 "from pkg_resources import require; require(%(spec)r)\n"
591                 "del require\n"
592                 "__file__ = %(dev_path)r\n"
593                 "execfile(__file__)\n"
594             ) % locals()
595         elif is_script:
596             script_text = get_script_header(script_text) + (
597                 "# EASY-INSTALL-SCRIPT: %(spec)r,%(script_name)r\n"
598                 "__requires__ = %(spec)r\n"
599                 "import pkg_resources\n"
600                 "pkg_resources.run_script(%(spec)r, %(script_name)r)\n"
601             ) % locals()
602         self.write_script(script_name, script_text, 'b')
603
604     def write_script(self, script_name, contents, mode="t", blockers=()):
605         """Write an executable file to the scripts directory"""
606         self.delete_blockers(   # clean up old .py/.pyw w/o a script
607             [os.path.join(self.script_dir,x) for x in blockers])
608         log.info("Installing %s script to %s", script_name, self.script_dir)
609         target = os.path.join(self.script_dir, script_name)
610         self.add_output(target)
611
612         if not self.dry_run:
613             ensure_directory(target)
614             f = open(target,"w"+mode)
615             f.write(contents)
616             f.close()
617             chmod(target,0755)
618
619
620
621
622     def install_eggs(self, spec, dist_filename, tmpdir):
623         # .egg dirs or files are already built, so just return them
624         if dist_filename.lower().endswith('.egg'):
625             return [self.install_egg(dist_filename, tmpdir)]
626         elif dist_filename.lower().endswith('.exe'):
627             return [self.install_exe(dist_filename, tmpdir)]
628
629         # Anything else, try to extract and build
630         setup_base = tmpdir
631         if os.path.isfile(dist_filename) and not dist_filename.endswith('.py'):
632             unpack_archive(dist_filename, tmpdir, self.unpack_progress)
633         elif os.path.isdir(dist_filename):
634             setup_base = os.path.abspath(dist_filename)
635
636         if (setup_base.startswith(tmpdir)   # something we downloaded
637             and self.build_directory and spec is not None
638         ):
639             setup_base = self.maybe_move(spec, dist_filename, setup_base)
640
641         # Find the setup.py file
642         setup_script = os.path.join(setup_base, 'setup.py')
643
644         if not os.path.exists(setup_script):
645             setups = glob(os.path.join(setup_base, '*', 'setup.py'))
646             if not setups:
647                 raise DistutilsError(
648                     "Couldn't find a setup script in %s" % os.path.abspath(dist_filename)
649                 )
650             if len(setups)>1:
651                 raise DistutilsError(
652                     "Multiple setup scripts in %s" % os.path.abspath(dist_filename)
653                 )
654             setup_script = setups[0]
655
656         # Now run it, and return the result
657         if self.editable:
658             log.info(self.report_editable(spec, setup_script))
659             return []
660         else:
661             return self.build_and_install(setup_script, setup_base)
662
663     def egg_distribution(self, egg_path):
664         if os.path.isdir(egg_path):
665             metadata = PathMetadata(egg_path,os.path.join(egg_path,'EGG-INFO'))
666         else:
667             metadata = EggMetadata(zipimport.zipimporter(egg_path))
668         return Distribution.from_filename(egg_path,metadata=metadata)
669
670     def install_egg(self, egg_path, tmpdir):
671         destination = os.path.join(self.install_dir,os.path.basename(egg_path))
672         destination = os.path.abspath(destination)
673         if not self.dry_run:
674             ensure_directory(destination)
675
676         dist = self.egg_distribution(egg_path)
677         self.check_conflicts(dist)
678         if not samefile(egg_path, destination):
679             if os.path.isdir(destination) and not os.path.islink(destination):
680                 dir_util.remove_tree(destination, dry_run=self.dry_run)
681             elif os.path.exists(destination):
682                 self.execute(os.unlink,(destination,),"Removing "+destination)
683             uncache_zipdir(destination)
684             if os.path.isdir(egg_path):
685                 if egg_path.startswith(tmpdir):
686                     f,m = shutil.move, "Moving"
687                 else:
688                     f,m = shutil.copytree, "Copying"
689             elif self.should_unzip(dist):
690                 self.mkpath(destination)
691                 f,m = self.unpack_and_compile, "Extracting"
692             elif egg_path.startswith(tmpdir):
693                 f,m = shutil.move, "Moving"
694             else:
695                 f,m = shutil.copy2, "Copying"
696
697             self.execute(f, (egg_path, destination),
698                 (m+" %s to %s") %
699                 (os.path.basename(egg_path),os.path.dirname(destination)))
700
701         self.add_output(destination)
702         return self.egg_distribution(destination)
703
704     def install_exe(self, dist_filename, tmpdir):
705         # See if it's valid, get data
706         cfg = extract_wininst_cfg(dist_filename)
707         if cfg is None:
708             raise DistutilsError(
709                 "%s is not a valid distutils Windows .exe" % dist_filename
710             )
711         # Create a dummy distribution object until we build the real distro
712         dist = Distribution(None,
713             project_name=cfg.get('metadata','name'),
714             version=cfg.get('metadata','version'), platform="win32"
715         )
716
717         # Convert the .exe to an unpacked egg
718         egg_path = dist.location = os.path.join(tmpdir, dist.egg_name()+'.egg')
719         egg_tmp  = egg_path+'.tmp'
720         egg_info = os.path.join(egg_tmp, 'EGG-INFO')
721         pkg_inf = os.path.join(egg_info, 'PKG-INFO')
722         ensure_directory(pkg_inf)   # make sure EGG-INFO dir exists
723         dist._provider = PathMetadata(egg_tmp, egg_info)    # XXX
724         self.exe_to_egg(dist_filename, egg_tmp)
725
726         # Write EGG-INFO/PKG-INFO
727         if not os.path.exists(pkg_inf):
728             f = open(pkg_inf,'w')
729             f.write('Metadata-Version: 1.0\n')
730             for k,v in cfg.items('metadata'):
731                 if k!='target_version':
732                     f.write('%s: %s\n' % (k.replace('_','-').title(), v))
733             f.close()
734         script_dir = os.path.join(egg_info,'scripts')
735         self.delete_blockers(   # delete entry-point scripts to avoid duping
736             [os.path.join(script_dir,args[0]) for args in get_script_args(dist)]
737         )
738         # Build .egg file from tmpdir
739         bdist_egg.make_zipfile(
740             egg_path, egg_tmp, verbose=self.verbose, dry_run=self.dry_run
741         )
742         # install the .egg
743         return self.install_egg(egg_path, tmpdir)
744
745     def exe_to_egg(self, dist_filename, egg_tmp):
746         """Extract a bdist_wininst to the directories an egg would use"""
747         # Check for .pth file and set up prefix translations
748         prefixes = get_exe_prefixes(dist_filename)
749         to_compile = []
750         native_libs = []
751         top_level = {}
752         def process(src,dst):
753             s = src.lower()
754             for old,new in prefixes:
755                 if s.startswith(old):
756                     src = new+src[len(old):]
757                     parts = src.split('/')
758                     dst = os.path.join(egg_tmp, *parts)
759                     dl = dst.lower()
760                     if dl.endswith('.pyd') or dl.endswith('.dll'):
761                         parts[-1] = bdist_egg.strip_module(parts[-1])
762                         top_level[os.path.splitext(parts[0])[0]] = 1
763                         native_libs.append(src)
764                     elif dl.endswith('.py') and old!='SCRIPTS/':
765                         top_level[os.path.splitext(parts[0])[0]] = 1
766                         to_compile.append(dst)
767                     return dst
768             if not src.endswith('.pth'):
769                 log.warn("WARNING: can't process %s", src)
770             return None
771         # extract, tracking .pyd/.dll->native_libs and .py -> to_compile
772         unpack_archive(dist_filename, egg_tmp, process)
773         stubs = []
774         for res in native_libs:
775             if res.lower().endswith('.pyd'):    # create stubs for .pyd's
776                 parts = res.split('/')
777                 resource = parts[-1]
778                 parts[-1] = bdist_egg.strip_module(parts[-1])+'.py'
779                 pyfile = os.path.join(egg_tmp, *parts)
780                 to_compile.append(pyfile); stubs.append(pyfile)
781                 bdist_egg.write_stub(resource, pyfile)
782         self.byte_compile(to_compile)   # compile .py's
783         bdist_egg.write_safety_flag(os.path.join(egg_tmp,'EGG-INFO'),
784             bdist_egg.analyze_egg(egg_tmp, stubs))  # write zip-safety flag
785
786         for name in 'top_level','native_libs':
787             if locals()[name]:
788                 txt = os.path.join(egg_tmp, 'EGG-INFO', name+'.txt')
789                 if not os.path.exists(txt):
790                     open(txt,'w').write('\n'.join(locals()[name])+'\n')
791
792     def check_conflicts(self, dist):
793         """Verify that there are no conflicting "old-style" packages"""
794
795         return dist     # XXX temporarily disable until new strategy is stable
796         from imp import find_module, get_suffixes
797         from glob import glob
798
799         blockers = []
800         names = dict.fromkeys(dist._get_metadata('top_level.txt')) # XXX private attr
801
802         exts = {'.pyc':1, '.pyo':1}     # get_suffixes() might leave one out
803         for ext,mode,typ in get_suffixes():
804             exts[ext] = 1
805
806         for path,files in expand_paths([self.install_dir]+self.all_site_dirs):
807             for filename in files:
808                 base,ext = os.path.splitext(filename)
809                 if base in names:
810                     if not ext:
811                         # no extension, check for package
812                         try:
813                             f, filename, descr = find_module(base, [path])
814                         except ImportError:
815                             continue
816                         else:
817                             if f: f.close()
818                             if filename not in blockers:
819                                 blockers.append(filename)
820                     elif ext in exts and base!='site':  # XXX ugh
821                         blockers.append(os.path.join(path,filename))
822         if blockers:
823             self.found_conflicts(dist, blockers)
824
825         return dist
826
827     def found_conflicts(self, dist, blockers):
828         if self.delete_conflicting:
829             log.warn("Attempting to delete conflicting packages:")
830             return self.delete_blockers(blockers)
831
832         msg = """\
833 -------------------------------------------------------------------------
834 CONFLICT WARNING:
835
836 The following modules or packages have the same names as modules or
837 packages being installed, and will be *before* the installed packages in
838 Python's search path.  You MUST remove all of the relevant files and
839 directories before you will be able to use the package(s) you are
840 installing:
841
842    %s
843
844 """ % '\n   '.join(blockers)
845
846         if self.ignore_conflicts_at_my_risk:
847             msg += """\
848 (Note: you can run EasyInstall on '%s' with the
849 --delete-conflicting option to attempt deletion of the above files
850 and/or directories.)
851 """ % dist.project_name
852         else:
853             msg += """\
854 Note: you can attempt this installation again with EasyInstall, and use
855 either the --delete-conflicting (-D) option or the
856 --ignore-conflicts-at-my-risk option, to either delete the above files
857 and directories, or to ignore the conflicts, respectively.  Note that if
858 you ignore the conflicts, the installed package(s) may not work.
859 """
860         msg += """\
861 -------------------------------------------------------------------------
862 """
863         sys.stderr.write(msg)
864         sys.stderr.flush()
865         if not self.ignore_conflicts_at_my_risk:
866             raise DistutilsError("Installation aborted due to conflicts")
867
868     def installation_report(self, req, dist, what="Installed"):
869         """Helpful installation message for display to package users"""
870         msg = "\n%(what)s %(eggloc)s%(extras)s"
871         if self.multi_version and not self.no_report:
872             msg += """
873
874 Because this distribution was installed --multi-version, before you can
875 import modules from this package in an application, you will need to
876 'import pkg_resources' and then use a 'require()' call similar to one of
877 these examples, in order to select the desired version:
878
879     pkg_resources.require("%(name)s")  # latest installed version
880     pkg_resources.require("%(name)s==%(version)s")  # this exact version
881     pkg_resources.require("%(name)s>=%(version)s")  # this version or higher
882 """
883             if self.install_dir not in map(normalize_path,sys.path):
884                 msg += """
885
886 Note also that the installation directory must be on sys.path at runtime for
887 this to work.  (e.g. by being the application's script directory, by being on
888 PYTHONPATH, or by being added to sys.path by your code.)
889 """
890         eggloc = dist.location
891         name = dist.project_name
892         version = dist.version
893         extras = '' # TODO: self.report_extras(req, dist)
894         return msg % locals()
895
896     def report_editable(self, spec, setup_script):
897         dirname = os.path.dirname(setup_script)
898         python = sys.executable
899         return """\nExtracted editable version of %(spec)s to %(dirname)s
900
901 If it uses setuptools in its setup script, you can activate it in
902 "development" mode by going to that directory and running::
903
904     %(python)s setup.py develop
905
906 See the setuptools documentation for the "develop" command for more info.
907 """ % locals()
908
909     def run_setup(self, setup_script, setup_base, args):
910         sys.modules.setdefault('distutils.command.bdist_egg', bdist_egg)
911         sys.modules.setdefault('distutils.command.egg_info', egg_info)
912
913         args = list(args)
914         if self.verbose>2:
915             v = 'v' * (self.verbose - 1)
916             args.insert(0,'-'+v)
917         elif self.verbose<2:
918             args.insert(0,'-q')
919         if self.dry_run:
920             args.insert(0,'-n')
921         log.info(
922             "Running %s %s", setup_script[len(setup_base)+1:], ' '.join(args)
923         )
924         try:
925             run_setup(setup_script, args)
926         except SystemExit, v:
927             raise DistutilsError("Setup script exited with %s" % (v.args[0],))
928
929     def build_and_install(self, setup_script, setup_base):
930         args = ['bdist_egg', '--dist-dir']
931         dist_dir = tempfile.mkdtemp(
932             prefix='egg-dist-tmp-', dir=os.path.dirname(setup_script)
933         )
934         try:
935             args.append(dist_dir)
936             self.run_setup(setup_script, setup_base, args)
937             all_eggs = Environment([dist_dir])
938             eggs = []
939             for key in all_eggs:
940                 for dist in all_eggs[key]:
941                     eggs.append(self.install_egg(dist.location, setup_base))
942             if not eggs and not self.dry_run:
943                 log.warn("No eggs found in %s (setup script problem?)",
944                     dist_dir)
945             return eggs
946         finally:
947             rmtree(dist_dir)
948             log.set_verbosity(self.verbose) # restore our log verbosity
949
950     def update_pth(self,dist):
951         if self.pth_file is None:
952             return
953
954         for d in self.pth_file[dist.key]:    # drop old entries
955             if self.multi_version or d.location != dist.location:
956                 log.info("Removing %s from easy-install.pth file", d)
957                 self.pth_file.remove(d)
958                 if d.location in self.shadow_path:
959                     self.shadow_path.remove(d.location)
960
961         if not self.multi_version:
962             if dist.location in self.pth_file.paths:
963                 log.info(
964                     "%s is already the active version in easy-install.pth",
965                     dist
966                 )
967             else:
968                 log.info("Adding %s to easy-install.pth file", dist)
969                 self.pth_file.add(dist) # add new entry
970                 if dist.location not in self.shadow_path:
971                     self.shadow_path.append(dist.location)
972
973         if not self.dry_run:
974
975             self.pth_file.save()
976
977             if dist.key=='setuptools':
978                 # Ensure that setuptools itself never becomes unavailable!
979                 # XXX should this check for latest version?
980                 filename = os.path.join(self.install_dir,'setuptools.pth')
981                 if os.path.islink(filename): os.unlink(filename)
982                 f = open(filename, 'wt')
983                 f.write(self.pth_file.make_relative(dist.location)+'\n')
984                 f.close()
985
986     def unpack_progress(self, src, dst):
987         # Progress filter for unpacking
988         log.debug("Unpacking %s to %s", src, dst)
989         return dst     # only unpack-and-compile skips files for dry run
990
991     def unpack_and_compile(self, egg_path, destination):
992         to_compile = []; to_chmod = []
993
994         def pf(src,dst):
995             if dst.endswith('.py') and not src.startswith('EGG-INFO/'):
996                 to_compile.append(dst)
997             elif dst.endswith('.dll') or dst.endswith('.so'):
998                 to_chmod.append(dst)
999             self.unpack_progress(src,dst)
1000             return not self.dry_run and dst or None
1001
1002         unpack_archive(egg_path, destination, pf)
1003         self.byte_compile(to_compile)
1004         if not self.dry_run:
1005             for f in to_chmod:
1006                 mode = ((os.stat(f)[stat.ST_MODE]) | 0555) & 07755
1007                 chmod(f, mode)
1008
1009     def byte_compile(self, to_compile):
1010         from distutils.util import byte_compile
1011         try:
1012             # try to make the byte compile messages quieter
1013             log.set_verbosity(self.verbose - 1)
1014
1015             byte_compile(to_compile, optimize=0, force=1, dry_run=self.dry_run)
1016             if self.optimize:
1017                 byte_compile(
1018                     to_compile, optimize=self.optimize, force=1,
1019                     dry_run=self.dry_run
1020                 )
1021         finally:
1022             log.set_verbosity(self.verbose)     # restore original verbosity
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032     def no_default_version_msg(self):
1033         return """bad install directory or PYTHONPATH
1034
1035 You are attempting to install a package to a directory that is not
1036 on PYTHONPATH and which Python does not read ".pth" files from.  The
1037 installation directory you specified (via --install-dir, --prefix, or
1038 the distutils default setting) was:
1039
1040     %s
1041
1042 and your PYTHONPATH environment variable currently contains:
1043
1044     %r
1045
1046 Here are some of your options for correcting the problem:
1047
1048 * You can choose a different installation directory, i.e., one that is
1049   on PYTHONPATH or supports .pth files
1050
1051 * You can add the installation directory to the PYTHONPATH environment
1052   variable.  (It must then also be on PYTHONPATH whenever you run
1053   Python and want to use the package(s) you are installing.)
1054
1055 * You can set up the installation directory to support ".pth" files by
1056   using one of the approaches described here:
1057
1058   http://peak.telecommunity.com/EasyInstall.html#custom-installation-locations
1059
1060 Proceeding to install.  Please remember that unless you make one of
1061 these changes you will not be able to run the installed code.
1062 """ % (
1063         self.install_dir, os.environ.get('PYTHONPATH','')
1064     )
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075     def install_site_py(self):
1076         """Make sure there's a site.py in the target dir, if needed"""
1077
1078         if self.sitepy_installed:
1079             return  # already did it, or don't need to
1080
1081         sitepy = os.path.join(self.install_dir, "site.py")
1082         source = resource_string("setuptools", "site-patch.py")
1083         current = ""
1084
1085         if os.path.exists(sitepy):
1086             log.debug("Checking existing site.py in %s", self.install_dir)
1087             current = open(sitepy,'rb').read()
1088             if not current.startswith('def __boot():'):
1089                 raise DistutilsError(
1090                     "%s is not a setuptools-generated site.py; please"
1091                     " remove it." % sitepy
1092                 )
1093
1094         if current != source:
1095             log.info("Creating %s", sitepy)
1096             if not self.dry_run:
1097                 ensure_directory(sitepy)
1098                 f = open(sitepy,'wb')
1099                 f.write(source)
1100                 f.close()
1101             self.byte_compile([sitepy])
1102
1103         self.sitepy_installed = True
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116     INSTALL_SCHEMES = dict(
1117         posix = dict(
1118             install_dir = '$base/lib/python$py_version_short/site-packages',
1119             script_dir  = '$base/bin',
1120         ),
1121     )
1122
1123     DEFAULT_SCHEME = dict(
1124         install_dir = '$base/Lib/site-packages',
1125         script_dir  = '$base/Scripts',
1126     )
1127
1128     def _expand(self, *attrs):
1129         config_vars = self.get_finalized_command('install').config_vars
1130
1131         if self.prefix:
1132             # Set default install_dir/scripts from --prefix
1133             config_vars = config_vars.copy()
1134             config_vars['base'] = self.prefix
1135             scheme = self.INSTALL_SCHEMES.get(os.name,self.DEFAULT_SCHEME)
1136             for attr,val in scheme.items():
1137                 if getattr(self,attr,None) is None:
1138                     setattr(self,attr,val)
1139
1140         from distutils.util import subst_vars
1141         for attr in attrs:
1142             val = getattr(self, attr)
1143             if val is not None:
1144                 val = subst_vars(val, config_vars)
1145                 if os.name == 'posix':
1146                     val = os.path.expanduser(val)
1147                 setattr(self, attr, val)
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157 def get_site_dirs():
1158     # return a list of 'site' dirs
1159     sitedirs = filter(None,os.environ.get('PYTHONPATH','').split(os.pathsep))
1160     prefixes = [sys.prefix]
1161     if sys.exec_prefix != sys.prefix:
1162         prefixes.append(sys.exec_prefix)
1163     for prefix in prefixes:
1164         if prefix:
1165             if sys.platform in ('os2emx', 'riscos'):
1166                 sitedirs.append(os.path.join(prefix, "Lib", "site-packages"))
1167             elif os.sep == '/':
1168                 sitedirs.extend([os.path.join(prefix,
1169                                          "lib",
1170                                          "python" + sys.version[:3],
1171                                          "site-packages"),
1172                             os.path.join(prefix, "lib", "site-python")])
1173             else:
1174                 sitedirs.extend(
1175                     [prefix, os.path.join(prefix, "lib", "site-packages")]
1176                 )
1177             if sys.platform == 'darwin':
1178                 # for framework builds *only* we add the standard Apple
1179                 # locations. Currently only per-user, but /Library and
1180                 # /Network/Library could be added too
1181                 if 'Python.framework' in prefix:
1182                     home = os.environ.get('HOME')
1183                     if home:
1184                         sitedirs.append(
1185                             os.path.join(home,
1186                                          'Library',
1187                                          'Python',
1188                                          sys.version[:3],
1189                                          'site-packages'))
1190     for plat_specific in (0,1):
1191         site_lib = get_python_lib(plat_specific)
1192         if site_lib not in sitedirs: sitedirs.append(site_lib)
1193
1194     sitedirs = map(normalize_path, sitedirs)
1195     return sitedirs
1196
1197
1198 def expand_paths(inputs):
1199     """Yield sys.path directories that might contain "old-style" packages"""
1200
1201     seen = {}
1202
1203     for dirname in inputs:
1204         dirname = normalize_path(dirname)
1205         if dirname in seen:
1206             continue
1207
1208         seen[dirname] = 1
1209         if not os.path.isdir(dirname):
1210             continue
1211
1212         files = os.listdir(dirname)
1213         yield dirname, files
1214
1215         for name in files:
1216             if not name.endswith('.pth'):
1217                 # We only care about the .pth files
1218                 continue
1219             if name in ('easy-install.pth','setuptools.pth'):
1220                 # Ignore .pth files that we control
1221                 continue
1222
1223             # Read the .pth file
1224             f = open(os.path.join(dirname,name))
1225             lines = list(yield_lines(f))
1226             f.close()
1227
1228             # Yield existing non-dupe, non-import directory lines from it
1229             for line in lines:
1230                 if not line.startswith("import"):
1231                     line = normalize_path(line.rstrip())
1232                     if line not in seen:
1233                         seen[line] = 1
1234                         if not os.path.isdir(line):
1235                             continue
1236                         yield line, os.listdir(line)
1237
1238
1239 def extract_wininst_cfg(dist_filename):
1240     """Extract configuration data from a bdist_wininst .exe
1241
1242     Returns a ConfigParser.RawConfigParser, or None
1243     """
1244     f = open(dist_filename,'rb')
1245     try:
1246         endrec = zipfile._EndRecData(f)
1247         if endrec is None:
1248             return None
1249
1250         prepended = (endrec[9] - endrec[5]) - endrec[6]
1251         if prepended < 12:  # no wininst data here
1252             return None
1253         f.seek(prepended-12)
1254
1255         import struct, StringIO, ConfigParser
1256         tag, cfglen, bmlen = struct.unpack("<iii",f.read(12))
1257         if tag not in (0x1234567A, 0x1234567B):
1258             return None     # not a valid tag
1259
1260         f.seek(prepended-(12+cfglen))
1261         cfg = ConfigParser.RawConfigParser({'version':'','target_version':''})
1262         try:
1263             cfg.readfp(StringIO.StringIO(f.read(cfglen).split(chr(0),1)[0]))
1264         except ConfigParser.Error:
1265             return None
1266         if not cfg.has_section('metadata') or not cfg.has_section('Setup'):
1267             return None
1268         return cfg
1269
1270     finally:
1271         f.close()
1272
1273
1274
1275
1276
1277
1278
1279
1280 def get_exe_prefixes(exe_filename):
1281     """Get exe->egg path translations for a given .exe file"""
1282
1283     prefixes = [
1284         ('PURELIB/', ''), ('PLATLIB/pywin32_system32', ''),
1285         ('PLATLIB/', ''),
1286         ('SCRIPTS/', 'EGG-INFO/scripts/')
1287     ]
1288     z = zipfile.ZipFile(exe_filename)
1289     try:
1290         for info in z.infolist():
1291             name = info.filename
1292             parts = name.split('/')
1293             if len(parts)==3 and parts[2]=='PKG-INFO':
1294                 if parts[1].endswith('.egg-info'):
1295                     prefixes.insert(0,('/'.join(parts[:2]), 'EGG-INFO/'))
1296                     break
1297             if len(parts)!=2 or not name.endswith('.pth'):
1298                 continue
1299             if name.endswith('-nspkg.pth'):
1300                 continue
1301             if parts[0].upper() in ('PURELIB','PLATLIB'):
1302                 for pth in yield_lines(z.read(name)):
1303                     pth = pth.strip().replace('\\','/')
1304                     if not pth.startswith('import'):
1305                         prefixes.append((('%s/%s/' % (parts[0],pth)), ''))
1306     finally:
1307         z.close()
1308     prefixes = [(x.lower(),y) for x, y in prefixes]
1309     prefixes.sort(); prefixes.reverse()
1310     return prefixes
1311
1312
1313 def parse_requirement_arg(spec):
1314     try:
1315         return Requirement.parse(spec)
1316     except ValueError:
1317         raise DistutilsError(
1318             "Not a URL, existing file, or requirement spec: %r" % (spec,)
1319         )
1320
1321 class PthDistributions(Environment):
1322     """A .pth file with Distribution paths in it"""
1323
1324     dirty = False
1325
1326     def __init__(self, filename, sitedirs=()):
1327         self.filename = filename; self.sitedirs=map(normalize_path, sitedirs)
1328         self.basedir = normalize_path(os.path.dirname(self.filename))
1329         self._load(); Environment.__init__(self, [], None, None)
1330         for path in yield_lines(self.paths):
1331             map(self.add, find_distributions(path, True))
1332
1333     def _load(self):
1334         self.paths = []
1335         saw_import = False
1336         seen = dict.fromkeys(self.sitedirs)
1337         if os.path.isfile(self.filename):
1338             for line in open(self.filename,'rt'):
1339                 if line.startswith('import'):
1340                     saw_import = True
1341                     continue
1342                 path = line.rstrip()
1343                 self.paths.append(path)
1344                 if not path.strip() or path.strip().startswith('#'):
1345                     continue
1346                 # skip non-existent paths, in case somebody deleted a package
1347                 # manually, and duplicate paths as well
1348                 path = self.paths[-1] = normalize_path(
1349                     os.path.join(self.basedir,path)
1350                 )
1351                 if not os.path.exists(path) or path in seen:
1352                     self.paths.pop()    # skip it
1353                     self.dirty = True   # we cleaned up, so we're dirty now :)
1354                     continue
1355                 seen[path] = 1
1356
1357         if self.paths and not saw_import:
1358             self.dirty = True   # ensure anything we touch has import wrappers
1359         while self.paths and not self.paths[-1].strip():
1360             self.paths.pop()
1361
1362     def save(self):
1363         """Write changed .pth file back to disk"""
1364         if not self.dirty:
1365             return
1366
1367         data = '\n'.join(map(self.make_relative,self.paths))
1368         if data:
1369             log.debug("Saving %s", self.filename)
1370             data = (
1371                 "import sys; sys.__plen = len(sys.path)\n"
1372                 "%s\n"
1373                 "import sys; new=sys.path[sys.__plen:];"
1374                 " del sys.path[sys.__plen:];"
1375                 " p=getattr(sys,'__egginsert',len(os.environ.get('PYTHONPATH','').split(os.pathsep))); sys.path[p:p]=new;"
1376                 " sys.__egginsert = p+len(new)\n"
1377             ) % data
1378
1379             if os.path.islink(self.filename):
1380                 os.unlink(self.filename)
1381             f = open(self.filename,'wb')
1382             f.write(data); f.close()
1383
1384         elif os.path.exists(self.filename):
1385             log.debug("Deleting empty %s", self.filename)
1386             os.unlink(self.filename)
1387
1388         self.dirty = False
1389
1390     def add(self,dist):
1391         """Add `dist` to the distribution map"""
1392         if dist.location not in self.paths and dist.location not in self.sitedirs:
1393             self.paths.append(dist.location); self.dirty = True
1394         Environment.add(self,dist)
1395
1396     def remove(self,dist):
1397         """Remove `dist` from the distribution map"""
1398         while dist.location in self.paths:
1399             self.paths.remove(dist.location); self.dirty = True
1400         Environment.remove(self,dist)
1401
1402
1403     def make_relative(self,path):
1404         npath, last = os.path.split(normalize_path(path))
1405         baselen = len(self.basedir)
1406         parts = [last]
1407         sep = os.altsep=='/' and '/' or os.sep
1408         while len(npath)>=baselen:
1409             if npath==self.basedir:
1410                 parts.append(os.curdir)
1411                 parts.reverse()
1412                 return sep.join(parts)
1413             npath, last = os.path.split(npath)
1414             parts.append(last)
1415         else:
1416             return path
1417
1418 def get_script_header(script_text, executable=sys_executable, wininst=False):
1419     """Create a #! line, getting options (if any) from script_text"""
1420     from distutils.command.build_scripts import first_line_re
1421     first = (script_text+'\n').splitlines()[0]
1422     match = first_line_re.match(first)
1423     options = ''
1424     if match:
1425         options = match.group(1) or ''
1426         if options: options = ' '+options
1427     if wininst:
1428         executable = "python.exe"
1429     else:
1430         executable = nt_quote_arg(executable)
1431     hdr = "#!%(executable)s%(options)s\n" % locals()
1432     if unicode(hdr,'ascii','ignore').encode('ascii') != hdr:
1433         # Non-ascii path to sys.executable, use -x to prevent warnings
1434         if options:
1435             if options.strip().startswith('-'):
1436                 options = ' -x'+options.strip()[1:]
1437             # else: punt, we can't do it, let the warning happen anyway
1438         else:
1439             options = ' -x'
1440     executable = fix_jython_executable(executable, options)
1441     hdr = "#!%(executable)s%(options)s\n" % locals()
1442     return hdr
1443
1444 def auto_chmod(func, arg, exc):
1445     if func is os.remove and os.name=='nt':
1446         chmod(arg, stat.S_IWRITE)
1447         return func(arg)
1448     exc = sys.exc_info()
1449     raise exc[0], (exc[1][0], exc[1][1] + (" %s %s" % (func,arg)))
1450
1451 def uncache_zipdir(path):
1452     """Ensure that the importer caches dont have stale info for `path`"""
1453     from zipimport import _zip_directory_cache as zdc
1454     _uncache(path, zdc)
1455     _uncache(path, sys.path_importer_cache)
1456
1457 def _uncache(path, cache):
1458     if path in cache:
1459         del cache[path]
1460     else:
1461         path = normalize_path(path)
1462         for p in cache:
1463             if normalize_path(p)==path:
1464                 del cache[p]
1465                 return
1466
1467 def is_python(text, filename='<string>'):
1468     "Is this string a valid Python script?"
1469     try:
1470         compile(text, filename, 'exec')
1471     except (SyntaxError, TypeError):
1472         return False
1473     else:
1474         return True
1475
1476 def is_sh(executable):
1477     """Determine if the specified executable is a .sh (contains a #! line)"""
1478     try:
1479         fp = open(executable)
1480         magic = fp.read(2)
1481         fp.close()
1482     except (OSError,IOError): return executable
1483     return magic == '#!'
1484
1485 def nt_quote_arg(arg):
1486     """Quote a command line argument according to Windows parsing rules"""
1487
1488     result = []
1489     needquote = False
1490     nb = 0
1491
1492     needquote = (" " in arg) or ("\t" in arg)
1493     if needquote:
1494         result.append('"')
1495
1496     for c in arg:
1497         if c == '\\':
1498             nb += 1
1499         elif c == '"':
1500             # double preceding backslashes, then add a \"
1501             result.append('\\' * (nb*2) + '\\"')
1502             nb = 0
1503         else:
1504             if nb:
1505                 result.append('\\' * nb)
1506                 nb = 0
1507             result.append(c)
1508
1509     if nb:
1510         result.append('\\' * nb)
1511
1512     if needquote:
1513         result.append('\\' * nb)    # double the trailing backslashes
1514         result.append('"')
1515
1516     return ''.join(result)
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526 def is_python_script(script_text, filename):
1527     """Is this text, as a whole, a Python script? (as opposed to shell/bat/etc.
1528     """
1529     if filename.endswith('.py') or filename.endswith('.pyw'):
1530         return True     # extension says it's Python
1531     if is_python(script_text, filename):
1532         return True     # it's syntactically valid Python
1533     if script_text.startswith('#!'):
1534         # It begins with a '#!' line, so check if 'python' is in it somewhere
1535         return 'python' in script_text.splitlines()[0].lower()
1536
1537     return False    # Not any Python I can recognize
1538
1539 try:
1540     from os import chmod as _chmod
1541 except ImportError:
1542     # Jython compatibility
1543     def _chmod(*args): pass
1544
1545 def chmod(path, mode):
1546     log.debug("changing mode of %s to %o", path, mode)
1547     try:
1548         _chmod(path, mode)
1549     except os.error, e:
1550         log.debug("chmod failed: %s", e)
1551
1552 def fix_jython_executable(executable, options):
1553     if sys.platform.startswith('java') and is_sh(executable):
1554         # Workaround Jython's sys.executable being a .sh (an invalid
1555         # shebang line interpreter)
1556         if options:
1557             # Can't apply the workaround, leave it broken
1558             log.warn("WARNING: Unable to adapt shebang line for Jython,"
1559                              " the following script is NOT executable\n"
1560                      "         see http://bugs.jython.org/issue1112 for"
1561                              " more information.")
1562         else:
1563             return '/usr/bin/env %s' % executable
1564     return executable
1565
1566
1567 def get_script_args(dist, executable=sys_executable, wininst=False):
1568     """Yield write_script() argument tuples for a distribution's entrypoints"""
1569     spec = str(dist.as_requirement())
1570     header = get_script_header("", executable, wininst)
1571     for group in 'console_scripts', 'gui_scripts':
1572         for name,ep in dist.get_entry_map(group).items():
1573             script_text = (
1574                 "# EASY-INSTALL-ENTRY-SCRIPT: %(spec)r,%(group)r,%(name)r\n"
1575                 "__requires__ = %(spec)r\n"
1576                 "import sys\n"
1577                 "from pkg_resources import load_entry_point\n"
1578                 "\n"
1579                 "sys.exit(\n"
1580                 "   load_entry_point(%(spec)r, %(group)r, %(name)r)()\n"
1581                 ")\n"
1582             ) % locals()
1583             if sys.platform=='win32' or wininst:
1584                 # On Windows/wininst, add a .py extension and an .exe launcher
1585                 if group=='gui_scripts':
1586                     ext, launcher = '-script.pyw', 'gui.exe'
1587                     old = ['.pyw']
1588                     new_header = re.sub('(?i)python.exe','pythonw.exe',header)
1589                 else:
1590                     ext, launcher = '-script.py', 'cli.exe'
1591                     old = ['.py','.pyc','.pyo']
1592                     new_header = re.sub('(?i)pythonw.exe','python.exe',header)
1593
1594                 if os.path.exists(new_header[2:-1]) or sys.platform!='win32':
1595                     hdr = new_header
1596                 else:
1597                     hdr = header
1598                 yield (name+ext, hdr+script_text, 't', [name+x for x in old])
1599                 yield (
1600                     name+'.exe', resource_string('setuptools', launcher),
1601                     'b') # write in binary mode
1602                 yield (name+'.exe.manifest', _launcher_manifest % (name,), 't')
1603             else:
1604                 # On other platforms, we assume the right thing to do is to
1605                 # just write the stub with no extension.
1606                 yield (name, header+script_text)
1607
1608 _launcher_manifest = """
1609 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
1610 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
1611  <assemblyIdentity version="1.0.0.0"
1612  processorArchitecture="X86"
1613  name="%s.exe"
1614  type="win32"/>
1615
1616  <!-- Identify the application security requirements. -->
1617  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
1618  <security>
1619  <requestedPrivileges>
1620  <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
1621  </requestedPrivileges>
1622  </security>
1623  </trustInfo>
1624 </assembly>"""
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649 def rmtree(path, ignore_errors=False, onerror=auto_chmod):
1650     """Recursively delete a directory tree.
1651
1652     This code is taken from the Python 2.4 version of 'shutil', because
1653     the 2.3 version doesn't really work right.
1654     """
1655     if ignore_errors:
1656         def onerror(*args):
1657             pass
1658     elif onerror is None:
1659         def onerror(*args):
1660             raise
1661     names = []
1662     try:
1663         names = os.listdir(path)
1664     except os.error, err:
1665         onerror(os.listdir, path, sys.exc_info())
1666     for name in names:
1667         fullname = os.path.join(path, name)
1668         try:
1669             mode = os.lstat(fullname).st_mode
1670         except os.error:
1671             mode = 0
1672         if stat.S_ISDIR(mode):
1673             rmtree(fullname, ignore_errors, onerror)
1674         else:
1675             try:
1676                 os.remove(fullname)
1677             except os.error, err:
1678                 onerror(os.remove, fullname, sys.exc_info())
1679     try:
1680         os.rmdir(path)
1681     except os.error:
1682         onerror(os.rmdir, path, sys.exc_info())
1683
1684 def bootstrap():
1685     # This function is called when setuptools*.egg is run using /bin/sh
1686     import setuptools; argv0 = os.path.dirname(setuptools.__path__[0])
1687     sys.argv[0] = argv0; sys.argv.append(argv0); main()
1688
1689
1690 def main(argv=None, **kw):
1691     from setuptools import setup
1692     from setuptools.dist import Distribution
1693     import distutils.core
1694
1695     USAGE = """\
1696 usage: %(script)s [options] requirement_or_url ...
1697    or: %(script)s --help
1698 """
1699
1700     def gen_usage (script_name):
1701         script = os.path.basename(script_name)
1702         return USAGE % vars()
1703
1704     def with_ei_usage(f):
1705         old_gen_usage = distutils.core.gen_usage
1706         try:
1707             distutils.core.gen_usage = gen_usage
1708             return f()
1709         finally:
1710             distutils.core.gen_usage = old_gen_usage
1711
1712     class DistributionWithoutHelpCommands(Distribution):
1713         common_usage = ""
1714         def _show_help(self,*args,**kw):
1715             with_ei_usage(lambda: Distribution._show_help(self,*args,**kw))
1716
1717     if argv is None:
1718         argv = sys.argv[1:]
1719
1720     with_ei_usage(lambda:
1721         setup(
1722             script_args = ['-q','easy_install', '-v']+argv,
1723             script_name = sys.argv[0] or 'easy_install',
1724             distclass=DistributionWithoutHelpCommands, **kw
1725         )
1726     )
1727
1728
1729
1730