118 lines
3.5 KiB
Python
118 lines
3.5 KiB
Python
from __future__ import annotations
|
|
|
|
import argparse
|
|
import shutil
|
|
from pathlib import Path
|
|
from typing import List, Optional
|
|
|
|
from textual.app import App
|
|
|
|
from cobot.tui import SCREEN_CSS, LogScreen, MultiPickScreen
|
|
|
|
_PROJECT_DIR = Path(__file__).parent.parent.parent
|
|
|
|
_DIR_OPTIONS = ["build/", "install/", "log/"]
|
|
_DIR_MAP = {
|
|
"build/": _PROJECT_DIR / "build",
|
|
"install/": _PROJECT_DIR / "install",
|
|
"log/": _PROJECT_DIR / "log",
|
|
}
|
|
|
|
|
|
def _task_clean(screen: LogScreen, dirs: List[str]) -> None:
|
|
"""Delete the selected top-level directories.
|
|
Удаляет выбранные директории верхнего уровня.
|
|
"""
|
|
try:
|
|
screen.write("[bold]Cleaning build artifacts[/bold]\n")
|
|
total = len(dirs)
|
|
for i, label in enumerate(dirs):
|
|
if screen.is_stopped():
|
|
return
|
|
screen.set_progress(i / total * 100, f"Removing {label}...")
|
|
path = _DIR_MAP[label]
|
|
if path.exists():
|
|
shutil.rmtree(path)
|
|
screen.write(f"[green][ok][/green] Removed {label}")
|
|
else:
|
|
screen.write(f"[dim]Not found: {label}[/dim]")
|
|
|
|
if not screen.is_stopped():
|
|
screen.set_progress(100, "Done")
|
|
screen.write("\n[green]Done.[/green]")
|
|
screen.finish(True)
|
|
|
|
except Exception as exc:
|
|
if not screen.is_stopped():
|
|
screen.write(f"\n[red]Error:[/red] {exc}")
|
|
screen.finish(False)
|
|
|
|
|
|
class _CleanApp(App[None]):
|
|
"""Clean wizard: lets the user pick which directories to delete, then removes them.
|
|
Мастер очистки: позволяет выбрать директории для удаления, затем удаляет их.
|
|
"""
|
|
|
|
CSS = SCREEN_CSS
|
|
|
|
def __init__(self, all_dirs: bool):
|
|
super().__init__()
|
|
# True = skip the question and delete everything right away.
|
|
# True = пропустить вопрос и сразу удалить всё.
|
|
self._all_dirs = all_dirs
|
|
|
|
def on_mount(self) -> None:
|
|
if self._all_dirs:
|
|
self._start(_DIR_OPTIONS)
|
|
else:
|
|
self._ask_dirs()
|
|
|
|
def _ask_dirs(self) -> None:
|
|
self.push_screen(
|
|
MultiPickScreen(
|
|
"clean",
|
|
"Which directories to delete?",
|
|
_DIR_OPTIONS,
|
|
note="Space — toggle · Enter — confirm",
|
|
),
|
|
self._got_dirs,
|
|
)
|
|
|
|
def _got_dirs(self, dirs: Optional[List[str]]) -> None:
|
|
if not dirs:
|
|
self.exit()
|
|
return
|
|
self._start(dirs)
|
|
|
|
def _start(self, dirs: List[str]) -> None:
|
|
self.push_screen(
|
|
LogScreen(
|
|
"Cleaning",
|
|
lambda s: _task_clean(s, dirs),
|
|
show_progress=True,
|
|
),
|
|
lambda _: self.exit(),
|
|
)
|
|
|
|
|
|
def register(subparsers: argparse._SubParsersAction) -> None:
|
|
p = subparsers.add_parser(
|
|
"clean",
|
|
help="Remove colcon build artifacts (build/ install/ log/)",
|
|
)
|
|
p.add_argument(
|
|
"target",
|
|
nargs="?",
|
|
metavar="all",
|
|
default=None,
|
|
help="'all' to skip the prompt and delete all three directories at once",
|
|
)
|
|
p.set_defaults(func=run)
|
|
|
|
|
|
def run(args: argparse.Namespace) -> None:
|
|
"""Entry point for the clean command.
|
|
Точка входа для команды clean.
|
|
"""
|
|
_CleanApp(all_dirs=(getattr(args, "target", None) == "all")).run()
|