codekingpro/portable-devtools
115k
1from distutils.util import convert_path2from distutils import log3from distutils.errors import DistutilsOptionError4import os5import glob6 7from setuptools.command.easy_install import easy_install8from setuptools import _normalization9from setuptools import _path10from setuptools import namespaces11import setuptools12 13 14class develop(namespaces.DevelopInstaller, easy_install):15 """Set up package for development"""16 17 description = "install package in 'development mode'"18 19 user_options = easy_install.user_options + [20 ("uninstall", "u", "Uninstall this source package"),21 ("egg-path=", None, "Set the path to be used in the .egg-link file"),22 ]23 24 boolean_options = easy_install.boolean_options + ['uninstall']25 26 command_consumes_arguments = False # override base27 28 def run(self):29 if self.uninstall:30 self.multi_version = True31 self.uninstall_link()32 self.uninstall_namespaces()33 else:34 self.install_for_development()35 self.warn_deprecated_options()36 37 def initialize_options(self):38 self.uninstall = None39 self.egg_path = None40 easy_install.initialize_options(self)41 self.setup_path = None42 self.always_copy_from = '.' # always copy eggs installed in curdir43 44 def finalize_options(self):45 import pkg_resources46 47 ei = self.get_finalized_command("egg_info")48 self.args = [ei.egg_name]49 50 easy_install.finalize_options(self)51 self.expand_basedirs()52 self.expand_dirs()53 # pick up setup-dir .egg files only: no .egg-info54 self.package_index.scan(glob.glob('*.egg'))55 56 egg_link_fn = (57 _normalization.filename_component_broken(ei.egg_name) + '.egg-link'58 )59 self.egg_link = os.path.join(self.install_dir, egg_link_fn)60 self.egg_base = ei.egg_base61 if self.egg_path is None:62 self.egg_path = os.path.abspath(ei.egg_base)63 64 target = _path.normpath(self.egg_base)65 egg_path = _path.normpath(os.path.join(self.install_dir, self.egg_path))66 if egg_path != target:67 raise DistutilsOptionError(68 "--egg-path must be a relative path from the install"69 " directory to " + target70 )71 72 # Make a distribution for the package's source73 self.dist = pkg_resources.Distribution(74 target,75 pkg_resources.PathMetadata(target, os.path.abspath(ei.egg_info)),76 project_name=ei.egg_name,77 )78 79 self.setup_path = self._resolve_setup_path(80 self.egg_base,81 self.install_dir,82 self.egg_path,83 )84 85 @staticmethod86 def _resolve_setup_path(egg_base, install_dir, egg_path):87 """88 Generate a path from egg_base back to '.' where the89 setup script resides and ensure that path points to the90 setup path from $install_dir/$egg_path.91 """92 path_to_setup = egg_base.replace(os.sep, '/').rstrip('/')93 if path_to_setup != os.curdir:94 path_to_setup = '../' * (path_to_setup.count('/') + 1)95 resolved = _path.normpath(os.path.join(install_dir, egg_path, path_to_setup))96 curdir = _path.normpath(os.curdir)97 if resolved != curdir:98 raise DistutilsOptionError(99 "Can't get a consistent path to setup script from"100 " installation directory",101 resolved,102 curdir,103 )104 return path_to_setup105 106 def install_for_development(self):107 self.run_command('egg_info')108 109 # Build extensions in-place110 self.reinitialize_command('build_ext', inplace=1)111 self.run_command('build_ext')112 113 if setuptools.bootstrap_install_from:114 self.easy_install(setuptools.bootstrap_install_from)115 setuptools.bootstrap_install_from = None116 117 self.install_namespaces()118 119 # create an .egg-link in the installation dir, pointing to our egg120 log.info("Creating %s (link to %s)", self.egg_link, self.egg_base)121 if not self.dry_run:122 with open(self.egg_link, "w") as f:123 f.write(self.egg_path + "\n" + self.setup_path)124 # postprocess the installed distro, fixing up .pth, installing scripts,125 # and handling requirements126 self.process_distribution(None, self.dist, not self.no_deps)127 128 def uninstall_link(self):129 if os.path.exists(self.egg_link):130 log.info("Removing %s (link to %s)", self.egg_link, self.egg_base)131 egg_link_file = open(self.egg_link)132 contents = [line.rstrip() for line in egg_link_file]133 egg_link_file.close()134 if contents not in ([self.egg_path], [self.egg_path, self.setup_path]):135 log.warn("Link points to %s: uninstall aborted", contents)136 return137 if not self.dry_run:138 os.unlink(self.egg_link)139 if not self.dry_run:140 self.update_pth(self.dist) # remove any .pth link to us141 if self.distribution.scripts:142 # XXX should also check for entry point scripts!143 log.warn("Note: you must uninstall or replace scripts manually!")144 145 def install_egg_scripts(self, dist):146 if dist is not self.dist:147 # Installing a dependency, so fall back to normal behavior148 return easy_install.install_egg_scripts(self, dist)149 150 # create wrapper scripts in the script dir, pointing to dist.scripts151 152 # new-style...153 self.install_wrapper_scripts(dist)154 155 # ...and old-style156 for script_name in self.distribution.scripts or []:157 script_path = os.path.abspath(convert_path(script_name))158 script_name = os.path.basename(script_path)159 with open(script_path) as strm:160 script_text = strm.read()161 self.install_script(dist, script_name, script_text, script_path)162 163 return None164 165 def install_wrapper_scripts(self, dist):166 dist = VersionlessRequirement(dist)167 return easy_install.install_wrapper_scripts(self, dist)168 169 170class VersionlessRequirement:171 """172 Adapt a pkg_resources.Distribution to simply return the project173 name as the 'requirement' so that scripts will work across174 multiple versions.175 176 >>> from pkg_resources import Distribution177 >>> dist = Distribution(project_name='foo', version='1.0')178 >>> str(dist.as_requirement())179 'foo==1.0'180 >>> adapted_dist = VersionlessRequirement(dist)181 >>> str(adapted_dist.as_requirement())182 'foo'183 """184 185 def __init__(self, dist):186 self.__dist = dist187 188 def __getattr__(self, name):189 return getattr(self.__dist, name)190 191 def as_requirement(self):192 return self.project_name193 