fix: keep the dry-run total in view

This commit is contained in:
Abdessamad Derraz committed 2026-11-05 12:13:04 +01:00
1 parent 0d5911f614
commit bc6bd590f1
5 files changed
+65 -20

No files matched your search

+1 -1
View File
@@ -16,7 +16,7 @@
# and Invoke-WebRequest throws on a cut transfer before the hash is read:
# the site's build rewrites this line there (scripts/sitebootstrap.py).
$mismatchAdvice = "The download was most likely cut short: try again. Within minutes of an update of this project the two files can come from caches of different ages. Waiting five minutes settles that."
$defaultInstallSha256 = "d3bfabb88e93d8ddf991965cd69929e73b0a254550f8f4c86a11ad34fe710a0b"
$defaultInstallSha256 = "e7df99e3ac458c7717bd2ca415bc7d3d8701545652cd303ed19de67077531ab2"
$maximumInstallerBytes = 2MB
$installerExit = 0
$installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null }
+24 -10
View File
@@ -6625,6 +6625,8 @@ def installer_id() -> str:
PLAN_FILES_PER_SYSTEM = 8
PLAN_LARGEST_SYSTEMS = 10
PLAN_FRAME_LINES = 6
# Past this many systems a group sharing files is named by its first two.
PLAN_GROUP_TITLES = 3
# Answers that stop: every menu before this one taught q as quit.
_REFUSALS = ("n", "q", "quit", "exit", "stop", "abort")
@@ -6692,22 +6694,34 @@ def _print_plan(
if not parts:
print(f"\n Nothing to {verb}.")
by_system: dict[str, list[dict]] = {}
titles: dict[str, str] = {}
for entry in to_download:
system = (", ".join(system_title(name, manifest) for name in entry_systems(entry))
or OTHER_TITLE)
names = [system_title(name, manifest) for name in entry_systems(entry)]
system = ", ".join(names) or OTHER_TITLE
by_system.setdefault(system, []).append(entry)
# Batocera's group of systems sharing MAME's device ROMs was one line
# of 732 characters, ten rows on an 80-column terminal.
titles[system] = (system if verbose or len(names) <= PLAN_GROUP_TITLES
else f"{', '.join(names[:2])} and {len(names) - 2} more systems")
shown = None if verbose else PLAN_FILES_PER_SYSTEM
listing: list[str] = []
# (line, its text without styles), the second measuring the rows it takes.
listing: list[tuple[str, str]] = []
for system in sorted(by_system):
entries = sorted(by_system[system], key=lambda e: e["dest"])
listing.append(f" {term.bold(system)} {_sized(entries)}")
listing += [f" {entry['dest']} {term.dim(format_size(entry.get('size', 0)))}"
listing.append((f" {term.bold(titles[system])} {_sized(entries)}",
f" {titles[system]} {_sized(entries)}"))
listing += [(f" {entry['dest']} {term.dim(format_size(entry.get('size', 0)))}",
f" {entry['dest']} {format_size(entry.get('size', 0))}")
for entry in entries[:shown]]
if shown is not None and len(entries) > shown:
listing.append(f" ... and {len(entries) - shown} more")
screen = terminal_size()[1]
if verbose or len(listing) + len(trees) + PLAN_FRAME_LINES <= screen:
for line in listing:
more = f" ... and {len(entries) - shown} more"
listing.append((more, more))
columns, screen = terminal_size()
# A line wider than the terminal wraps: counted as one, the total the
# listing must leave in view scrolled out of sight.
rows = sum(-(-max(1, cell_width(plain)) // max(1, columns)) for _line, plain in listing)
if verbose or rows + len(trees) + PLAN_FRAME_LINES <= screen:
for line, _plain in listing:
print(line)
else:
largest = sorted(by_system, key=lambda s: (-_bytes(by_system[s]), s))
@@ -6719,7 +6733,7 @@ def _print_plan(
else _plural(len(largest), 'system'))
print(f" {groups}, the largest first:")
for system in largest[:PLAN_LARGEST_SYSTEMS]:
print(f" {term.bold(system)} {_sized(by_system[system])}")
print(f" {term.bold(titles[system])} {_sized(by_system[system])}")
if len(largest) > PLAN_LARGEST_SYSTEMS:
# Counted as the line above counts: the groups, when it names them.
unit = "group" if "groups" in groups else "system"
+1 -1
View File
@@ -23,7 +23,7 @@ DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/ins
# curl or wget stop on a cut transfer before the hash is read: the site's
# build rewrites this line there (scripts/sitebootstrap.py).
MISMATCH_ADVICE="The download was most likely cut short: try again. Within minutes of an update of this project the two files can come from caches of different ages. Waiting five minutes settles that."
DEFAULT_INSTALL_SHA256="d3bfabb88e93d8ddf991965cd69929e73b0a254550f8f4c86a11ad34fe710a0b"
DEFAULT_INSTALL_SHA256="e7df99e3ac458c7717bd2ca415bc7d3d8701545652cd303ed19de67077531ab2"
MAX_INSTALLER_BYTES=2097152
cleanup() {
+8 -8
View File
@@ -27,8 +27,8 @@
{
"dest": "roms/ports/retrobios/install.py",
"repo_path": "install.py",
"size": 1086137,
"sha256": "d3bfabb88e93d8ddf991965cd69929e73b0a254550f8f4c86a11ad34fe710a0b",
"size": 1087102,
"sha256": "e7df99e3ac458c7717bd2ca415bc7d3d8701545652cd303ed19de67077531ab2",
"executable": false
},
{
@@ -71,8 +71,8 @@
"muos": {
"archive": {
"dest": "ARCHIVE/RetroBIOS.muxapp",
"size": 1139764,
"sha256": "f9b58890f89971a8c0b9850ece3d132955cbc4823230e59a9224f04305055fba"
"size": 1140729,
"sha256": "5091f7a52ce8e2db24d3afa23a2d3e4a035fd3166d0a0389fb207dcc07fa0d3f"
},
"members": [
{
@@ -92,8 +92,8 @@
{
"name": "RetroBIOS/install.py",
"repo_path": "install.py",
"size": 1086137,
"sha256": "d3bfabb88e93d8ddf991965cd69929e73b0a254550f8f4c86a11ad34fe710a0b",
"size": 1087102,
"sha256": "e7df99e3ac458c7717bd2ca415bc7d3d8701545652cd303ed19de67077531ab2",
"executable": false
},
{
@@ -166,8 +166,8 @@
{
"dest": ".config/modules/retrobios/install.py",
"repo_path": "install.py",
"size": 1086137,
"sha256": "d3bfabb88e93d8ddf991965cd69929e73b0a254550f8f4c86a11ad34fe710a0b",
"size": 1087102,
"sha256": "e7df99e3ac458c7717bd2ca415bc7d3d8701545652cd303ed19de67077531ab2",
"executable": false
},
{
+31
View File
@@ -4397,6 +4397,37 @@ class AQuestionLeftWithCtrlDOrCtrlCIsAStop(unittest.TestCase):
self.assertIn("Stopped", out)
class APlanGroupFitsItsLine(unittest.TestCase):
"""Batocera's group of systems sharing MAME's device ROMs was one plan
line of 732 characters: counted as one row, it wrapped to ten and the
total scrolled out of sight."""
def _plan(self, files: list[dict], size: tuple[int, int], verbose: bool = False) -> str:
out = io.StringIO()
with unittest.mock.patch.object(install.shutil, "get_terminal_size",
return_value=os.terminal_size(size)), \
contextlib.redirect_stdout(out):
install._print_plan(files, Path("dest"), install.Terminal(io.StringIO()),
verbose=verbose)
return out.getvalue()
def test_a_wide_group_is_named_by_its_first_two(self):
shared = [f"system-number-{n:02d}" for n in range(40)]
text = self._plan([{"dest": "dev.rom", "size": 1, "systems": shared}], (80, 40))
self.assertIn("system-number-00, system-number-01 and 38 more systems", text)
self.assertLess(max(map(len, text.splitlines())), 80)
self.assertIn("system-number-39", self._plan(
[{"dest": "dev.rom", "size": 1, "systems": shared}], (80, 40), verbose=True))
def test_wrapped_rows_count_against_the_screen(self):
# Six lines that each wrap to three rows on a 20-column terminal of
# 20 rows: 18 rows of listing, past what the screen leaves it.
files = [{"dest": f"{'x' * 50}{n}.bin", "size": 1, "systems": [f"s{n}"]}
for n in range(3)]
text = self._plan(files, (20, 20))
self.assertIn("the largest first", text)
class ReadersAreThePlatformsCores(unittest.TestCase):
"""--check said bbcb.zip is "read by clk, mame, mame0258, mame0278" on
Batocera: system_cores reaches every profile, Recalbox's builds too."""