commands: new submodule (MR 2252)

The current mechanism of invoking pmbootstrap actions can be a bit
confusing, and relies heavily on args being a big namespace with lots of
properties (which may or may not be valid depending on the context).

To aid in slowly removing args from the codebase, introduce a new
mechanism for running commands. This works by having a class for each
command, where the arguments are passed in as parameters to the
constructor.

No doubt this won't scale very far, but it's a skeleton we can continue
to build on as we migrate more commands over to not require args in
order to run.

Signed-off-by: Caleb Connolly <caleb@postmarketos.org>
This commit is contained in:
Caleb Connolly 2024-05-24 18:46:21 +02:00 committed by Oliver Smith
parent 52cf0e0fe3
commit 8526631589
No known key found for this signature in database
GPG key ID: 5AE7F5513E0885CB
6 changed files with 121 additions and 25 deletions

View file

@ -76,7 +76,7 @@ def main() -> int:
# Run the function with the action's name (in pmb/helpers/frontend.py)
if args.action:
getattr(frontend, args.action)(args)
run_command(args)
else:
logging.info("Run pmbootstrap -h for usage information.")

68
pmb/commands/__init__.py Normal file
View file

@ -0,0 +1,68 @@
# Copyright 2024 Caleb Connolly
# SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import annotations
import enum
from typing import Generator, Optional
from pathlib import Path, PosixPath, PurePosixPath
import pmb.config
from pmb.core.types import PmbArgs
from pmb.helpers import frontend
from .base import Command
from .log import Log
"""New way to model pmbootstrap subcommands that can be invoked without PmbArgs."""
# Commands that are still invoked via pmb/helpers/frontend.py
unmigrated_commands = [
"init",
"shutdown",
"index",
"work_migrate",
"repo_bootstrap",
"repo_missing",
"kconfig",
"export",
"sideload",
"netboot",
"flasher",
"initfs",
"qemu",
"pkgrel_bump",
"aportupgrade",
"newapkbuild",
"lint",
"status",
"ci",
"zap",
"stats",
"update",
"build_init",
"chroot",
"install",
"checksum",
"aportgen",
"build",
"deviceinfo_parse",
"apkbuild_parse",
"apkindex_parse",
"config",
"bootimg_analyze",
"pull",
]
def run_command(args: PmbArgs):
# Handle deprecated command format
if args.action in unmigrated_commands:
getattr(frontend, args.action)(args)
return
command: Command
# FIXME: would be nice to use match case...
if args.action == "log":
command = Log(args.clear_log, int(args.lines))
else:
raise NotImplementedError(f"Command '{args.action}' is not implemented.")
command.run()

9
pmb/commands/base.py Normal file
View file

@ -0,0 +1,9 @@
# Copyright 2024 Caleb Connolly
# SPDX-License-Identifier: GPL-3.0-or-later
class Command():
"""Base class for pmbootstrap commands."""
def run(self):
"""Run the command."""
raise NotImplementedError()

42
pmb/commands/log.py Normal file
View file

@ -0,0 +1,42 @@
# Copyright 2024 Caleb Connolly
# SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import annotations
from typing import Generator, List, Optional
from pathlib import Path, PosixPath, PurePosixPath
from pmb import commands
from pmb.core.types import PathString
from pmb.helpers import run
from pmb.core import get_context
from pmb import config
class Log(commands.Command):
clear_log: bool
lines: int
def __init__(self, clear_log: bool, lines: int):
self.clear_log = clear_log
self.lines = lines
def run(self):
context = get_context()
log_testsuite = config.work / "log_testsuite.txt"
if self.clear_log:
run.user(["truncate", "-s", "0", context.log])
run.user(["truncate", "-s", "0", log_testsuite])
cmd: List[PathString] = ["tail", "-n", str(self.lines), "-F"]
# Follow the testsuite's log file too if it exists. It will be created when
# starting a test case that writes to it (git -C test grep log_testsuite).
if log_testsuite.exists():
cmd += [log_testsuite]
# tail writes the last lines of the files to the terminal. Put the regular
# log at the end, so that output is visible at the bottom (where the user
# looks for an error / what's currently going on).
cmd += [context.log]
run.user(cmd, output="tui")

View file

@ -48,7 +48,7 @@ class PmbArgs(Namespace):
built: str
ccache_size: str
cipher: str
clear_log: str
clear_log: bool
cmdline: str
command: str
config: Path

View file

@ -561,29 +561,6 @@ def work_migrate(args: PmbArgs):
pmb.helpers.logging.disable()
def log(args: PmbArgs):
context = pmb.core.get_context()
log_testsuite = pmb.config.work / "log_testsuite.txt"
if args.clear_log:
pmb.helpers.run.user(["truncate", "-s", "0", context.log])
pmb.helpers.run.user(["truncate", "-s", "0", log_testsuite])
cmd: List[PathString] = ["tail", "-n", args.lines, "-F"]
# Follow the testsuite's log file too if it exists. It will be created when
# starting a test case that writes to it (git -C test grep log_testsuite).
if os.path.exists(log_testsuite):
cmd += [log_testsuite]
# tail writes the last lines of the files to the terminal. Put the regular
# log at the end, so that output is visible at the bottom (where the user
# looks for an error / what's currently going on).
cmd += [context.log]
pmb.helpers.run.user(cmd, output="tui")
def zap(args: PmbArgs):
pmb.chroot.zap(args, dry=args.dry, http=args.http,
distfiles=args.distfiles, pkgs_local=args.pkgs_local,