|
#!/usr/bin/env python3 |
|
# SPDX-FileCopyrightText: 2024 Dragorn421 |
|
# SPDX-License-Identifier: CC0-1.0 |
|
|
|
import dataclasses |
|
from pathlib import Path |
|
import pickle |
|
import subprocess |
|
|
|
from colorama import Fore |
|
|
|
# whether to ask for confirmation before running make commands |
|
CONFIRM_MAKE = False |
|
# whether to make assetclean and make clean before building |
|
CLEAN = False |
|
# whether to try run fix_bss after make fails |
|
AUTO_TRY_FIX_BSS = True |
|
|
|
VERSIONS = [p.name for p in Path("baseroms").iterdir()] |
|
|
|
|
|
CTX_PICKLE_P = Path(__file__).with_suffix(".pickle") |
|
|
|
|
|
@dataclasses.dataclass |
|
class BuildAllRoundContext: |
|
ok_versions: list[str] = dataclasses.field(default_factory=list) |
|
|
|
def save(self): |
|
with CTX_PICKLE_P.open("wb") as f: |
|
pickle.dump(self, f) |
|
|
|
@staticmethod |
|
def load(): |
|
if CTX_PICKLE_P.exists(): |
|
with CTX_PICKLE_P.open("rb") as f: |
|
ctx = pickle.load(f) |
|
assert isinstance(ctx, BuildAllRoundContext) |
|
return ctx |
|
else: |
|
return None |
|
|
|
|
|
def confirm_Popen(args, *posargs, **kwargs): |
|
assert all( |
|
(" " not in (arg_with_space := arg) for arg in args), |
|
), (args, arg_with_space) |
|
print(" ".join(args)) |
|
if CONFIRM_MAKE: |
|
input(f"{Fore.CYAN}(enter to proceed){Fore.RESET}") |
|
return subprocess.Popen(args, *posargs, **kwargs) |
|
|
|
|
|
def proc_expect_success_retry(args, label: str): |
|
while True: |
|
p = confirm_Popen(args) |
|
p.communicate() |
|
if p.returncode == 0: |
|
print(f"{Fore.GREEN}Succeeded: {label}{Fore.RESET}") |
|
break |
|
print(f"{Fore.RED}Error: {label}{Fore.RESET}") |
|
input(f"{Fore.CYAN}(enter to retry){Fore.RESET}") |
|
|
|
|
|
def main(): |
|
ctx = BuildAllRoundContext.load() |
|
|
|
if ctx is not None: |
|
cont = None |
|
while cont is None: |
|
c_or_r = input( |
|
f"{Fore.CYAN}Continue or Restart? [C/R] {Fore.RESET}" |
|
).lower() |
|
cont = {"c": True, "r": False}.get(c_or_r) |
|
if cont: |
|
print("Continuing build round") |
|
else: |
|
print("Restarting build round") |
|
ctx = None |
|
|
|
if ctx is None: |
|
print("Starting new build round") |
|
ctx = BuildAllRoundContext() |
|
ctx.save() |
|
|
|
for version in sorted(VERSIONS): |
|
if version in ctx.ok_versions: |
|
print(f"{version}: {Fore.RESET}OK{Fore.RESET}") |
|
else: |
|
make_cmd = ["make", "--quiet", "-j7", f"VERSION={version}"] |
|
if CLEAN: |
|
proc_expect_success_retry( |
|
make_cmd + ["assetclean"], |
|
f"make assetclean VERSION={version}", |
|
) |
|
proc_expect_success_retry( |
|
make_cmd + ["clean"], |
|
f"make clean VERSION={version}", |
|
) |
|
proc_expect_success_retry( |
|
make_cmd + ["setup"], |
|
f"make setup VERSION={version}", |
|
) |
|
is_first_make = True |
|
has_tried_fix_bss = False |
|
while True: |
|
p = confirm_Popen(make_cmd) |
|
p.communicate() |
|
if p.returncode == 0: |
|
print(f"{Fore.GREEN}Succeeded: make VERSION={version}{Fore.RESET}") |
|
break |
|
print(f"{Fore.RED}Error: make VERSION={version}{Fore.RESET}") |
|
while True: |
|
if AUTO_TRY_FIX_BSS and is_first_make: |
|
if has_tried_fix_bss: |
|
opt = "" |
|
print( |
|
f"{Fore.YELLOW}Auto-fix-bss: retrying make VERSION={version}{Fore.RESET}" |
|
) |
|
else: |
|
opt = "b" |
|
print( |
|
f"{Fore.YELLOW}Auto-fix-bss: running fix_bss {version}{Fore.RESET}" |
|
) |
|
else: |
|
opt = input( |
|
f"{Fore.CYAN}(enter to retry make VERSION={version}" |
|
f" or fix Bss) [ /B]{Fore.RESET}" |
|
).lower() |
|
if opt == "b": |
|
has_tried_fix_bss = True |
|
p = confirm_Popen(["./tools/fix_bss.py", "-v", version]) |
|
p.communicate() |
|
if p.returncode == 0: |
|
print(f"{Fore.GREEN}Success: fix_bss {version}{Fore.RESET}") |
|
else: |
|
print( |
|
f"{Fore.RED}Error: fix_bss {version}" |
|
f" ended with {p.returncode}{Fore.RESET}" |
|
) |
|
if opt == "": |
|
break |
|
is_first_make = False |
|
|
|
print(f"{Fore.GREEN}{version}: OK{Fore.RESET}") |
|
ctx.ok_versions.append(version) |
|
ctx.save() |
|
|
|
print( |
|
f"{Fore.GREEN}All OK versions:{Fore.RESET}", |
|
", ".join(sorted(ctx.ok_versions)), |
|
) |
|
|
|
print(f"{Fore.GREEN}All versions OK!{Fore.RESET}") |
|
|
|
|
|
if __name__ == "__main__": |
|
main() |