From c9b959de00fb2f148d4d76a7a5e6cc5ce3f3a8a2 Mon Sep 17 00:00:00 2001 From: Bernat Gabor Date: Tue, 11 Feb 2020 17:14:50 +0000 Subject: [PATCH] support long path names for the app-data seeder generates console entry points Signed-off-by: Bernat Gabor --- docs/changelog/997.bugfix.rst | 2 + setup.cfg | 2 +- .../seed/via_app_data/pip_install/base.py | 57 ++++--------------- tests/unit/create/test_creator.py | 15 +++++ 4 files changed, 29 insertions(+), 47 deletions(-) create mode 100644 docs/changelog/997.bugfix.rst diff --git a/docs/changelog/997.bugfix.rst b/docs/changelog/997.bugfix.rst new file mode 100644 index 000000000..354a3d3d1 --- /dev/null +++ b/docs/changelog/997.bugfix.rst @@ -0,0 +1,2 @@ +Support long path names for generated virtual environment console entry points (such as ``pip``) when using the +``app-data`` :option:`seeder` - by :user:`gaborbernat`. diff --git a/setup.cfg b/setup.cfg index 55324a858..99618df96 100644 --- a/setup.cfg +++ b/setup.cfg @@ -41,10 +41,10 @@ project_urls = packages = find: install_requires = appdirs>=1.4.3,<2 + distlib>=0.3.0,<1 filelock>=3.0.0,<4 six>=1.12.0,<2 contextlib2>=0.6.0,<1;python_version<"3.3" - distlib>=0.3.0,<1;sys.platform == 'win32' importlib-metadata>=0.12,<2;python_version<"3.8" importlib-resources>=1.0,<2;python_version<"3.7" pathlib2>=2.3.3,<3;python_version < '3.4' and sys.platform != 'win32' diff --git a/src/virtualenv/seed/via_app_data/pip_install/base.py b/src/virtualenv/seed/via_app_data/pip_install/base.py index 2878a65a6..0a8a4c98b 100644 --- a/src/virtualenv/seed/via_app_data/pip_install/base.py +++ b/src/virtualenv/seed/via_app_data/pip_install/base.py @@ -7,14 +7,12 @@ import zipfile from abc import ABCMeta, abstractmethod from tempfile import mkdtemp -from textwrap import dedent import six from six import PY3 -from virtualenv.info import IS_WIN from virtualenv.util import ConfigParser -from virtualenv.util.path import Path, make_exe +from virtualenv.util.path import Path @six.add_metaclass(ABCMeta) @@ -131,49 +129,16 @@ def _console_scripts(self): def _create_console_entry_point(self, name, value, to_folder): result = [] - if IS_WIN: - # windows doesn't support simple script files, so fallback to more complicated exe generator - from distlib.scripts import ScriptMaker - - maker = ScriptMaker(None, str(to_folder)) - maker.clobber = True # overwrite - maker.variants = {"", "X", "X.Y"} # create all variants - maker.set_mode = True # ensure they are executable - maker.executable = str(self._creator.exe) - specification = "{} = {}".format(name, value) - new_files = maker.make(specification) - result.extend(Path(i) for i in new_files) - else: - module, func = value.split(":") - content = ( - dedent( - """ - #!{0} - # -*- coding: utf-8 -*- - import re - import sys - - from {1} import {2} - - if __name__ == "__main__": - sys.argv[0] = re.sub(r"(-script.pyw?|.exe)?$", "", sys.argv[0]) - sys.exit({2}()) - """ - ) - .lstrip() - .format(self._creator.exe, module, func) - ) - - version = self._creator.interpreter.version_info - for new_name in ( - name, - "{}{}".format(name, version.major), - "{}-{}.{}".format(name, version.major, version.minor), - ): - exe = to_folder / new_name - exe.write_text(content, encoding="utf-8") - make_exe(exe) - result.append(exe) + from distlib.scripts import ScriptMaker + + maker = ScriptMaker(None, str(to_folder)) + maker.clobber = True # overwrite + maker.variants = {"", "X", "X.Y"} # create all variants + maker.set_mode = True # ensure they are executable + maker.executable = str(self._creator.exe) + specification = "{} = {}".format(name, value) + new_files = maker.make(specification) + result.extend(Path(i) for i in new_files) return result def clear(self): diff --git a/tests/unit/create/test_creator.py b/tests/unit/create/test_creator.py index bcad0cc8c..03fc4ce87 100644 --- a/tests/unit/create/test_creator.py +++ b/tests/unit/create/test_creator.py @@ -297,3 +297,18 @@ def test_creator_input_passed_is_abs(tmp_path, monkeypatch): monkeypatch.chdir(tmp_path) result = Creator.validate_dest("venv") assert str(result) == str(tmp_path / "venv") + + +def test_create_long_path(current_fastest, tmp_path): + if sys.platform == "darwin": + max_shebang_length = 512 + else: + max_shebang_length = 127 + # filenames can be at most 255 long on macOS, so split to to levels + count = max_shebang_length - len(str(tmp_path)) + folder = tmp_path / ("a" * (count // 2)) / ("b" * (count // 2)) / "c" + folder.mkdir(parents=True) + + cmd = [str(folder)] + result = run_via_cli(cmd) + subprocess.check_call([str(result.creator.exe.parent / "pip"), "--version"])