remap-badblocks 0.8__py3-none-any.whl → 0.8.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- remap_badblocks/__init__.py +1 -1
- remap_badblocks-0.8.1.dist-info/METADATA +107 -0
- remap_badblocks-0.8.1.dist-info/RECORD +36 -0
- __init__.py +0 -0
- cli/__init__.py +0 -0
- cli/__main__.py +0 -239
- cli/commands/__init__.py +0 -8
- cli/commands/add.py +0 -91
- cli/commands/apply.py +0 -81
- cli/commands/get.py +0 -28
- cli/commands/remove.py +0 -45
- cli/commands/update.py +0 -208
- cli/commands/version.py +0 -15
- remap_badblocks-0.8.dist-info/METADATA +0 -130
- remap_badblocks-0.8.dist-info/RECORD +0 -66
- src/badblocks/_compute_good_ranges.py +0 -43
- src/badblocks/_find_badblocks.py +0 -76
- src/badblocks/_mapping_generation.py +0 -12
- src/badblocks/_remap_badblocks.py +0 -114
- src/badblocks/badblocks.py +0 -40
- src/devices/__init__.py +0 -0
- src/devices/device_config.py +0 -62
- src/devices/devices_config.py +0 -300
- src/devices/exceptions.py +0 -22
- src/devices_config_constants.py +0 -3
- src/mapping.py +0 -109
- src/remappers/_check_applied_devices.py +0 -10
- src/remappers/_generate_dm_table.py +0 -27
- src/test_utils.py +0 -18
- src/utils/__init__.py +0 -0
- src/utils/_get_device_info.py +0 -43
- src/utils/_iterable_bytes_converter.py +0 -19
- src/utils/_parse_inputs.py +0 -84
- src/utils/_run_command.py +0 -76
- src/utils/_sort_devices.py +0 -26
- {remap_badblocks-0.8.dist-info → remap_badblocks-0.8.1.dist-info}/WHEEL +0 -0
- {remap_badblocks-0.8.dist-info → remap_badblocks-0.8.1.dist-info}/entry_points.txt +0 -0
- {remap_badblocks-0.8.dist-info → remap_badblocks-0.8.1.dist-info}/licenses/LICENSE +0 -0
- {remap_badblocks-0.8.dist-info → remap_badblocks-0.8.1.dist-info}/top_level.txt +0 -0
src/utils/_parse_inputs.py
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import re
|
|
2
|
-
from typing import Optional
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
def parse_string_with_unit_to_bytes(txt: str, unit_multiplier: int) -> int:
|
|
6
|
-
return round(float(txt) * unit_multiplier)
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def parse_bytes_to_sectors(_input: int, sector_size: int) -> int:
|
|
10
|
-
if _input % sector_size != 0:
|
|
11
|
-
raise ValueError(
|
|
12
|
-
f"{_input}B is not a multiple of the sector size {sector_size}B."
|
|
13
|
-
)
|
|
14
|
-
return int(_input / sector_size)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def parse_memory_number_to_bytes(txt: str, sector_size: int) -> int:
|
|
18
|
-
"""
|
|
19
|
-
Parses a memory value (a sector number or a space size) and outputs a sector number.
|
|
20
|
-
"""
|
|
21
|
-
txt = txt.strip()
|
|
22
|
-
|
|
23
|
-
try:
|
|
24
|
-
return parse_string_with_unit_to_bytes(txt, sector_size)
|
|
25
|
-
except ValueError:
|
|
26
|
-
pass
|
|
27
|
-
try:
|
|
28
|
-
if txt.endswith("MB"):
|
|
29
|
-
return parse_string_with_unit_to_bytes(txt[:-2], 1024**2)
|
|
30
|
-
elif txt.endswith("GB"):
|
|
31
|
-
return parse_string_with_unit_to_bytes(txt[:-2], 1024**3)
|
|
32
|
-
elif txt.endswith("KB"):
|
|
33
|
-
return parse_string_with_unit_to_bytes(txt[:-2], 1024)
|
|
34
|
-
elif txt.endswith("B"):
|
|
35
|
-
return parse_string_with_unit_to_bytes(txt[:-1], 1)
|
|
36
|
-
else:
|
|
37
|
-
raise ValueError(f"Invalid format: {txt}")
|
|
38
|
-
except ValueError as e:
|
|
39
|
-
raise ValueError(f"Failed to parse memory space from '{txt}': {e}") from e
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def parse_memory_range_to_bytes(
|
|
43
|
-
txt: str, sector_size: int
|
|
44
|
-
) -> tuple[Optional[int], Optional[int]]:
|
|
45
|
-
"""
|
|
46
|
-
Parse a memory space range from a string and check the format is valid. Returns a sector range.
|
|
47
|
-
I.e. checks that the format is 'start-end', where each can be omitted, and start <= end.
|
|
48
|
-
"""
|
|
49
|
-
txt = txt.strip()
|
|
50
|
-
|
|
51
|
-
m = re.match(
|
|
52
|
-
r"^(?P<start>\d+(\.\d+)?(?:[KMGT]?B)?)?-(?P<end>\d+(\.\d+)?(?:[KMGT]?B)?)?$",
|
|
53
|
-
txt,
|
|
54
|
-
)
|
|
55
|
-
if m is None:
|
|
56
|
-
raise ValueError(
|
|
57
|
-
f"Invalid format: {txt}. Expected format: 'start-end', where each can be omitted."
|
|
58
|
-
)
|
|
59
|
-
groups: dict[str, str | None] = {key: m.group(key) for key in ("start", "end")}
|
|
60
|
-
values: dict[str, int] = {
|
|
61
|
-
key: parse_memory_number_to_bytes(value, sector_size)
|
|
62
|
-
for key, value in groups.items()
|
|
63
|
-
if value is not None
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
start, end = values.get("start"), values.get("end")
|
|
67
|
-
|
|
68
|
-
if start is not None and end is not None and (end < start):
|
|
69
|
-
raise ValueError(f"End {end} must be greater than or equal to start {start}.")
|
|
70
|
-
|
|
71
|
-
return start, end
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
def parse_memory_range_to_sectors(
|
|
75
|
-
txt: str, sector_size: int
|
|
76
|
-
) -> tuple[Optional[int], Optional[int]]:
|
|
77
|
-
start, end = parse_memory_range_to_bytes(txt, sector_size)
|
|
78
|
-
|
|
79
|
-
if start is not None:
|
|
80
|
-
start = parse_bytes_to_sectors(start, sector_size)
|
|
81
|
-
if end is not None:
|
|
82
|
-
end = parse_bytes_to_sectors(end, sector_size)
|
|
83
|
-
|
|
84
|
-
return start, end
|
src/utils/_run_command.py
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import subprocess
|
|
2
|
-
import sys
|
|
3
|
-
import threading
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
from typing import IO, Iterable, Optional, Protocol, Union
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class Stringifyiable(Protocol):
|
|
9
|
-
"""Protocol for objects that can be converted to a string."""
|
|
10
|
-
|
|
11
|
-
def __str__(self) -> str:
|
|
12
|
-
"""Return the string representation of the object."""
|
|
13
|
-
...
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def pipe_stderr_to_stream(pipe: IO[str], stream: IO[str]) -> None:
|
|
17
|
-
for line in pipe:
|
|
18
|
-
print(f"[stderr] {line.strip()}", file=stream)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def run_command_realtime(cmd: list[str], stdin: Optional[str] = None) -> Iterable[str]:
|
|
22
|
-
"""Run a command and yield its output line by line in real-time."""
|
|
23
|
-
with subprocess.Popen(
|
|
24
|
-
cmd,
|
|
25
|
-
stdout=subprocess.PIPE,
|
|
26
|
-
stderr=subprocess.PIPE,
|
|
27
|
-
stdin=subprocess.PIPE,
|
|
28
|
-
text=True,
|
|
29
|
-
) as process:
|
|
30
|
-
if process.stdout is None:
|
|
31
|
-
raise RuntimeError("Failed to capture stdout from the command.")
|
|
32
|
-
|
|
33
|
-
if stdin is not None:
|
|
34
|
-
if process.stdin is None:
|
|
35
|
-
raise RuntimeError("Failed to pass stdin to command.")
|
|
36
|
-
else:
|
|
37
|
-
if not stdin.endswith("\n"):
|
|
38
|
-
stdin += "\n"
|
|
39
|
-
process.stdin.write(stdin)
|
|
40
|
-
process.stdin.close()
|
|
41
|
-
|
|
42
|
-
# Start background stderr reader
|
|
43
|
-
stderr_thread: Optional[threading.Thread] = None
|
|
44
|
-
if process.stderr is not None:
|
|
45
|
-
stderr_thread = threading.Thread(
|
|
46
|
-
target=pipe_stderr_to_stream, args=(process.stderr, sys.stderr)
|
|
47
|
-
)
|
|
48
|
-
stderr_thread.start()
|
|
49
|
-
|
|
50
|
-
for line in process.stdout:
|
|
51
|
-
yield line.strip()
|
|
52
|
-
|
|
53
|
-
process.wait()
|
|
54
|
-
if stderr_thread is not None:
|
|
55
|
-
stderr_thread.join()
|
|
56
|
-
|
|
57
|
-
if process.returncode != 0:
|
|
58
|
-
# Capture stderr if needed
|
|
59
|
-
raise RuntimeError(f"Command failed with code {process.returncode}")
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
def pipe_lines_to_file(
|
|
63
|
-
lines: Iterable[Stringifyiable], output_file: Union[str, Path, IO[str]]
|
|
64
|
-
) -> None:
|
|
65
|
-
"""Save the lines to the specified output file in real-time."""
|
|
66
|
-
f: Optional[IO[str]] = None
|
|
67
|
-
try:
|
|
68
|
-
if not isinstance(output_file, IO):
|
|
69
|
-
f = open(output_file, "w")
|
|
70
|
-
output_file = f
|
|
71
|
-
for line in lines:
|
|
72
|
-
output_file.write(str(line) + "\n")
|
|
73
|
-
output_file.flush() # Ensure the content is written to the file immediately
|
|
74
|
-
finally:
|
|
75
|
-
if f is not None:
|
|
76
|
-
f.close()
|
src/utils/_sort_devices.py
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
from typing import Collection, Iterable
|
|
2
|
-
|
|
3
|
-
from remap_badblocks.src.devices.devices_config import DeviceConfig
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def sort_devices_by_dependencies(
|
|
7
|
-
devices: Collection[DeviceConfig],
|
|
8
|
-
already_applied_devices: Iterable[DeviceConfig] = set(),
|
|
9
|
-
) -> Iterable[DeviceConfig]:
|
|
10
|
-
devices = list(devices)
|
|
11
|
-
sorted_devices: list[DeviceConfig] = []
|
|
12
|
-
already_sorted_ids: set[int] = set(map(lambda x: x.id, already_applied_devices))
|
|
13
|
-
|
|
14
|
-
while devices:
|
|
15
|
-
for device in devices:
|
|
16
|
-
if all(dep in already_sorted_ids for dep in device.depends_on):
|
|
17
|
-
sorted_devices.append(device)
|
|
18
|
-
already_sorted_ids.add(device.id)
|
|
19
|
-
devices.remove(device)
|
|
20
|
-
break
|
|
21
|
-
else:
|
|
22
|
-
raise ValueError(
|
|
23
|
-
"Circular dependency detected or no device can be applied."
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
return sorted_devices
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|