Files
openide/python/helpers/packaging_tool.py
Mikhail Golubev ca3e96dbee PY-38479 Rely on "venv" defaults regarding symlinks when creating virtualenvs
Because we used to call venv.create() function directly in packaging_tool.py when
creating environments we ended up using function's own default unconditionally
creating copies of executables on all platforms, including those where venv itself
creates symlinks (Linux, MacOS). Turned out, it leads to issues with locating
dynamic libraries when one attempts to create a virtualenv with MacOS 10.15 system
Python 3 interpreter. Now we call venv module directly as we already do with "pip"
relying on its default behavior and patching the only command-line flag that we
actually need -- "--without-pip".

GitOrigin-RevId: d65aaa325817933de7121225038a5cf84fa2c77a
2019-12-05 12:38:14 +00:00

174 lines
4.4 KiB
Python

import sys
import traceback
import getopt
import os
ERROR_WRONG_USAGE = 1
ERROR_NO_PIP = 2
ERROR_NO_SETUPTOOLS = 3
ERROR_EXCEPTION = 4
os.putenv("PIP_REQUIRE_VIRTUALENV", "false")
def exit(retcode):
major, minor, micro, release, serial = sys.version_info
version = major * 10 + minor
if version < 25:
import os
os._exit(retcode)
else:
sys.exit(retcode)
def usage():
sys.stderr.write('Usage: packaging_tool.py <list|install|uninstall|pyvenv>\n')
sys.stderr.flush()
exit(ERROR_WRONG_USAGE)
def error(message, retcode):
sys.stderr.write('Error: %s\n' % message)
sys.stderr.flush()
exit(retcode)
def error_no_pip():
type, value, tb = sys.exc_info()
if tb is not None and tb.tb_next is None:
error("Python packaging tool 'pip' not found", ERROR_NO_PIP)
else:
error(traceback.format_exc(), ERROR_EXCEPTION)
def do_list():
try:
import pkg_resources
except ImportError:
error("Python packaging tool 'setuptools' not found", ERROR_NO_SETUPTOOLS)
for pkg in pkg_resources.working_set:
try:
requirements = pkg.requires()
except Exception:
requirements = []
requires = ':'.join([str(x) for x in requirements])
sys.stdout.write('\t'.join([pkg.project_name, pkg.version, pkg.location, requires])+chr(10))
sys.stdout.flush()
def do_install(pkgs):
run_pip(['install'] + pkgs)
def do_uninstall(pkgs):
run_pip(['uninstall', '-y'] + pkgs)
def run_pip(args):
import runpy
sys.argv[1:] = args
# pip.__main__ has been around since 2010 but support for executing it automatically
# was added in runpy.run_module only in Python 2.7/3.1
module_name = 'pip.__main__' if sys.version_info < (2, 7) else 'pip'
try:
runpy.run_module(module_name, run_name='__main__', alter_sys=True)
except ImportError:
error_no_pip()
def do_pyvenv(args):
import runpy
# We cannot rely on automatic installation of setuptools and pip and
# have to bootstrap these packages ourselves, since some distributions
# of CPython on Ubuntu and MacOS don't include "ensurepip" module.
sys.argv[1:] = ['--without-pip'] + args
try:
runpy.run_module('venv', run_name='__main__', alter_sys=True)
except ImportError:
error("Standard Python 'venv' module not found", ERROR_EXCEPTION)
def do_untar(name):
import tempfile
directory_name = tempfile.mkdtemp("pycharm-management")
import tarfile
tar = tarfile.open(name)
for item in tar:
tar.extract(item, directory_name)
sys.stdout.write(directory_name+chr(10))
sys.stdout.flush()
def mkdtemp_ifneeded():
try:
ind = sys.argv.index('--build-dir')
if not os.path.exists(sys.argv[ind + 1]):
import tempfile
sys.argv[ind + 1] = tempfile.mkdtemp('pycharm-packaging')
return sys.argv[ind + 1]
except:
pass
return None
def main():
try:
# As a workaround for #885 in setuptools, don't expose other helpers
# in sys.path so as not no confuse it with possible combination of
# namespace/ordinary packages
sys.path.remove(os.path.dirname(__file__))
except ValueError:
pass
try:
if len(sys.argv) < 2:
usage()
cmd = sys.argv[1]
if cmd == 'list':
if len(sys.argv) != 2:
usage()
do_list()
elif cmd == 'install':
if len(sys.argv) < 2:
usage()
rmdir = mkdtemp_ifneeded()
pkgs = sys.argv[2:]
try:
do_install(pkgs)
finally:
if rmdir is not None:
import shutil
shutil.rmtree(rmdir)
elif cmd == 'untar':
if len(sys.argv) < 2:
usage()
name = sys.argv[2]
do_untar(name)
elif cmd == 'uninstall':
if len(sys.argv) < 2:
usage()
pkgs = sys.argv[2:]
do_uninstall(pkgs)
elif cmd == 'pyvenv':
opts, args = getopt.getopt(sys.argv[2:], '', ['system-site-packages'])
if len(args) != 1:
usage()
do_pyvenv(sys.argv[2:])
else:
usage()
except Exception:
traceback.print_exc()
exit(ERROR_EXCEPTION)
if __name__ == '__main__':
main()