mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-11 12:33:53 -06:00
feat: line mode says details only with --verbose
By default a run prints what it installs, the BIOS folder, the progress at a terminal, the result and the next step. The steps, the per-file log lines, the counts and the reasons a file is left out come back with --verbose. --check gives the count and the folder, and lists each file with --verbose. The installer page shows the default run and walks through the --verbose one.
This commit is contained in:
1 parent
dc5fc93f23
commit
36745abf10
16 files changed
+281
-152
No files matched your search
+1
-1
@@ -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 = "185fa0951fa9a7cce617547c72770819ef4df08ebb3b29857126713083179fe7"
|
||||
$defaultInstallSha256 = "00376e0108c51fc9dbd27470080028be84251b1aa8d7bdfe28db3a71b2eae29e"
|
||||
# The pin above refuses any changed byte: this cap only stops a body that
|
||||
# cannot be the installer (a sign-in portal's page) before it is hashed.
|
||||
$maximumInstallerBytes = 8MB
|
||||
|
||||
+150
-83
@@ -494,6 +494,25 @@ class Terminal:
|
||||
return self.paint(text, "strong")
|
||||
|
||||
|
||||
class _Output:
|
||||
"""What a run's text says. By default: what will happen, where, the
|
||||
progress, the result and the next step. --verbose adds every step, list
|
||||
and reason, the lines a beginner lost the result among. where_said is
|
||||
set once the BIOS folder was named before the result."""
|
||||
|
||||
verbose = False
|
||||
where_said = False
|
||||
|
||||
|
||||
OUTPUT = _Output()
|
||||
|
||||
|
||||
def detail(*args: Any, **kwargs: Any) -> None:
|
||||
"""Print a line only --verbose shows."""
|
||||
if OUTPUT.verbose:
|
||||
print(*args, **kwargs)
|
||||
|
||||
|
||||
def format_duration(seconds: float) -> str:
|
||||
"""0:42, 3:05 or 1:02:09."""
|
||||
seconds = max(0, int(seconds + 0.5))
|
||||
@@ -521,8 +540,8 @@ class Progress:
|
||||
"""Bytes and files across the parallel downloads, shown as they move.
|
||||
|
||||
On a terminal one line redraws in place: a bar, the bytes, the speed and
|
||||
the time left. Elsewhere each finished file gets its line, as a log
|
||||
wants it. Failures are always printed, quiet or not.
|
||||
the time left. Elsewhere each finished file gets its line with --verbose,
|
||||
as a log wants it. Failures are always printed, quiet or not.
|
||||
"""
|
||||
|
||||
BAR = 24
|
||||
@@ -601,7 +620,7 @@ class Progress:
|
||||
why = f" ({reason})" if reason else ""
|
||||
line = f" {self.term.bad('FAILED')} {dest}{why}"
|
||||
SAID_FAILED.add(dest)
|
||||
elif not self.term.live and not self.term.quiet:
|
||||
elif not self.term.live and not self.term.quiet and OUTPUT.verbose:
|
||||
line = f" [{self.files}/{self.total_files}] {dest} {self.term.ok('ok')}"
|
||||
if line is not None:
|
||||
self._clear()
|
||||
@@ -5228,7 +5247,7 @@ def say_saves(plat: str, files: list[dict], omitted: list[dict], bios_path: Path
|
||||
if printed:
|
||||
return
|
||||
for line in save_lines([], omitted, bios_path, display):
|
||||
print(f" {line}")
|
||||
detail(f" {line}")
|
||||
|
||||
|
||||
# The digests the line menu's head read of the files in place, by path and
|
||||
@@ -5701,8 +5720,9 @@ def _kept_lines() -> list[str]:
|
||||
lines.append(f"Kept {_plural(item['files'], 'file')} already there "
|
||||
f"({format_size(item['bytes'])}), which the collection's "
|
||||
f"copies replaced, in {folder}")
|
||||
lines.append(f" To put them back: {_INVOCATION.launcher()} --restore "
|
||||
f"{_INVOCATION.word(str(folder))}")
|
||||
if OUTPUT.verbose:
|
||||
lines.append(f" To put them back: {_INVOCATION.launcher()} --restore "
|
||||
f"{_INVOCATION.word(str(folder))}")
|
||||
return lines
|
||||
|
||||
|
||||
@@ -6634,7 +6654,7 @@ def _report_outcome(
|
||||
# The command making the same choice ends every result the screen ends
|
||||
# with it: "Finished with files missing" gave none.
|
||||
same_lines = ([f"Same choice without questions: {screen_text(same_choice)}"]
|
||||
if same_choice else [])
|
||||
if same_choice and OUTPUT.verbose else [])
|
||||
# A file --offline left out is not a failure, whether the run asked or
|
||||
# not: without questions it was "14698 files failed", and "Run the same
|
||||
# command again to retry only those", which cannot fetch them.
|
||||
@@ -6644,7 +6664,7 @@ def _report_outcome(
|
||||
if not isinstance(failure[1], OfflineReason)]
|
||||
errors = max(0, errors - len(left))
|
||||
offline += len(left)
|
||||
if transferred and seconds > 0:
|
||||
if transferred and seconds > 0 and OUTPUT.verbose:
|
||||
verb = "copied from the pack" if LOCAL.pack is not None else "downloaded"
|
||||
say(f"\n{format_size(transferred)} {verb} in "
|
||||
f"{format_duration(seconds)} ({format_size(int(transferred / seconds))}/s).")
|
||||
@@ -6723,7 +6743,7 @@ def _report_outcome(
|
||||
# The kinds installed, on every end that installed some, under where
|
||||
# they came from: as the screen's result says them.
|
||||
installed_kinds = (f" Installed: {installed_words(kinds[0].bios, kinds[0].games, kinds[1])}."
|
||||
if kinds and kinds[0].files and downloaded else "")
|
||||
if kinds and kinds[0].files and downloaded and OUTPUT.verbose else "")
|
||||
if offline:
|
||||
remedy = _offline_remedy()
|
||||
if not downloaded and not errors:
|
||||
@@ -6829,25 +6849,43 @@ def _report_outcome(
|
||||
say(f" {sources}")
|
||||
if installed_kinds:
|
||||
say(installed_kinds)
|
||||
say(f"BIOS folder: {_locations(paths)}")
|
||||
if OUTPUT.verbose or not OUTPUT.where_said:
|
||||
say(f"BIOS folder: {_locations(paths)}")
|
||||
for line in kept:
|
||||
say(line)
|
||||
if omitted > len(unplaced):
|
||||
if omitted > len(unplaced) and OUTPUT.verbose:
|
||||
for line in _omission_lines(omitted - len(unplaced),
|
||||
[entry for entry in omitted_entries or []
|
||||
if entry.get("reason") != "no_save_directory"],
|
||||
Path(paths[0]) if len(paths) == 1 else None):
|
||||
say(line)
|
||||
# RomM's scan is the step after the install: the other hints say how to
|
||||
# install less, a detail.
|
||||
for line in hints or []:
|
||||
say(line)
|
||||
if same_choice:
|
||||
if OUTPUT.verbose or line == ROMM_SCAN_WORDS:
|
||||
say(line)
|
||||
if same_choice and OUTPUT.verbose:
|
||||
# After the questions, as the screen's result ends: "the same
|
||||
# command" was one that asked them.
|
||||
for line in same_lines:
|
||||
say(line)
|
||||
say("To check this later, run that command with --check.")
|
||||
return
|
||||
say("To check this later, run the same command with --check.")
|
||||
elif OUTPUT.verbose:
|
||||
say("To check this later, run the same command with --check.")
|
||||
say(next_step_words(platform_of or {}, paths))
|
||||
|
||||
|
||||
def next_step_words(platform_of: dict[Path, str], paths: list[Path]) -> str:
|
||||
"""The step after an install that ended well: a card goes back in its
|
||||
device, a setup on this machine is started."""
|
||||
setups = [(platform_of.get(path, ""), path) for path in paths]
|
||||
if setups and all(plat and on_its_card(plat, path) for plat, path in setups):
|
||||
return "Next: put the card back in the device and start a game."
|
||||
names = list(dict.fromkeys(detected_os(plat, path) or display_name(plat)
|
||||
for plat, path in setups if plat))
|
||||
if len(names) == 1:
|
||||
return f"Next: start {names[0]} and play."
|
||||
return "Next: start your emulators and play."
|
||||
|
||||
|
||||
def _offline_remedy(folders: list[str] | None = None, named: bool = False) -> str:
|
||||
@@ -6904,8 +6942,10 @@ def _check_fetch_line(fetch: int, beside: str, lacking: int = 0) -> str:
|
||||
return " Run the same command without --check to copy them into place."
|
||||
return (f" {agree(fetch, 'file needs', 'files need')} the "
|
||||
f"internet, which {offline_named()} does not use. {_offline_remedy()}")
|
||||
return (" Run the same command without --check to fetch them. A wrong copy is "
|
||||
f"replaced, and the one in place kept in {BACKUP_DIR} beside {beside}.")
|
||||
# Why nothing is lost goes with the details: the remedy is the line.
|
||||
return (" Run the same command without --check to fetch them."
|
||||
+ (f" A wrong copy is replaced, and the one in place kept in {BACKUP_DIR} "
|
||||
f"beside {beside}." if OUTPUT.verbose else ""))
|
||||
|
||||
|
||||
def _offline_failure(reason: str) -> bool:
|
||||
@@ -11335,7 +11375,7 @@ def read_games(args: argparse.Namespace, plat: str, bios_path: Path, manifest: d
|
||||
os_type=os_type):
|
||||
return None
|
||||
where = "on the card" if folder is None else f"in {folder}"
|
||||
print(f"\nReading the games {where}...")
|
||||
detail(f"\nReading the games {where}...")
|
||||
try:
|
||||
plan = plan_games(plat, bios_path, manifest, folder, term, os_type=os_type,
|
||||
network=network)
|
||||
@@ -11356,7 +11396,7 @@ def read_games(args: argparse.Namespace, plat: str, bios_path: Path, manifest: d
|
||||
return None
|
||||
emit_games(plat, plan, bool(args.required_only))
|
||||
for line in games_lines(plan, manifest, bool(args.verbose)):
|
||||
print(fold_line(line if line.startswith(" ") else f" {line}"))
|
||||
detail(fold_line(line if line.startswith(" ") else f" {line}"))
|
||||
return plan
|
||||
|
||||
|
||||
@@ -14017,6 +14057,9 @@ def _run(args: argparse.Namespace) -> None:
|
||||
raise
|
||||
finally:
|
||||
LOCAL.close_indexes()
|
||||
# A caller running the installer in its own process gets the next
|
||||
# run's text as quiet as any first run.
|
||||
OUTPUT.verbose = OUTPUT.where_said = False
|
||||
|
||||
|
||||
def _run_text(args: argparse.Namespace) -> None:
|
||||
@@ -14268,8 +14311,10 @@ def _missing_dest(dest: Path, ask: bool, named: str = "named with --dest",
|
||||
while not nearest.exists() and nearest.parent != nearest:
|
||||
nearest = nearest.parent
|
||||
missing = len(dest.absolute().relative_to(nearest).parts)
|
||||
print(f" {shown_path(dest)} does not exist. The nearest folder that does: "
|
||||
f"{shown_path(nearest)}")
|
||||
# Said where it comes before a question: elsewhere the folder is made.
|
||||
(print if missing > 1 and ask else detail)(
|
||||
f" {shown_path(dest)} does not exist. The nearest folder that does: "
|
||||
f"{shown_path(nearest)}")
|
||||
if missing > 1 and ask:
|
||||
answer = _ask(f" Create {_plural(missing, 'folder')} under {shown_path(nearest)}? [y/N] ")
|
||||
if not answer.strip().lower().startswith("y"):
|
||||
@@ -15334,7 +15379,9 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
print(f"{where}, so nothing is asked: the run goes on as with --no-input. "
|
||||
f"Add --no-input to say so, or run it without {undo} to answer.",
|
||||
file=sys.stderr)
|
||||
print(f"{term.bold('RetroBIOS')} {term.dim(installer_id())}\n")
|
||||
OUTPUT.verbose = bool(getattr(args, "verbose", False))
|
||||
OUTPUT.where_said = False
|
||||
detail(f"{term.bold('RetroBIOS')} {term.dim(installer_id())}\n")
|
||||
|
||||
os_type = detect_os()
|
||||
if os_type == "wsl":
|
||||
@@ -15382,7 +15429,7 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
if args.platform and args.dest:
|
||||
platforms = [(args.platform, args.dest)]
|
||||
elif args.platform:
|
||||
print("Looking for setups here...")
|
||||
detail("Looking for setups here...")
|
||||
if not listing:
|
||||
# The cards mounted here too, as the screen finds them, with or
|
||||
# without questions: a pack's RetroArch list went to this
|
||||
@@ -15401,7 +15448,7 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
platforms = matched
|
||||
offer = getattr(args, "platform_from_list", False)
|
||||
for name, path in matched:
|
||||
print(fold_line(f" Found {found_label(name, path)}"))
|
||||
detail(fold_line(f" Found {found_label(name, path)}"))
|
||||
elif listing:
|
||||
# A listing reads the manifest and writes nothing: no folder is
|
||||
# needed, and asking BizHawk's for one refused a question asked
|
||||
@@ -15501,16 +15548,16 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
platforms = [(args.platform, default_dest)]
|
||||
assumed_dests.add(default_dest)
|
||||
elif args.dest:
|
||||
print(f" Using destination: {args.dest}")
|
||||
detail(f" Using destination: {args.dest}")
|
||||
plat, args.dest = _platform_for_dest(os_type, args.dest, interactive and not listing)
|
||||
platforms = [(plat, args.dest)]
|
||||
else:
|
||||
print("Looking for setups here...")
|
||||
detail("Looking for setups here...")
|
||||
frontends = detect_frontends(os_type)
|
||||
if "esde" in frontends:
|
||||
print(" Found ES-DE (BIOS files go to each emulator, not to ES-DE itself)")
|
||||
detail(" Found ES-DE (BIOS files go to each emulator, not to ES-DE itself)")
|
||||
if "launchbox" in frontends:
|
||||
print(" Found LaunchBox")
|
||||
detail(" Found LaunchBox")
|
||||
if not listing:
|
||||
# A card mounted here is found as the screen finds it, in every
|
||||
# mode: line mode said "No supported platform detected" beside
|
||||
@@ -15553,7 +15600,7 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
offer = False
|
||||
else:
|
||||
for name, path in platforms:
|
||||
print(fold_line(f" Found {found_label(name, path)}"))
|
||||
detail(fold_line(f" Found {found_label(name, path)}"))
|
||||
|
||||
if len(platforms) > 1 and not interactive and not listing:
|
||||
# A run without questions installs for one setup, the one a person
|
||||
@@ -15674,11 +15721,11 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
if bios_path not in installed_paths:
|
||||
installed_paths.append(bios_path)
|
||||
if LOCAL.manifest is not None:
|
||||
print(f"\nReading the file index for {plat_name} from {LOCAL.manifest}...")
|
||||
detail(f"\nReading the file index for {plat_name} from {LOCAL.manifest}...")
|
||||
elif LOCAL.pack is not None:
|
||||
print(f"\nReading the file index for {plat_name} from {LOCAL.pack.name}...")
|
||||
detail(f"\nReading the file index for {plat_name} from {LOCAL.pack.name}...")
|
||||
else:
|
||||
print(f"\nFetching file index for {plat_name}...")
|
||||
detail(f"\nFetching file index for {plat_name}...")
|
||||
manifest = fetch_manifest(plat_name)
|
||||
categorized = categorized or bool(manifest.get("categorized"))
|
||||
files = manifest.get("files", [])
|
||||
@@ -15696,7 +15743,7 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
# spelling overwrote the first, and every --check found one
|
||||
# of them wrong and fetched it again.
|
||||
shown = ", ".join(folded[:3]) + (" ..." if len(folded) > 3 else "")
|
||||
print(
|
||||
detail(
|
||||
f" {_plural(len(folded), 'file')} left out: {bios_path} does not keep "
|
||||
f"case and holds another file under the same name ({shown})"
|
||||
)
|
||||
@@ -15704,7 +15751,7 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
and not holds_fat_refused_names(bios_path):
|
||||
files, refused = split_fat_refused(files)
|
||||
shown = ", ".join(refused[:3]) + (" ..." if len(refused) > 3 else "")
|
||||
print(
|
||||
detail(
|
||||
f" {_plural(len(refused), 'file')} left out: the file system of "
|
||||
f"{shown_path(bios_path)} cannot hold a name with any of "
|
||||
f"{FAT_REFUSED_SHOWN} ({screen_text(shown)})"
|
||||
@@ -15722,7 +15769,7 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
if args.declared_only:
|
||||
before = len(files)
|
||||
files, omitted_files = keep_declared(files, omitted_files)
|
||||
print(f" The platform's own list: {before} to {len(files)} files "
|
||||
detail(f" The platform's own list: {before} to {len(files)} files "
|
||||
"(--declared-only)")
|
||||
|
||||
if args.list_targets:
|
||||
@@ -15761,7 +15808,7 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
words = (f"Board {board} {where} has no "
|
||||
f"{PLATFORM_NAMES.get(plat_name, plat_name)} core list: "
|
||||
"installing the files of every board")
|
||||
print(f" {words}")
|
||||
detail(f" {words}")
|
||||
EVENTS.emit("board", platform=plat_name, board=board,
|
||||
applied=target == board, message=words)
|
||||
if target:
|
||||
@@ -15777,7 +15824,7 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
# the subset the target needs. Refuse rather than ignore.
|
||||
_unknown_target(target, plat_name, targets)
|
||||
elif target_info.get("cores") is None:
|
||||
print(
|
||||
detail(
|
||||
f" Target '{target}' publishes no core list: "
|
||||
"installing every file"
|
||||
)
|
||||
@@ -15786,13 +15833,13 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
files, omitted_files = narrow_to_cores(
|
||||
manifest, target_info["cores"], files, omitted_files
|
||||
)
|
||||
print(f" Filtered {before} to {len(files)} files for target {target}")
|
||||
detail(f" Filtered {before} to {len(files)} files for target {target}")
|
||||
|
||||
found_cores = cores_found.get((plat_name, bios_path), [])
|
||||
if "system_cores" not in manifest:
|
||||
found_cores = []
|
||||
elif found_cores:
|
||||
print(f" {_plural(len(found_cores), 'core')} installed")
|
||||
detail(f" {_plural(len(found_cores), 'core')} installed")
|
||||
if args.installed_cores:
|
||||
if "system_cores" not in manifest:
|
||||
print(
|
||||
@@ -15806,7 +15853,7 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
files, omitted_files = narrow_to_cores(
|
||||
manifest, found_cores, files, omitted_files
|
||||
)
|
||||
print(f" Narrowed {before} to {len(files)} files to the installed cores")
|
||||
detail(f" Narrowed {before} to {len(files)} files to the installed cores")
|
||||
|
||||
if args.list_emulators:
|
||||
_print_emulators(plat_name, manifest, *(
|
||||
@@ -15863,10 +15910,10 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
files, omitted_files = games_plan.apply(files, omitted_files, args.required_only)
|
||||
unplaced = games_plan.apply([], unplaced, args.required_only)[1]
|
||||
games_applied = True
|
||||
print(f" For the games: {_plural(len(files), 'file')} of the list"
|
||||
+ (f", {GAMES_REQUIRED_WORDS}" if args.required_only else ""))
|
||||
detail(f" For the games: {_plural(len(files), 'file')} of the list"
|
||||
+ (f", {GAMES_REQUIRED_WORDS}" if args.required_only else ""))
|
||||
if args.for_games is None:
|
||||
print(" The card holds games, so only what they need is installed. "
|
||||
detail(" The card holds games, so only what they need is installed. "
|
||||
"--all-files installs the whole list.")
|
||||
version_notes += [line.strip() for line in fallback_lines(games_plan)]
|
||||
# --no-game-data leaves the game data out once the list is narrowed
|
||||
@@ -15934,6 +15981,8 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
if args.no_game_data else "",
|
||||
None if games_applied else games_plan,
|
||||
)
|
||||
# Its head named the BIOS folder: the result does not again.
|
||||
OUTPUT.where_said = True
|
||||
if selection is None and LOCAL.pack is not None:
|
||||
smaller = " Nothing copied."
|
||||
elif selection is None:
|
||||
@@ -15972,7 +16021,7 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
if len(files) != before and not menu:
|
||||
# Enter for every system narrows nothing: "Narrowed 23 to 23".
|
||||
# The menu counted the choice again before Enter.
|
||||
print(f" Narrowed {before} to {len(files)} files")
|
||||
detail(f" Narrowed {before} to {len(files)} files")
|
||||
if (cut and cut[0]) or args.no_game_data:
|
||||
# Left out at g or by --no-game-data, from what the choice kept:
|
||||
# g offered the game data of the systems chosen, and the line
|
||||
@@ -15985,7 +16034,7 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
_INVOCATION.chosen[plat_name] = (_INVOCATION.chosen.get(plat_name, [])
|
||||
+ [("--no-game-data", None)])
|
||||
for line in _left_out_lines(left_out, args.verbose):
|
||||
print(line)
|
||||
detail(line)
|
||||
if unplaced:
|
||||
total_omitted += len(unplaced)
|
||||
omitted_seen.extend(unplaced)
|
||||
@@ -16022,18 +16071,18 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
if not menu:
|
||||
# An answered menu said these lines right above: the run head
|
||||
# repeated them under it.
|
||||
print(f" {_plural(run_counts.files + head_data, 'file')} "
|
||||
f"({format_size(run_counts.size + head_bytes)})")
|
||||
detail(f" {_plural(run_counts.files + head_data, 'file')} "
|
||||
f"({format_size(run_counts.size + head_bytes)})")
|
||||
categorized_list = bool(manifest.get("categorized"))
|
||||
kinds = run_counts if categorized_list else tally(
|
||||
{"size": entry.get("size")} for entry in files)
|
||||
parts = parts_words(kinds, head_data, head_bytes, game_data_cut)
|
||||
if parts:
|
||||
print(f" {parts}.")
|
||||
detail(f" {parts}.")
|
||||
defined = kinds_definition(
|
||||
categorized_list and bool(run_counts.games or game_data_cut), bool(head_data))
|
||||
if defined:
|
||||
print(f" {defined}")
|
||||
detail(f" {defined}")
|
||||
# A choice that keeps no file says so where "All files up to date"
|
||||
# was said of it.
|
||||
empty_choice = "" if run_counts.files or not (selection or game_data_cut) else (
|
||||
@@ -16051,7 +16100,7 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
for entry in omitted_files:
|
||||
reason = entry.get("reason", "unknown")
|
||||
reasons[reason] = reasons.get(reason, 0) + 1
|
||||
print(f" {not_installable_words(len(omitted_files), required_omitted, reasons)}")
|
||||
detail(f" {not_installable_words(len(omitted_files), required_omitted, reasons)}")
|
||||
total_omitted += len(omitted_files)
|
||||
# Named for the end of the run: ROCKNIX's own list leaves them out,
|
||||
# and the end said "the frontend's save directory".
|
||||
@@ -16071,11 +16120,11 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
files, library = romm_relayout(files, bios_path, *layout)
|
||||
if library != bios_path:
|
||||
installed_paths[installed_paths.index(bios_path)] = library
|
||||
print(f" Firmware laid out as {'/'.join(layout[0] + ('{platform}',) + layout[1])} "
|
||||
f"under {library}")
|
||||
detail(f" Firmware laid out as {'/'.join(layout[0] + ('{platform}',) + layout[1])} "
|
||||
f"under {library}")
|
||||
bios_path = library
|
||||
|
||||
print("\nChecking existing files...")
|
||||
detail("\nChecking existing files...")
|
||||
to_download, up_to_date, mismatched = check_local(
|
||||
files, bios_path, jobs=args.jobs, term=term
|
||||
)
|
||||
@@ -16090,9 +16139,9 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
head_reads_done()
|
||||
trees_missing = sum(len(state[1]) for _entry, state in data_states)
|
||||
trees_held = head_data - trees_missing
|
||||
print(f" {len(up_to_date) + trees_held} in place, "
|
||||
f"{run_counts.files - present + trees_missing} missing, "
|
||||
f"{_plural(wrong, 'wrong copy')}")
|
||||
detail(f" {len(up_to_date) + trees_held} in place, "
|
||||
f"{run_counts.files - present + trees_missing} missing, "
|
||||
f"{_plural(wrong, 'wrong copy')}")
|
||||
|
||||
# A partial copy left by an interrupted run is useless once the file
|
||||
# is in place: it goes.
|
||||
@@ -16157,14 +16206,18 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
# One total with the count above it, the data files among
|
||||
# them as the screen counts them: "0 in place, 10805 missing"
|
||||
# stood over "8164 files to download".
|
||||
# The count and the folder by default, each file with
|
||||
# --verbose: 20 paths hid the line saying what to do.
|
||||
print(f"\n {_plural(len(to_download) + trees_missing, 'file')} "
|
||||
+ ("not in place:" if offline or LOCAL.pack is not None
|
||||
else "to download:"))
|
||||
+ ("not in place" if offline or LOCAL.pack is not None
|
||||
else "to download") + (":" if OUTPUT.verbose else "."))
|
||||
for line in check_lines(missing, mismatched, files, manifest, bios_path,
|
||||
args.verbose, up_to_date, bios_index, copies):
|
||||
print(line)
|
||||
detail(line)
|
||||
for line in unreadable_lines(unread, args.verbose):
|
||||
print(line)
|
||||
if not OUTPUT.verbose:
|
||||
print(f" BIOS folder: {shown_path(bios_path)}")
|
||||
# The data files need the internet too: offline, "8164 files
|
||||
# need the internet" stood under "10805 files not in place".
|
||||
trees_fetched = trees_missing if LOCAL.pack is None else 0
|
||||
@@ -16177,6 +16230,7 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
print(f"\n {_plural(trees_missing, 'data file')} to fetch")
|
||||
else:
|
||||
print(f"\n {EVERYTHING_IN_PLACE}")
|
||||
print(f" BIOS folder: {shown_path(bios_path)}")
|
||||
absent = _absent_required(omitted_files, bios_path)
|
||||
# The collection cannot supply these, so they leave the exit
|
||||
# code alone, but a user asking why a game will not start needs
|
||||
@@ -16185,11 +16239,11 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
absent, "Not in the collection and absent here, needed to start an emulator",
|
||||
every=args.verbose,
|
||||
):
|
||||
print(line)
|
||||
detail(line)
|
||||
for entry, (_root, needed, present) in data_states:
|
||||
if needed:
|
||||
print(f" {entry['ref']}: {present}/{len(entry['files'])} data files "
|
||||
f"present, {len(needed)} to fetch")
|
||||
detail(f" {entry['ref']}: {present}/{len(entry['files'])} data files "
|
||||
f"present, {len(needed)} to fetch")
|
||||
check_pending += len(needed)
|
||||
continue
|
||||
|
||||
@@ -16280,15 +16334,28 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
files_pending += len(to_download)
|
||||
continue
|
||||
EVENTS.emit("download", platform=plat_name, files=len(to_download), bytes=dl_size)
|
||||
if not menu:
|
||||
# What happens and where, the two lines a run without questions
|
||||
# opens on: the menu's head said them where it was asked.
|
||||
coming = len(to_download) - len(lacking) + trees_missing
|
||||
weight = dl_size + sum(data_fetch_bytes(entry, state[1])
|
||||
for entry, state in data_states)
|
||||
print(f"\nInstalling {_plural(coming, 'file')} ({format_size(weight)}) for "
|
||||
f"{detected_os(plat_name, bios_path) or display}"
|
||||
+ (", what the games need" if games_applied else "") + ".")
|
||||
print(f"BIOS folder: {shown_path(bios_path)}")
|
||||
OUTPUT.where_said = True
|
||||
if unread:
|
||||
# A file of the user's that could not be read is said in
|
||||
# every mode: it was expected to be copied.
|
||||
print()
|
||||
for line in unreadable_lines(unread, args.verbose):
|
||||
print(line)
|
||||
if copies:
|
||||
print()
|
||||
detail()
|
||||
for line in copy_plan_lines(to_download, copies, bios_index, bios_path,
|
||||
files, args.verbose, False):
|
||||
print(line)
|
||||
detail(line)
|
||||
held = len(fetched) - len(lacking)
|
||||
rest = (f" and {'copying' if LOCAL.pack is not None else 'downloading'} "
|
||||
f"{held}" if held else "")
|
||||
@@ -16303,17 +16370,17 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
# The size beside what it weighs: after "and downloading
|
||||
# 19" it read as theirs alone.
|
||||
sized = f" ({format_size(dl_size)})"
|
||||
print(f"\nCopying {_plural(len(copies), 'file')}{'' if rest else sized} "
|
||||
f"{origin}{rest}{where}{sized if rest else ''}...")
|
||||
detail(f"\nCopying {_plural(len(copies), 'file')}{'' if rest else sized} "
|
||||
f"{origin}{rest}{where}{sized if rest else ''}...")
|
||||
elif LOCAL.pack is not None:
|
||||
# The files the pack holds: "Copying 23 files (85.0 KB)" sat
|
||||
# beside the size of 20.
|
||||
print(f"\nCopying {_plural(len(to_download) - len(lacking), 'file')} "
|
||||
f"({format_size(dl_size)}) from {LOCAL.pack.name}...")
|
||||
detail(f"\nCopying {_plural(len(to_download) - len(lacking), 'file')} "
|
||||
f"({format_size(dl_size)}) from {LOCAL.pack.name}...")
|
||||
else:
|
||||
print(f"\nDownloading {len(to_download)} files ({format_size(dl_size)})...")
|
||||
print(" Press Ctrl+C to stop. Running the same command again "
|
||||
"carries on from here.")
|
||||
detail(f"\nDownloading {len(to_download)} files ({format_size(dl_size)})...")
|
||||
detail(" Press Ctrl+C to stop. Running the same command again "
|
||||
"carries on from here.")
|
||||
# Checked before the folder is created: a run stopped for space
|
||||
# left an empty BIOS folder behind. The data trees count too,
|
||||
# written after the files on the same drive.
|
||||
@@ -16345,7 +16412,7 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
# of the run installed something.
|
||||
sys.exit(1 if total_downloaded else 2)
|
||||
if created:
|
||||
print(f" Created {shown_path(bios_path)}")
|
||||
detail(f" Created {shown_path(bios_path)}")
|
||||
progress = Progress(len(to_download), dl_size, term)
|
||||
failed, interrupted = download_files(
|
||||
to_download, bios_path, jobs=args.jobs, verbose=args.verbose,
|
||||
@@ -16404,7 +16471,7 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
1 if total_downloaded else 2,
|
||||
on_its_card(plat_name, bios_path))
|
||||
if writable:
|
||||
print("\nData directories:")
|
||||
detail("\nData directories:")
|
||||
for entry, state in writable:
|
||||
# Its archive is drawn as the BIOS files were, and counted
|
||||
# in the bytes and time the run ends on: 82 MB came in
|
||||
@@ -16424,9 +16491,9 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
if isinstance(counts["error"], OfflineReason):
|
||||
# Left out as the BIOS files above are: counted missing,
|
||||
# not as one failure per tree.
|
||||
print(f" {entry['ref']}: {counts['present']} already in place, "
|
||||
f"{agree(counts['absent'], 'needs', 'need')} the internet "
|
||||
f"({offline_named()})")
|
||||
detail(f" {entry['ref']}: {counts['present']} already in place, "
|
||||
f"{agree(counts['absent'], 'needs', 'need')} the internet "
|
||||
f"({offline_named()})")
|
||||
total_offline += counts["absent"]
|
||||
files_pending += counts["absent"]
|
||||
continue
|
||||
@@ -16442,7 +16509,7 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
f"{LOCAL.pack.name}" if LOCAL.pack is not None else
|
||||
f", {counts['changed'] + counts['absent']} no longer in "
|
||||
"the source (the pack has them)")
|
||||
print(line)
|
||||
detail(line)
|
||||
if counts["error"] in (NOT_WRITABLE, DRIVE_FULL):
|
||||
if counts["error"] == DRIVE_FULL:
|
||||
print(f" {entry['ref']}: {DRIVE_FULL} ({shown_path(bios_path)})",
|
||||
@@ -16461,8 +16528,8 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
total_errors += 1
|
||||
|
||||
if os_type == "android" and not args.check and hide_from_media_scanner(bios_path):
|
||||
print(f" Added {NOMEDIA} to {shown_path(bios_path)}: the gallery and music "
|
||||
"apps leave its images, sounds and videos out")
|
||||
detail(f" Added {NOMEDIA} to {shown_path(bios_path)}: the gallery and music "
|
||||
"apps leave its images, sounds and videos out")
|
||||
|
||||
# Standalone copies
|
||||
if (
|
||||
@@ -16490,11 +16557,11 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
manifest, os_type, launchbox_bios_dirs(lb_root) if lb_root else None
|
||||
)
|
||||
if folders:
|
||||
print("\nStandalone emulator folders found here:")
|
||||
detail("\nStandalone emulator folders found here:")
|
||||
for folder in folders:
|
||||
print(f" {folder}")
|
||||
print(" --standalone-copies also copies the BIOS files and keys "
|
||||
"they read into them.")
|
||||
detail(f" {folder}")
|
||||
detail(" --standalone-copies also copies the BIOS files and keys "
|
||||
"they read into them.")
|
||||
|
||||
sys.stdout = real_stdout
|
||||
if not listing:
|
||||
|
||||
+1
-1
@@ -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="185fa0951fa9a7cce617547c72770819ef4df08ebb3b29857126713083179fe7"
|
||||
DEFAULT_INSTALL_SHA256="00376e0108c51fc9dbd27470080028be84251b1aa8d7bdfe28db3a71b2eae29e"
|
||||
# The pin above refuses any changed byte: this cap only stops a body that
|
||||
# cannot be the installer (a sign-in portal's page) before it is hashed.
|
||||
MAX_INSTALLER_BYTES=8388608
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
{
|
||||
"dest": "roms/ports/retrobios/install.py",
|
||||
"repo_path": "install.py",
|
||||
"size": 1132111,
|
||||
"sha256": "185fa0951fa9a7cce617547c72770819ef4df08ebb3b29857126713083179fe7",
|
||||
"size": 1135666,
|
||||
"sha256": "00376e0108c51fc9dbd27470080028be84251b1aa8d7bdfe28db3a71b2eae29e",
|
||||
"executable": false
|
||||
},
|
||||
{
|
||||
@@ -71,8 +71,8 @@
|
||||
"muos": {
|
||||
"archive": {
|
||||
"dest": "ARCHIVE/RetroBIOS.muxapp",
|
||||
"size": 1185736,
|
||||
"sha256": "cb245dc33b894a9720ae3734bf55512c2b0fca99e0bd33e8c12a72738085f5cc"
|
||||
"size": 1189291,
|
||||
"sha256": "c56ce912e436173542905c89c1aee7de025f93bea5df130ab51e589c071f6369"
|
||||
},
|
||||
"members": [
|
||||
{
|
||||
@@ -92,8 +92,8 @@
|
||||
{
|
||||
"name": "RetroBIOS/install.py",
|
||||
"repo_path": "install.py",
|
||||
"size": 1132111,
|
||||
"sha256": "185fa0951fa9a7cce617547c72770819ef4df08ebb3b29857126713083179fe7",
|
||||
"size": 1135666,
|
||||
"sha256": "00376e0108c51fc9dbd27470080028be84251b1aa8d7bdfe28db3a71b2eae29e",
|
||||
"executable": false
|
||||
},
|
||||
{
|
||||
@@ -166,8 +166,8 @@
|
||||
{
|
||||
"dest": ".config/modules/retrobios/install.py",
|
||||
"repo_path": "install.py",
|
||||
"size": 1132111,
|
||||
"sha256": "185fa0951fa9a7cce617547c72770819ef4df08ebb3b29857126713083179fe7",
|
||||
"size": 1135666,
|
||||
"sha256": "00376e0108c51fc9dbd27470080028be84251b1aa8d7bdfe28db3a71b2eae29e",
|
||||
"executable": false
|
||||
},
|
||||
{
|
||||
|
||||
@@ -444,14 +444,14 @@ class Sandbox:
|
||||
with zipfile.ZipFile(system / "PSX BIOS.zip", "w") as archive:
|
||||
archive.writestr("extra.bin", data["pcsx/extra.bin"])
|
||||
# A check that flags a file ends on 3, as documented.
|
||||
return self.run("retroarch", "--check", "--manifest", str(listed), home=home,
|
||||
codes=(3,))
|
||||
return self.run("retroarch", "--check", "--verbose", "--manifest", str(listed),
|
||||
home=home, codes=(3,))
|
||||
old = home / "old"
|
||||
old.mkdir()
|
||||
for dest in ("scph5500.bin", "scph5501.bin"):
|
||||
(old / dest).write_bytes(data[dest])
|
||||
return self.run("retroarch", "--yes", "--manifest", str(listed), "--from", str(old),
|
||||
home=home, landed=True)
|
||||
return self.run("retroarch", "--yes", "--verbose", "--manifest", str(listed),
|
||||
"--from", str(old), home=home, landed=True)
|
||||
|
||||
def run(self, platform: str, *argv: str, landed: bool = False,
|
||||
held: bool = False, home: Path | None = None, codes: tuple = (0,)) -> str:
|
||||
@@ -551,7 +551,7 @@ BULK_SYSTEM = "sony-playstation"
|
||||
|
||||
|
||||
def _bulk_line(box: Sandbox | _LazySandbox) -> str:
|
||||
run = box.run("retroarch", "--dry-run", "--system", BULK_SYSTEM)
|
||||
run = box.run("retroarch", "--dry-run", "--verbose", "--system", BULK_SYSTEM)
|
||||
found = [line for line in run.splitlines() if re.match(r" \S+ pulls ", line)]
|
||||
if len(found) != 1:
|
||||
raise SampleFailed(f"a RetroArch run with --system {BULK_SYSTEM} names no core "
|
||||
@@ -560,11 +560,17 @@ def _bulk_line(box: Sandbox | _LazySandbox) -> str:
|
||||
|
||||
|
||||
def sample_writers(box: Sandbox) -> dict[str, Callable[[str], str]]:
|
||||
"""The run samples, each from the run that prints it."""
|
||||
install_run = lambda: box.run(WALKTHROUGH, "--yes", "--jobs", "1", landed=True) # noqa: E731
|
||||
check_run = lambda: box.run(WALKTHROUGH, "--check", held=True) # noqa: E731
|
||||
dry_run = lambda: box.run("retroarch", "--dry-run") # noqa: E731
|
||||
"""The run samples, each from the run that prints it: the walk through a
|
||||
run reads its --verbose lines, the default sample the lines it hides them
|
||||
from."""
|
||||
default_run = lambda: box.run(WALKTHROUGH, "--yes", "--jobs", "1", landed=True) # noqa: E731
|
||||
install_run = lambda: box.run(WALKTHROUGH, "--yes", "--jobs", "1", "--verbose", # noqa: E731
|
||||
landed=True)
|
||||
check_run = lambda: box.run(WALKTHROUGH, "--check", "--verbose", held=True) # noqa: E731
|
||||
dry_run = lambda: box.run("retroarch", "--dry-run", "--verbose") # noqa: E731
|
||||
return {
|
||||
"run-default": lambda _body: _fenced(
|
||||
_lines_from(default_run(), "Installing ", "Next: ")),
|
||||
"dry-run": lambda _body: (
|
||||
f"A RetroArch dry run into an empty folder, with the list of "
|
||||
f"{list_date('retroarch')}, printed this:\n\n"
|
||||
|
||||
@@ -201,7 +201,7 @@ class InstallerSamplesSayWhatTheCodePrints(unittest.TestCase):
|
||||
at = page.index("<!-- generated: run-download -->")
|
||||
before = page[page.rindex("\n\n", 0, at - 2):at]
|
||||
self.assertIn("At a terminal one progress line", before)
|
||||
self.assertIn("A pipe or a log gets one line per file", before)
|
||||
self.assertIn("a pipe or a log gets one\nline per file", before)
|
||||
|
||||
def test_the_generator_pages_name_the_run_samples_and_step_7(self):
|
||||
tools = _page("tools.md")
|
||||
|
||||
+29
-15
@@ -331,11 +331,16 @@ class TestRunOutcome(unittest.TestCase):
|
||||
return buf.getvalue(), code
|
||||
|
||||
def test_success_names_the_location_and_the_way_to_check(self):
|
||||
install.OUTPUT.verbose = install.OUTPUT.where_said = False
|
||||
out, code = self._report(downloaded=12, up_to_date=3)
|
||||
self.assertEqual(code, 0)
|
||||
self.assertIn("12 files installed", out)
|
||||
self.assertIn("/userdata/bios", out)
|
||||
self.assertIn("--check", out)
|
||||
self.assertIn("Next: ", out)
|
||||
self.assertNotIn("--check", out)
|
||||
self.addCleanup(setattr, install.OUTPUT, "verbose", False)
|
||||
install.OUTPUT.verbose = True
|
||||
self.assertIn("--check", self._report(downloaded=12, up_to_date=3)[0])
|
||||
|
||||
def test_total_failure_does_not_say_done_and_exits_two(self):
|
||||
out, code = self._report(errors=7)
|
||||
@@ -523,7 +528,12 @@ class AMissingDestIsSaid(unittest.TestCase):
|
||||
|
||||
def test_one_missing_level_or_no_terminal_is_said_not_asked(self):
|
||||
root = Path(_tempdir(self))
|
||||
# A "no" that was asked would stop the run with 2.
|
||||
# A "no" that was asked would stop the run with 2. Said with
|
||||
# --verbose: the folder is made, and the run names it.
|
||||
install.OUTPUT.verbose = False
|
||||
self.assertEqual(self._call(root / "bios", True, "n"), ("", None))
|
||||
self.addCleanup(setattr, install.OUTPUT, "verbose", False)
|
||||
install.OUTPUT.verbose = True
|
||||
out, code = self._call(root / "bios", True, "n")
|
||||
self.assertIsNone(code)
|
||||
self.assertIn("does not exist", out)
|
||||
@@ -1512,7 +1522,7 @@ class InstallerStaysOnPython38AndTheStdlib(unittest.TestCase):
|
||||
check=False,
|
||||
)
|
||||
self.assertEqual(proc.returncode, 3, proc.stdout + proc.stderr)
|
||||
self.assertIn("to download:", proc.stdout)
|
||||
self.assertIn("to download.", proc.stdout)
|
||||
|
||||
def test_no_syntax_a_312_parser_lets_through(self):
|
||||
"""Parenthesized context managers (3.9) and f-strings reusing their
|
||||
@@ -2157,7 +2167,7 @@ class TestLaunchboxDetectionPowershell(unittest.TestCase):
|
||||
proc = subprocess.run(
|
||||
[
|
||||
"pwsh", "-NoProfile", "-File",
|
||||
str(REPO_ROOT / "install.ps1"), "--standalone-copies",
|
||||
str(REPO_ROOT / "install.ps1"), "--standalone-copies", "--verbose",
|
||||
],
|
||||
env=env,
|
||||
capture_output=True,
|
||||
@@ -4163,7 +4173,7 @@ class DataDirectoriesAreInstalled(unittest.TestCase):
|
||||
"files": {"Sys/big.bin": {"sha1": hashlib.sha1(member).hexdigest(),
|
||||
"size": len(member)}}}]
|
||||
(repo.root / "install" / "retroarch.json").write_text(json.dumps(listed))
|
||||
proc = repo.run("--no-input")
|
||||
proc = repo.run("--no-input", "--verbose")
|
||||
bios = sum(len(payload) for payload, *_ in FakeRepository.PAYLOADS.values())
|
||||
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
|
||||
self.assertIn(f"{install.format_size(bios + archive)} downloaded in", proc.stdout)
|
||||
@@ -4447,7 +4457,7 @@ class ACheckNamesWhatTheCollectionLacks(unittest.TestCase):
|
||||
}
|
||||
proc = subprocess.run(
|
||||
[sys.executable, "-I", "install.py", "--platform", "recalbox",
|
||||
"--no-input", "--dest", str(home / "bios"), "--check"],
|
||||
"--no-input", "--dest", str(home / "bios"), "--check", "--verbose"],
|
||||
cwd=REPO_ROOT, env=env, capture_output=True, text=True, timeout=300,
|
||||
check=False,
|
||||
)
|
||||
@@ -4969,6 +4979,9 @@ class TheInstallerSaysWhatItFound(unittest.TestCase):
|
||||
(dest / "lynxboot.img").write_bytes(b"corrupt")
|
||||
proc = self._run("--dest", str(dest), "--system", "atari-lynx", "--check")
|
||||
self.assertEqual(proc.returncode, 3)
|
||||
self.assertIn("1 file to download.", proc.stdout)
|
||||
self.assertNotIn("lynxboot.img", proc.stdout)
|
||||
proc = self._run("--dest", str(dest), "--system", "atari-lynx", "--check", "--verbose")
|
||||
self.assertIn("wrong copy: lynxboot.img", proc.stdout)
|
||||
self.assertIn("without --check", proc.stdout)
|
||||
|
||||
@@ -4988,7 +5001,7 @@ class TheInstallerSaysWhatItFound(unittest.TestCase):
|
||||
def test_a_piped_log_keeps_its_order(self):
|
||||
proc = subprocess.run(
|
||||
[sys.executable, "install.py", "--platform", "retroarch", "--no-input",
|
||||
"--target", "no-such-target", "--dest", str(self.home / "s")],
|
||||
"--verbose", "--target", "no-such-target", "--dest", str(self.home / "s")],
|
||||
cwd=REPO_ROOT, env=self.env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
||||
text=True, timeout=300, check=False,
|
||||
)
|
||||
@@ -5653,7 +5666,7 @@ class RunsAgainstTheRealLists(unittest.TestCase, _LoopbackRun):
|
||||
dest.mkdir()
|
||||
(dest / "scph5501.bin").write_bytes(b"junk")
|
||||
proc = _install_run(self.env, "--platform", "retroarch", "--dest", str(dest),
|
||||
"--check", "--no-input")
|
||||
"--check", "--no-input", "--verbose")
|
||||
self.assertEqual(proc.returncode, 3, proc.stderr)
|
||||
listing = proc.stdout.split("to download:\n", 1)[1].splitlines()
|
||||
self.assertEqual(listing[0].strip(), "wrong copy: scph5501.bin")
|
||||
@@ -5685,7 +5698,7 @@ class RunsAgainstTheRealLists(unittest.TestCase, _LoopbackRun):
|
||||
"bios/Other/ppsspp/PPSSPP/ppge_atlas.meta"):
|
||||
shutil.copy(REPO_ROOT / repo_path, dest / "PPSSPP")
|
||||
proc = _install_run(self.env, "--platform", "retroarch", "--dest", str(dest),
|
||||
"--system", "sony-psp", "--check", "--no-input")
|
||||
"--system", "sony-psp", "--check", "--no-input", "--verbose")
|
||||
self.assertEqual(proc.returncode, 3, proc.stdout + proc.stderr)
|
||||
self.assertNotIn("Every file on the list is in place", proc.stdout)
|
||||
found = re.search(r"(\d+) in place, (\d+) missing", proc.stdout)
|
||||
@@ -5699,6 +5712,7 @@ class RunsAgainstTheRealLists(unittest.TestCase, _LoopbackRun):
|
||||
dest.mkdir()
|
||||
proc = _install_run({**self.env, "RETROBIOS_INSTALL_OFFLINE": "1"}, "--platform",
|
||||
"retroarch", "--dest", str(dest), "--check", "--no-input",
|
||||
"--verbose",
|
||||
"--manifest", str(REPO_ROOT / "install" / "retroarch.json"))
|
||||
self.assertEqual(proc.returncode, 3, proc.stdout + proc.stderr)
|
||||
missing = re.search(r"0 in place, (\d+) missing", proc.stdout).group(1)
|
||||
@@ -5711,7 +5725,7 @@ class RunsAgainstTheRealLists(unittest.TestCase, _LoopbackRun):
|
||||
(cores / "handy_libretro.so").write_bytes(b"")
|
||||
proc = _install_run(self.env, "--platform", "retroarch", "--dest",
|
||||
str(self.home / "s"), "--cores-dir", str(cores),
|
||||
"--dry-run", "--no-input")
|
||||
"--dry-run", "--no-input", "--verbose")
|
||||
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
|
||||
self.assertIn("to the installed cores", proc.stdout)
|
||||
|
||||
@@ -5912,7 +5926,7 @@ class StandaloneFoldersAreNamedWhenThereAreAny(unittest.TestCase, _LoopbackRun):
|
||||
def _run(self) -> str:
|
||||
proc = _install_run(self.env, "--platform", "retroarch", "--dest",
|
||||
str(self.home / "system"), "--system", "atari-lynx",
|
||||
"--no-input")
|
||||
"--no-input", "--verbose")
|
||||
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
|
||||
return proc.stdout
|
||||
|
||||
@@ -6661,7 +6675,7 @@ class RomMFirmwareInstallsUnderItsTemplate(unittest.TestCase, _LoopbackRun):
|
||||
" firmware: \"{platform}/bios\"\n")
|
||||
proc = _install_run(self.env, "--platform", "romm", "--dest",
|
||||
str(base / "library" / "bios"), "--system", "atari-lynx",
|
||||
"--no-input")
|
||||
"--no-input", "--verbose")
|
||||
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
|
||||
self.assertTrue((base / "library" / "lynx" / "bios" / "lynxboot.img").is_file())
|
||||
self.assertFalse((base / "library" / "bios").exists())
|
||||
@@ -6810,7 +6824,7 @@ class EventsDescribeTheRun(unittest.TestCase, _SyntheticTree):
|
||||
SKIPPED = [{"reason": "not_found", "label": "not found", "files": 1, "required": 1}]
|
||||
|
||||
def test_a_check_run(self):
|
||||
proc, events = self._run("--check")
|
||||
proc, events = self._run("--check", "--verbose")
|
||||
self.assertEqual(proc.returncode, 3)
|
||||
installer = events[0]["installer"]
|
||||
self.assertEqual(events, self._head("check", installer) + [
|
||||
@@ -7448,7 +7462,7 @@ class KeptFilesEndToEnd(unittest.TestCase, _SyntheticTree):
|
||||
|
||||
def test_install_then_restore(self):
|
||||
proc = _install_run(self.env, "--platform", "retroarch", "--dest", str(self.bios),
|
||||
"--no-input", "--jobs", "1")
|
||||
"--no-input", "--jobs", "1", "--verbose")
|
||||
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
|
||||
self.assertEqual((self.bios / "b.bin").read_bytes(), self.FILES["bios/A/b.bin"])
|
||||
runs = list((self.home / install.BACKUP_DIR).iterdir())
|
||||
@@ -7614,7 +7628,7 @@ class TheListVersionIsSaidBeforeAndAfter(unittest.TestCase):
|
||||
"may show some files as not matching it.")
|
||||
|
||||
def test_line_mode_says_it_before_the_install_and_with_the_result(self):
|
||||
proc = self.run_installer()
|
||||
proc = self.run_installer("--verbose")
|
||||
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
|
||||
self.assertEqual(proc.stdout.count(self.SAID), 2, proc.stdout)
|
||||
self.assertLess(proc.stdout.index(self.SAID), proc.stdout.index("Checking existing"))
|
||||
|
||||
@@ -483,7 +483,7 @@ class TheOneLinerReadsInstalledCores(unittest.TestCase):
|
||||
def test_only_what_the_installed_cores_read(self):
|
||||
with _CoreRepository() as repo:
|
||||
repo.install_core("pcsx_rearmed_neon")
|
||||
proc = repo.run("--installed-cores")
|
||||
proc = repo.run("--installed-cores", "--verbose")
|
||||
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
|
||||
self.assertIn("1 core installed", proc.stdout)
|
||||
self.assertEqual(
|
||||
@@ -562,7 +562,7 @@ class TheInterfaceFindsTheCoresLineModeFinds(unittest.TestCase):
|
||||
found = []
|
||||
for given in ((), ("--dest", str(repo.dest))):
|
||||
command = [sys.executable, str(REPO_ROOT / "install.py"), "--platform",
|
||||
"retroarch", *given, "--installed-cores", "--check"]
|
||||
"retroarch", *given, "--installed-cores", "--check", "--verbose"]
|
||||
proc = subprocess.run(command, env=env, capture_output=True, text=True,
|
||||
timeout=60, check=False, stdin=subprocess.DEVNULL)
|
||||
self.assertNotIn("no installed core found", proc.stderr)
|
||||
|
||||
@@ -308,6 +308,15 @@ class ProgressOutput(unittest.TestCase):
|
||||
return stream, term
|
||||
|
||||
def test_a_log_gets_one_line_per_file_and_failures_say_why(self):
|
||||
# A file that went well is a line of --verbose, a failure of every run.
|
||||
install.OUTPUT.verbose = False
|
||||
stream, term = self._term()
|
||||
progress = install.Progress(2, 10, term)
|
||||
progress.done("a.bin", True)
|
||||
progress.done("b.bin", False, "HTTP 404")
|
||||
self.assertEqual(stream.getvalue(), " FAILED b.bin (HTTP 404)\n")
|
||||
self.addCleanup(setattr, install.OUTPUT, "verbose", False)
|
||||
install.OUTPUT.verbose = True
|
||||
stream, term = self._term()
|
||||
progress = install.Progress(2, 10, term)
|
||||
progress.done("a.bin", True)
|
||||
@@ -329,6 +338,8 @@ class ProgressOutput(unittest.TestCase):
|
||||
["0:00", "0:42", "3:05", "1:02:09"])
|
||||
|
||||
def test_the_summary_names_each_failure(self):
|
||||
self.addCleanup(setattr, install.OUTPUT, "verbose", False)
|
||||
install.OUTPUT.verbose = True
|
||||
buf = io.StringIO()
|
||||
with contextlib.redirect_stdout(buf), self.assertRaises(SystemExit):
|
||||
install._report_outcome(
|
||||
@@ -544,7 +555,7 @@ class AFolderThisUserCannotEnter(unittest.TestCase):
|
||||
with FakeRepository() as repo:
|
||||
locked = self._locked(repo)
|
||||
try:
|
||||
proc = repo.run("--check")
|
||||
proc = repo.run("--check", "--verbose")
|
||||
finally:
|
||||
os.chmod(locked, 0o755)
|
||||
self.assertNotIn("Traceback", proc.stderr)
|
||||
@@ -671,7 +682,7 @@ class AHomeThisUserCannotOpen(unittest.TestCase):
|
||||
("detected", [])):
|
||||
runs[name] = subprocess.run(
|
||||
[sys.executable, str(REPO_ROOT / "install.py"), "--check",
|
||||
"--no-input", *extra],
|
||||
"--no-input", "--verbose", *extra],
|
||||
env=env, capture_output=True, text=True, timeout=60,
|
||||
stdin=subprocess.DEVNULL)
|
||||
finally:
|
||||
@@ -864,7 +875,7 @@ class APartlyClosedHome(unittest.TestCase):
|
||||
("events", ["--events"])):
|
||||
runs[name] = subprocess.run(
|
||||
[sys.executable, str(REPO_ROOT / "install.py"), "--check",
|
||||
"--no-input", *extra],
|
||||
"--no-input", "--verbose", *extra],
|
||||
env=env, capture_output=True, text=True, timeout=60,
|
||||
stdin=subprocess.DEVNULL)
|
||||
finally:
|
||||
|
||||
@@ -42,7 +42,7 @@ class AndroidMediaScanner(unittest.TestCase):
|
||||
return self.repo, proc
|
||||
|
||||
def test_an_android_install_writes_one(self):
|
||||
repo, proc = self._run("android")
|
||||
repo, proc = self._run("android", "--verbose")
|
||||
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
|
||||
marker = repo.dest / ".nomedia"
|
||||
self.assertTrue(marker.is_file())
|
||||
@@ -106,7 +106,7 @@ class NamesAFatCardCannotHold(unittest.TestCase):
|
||||
"files": files}))
|
||||
out = io.StringIO()
|
||||
argv = ["install.py", "--platform", "retrodeck", "--dest", str(dest),
|
||||
"--manifest", str(listed), "--from", str(old), "--no-input"]
|
||||
"--manifest", str(listed), "--from", str(old), "--no-input", "--verbose"]
|
||||
with mock.patch.object(install, "holds_fat_refused_names", return_value=holds), \
|
||||
mock.patch.object(install, "detect_os", return_value="linux"), \
|
||||
mock.patch("sys.argv", argv), contextlib.redirect_stdout(out), \
|
||||
|
||||
@@ -219,8 +219,8 @@ class CopyFromAnOldCard(FromFolder):
|
||||
def test_check_names_what_the_folder_would_give_and_writes_nothing(self):
|
||||
self.keep("BIOS/SCPH5501.BIN", US)
|
||||
self.keep("gba_bios.bin", GBA)
|
||||
proc = self.run_installer("--check", "--manifest", str(self.list), "--from",
|
||||
str(self.old))
|
||||
proc = self.run_installer("--check", "--verbose", "--manifest", str(self.list),
|
||||
"--from", str(self.old))
|
||||
self.assertEqual(proc.returncode, 3, proc.stdout + proc.stderr)
|
||||
self.assertIn(f"{self.old} holds 2 of these files: a run without --check "
|
||||
"copies them.", proc.stdout)
|
||||
@@ -376,7 +376,7 @@ class MisplacedInTheBiosFolder(Scratch):
|
||||
def test_a_nested_bios_folder_is_fixed_and_left_in_place(self):
|
||||
for name, data in PAYLOAD.items():
|
||||
self.place(f"system/{name}", data)
|
||||
proc = self.install()
|
||||
proc = self.install("--verbose")
|
||||
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
|
||||
for name, data in PAYLOAD.items():
|
||||
self.assertEqual((self.dest / name).read_bytes(), data)
|
||||
@@ -387,7 +387,7 @@ class MisplacedInTheBiosFolder(Scratch):
|
||||
def test_a_pack_extracted_into_a_folder_of_its_own_is_fixed(self):
|
||||
for name, data in PAYLOAD.items():
|
||||
self.place(f"RetroArch_BIOS_Pack/{name}", data)
|
||||
proc = self.install()
|
||||
proc = self.install("--verbose")
|
||||
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
|
||||
self.assertIn("one folder too deep: it is at RetroArch_BIOS_Pack/scph5501.bin",
|
||||
proc.stdout)
|
||||
|
||||
@@ -833,7 +833,7 @@ class CommandLine(unittest.TestCase):
|
||||
return [json.loads(line) for line in proc.stdout.splitlines() if line.startswith("{")]
|
||||
|
||||
def test_check_narrows_to_what_the_games_need(self):
|
||||
proc = run_cli(self.card, "--for-games", "--check", "--events")
|
||||
proc = run_cli(self.card, "--for-games", "--check", "--events", "--verbose")
|
||||
events = self.events(proc)
|
||||
games = next(e for e in events if e["event"] == "games")
|
||||
self.assertEqual(games["games"], 2)
|
||||
@@ -973,7 +973,8 @@ class ARunThatAsksNothing(unittest.TestCase):
|
||||
def test_it_installs_what_the_games_need(self):
|
||||
unasked, said = self.install("--yes")
|
||||
self.assertEqual(unasked, self.install("--for-games", "--yes")[0])
|
||||
self.assertIn("--all-files installs the whole list", said)
|
||||
self.assertIn("what the games need", said)
|
||||
self.assertIn("--all-files installs the whole list", self.install("--yes", "--verbose")[1])
|
||||
|
||||
def test_all_files_installs_the_whole_list(self):
|
||||
everything, said = self.install("--all-files", "--yes")
|
||||
|
||||
@@ -461,7 +461,7 @@ class ABoardWithoutTheNetwork(Scratch):
|
||||
(self.root / "targets" / "retroarch.json").write_text(json.dumps(BOARDS))
|
||||
self.complete()
|
||||
proc = self.run_installer("--offline", "--check", "--manifest", str(self.list),
|
||||
"--target", "psx-board", "--no-input")
|
||||
"--target", "psx-board", "--no-input", "--verbose")
|
||||
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
|
||||
self.assertIn("for target psx-board", proc.stdout)
|
||||
|
||||
@@ -500,7 +500,7 @@ class FromPackInstallsOffline(Scratch):
|
||||
for p in self.dest.rglob("*") if p.is_file()}
|
||||
|
||||
def test_the_pack_installs_with_no_network(self):
|
||||
proc = self.run_installer("--from-pack", str(self.pack))
|
||||
proc = self.run_installer("--from-pack", str(self.pack), "--verbose")
|
||||
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
|
||||
self.assertEqual(self.installed(), PAYLOAD)
|
||||
self.assertIn("Copying 4 files", proc.stdout)
|
||||
@@ -571,7 +571,8 @@ class FromPackInstallsOffline(Scratch):
|
||||
for rel, data in tree.items()},
|
||||
}]
|
||||
self.list.write_text(json.dumps(listed))
|
||||
proc = self.run_installer("--from-pack", str(self.pack), "--manifest", str(self.list))
|
||||
proc = self.run_installer("--from-pack", str(self.pack), "--manifest", str(self.list),
|
||||
"--verbose")
|
||||
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
|
||||
self.assertIn("dolphin-sys: 2 installed", proc.stdout)
|
||||
for rel, data in tree.items():
|
||||
@@ -708,6 +709,8 @@ class TheSummaryNamesTheBulk(unittest.TestCase):
|
||||
files, {"system_cores": {"3do": ["mame", "opera"]}}, True, True), [])
|
||||
|
||||
def test_the_end_summary_prints_the_line(self):
|
||||
self.addCleanup(setattr, install.OUTPUT, "verbose", False)
|
||||
install.OUTPUT.verbose = True
|
||||
out = io.StringIO()
|
||||
with contextlib.redirect_stdout(out):
|
||||
install._report_outcome([Path("/x")], 3, 0, 0, 0, False,
|
||||
@@ -950,7 +953,8 @@ class OfflineLeavesFilesMissing(Scratch):
|
||||
}]
|
||||
self.list.write_text(json.dumps(listed))
|
||||
self.complete()
|
||||
proc = self.run_installer("--offline", "--manifest", str(self.list), "--no-input")
|
||||
proc = self.run_installer("--offline", "--manifest", str(self.list), "--no-input",
|
||||
"--verbose")
|
||||
# Its files are missing, as the BIOS files --offline leaves out are,
|
||||
# with or without questions.
|
||||
self.assertIn("bluemsx: 0 already in place, 1 needs the internet (--offline)",
|
||||
|
||||
@@ -594,7 +594,7 @@ class FakeRepository:
|
||||
class TheOneLinerNarrows(unittest.TestCase):
|
||||
def test_options_install_only_the_choice(self):
|
||||
with FakeRepository() as repo:
|
||||
proc = repo.run("--system", "sony-playstation", "--region", "us")
|
||||
proc = repo.run("--system", "sony-playstation", "--region", "us", "--verbose")
|
||||
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
|
||||
self.assertIn("Narrowed 5 to 2 files", proc.stdout)
|
||||
self.assertEqual(repo.installed(), ["pcsx/extra.bin", "scph5501.bin"])
|
||||
@@ -1606,14 +1606,14 @@ class ThePlatformsOwnListAlone(unittest.TestCase):
|
||||
|
||||
def test_install_check_and_dry_run_apply_it(self):
|
||||
with FakeRepository() as repo:
|
||||
proc = repo.run("--declared-only")
|
||||
proc = repo.run("--declared-only", "--verbose")
|
||||
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
|
||||
self.assertIn("5 to 3 files", proc.stdout)
|
||||
self.assertEqual(repo.installed(),
|
||||
["gba_bios.bin", "scph5500.bin", "scph5501.bin"])
|
||||
for mode in ("--check", "--dry-run"):
|
||||
with self.subTest(mode=mode), FakeRepository() as repo:
|
||||
proc = repo.run("--declared-only", mode)
|
||||
proc = repo.run("--declared-only", mode, "--verbose")
|
||||
self.assertIn("5 to 3 files", proc.stdout, proc.stderr)
|
||||
self.assertIn("0 in place, 3 missing", proc.stdout)
|
||||
self.assertEqual(repo.installed(), [])
|
||||
@@ -1633,7 +1633,7 @@ class ThePlatformsOwnListAlone(unittest.TestCase):
|
||||
|
||||
def test_a_local_file_list_applies_it(self):
|
||||
with FakeRepository() as repo:
|
||||
proc = repo.run("--declared-only", "--dry-run", "--manifest",
|
||||
proc = repo.run("--declared-only", "--dry-run", "--verbose", "--manifest",
|
||||
str(repo.root / "install" / "retroarch.json"))
|
||||
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
|
||||
self.assertIn("5 to 3 files", proc.stdout)
|
||||
@@ -1778,7 +1778,7 @@ class SomethingElseAtADestination(unittest.TestCase):
|
||||
def test_each_says_why_in_the_check_and_the_install(self):
|
||||
with FakeRepository() as repo:
|
||||
self.prepare(repo)
|
||||
proc = repo.run("--check")
|
||||
proc = repo.run("--check", "--verbose")
|
||||
self.assertEqual(proc.returncode, 3, proc.stderr)
|
||||
self.assertNotIn("Traceback", proc.stderr)
|
||||
self.assertIn(" wrong copy: scph5500.bin\n a folder sits where this "
|
||||
|
||||
@@ -7017,6 +7017,8 @@ def line_decision(args: argparse.Namespace, answer) -> tuple[list, str]:
|
||||
def stop(_args, platforms):
|
||||
raise _Decided(platforms)
|
||||
|
||||
# --verbose's text, which names what detection found.
|
||||
args.verbose = True
|
||||
install.LOCAL.reset()
|
||||
with mock.patch.object(install, "app_refusal", side_effect=stop), \
|
||||
mock.patch.object(install, "detect_os", return_value="linux"), \
|
||||
@@ -7798,7 +7800,7 @@ class LineModeAndScreenDecideAlike(_LineModeFindings, _OutsideTextFindings,
|
||||
(backup / "gba_bios.bin").write_bytes(b"gba")
|
||||
(backup / "doom" / "doom1.wad").write_bytes(b"wad" * 10)
|
||||
args = _args(manifest=listing, dest=self.here, offline=True, declared_only=False,
|
||||
no_input=True)
|
||||
no_input=True, verbose=True)
|
||||
setattr(args, "from", [backup])
|
||||
real = io.StringIO()
|
||||
install.LOCAL.reset()
|
||||
@@ -7965,7 +7967,7 @@ class LineModeAndScreenDecideAlike(_LineModeFindings, _OutsideTextFindings,
|
||||
old = self.root / "OLD"
|
||||
old.mkdir()
|
||||
(old / "gba_bios.bin").write_bytes(payload)
|
||||
args = _args(manifest=listing, declared_only=False, offline=True)
|
||||
args = _args(manifest=listing, declared_only=False, offline=True, verbose=True)
|
||||
setattr(args, "from", [old])
|
||||
real = io.StringIO()
|
||||
install.LOCAL.reset()
|
||||
@@ -8047,7 +8049,10 @@ class LineModeAndScreenDecideAlike(_LineModeFindings, _OutsideTextFindings,
|
||||
def line_run(self, args: argparse.Namespace, answers: list, mounts: list = (),
|
||||
found: list = ()) -> tuple[str, list]:
|
||||
"""(text, prompts) of line mode at a terminal for args, the answers
|
||||
given in turn: the run stops at the first question left unanswered."""
|
||||
given in turn: the run stops at the first question left unanswered.
|
||||
Its text is --verbose's: these findings read the lines the default
|
||||
leaves out."""
|
||||
args.verbose = True
|
||||
given, asked = iter(answers), []
|
||||
|
||||
def answer(prompt: str) -> str:
|
||||
@@ -12619,7 +12624,7 @@ class ChoiceStateInBothModes(unittest.TestCase):
|
||||
self.assertNotIn("to fetch them", text)
|
||||
self.assertIn("to copy 1 of them from RetroArch_BIOS_Pack.zip", text)
|
||||
options = ("--platform", "retroarch", "--manifest", str(listing), "--dest", str(dest),
|
||||
"--yes")
|
||||
"--yes", "--verbose")
|
||||
proc = install_run(*options, "--from-pack", str(pack))
|
||||
text = proc.stdout + proc.stderr
|
||||
self.assertIn("Copying 1 file (1 B) from RetroArch_BIOS_Pack.zip...", text)
|
||||
@@ -12774,7 +12779,7 @@ class ChoiceStateInBothModes(unittest.TestCase):
|
||||
files = [self.entry("gba_bios.bin", b"gba", ["nintendo-gba"])]
|
||||
listing = self.listing("retroarch", files)
|
||||
proc = install_run("--platform", "retroarch", "--manifest", str(listing),
|
||||
"--dest", str(self.here), "--check", "--offline")
|
||||
"--dest", str(self.here), "--check", "--offline", "--verbose")
|
||||
self.assertIn("0 in place, 1 missing, 0 wrong copies", proc.stdout)
|
||||
self.assertNotIn("present (", proc.stdout)
|
||||
source = (REPO_ROOT / "install.py").read_text(encoding="utf-8")
|
||||
@@ -13232,6 +13237,8 @@ class OneVocabularyOneCount(unittest.TestCase):
|
||||
return listing, dest, old
|
||||
|
||||
def run_line(self, listing: Path, dest: Path, answers: list, **given) -> str:
|
||||
# --verbose's text: the counts compared are lines the default leaves out.
|
||||
given.setdefault("verbose", True)
|
||||
from_ = given.pop("from_", None)
|
||||
args = _args(manifest=listing, dest=dest, declared_only=False, **given)
|
||||
if from_:
|
||||
@@ -13626,7 +13633,9 @@ class ProvenCardsAndCounts(unittest.TestCase):
|
||||
def line_from(self, args: argparse.Namespace, answers: list,
|
||||
folders: list[Path] = ()) -> tuple[str, list]:
|
||||
"""(text, prompts) of line mode at a terminal, the result included,
|
||||
the folders --from names read first, as main() reads them."""
|
||||
the folders --from names read first, as main() reads them: --verbose's
|
||||
text."""
|
||||
args.verbose = True
|
||||
given, asked = iter(answers), []
|
||||
|
||||
def answer(prompt: str) -> str:
|
||||
|
||||
+23
-6
@@ -449,6 +449,23 @@ Batocera install into an empty folder, from the list of 2026-11-06.
|
||||
The figures change with each release.
|
||||
<!-- /generated: run-date -->
|
||||
|
||||
By default a run says five things: what it installs, where, a progress line
|
||||
at a terminal, the result and the next step.
|
||||
|
||||
<!-- generated: run-default -->
|
||||
|
||||
```
|
||||
Installing 18175 files (9.2 GB) for Batocera.
|
||||
BIOS folder: /userdata/bios
|
||||
|
||||
Done. 18175 files installed.
|
||||
Next: start Batocera and play.
|
||||
```
|
||||
<!-- /generated: run-default -->
|
||||
|
||||
With `--verbose` (`-v`) it says each step, the lists and the reasons too.
|
||||
The lines below are those of the same run with `--verbose`.
|
||||
|
||||
### Before the run
|
||||
|
||||
The size depends on the platform and changes with each release. The run prints
|
||||
@@ -473,8 +490,8 @@ Looking for setups here...
|
||||
<!-- /generated: run-first-lines -->
|
||||
|
||||
A line above them, `RetroBIOS` and a code, identifies the installer: the
|
||||
code is the start of the SHA-256 the command checked before running it. The
|
||||
path is the folder it will write to.
|
||||
code is the start of the SHA-256 the command checked before running it.
|
||||
`--version` prints it too. The path is the folder it will write to.
|
||||
|
||||
### The file index and the download
|
||||
|
||||
@@ -501,8 +518,8 @@ is already there, and only the rest is downloaded. A download of 1 GB or more
|
||||
is confirmed first, the size and the folder in the question.
|
||||
|
||||
The second phase downloads what is missing. At a terminal one progress line
|
||||
moves with the count and the size. A pipe or a log gets one line per file,
|
||||
as the log of the run below:
|
||||
moves with the count and the size. With `--verbose` a pipe or a log gets one
|
||||
line per file, as the log of the run below:
|
||||
|
||||
<!-- generated: run-download -->
|
||||
|
||||
@@ -537,8 +554,8 @@ To check this later, run the same command with --check.
|
||||
<!-- /generated: run-end -->
|
||||
|
||||
When most of a download of 100 MB or more comes from one system, or from
|
||||
one core of a single system, the end of the run says so and what narrowing
|
||||
would save, once that saving is over half.
|
||||
one core of a single system, the end of a `--verbose` run says so and what
|
||||
narrowing would save, once that saving is over half.
|
||||
|
||||
<!-- generated: bulk-hint -->
|
||||
|
||||
|
||||
Reference in new issue
Block a user