Skip to content

Commit

Permalink
Remove sys.exit from noarch_python and add unittests (#5425)
Browse files Browse the repository at this point in the history
  • Loading branch information
kenodegard authored Aug 6, 2024
1 parent d908fe1 commit 88b1995
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 21 deletions.
35 changes: 18 additions & 17 deletions conda_build/noarch_python.py
Original file line number Diff line number Diff line change
@@ -1,46 +1,47 @@
# Copyright (C) 2014 Anaconda, Inc
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations

import json
import locale
import logging
import os
import shutil
import sys
from os.path import basename, dirname, isfile, join
from pathlib import Path

from .utils import on_win
from .exceptions import CondaBuildUserError
from .utils import bin_dirname, on_win, rm_rf


def rewrite_script(fn, prefix):
def rewrite_script(fn: str, prefix: str | os.PathLike) -> str:
"""Take a file from the bin directory and rewrite it into the python-scripts
directory with the same permissions after it passes some sanity checks for
noarch pacakges"""

# Load and check the source file for not being a binary
src = join(prefix, "Scripts" if on_win else "bin", fn)
src = Path(prefix, bin_dirname, fn)
encoding = locale.getpreferredencoding()
# if default locale is ascii, allow UTF-8 (a reasonably modern ASCII extension)
if encoding == "ANSI_X3.4-1968":
encoding = "UTF-8"
with open(src, encoding=encoding) as fi:
try:
data = fi.read()
except UnicodeDecodeError: # file is binary
sys.exit(f"[noarch_python] Noarch package contains binary script: {fn}")
src_mode = os.stat(src).st_mode
os.unlink(src)
try:
data = src.read_text(encoding=encoding)
except UnicodeDecodeError: # binary file
raise CondaBuildUserError(f"Noarch package contains binary script: {fn}")
src_mode = src.stat().st_mode
rm_rf(src)

# Get rid of '-script.py' suffix on Windows
if on_win and fn.endswith("-script.py"):
fn = fn[:-10]

# Rewrite the file to the python-scripts directory
dst_dir = join(prefix, "python-scripts")
os.makedirs(dst_dir, exist_ok=True)
dst = join(dst_dir, fn)
with open(dst, "w") as fo:
fo.write(data)
os.chmod(dst, src_mode)
dst_dir = Path(prefix, "python-scripts")
dst_dir.mkdir(exist_ok=True)
dst = dst_dir / fn
dst.write_text(data)
dst.chmod(src_mode)
return fn


Expand Down
8 changes: 4 additions & 4 deletions conda_build/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1580,12 +1580,12 @@ def filter_info_files(files_list, prefix):
)


def rm_rf(path):
def rm_rf(path: str | os.PathLike) -> None:
from conda.core.prefix_data import delete_prefix_from_linked_data
from conda.gateways.disk.delete import rm_rf as rm_rf
from conda.gateways.disk.delete import rm_rf

rm_rf(path)
delete_prefix_from_linked_data(path)
rm_rf(str(path))
delete_prefix_from_linked_data(str(path))


# https://stackoverflow.com/a/31459386/1170370
Expand Down
60 changes: 60 additions & 0 deletions tests/test_noarch_python.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Copyright (C) 2014 Anaconda, Inc
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations

import stat
from typing import TYPE_CHECKING
from uuid import uuid4

import pytest

from conda_build.exceptions import CondaBuildUserError
from conda_build.noarch_python import rewrite_script
from conda_build.utils import bin_dirname, on_win

if TYPE_CHECKING:
from pathlib import Path


@pytest.mark.parametrize(
"before,after",
[
("script.py", "script.py"),
("script-script.py", "script" if on_win else "script-script.py"),
],
)
def test_rewrite_script(tmp_path: Path, before: str, after: str) -> None:
"""Test that a script file is rewritten to the python-scripts directory."""
script = tmp_path / bin_dirname / before
script.parent.mkdir()

# write some text to the script
script.write_text(text := uuid4().hex)

# change the permissions so we can check they are preserved
script.chmod(permissions := stat.S_IFREG | (0o444 if on_win else 0o456))

# rewrite the script to the python-scripts directory
rewrite_script(script.name, tmp_path)

# check that the original script has been removed
assert not script.exists()

# check that the script has been rewritten to the python-scripts directory,
# has the same text, and the same permissions
rewrite = tmp_path / "python-scripts" / after
assert rewrite.read_text() == text
assert rewrite.stat().st_mode == permissions


def test_rewrite_script_binary(tmp_path: Path) -> None:
"""Test that a binary file will raise an error."""
binary = tmp_path / bin_dirname / "binary"
binary.parent.mkdir()

# write some binary data to the script
binary.write_bytes(b"\x80\x81\x82\x83\x84\x85")

# try to rewrite the binary script to the python-scripts directory
with pytest.raises(CondaBuildUserError, match=r"package contains binary script"):
rewrite_script(binary.name, tmp_path)

0 comments on commit 88b1995

Please sign in to comment.