Skip to content

Commit 6c098d8

Browse files
Siddhant Kumargaborbernat
andauthored
Use unix line-endings in bash activate script (#1924)
Co-authored-by: Bernat Gabor <[email protected]>
1 parent 7de4f3f commit 6c098d8

File tree

10 files changed

+96
-73
lines changed

10 files changed

+96
-73
lines changed

.gitattributes

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
11
*.bat text eol=crlf
2+
*.ps1 text eol=lf
3+
*.fish text eol=lf
4+
*.csh text eol=lf
5+
*.sh text eol=lf

docs/changelog/1818.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
For activation scripts always use UNIX line endings (unless it's BATCH shell related) - by :user:`saytosid`.
Lines changed: 60 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,60 @@
1-
$script:THIS_PATH = $myinvocation.mycommand.path
2-
$script:BASE_DIR = Split-Path (Resolve-Path "$THIS_PATH/..") -Parent
3-
4-
function global:deactivate([switch] $NonDestructive) {
5-
if (Test-Path variable:_OLD_VIRTUAL_PATH) {
6-
$env:PATH = $variable:_OLD_VIRTUAL_PATH
7-
Remove-Variable "_OLD_VIRTUAL_PATH" -Scope global
8-
}
9-
10-
if (Test-Path function:_old_virtual_prompt) {
11-
$function:prompt = $function:_old_virtual_prompt
12-
Remove-Item function:\_old_virtual_prompt
13-
}
14-
15-
if ($env:VIRTUAL_ENV) {
16-
Remove-Item env:VIRTUAL_ENV -ErrorAction SilentlyContinue
17-
}
18-
19-
if (!$NonDestructive) {
20-
# Self destruct!
21-
Remove-Item function:deactivate
22-
Remove-Item function:pydoc
23-
}
24-
}
25-
26-
function global:pydoc {
27-
python -m pydoc $args
28-
}
29-
30-
# unset irrelevant variables
31-
deactivate -nondestructive
32-
33-
$VIRTUAL_ENV = $BASE_DIR
34-
$env:VIRTUAL_ENV = $VIRTUAL_ENV
35-
36-
New-Variable -Scope global -Name _OLD_VIRTUAL_PATH -Value $env:PATH
37-
38-
$env:PATH = "$env:VIRTUAL_ENV/__BIN_NAME____PATH_SEP__" + $env:PATH
39-
if (!$env:VIRTUAL_ENV_DISABLE_PROMPT) {
40-
function global:_old_virtual_prompt {
41-
""
42-
}
43-
$function:_old_virtual_prompt = $function:prompt
44-
45-
if ("__VIRTUAL_PROMPT__" -ne "") {
46-
function global:prompt {
47-
# Add the custom prefix to the existing prompt
48-
$previous_prompt_value = & $function:_old_virtual_prompt
49-
("__VIRTUAL_PROMPT__" + $previous_prompt_value)
50-
}
51-
}
52-
else {
53-
function global:prompt {
54-
# Add a prefix to the current prompt, but don't discard it.
55-
$previous_prompt_value = & $function:_old_virtual_prompt
56-
$new_prompt_value = "($( Split-Path $env:VIRTUAL_ENV -Leaf )) "
57-
($new_prompt_value + $previous_prompt_value)
58-
}
59-
}
60-
}
1+
$script:THIS_PATH = $myinvocation.mycommand.path
2+
$script:BASE_DIR = Split-Path (Resolve-Path "$THIS_PATH/..") -Parent
3+
4+
function global:deactivate([switch] $NonDestructive) {
5+
if (Test-Path variable:_OLD_VIRTUAL_PATH) {
6+
$env:PATH = $variable:_OLD_VIRTUAL_PATH
7+
Remove-Variable "_OLD_VIRTUAL_PATH" -Scope global
8+
}
9+
10+
if (Test-Path function:_old_virtual_prompt) {
11+
$function:prompt = $function:_old_virtual_prompt
12+
Remove-Item function:\_old_virtual_prompt
13+
}
14+
15+
if ($env:VIRTUAL_ENV) {
16+
Remove-Item env:VIRTUAL_ENV -ErrorAction SilentlyContinue
17+
}
18+
19+
if (!$NonDestructive) {
20+
# Self destruct!
21+
Remove-Item function:deactivate
22+
Remove-Item function:pydoc
23+
}
24+
}
25+
26+
function global:pydoc {
27+
python -m pydoc $args
28+
}
29+
30+
# unset irrelevant variables
31+
deactivate -nondestructive
32+
33+
$VIRTUAL_ENV = $BASE_DIR
34+
$env:VIRTUAL_ENV = $VIRTUAL_ENV
35+
36+
New-Variable -Scope global -Name _OLD_VIRTUAL_PATH -Value $env:PATH
37+
38+
$env:PATH = "$env:VIRTUAL_ENV/__BIN_NAME____PATH_SEP__" + $env:PATH
39+
if (!$env:VIRTUAL_ENV_DISABLE_PROMPT) {
40+
function global:_old_virtual_prompt {
41+
""
42+
}
43+
$function:_old_virtual_prompt = $function:prompt
44+
45+
if ("__VIRTUAL_PROMPT__" -ne "") {
46+
function global:prompt {
47+
# Add the custom prefix to the existing prompt
48+
$previous_prompt_value = & $function:_old_virtual_prompt
49+
("__VIRTUAL_PROMPT__" + $previous_prompt_value)
50+
}
51+
}
52+
else {
53+
function global:prompt {
54+
# Add a prefix to the current prompt, but don't discard it.
55+
$previous_prompt_value = & $function:_old_virtual_prompt
56+
$new_prompt_value = "($( Split-Path $env:VIRTUAL_ENV -Leaf )) "
57+
($new_prompt_value + $previous_prompt_value)
58+
}
59+
}
60+
}

src/virtualenv/activation/via_template.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
from .activator import Activator
1212

1313
if sys.version_info >= (3, 7):
14-
from importlib.resources import read_text
14+
from importlib.resources import read_binary
1515
else:
16-
from importlib_resources import read_text
16+
from importlib_resources import read_binary
1717

1818

1919
@add_metaclass(ABCMeta)
@@ -44,16 +44,18 @@ def _generate(self, replacements, templates, to_folder, creator):
4444
for template in templates:
4545
text = self.instantiate_template(replacements, template, creator)
4646
dest = to_folder / self.as_name(template)
47-
dest.write_text(text, encoding="utf-8")
47+
# use write_bytes to avoid platform specific line normalization (\n -> \r\n)
48+
dest.write_bytes(text.encode("utf-8"))
4849
generated.append(dest)
4950
return generated
5051

5152
def as_name(self, template):
5253
return template.name
5354

5455
def instantiate_template(self, replacements, template, creator):
55-
# read text and do replacements
56-
text = read_text(self.__module__, str(template), encoding="utf-8", errors="strict")
56+
# read content as binary to avoid platform specific line normalization (\n -> \r\n)
57+
binary = read_binary(self.__module__, str(template))
58+
text = binary.decode("utf-8", errors="strict")
5759
for key, value in replacements.items():
5860
value = self._repr_unicode(creator, value)
5961
text = text.replace(key, value)

src/virtualenv/create/via_global_ref/api.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
from virtualenv.info import fs_supports_symlink
1010
from virtualenv.util.path import Path
11+
from virtualenv.util.six import ensure_text
1112

1213
from ..creator import Creator, CreatorMeta
1314

@@ -91,10 +92,10 @@ def install_patch(self):
9192
text = self.env_patch_text()
9293
if text:
9394
pth = self.purelib / "_virtualenv.pth"
94-
logging.debug("create virtualenv import hook file %s", pth)
95+
logging.debug("create virtualenv import hook file %s", ensure_text(str(pth)))
9596
pth.write_text("import _virtualenv")
9697
dest_path = self.purelib / "_virtualenv.py"
97-
logging.debug("create %s", dest_path)
98+
logging.debug("create %s", ensure_text(str(dest_path)))
9899
dest_path.write_text(text)
99100

100101
def env_patch_text(self):

src/virtualenv/util/path/_pathlib/via_os_path.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,12 @@ def read_bytes(self):
8787
with open(self._path, "rb") as file_handler:
8888
return file_handler.read()
8989

90-
def write_text(self, text, encoding="utf-8"):
90+
def write_bytes(self, content):
9191
with open(self._path, "wb") as file_handler:
92-
file_handler.write(text.encode(encoding))
92+
file_handler.write(content)
93+
94+
def write_text(self, text, encoding="utf-8"):
95+
self.write_bytes(text.encode(encoding))
9396

9497
def iterdir(self):
9598
for p in os.listdir(self._path):

tests/unit/activation/conftest.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ def __init__(self, of_class, session, cmd, activate_script, extension):
3131
self.pydoc_call = "pydoc -w pydoc_test"
3232
self.script_encoding = "utf-8"
3333
self._version = None
34+
self.unix_line_ending = True
3435

3536
def get_version(self, raise_on_fail):
3637
if self._version is None:
@@ -63,6 +64,16 @@ def __repr__(self):
6364

6465
def __call__(self, monkeypatch, tmp_path):
6566
activate_script = self._creator.bin_dir / self.activate_script
67+
68+
# check line endings are correct type
69+
script_content = activate_script.read_bytes()
70+
for line in script_content.split(b"\n")[:-1]:
71+
cr = b"\r" if sys.version_info.major == 2 else 13
72+
if self.unix_line_ending:
73+
assert line == b"" or line[-1] != cr, script_content.decode("utf-8")
74+
else:
75+
assert line[-1] == cr, script_content.decode("utf-8")
76+
6677
test_script = self._generate_test_script(activate_script, tmp_path)
6778
monkeypatch.chdir(ensure_text(str(tmp_path)))
6879

tests/unit/activation/test_bash.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
from __future__ import absolute_import, unicode_literals
22

3-
import sys
4-
53
import pytest
64

75
from virtualenv.activation import BashActivator
6+
from virtualenv.info import IS_WIN
87

98

10-
@pytest.mark.skipif(sys.platform == "win32", reason="Github Actions ships with WSL bash")
9+
@pytest.mark.skipif(IS_WIN, reason="Github Actions ships with WSL bash")
1110
def test_bash(raise_on_non_source_class, activation_tester):
1211
class Bash(raise_on_non_source_class):
1312
def __init__(self, session):

tests/unit/activation/test_batch.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ def __init__(self, session):
1717
self.deactivate = "call deactivate"
1818
self.activate_cmd = "call"
1919
self.pydoc_call = "call {}".format(self.pydoc_call)
20+
self.unix_line_ending = False
2021

2122
def _get_test_lines(self, activate_script):
2223
# for BATCH utf-8 support need change the character code page to 650001

tests/unit/activation/test_python_activator.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from textwrap import dedent
77

88
from virtualenv.activation import PythonActivator
9-
from virtualenv.info import WIN_CPYTHON_2
9+
from virtualenv.info import IS_WIN, WIN_CPYTHON_2
1010
from virtualenv.util.six import ensure_text
1111

1212

@@ -21,6 +21,7 @@ def __init__(self, session):
2121
extension="py",
2222
non_source_fail_message="You must use exec(open(this_file).read(), {'__file__': this_file}))",
2323
)
24+
self.unix_line_ending = not IS_WIN
2425

2526
def env(self, tmp_path):
2627
env = os.environ.copy()

0 commit comments

Comments
 (0)