1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
|
import textwrap
from typing import Optional
import pytest
from debputy.highlevel_manifest import HighLevelManifest
from debputy.highlevel_manifest_parser import YAMLManifestParser
from debputy.interpreter import extract_shebang_interpreter
from debputy.plugin.api import virtual_path_def
from debputy.plugin.api.test_api import build_virtual_file_system
from debputy.transformation_rules import NormalizeShebangLineTransformation
@pytest.mark.parametrize(
"raw_shebang,original_command,command_full_basename,command_stem,correct_command,corrected_shebang_line",
[
(
b"#! /usr/bin/false\r\n",
"/usr/bin/false",
"false",
"false",
None,
None,
),
(
b"#!/usr/bin/python3 -b",
"/usr/bin/python3",
"python3",
"python",
"/usr/bin/python3",
None,
),
(
b"#!/usr/bin/env python3 -b",
"/usr/bin/env python3",
"python3",
"python",
"/usr/bin/python3",
"#! /usr/bin/python3 -b",
),
(
b"#! /bin/env python3.12-dbg -b",
"/bin/env python3.12-dbg",
"python3.12-dbg",
"python",
"/usr/bin/python3.12-dbg",
"#! /usr/bin/python3.12-dbg -b",
),
(
b"#! /usr/bin/bash",
"/usr/bin/bash",
"bash",
"bash",
"/bin/bash",
"#! /bin/bash",
),
(
b"#! /usr/bin/env sh",
"/usr/bin/env sh",
"sh",
"sh",
"/bin/sh",
"#! /bin/sh",
),
(
b"#! /usr/local/bin/perl",
"/usr/local/bin/perl",
"perl",
"perl",
"/usr/bin/perl",
"#! /usr/bin/perl",
),
],
)
def test_interpreter_detection(
raw_shebang: bytes,
original_command: str,
command_full_basename: str,
command_stem: str,
correct_command: str | None,
corrected_shebang_line: str | None,
) -> None:
interpreter = extract_shebang_interpreter(raw_shebang)
# The `and ...` part is just to get the raw line in the error message
assert interpreter is not None
assert interpreter.original_command == original_command
assert interpreter.command_full_basename == command_full_basename
assert interpreter.command_stem == command_stem
assert interpreter.correct_command == correct_command
assert interpreter.corrected_shebang_line == corrected_shebang_line
assert interpreter.fixup_needed == (corrected_shebang_line is not None)
@pytest.mark.parametrize(
"raw_data",
[
b"#!#!#! /usr/bin/false",
b"#!perl", # Used in files as an editor hint
b"\x7fELF/usr/bin/perl",
b"\x00\01\x02\x03/usr/bin/perl",
b"PK\x03\x03/usr/bin/perl",
],
)
def test_interpreter_negative(raw_data: bytes) -> None:
assert extract_shebang_interpreter(raw_data) is None
@pytest.fixture
def empty_manifest(
amd64_dpkg_architecture_variables,
dpkg_arch_query,
source_package,
package_single_foo_arch_all_cxt_amd64,
amd64_substitution,
no_profiles_or_build_options,
debputy_plugin_feature_set,
) -> HighLevelManifest:
# We need an empty directory to avoid triggering packager provided files.
debian_dir = build_virtual_file_system([])
return YAMLManifestParser(
"debian/test-debputy.manifest",
source_package,
package_single_foo_arch_all_cxt_amd64,
amd64_substitution,
amd64_dpkg_architecture_variables,
dpkg_arch_query,
no_profiles_or_build_options,
debputy_plugin_feature_set,
"full",
debian_dir=debian_dir,
).build_manifest()
def test_interpreter_rewrite(empty_manifest: HighLevelManifest) -> None:
condition_context = empty_manifest.condition_context("foo")
fs_root = build_virtual_file_system(
[
virtual_path_def("usr/bin/foo", content="random data"),
virtual_path_def(
"usr/bin/foo.sh",
materialized_content="#!/usr/bin/sh\nset -e\n",
),
]
)
interpreter_normalization = NormalizeShebangLineTransformation()
interpreter_normalization.transform_file_system(fs_root, condition_context)
foo = fs_root.lookup("usr/bin/foo")
foo_sh = fs_root.lookup("usr/bin/foo.sh")
assert foo is not None and foo.is_file
with foo.open() as fd:
assert fd.read() == "random data"
assert foo_sh is not None and foo_sh.is_file
with foo_sh.open() as fd:
expected = textwrap.dedent(
"""\
#! /bin/sh
set -e
"""
)
assert fd.read() == expected
|