Skip to content

Commit 9a150b3

Browse files
authored
Adds fallback search for 'python<TAG>.exe' style shebangs. (#97)
Fixes #91
1 parent b11b9d6 commit 9a150b3

File tree

5 files changed

+46
-18
lines changed

5 files changed

+46
-18
lines changed

src/manage/pathutils.py

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -124,23 +124,18 @@ def match(self, pattern, full_match=False):
124124
if "*" not in p:
125125
return m.casefold() == p
126126

127-
allow_skip = False
127+
must_start_with = True
128128
for bit in p.split("*"):
129129
if bit:
130-
if allow_skip:
131-
allow_skip = False
132-
try:
133-
i = m.index(bit)
134-
except ValueError:
135-
return False
136-
m = m[i + len(bit):]
137-
elif m.startswith(bit):
138-
m = m[len(bit):]
139-
else:
130+
try:
131+
i = m.index(bit)
132+
except ValueError:
140133
return False
141-
else:
142-
allow_skip = True
143-
return True
134+
if must_start_with and i != 0:
135+
return False
136+
m = m[i + len(bit):]
137+
must_start_with = False
138+
return not m or p.endswith("*")
144139

145140

146141
class Path(PurePath):

src/manage/scriptutils.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def _find_shebang_command(cmd, full_cmd):
2424
for i in cmd.get_installs():
2525
if is_default and i.get("default"):
2626
return i
27-
for a in i["alias"]:
27+
for a in i.get("alias", ()):
2828
if sh_cmd.match(a["name"]):
2929
LOGGER.debug("Matched alias %s in %s", a["name"], i["id"])
3030
return {**i, "executable": i["prefix"] / a["target"]}
@@ -34,8 +34,13 @@ def _find_shebang_command(cmd, full_cmd):
3434
if sh_cmd.match(i["executable"]):
3535
LOGGER.debug("Matched executable %s in %s", i["executable"], i["id"])
3636
return i
37-
else:
38-
raise LookupError
37+
38+
# Fallback search for 'python<TAG>.exe' shebangs
39+
if sh_cmd.match("python*.exe"):
40+
tag = sh_cmd.name[6:-4]
41+
return cmd.get_install_to_run(f"PythonCore/{tag}")
42+
43+
raise LookupError
3944

4045

4146
def _find_on_path(cmd, full_cmd):

tests/conftest.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ def __init__(self, installs=[]):
143143
def get_installs(self):
144144
return self.installs
145145

146+
def get_install_to_run(self, tag):
147+
company, _, tag = tag.replace("/", "\\").rpartition("\\")
148+
return [i for i in self.installs
149+
if i["tag"] == tag and (not company or i["company"] == company)][0]
150+
146151

147152
@pytest.fixture
148153
def fake_config():

tests/test_pathutils.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import pytest
2+
3+
from manage.pathutils import Path, PurePath
4+
5+
def test_path_match():
6+
p = Path("python3.12.exe")
7+
assert p.match("*.exe")
8+
assert p.match("python*")
9+
assert p.match("python*.exe")
10+
assert p.match("python3.12*.exe")
11+
assert p.match("*hon3.*")
12+
assert p.match("p*3.*.exe")
13+
14+
assert not p.match("*.com")
15+
assert not p.match("example*")
16+
assert not p.match("example*.com")
17+
assert not p.match("*ple*")

tests/test_scriptutils.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
def _fake_install(v, **kwargs):
1919
return {
20-
"company": "Test",
20+
"company": kwargs.get("company", "Test"),
2121
"id": f"test-{v}",
2222
"tag": str(v),
2323
"version": str(v),
@@ -29,6 +29,8 @@ def _fake_install(v, **kwargs):
2929
INSTALLS = [
3030
_fake_install("1.0", alias=[{"name": "test1.0.exe", "target": "./test-binary-1.0.exe"}]),
3131
_fake_install("1.1", alias=[{"name": "test1.1.exe", "target": "./test-binary-1.1.exe"}]),
32+
_fake_install("1.3.1", company="PythonCore"),
33+
_fake_install("1.3.2", company="PythonOther"),
3234
_fake_install("2.0", alias=[{"name": "test2.0.exe", "target": "./test-binary-2.0.exe"}]),
3335
]
3436

@@ -46,6 +48,10 @@ def _fake_install(v, **kwargs):
4648
("#! /usr/bin/env test1.0\n", "1.0"),
4749
("#! /usr/bin/env test2.0\n", "2.0"),
4850
("#! /usr/bin/env -S test2.0\n", "2.0"),
51+
# Legacy handling specifically for "python<TAG>"
52+
("#! /usr/bin/python1.3.1", "1.3.1"),
53+
("#! /usr/bin/env python1.3.1", "1.3.1"),
54+
("#! /usr/bin/python1.3.2", None),
4955
])
5056
def test_read_shebang(fake_config, tmp_path, script, expect):
5157
fake_config.installs.extend(INSTALLS)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy