Merge pull request #11052 from SpecLad/fix-script-record-hash

Update the RECORD entry when rewriting the shebang line in a script
This commit is contained in:
Stéphane Bidoul 2022-06-26 12:20:13 +02:00 committed by GitHub
commit 340054a6bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 52 additions and 13 deletions

2
news/10744.bugfix.rst Normal file
View File

@ -0,0 +1,2 @@
When pip rewrites the shebang line in a script during wheel installation,
update the hash and size in the corresponding ``RECORD`` file entry.

View File

@ -224,19 +224,16 @@ def _normalized_outrows(
)
def _record_to_fs_path(record_path: RecordPath) -> str:
return record_path
def _record_to_fs_path(record_path: RecordPath, lib_dir: str) -> str:
return os.path.join(lib_dir, record_path)
def _fs_to_record_path(path: str, relative_to: Optional[str] = None) -> RecordPath:
if relative_to is not None:
# On Windows, do not handle relative paths if they belong to different
# logical disks
if (
os.path.splitdrive(path)[0].lower()
== os.path.splitdrive(relative_to)[0].lower()
):
path = os.path.relpath(path, relative_to)
def _fs_to_record_path(path: str, lib_dir: str) -> RecordPath:
# On Windows, do not handle relative paths if they belong to different
# logical disks
if os.path.splitdrive(path)[0].lower() == os.path.splitdrive(lib_dir)[0].lower():
path = os.path.relpath(path, lib_dir)
path = path.replace(os.path.sep, "/")
return cast("RecordPath", path)
@ -259,7 +256,7 @@ def get_csv_rows_for_installed(
old_record_path = cast("RecordPath", row[0])
new_record_path = installed.pop(old_record_path, old_record_path)
if new_record_path in changed:
digest, length = rehash(_record_to_fs_path(new_record_path))
digest, length = rehash(_record_to_fs_path(new_record_path, lib_dir))
else:
digest = row[1] if len(row) > 1 else ""
length = row[2] if len(row) > 2 else ""
@ -475,7 +472,7 @@ def _install_wheel(
newpath = _fs_to_record_path(destfile, lib_dir)
installed[srcfile] = newpath
if modified:
changed.add(_fs_to_record_path(destfile))
changed.add(newpath)
def is_dir_path(path: RecordPath) -> bool:
return path.endswith("/")

View File

@ -1,5 +1,7 @@
import base64
import csv
import distutils
import hashlib
import os
import shutil
from pathlib import Path
@ -364,6 +366,44 @@ def test_wheel_record_lines_have_hash_for_data_files(
]
def test_wheel_record_lines_have_updated_hash_for_scripts(
script: PipTestEnvironment,
) -> None:
"""
pip rewrites "#!python" shebang lines in scripts when it installs them;
make sure it updates the RECORD file correspondingly.
"""
package = make_wheel(
"simple",
"0.1.0",
extra_data_files={
"scripts/dostuff": "#!python\n",
},
).save_to_dir(script.scratch_path)
script.pip("install", package)
record_file = script.site_packages_path / "simple-0.1.0.dist-info" / "RECORD"
record_text = record_file.read_text()
record_rows = list(csv.reader(record_text.splitlines()))
records = {r[0]: r[1:] for r in record_rows}
script_path = script.bin_path / "dostuff"
script_contents = script_path.read_bytes()
assert not script_contents.startswith(b"#!python\n")
script_digest = hashlib.sha256(script_contents).digest()
script_digest_b64 = (
base64.urlsafe_b64encode(script_digest).decode("US-ASCII").rstrip("=")
)
script_record_path = os.path.relpath(
script_path, script.site_packages_path
).replace(os.path.sep, "/")
assert records[script_record_path] == [
f"sha256={script_digest_b64}",
str(len(script_contents)),
]
@pytest.mark.incompatible_with_test_venv
@pytest.mark.usefixtures("with_wheel")
def test_install_user_wheel(