codekingpro/portable-devtools
114k
1from distutils.errors import DistutilsArgError2import inspect3import glob4import platform5import distutils.command.install as orig6from typing import cast7 8import setuptools9from ..warnings import SetuptoolsDeprecationWarning, SetuptoolsWarning10from .bdist_egg import bdist_egg as bdist_egg_cls11 12# Prior to numpy 1.9, NumPy relies on the '_install' name, so provide it for13# now. See https://github.com/pypa/setuptools/issues/199/14_install = orig.install15 16 17class install(orig.install):18 """Use easy_install to install the package, w/dependencies"""19 20 user_options = orig.install.user_options + [21 ('old-and-unmanageable', None, "Try not to use this!"),22 (23 'single-version-externally-managed',24 None,25 "used by system package builders to create 'flat' eggs",26 ),27 ]28 boolean_options = orig.install.boolean_options + [29 'old-and-unmanageable',30 'single-version-externally-managed',31 ]32 new_commands = [33 ('install_egg_info', lambda self: True),34 ('install_scripts', lambda self: True),35 ]36 _nc = dict(new_commands)37 38 def initialize_options(self):39 SetuptoolsDeprecationWarning.emit(40 "setup.py install is deprecated.",41 """42 Please avoid running ``setup.py`` directly.43 Instead, use pypa/build, pypa/installer or other44 standards-based tools.45 """,46 see_url="https://blog.ganssle.io/articles/2021/10/setup-py-deprecated.html",47 # TODO: Document how to bootstrap setuptools without install48 # (e.g. by unziping the wheel file)49 # and then add a due_date to this warning.50 )51 52 orig.install.initialize_options(self)53 self.old_and_unmanageable = None54 self.single_version_externally_managed = None55 56 def finalize_options(self):57 orig.install.finalize_options(self)58 if self.root:59 self.single_version_externally_managed = True60 elif self.single_version_externally_managed:61 if not self.root and not self.record:62 raise DistutilsArgError(63 "You must specify --record or --root when building system"64 " packages"65 )66 67 def handle_extra_path(self):68 if self.root or self.single_version_externally_managed:69 # explicit backward-compatibility mode, allow extra_path to work70 return orig.install.handle_extra_path(self)71 72 # Ignore extra_path when installing an egg (or being run by another73 # command without --root or --single-version-externally-managed74 self.path_file = None75 self.extra_dirs = ''76 return None77 78 def run(self):79 # Explicit request for old-style install? Just do it80 if self.old_and_unmanageable or self.single_version_externally_managed:81 return orig.install.run(self)82 83 if not self._called_from_setup(inspect.currentframe()):84 # Run in backward-compatibility mode to support bdist_* commands.85 orig.install.run(self)86 else:87 self.do_egg_install()88 89 return None90 91 @staticmethod92 def _called_from_setup(run_frame):93 """94 Attempt to detect whether run() was called from setup() or by another95 command. If called by setup(), the parent caller will be the96 'run_command' method in 'distutils.dist', and *its* caller will be97 the 'run_commands' method. If called any other way, the98 immediate caller *might* be 'run_command', but it won't have been99 called by 'run_commands'. Return True in that case or if a call stack100 is unavailable. Return False otherwise.101 """102 if run_frame is None:103 msg = "Call stack not available. bdist_* commands may fail."104 SetuptoolsWarning.emit(msg)105 if platform.python_implementation() == 'IronPython':106 msg = "For best results, pass -X:Frames to enable call stack."107 SetuptoolsWarning.emit(msg)108 return True109 110 frames = inspect.getouterframes(run_frame)111 for frame in frames[2:4]:112 (caller,) = frame[:1]113 info = inspect.getframeinfo(caller)114 caller_module = caller.f_globals.get('__name__', '')115 116 if caller_module == "setuptools.dist" and info.function == "run_command":117 # Starting from v61.0.0 setuptools overwrites dist.run_command118 continue119 120 return caller_module == 'distutils.dist' and info.function == 'run_commands'121 122 return False123 124 def do_egg_install(self):125 easy_install = self.distribution.get_command_class('easy_install')126 127 cmd = easy_install(128 self.distribution,129 args="x",130 root=self.root,131 record=self.record,132 )133 cmd.ensure_finalized() # finalize before bdist_egg munges install cmd134 cmd.always_copy_from = '.' # make sure local-dir eggs get installed135 136 # pick up setup-dir .egg files only: no .egg-info137 cmd.package_index.scan(glob.glob('*.egg'))138 139 self.run_command('bdist_egg')140 bdist_egg = cast(bdist_egg_cls, self.distribution.get_command_obj('bdist_egg'))141 args = [bdist_egg.egg_output]142 143 if setuptools.bootstrap_install_from:144 # Bootstrap self-installation of setuptools145 args.insert(0, setuptools.bootstrap_install_from)146 147 cmd.args = args148 cmd.run(show_deprecation=False)149 setuptools.bootstrap_install_from = None150 151 152# XXX Python 3.1 doesn't see _nc if this is inside the class153install.sub_commands = [154 cmd for cmd in orig.install.sub_commands if cmd[0] not in install._nc155] + install.new_commands156 