Skip to content

Commit

Permalink
support long path names for the app-data seeder generates console ent…
Browse files Browse the repository at this point in the history
…ry points

Signed-off-by: Bernat Gabor <bgabor8@bloomberg.net>
  • Loading branch information
gaborbernat committed Feb 11, 2020
1 parent f4fd6a0 commit c9b959d
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 47 deletions.
2 changes: 2 additions & 0 deletions docs/changelog/997.bugfix.rst
Original file line number Diff line number Diff line change
@@ -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`.
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
57 changes: 11 additions & 46 deletions src/virtualenv/seed/via_app_data/pip_install/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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):
Expand Down
15 changes: 15 additions & 0 deletions tests/unit/create/test_creator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"])

0 comments on commit c9b959d

Please sign in to comment.