Source code for conda_tui.widgets.progress

import asyncio
import subprocess
import tempfile
from pathlib import Path
from typing import Any

from rich.progress import BarColumn
from rich.progress import Progress
from rich.progress import TaskProgressColumn
from rich.progress import TextColumn
from textual.widgets import Log
from textual.widgets import Static

from conda_tui.package import Package


[docs] class PackageUpdateProgress(Static): def __init__(self, *args: Any, package: Package, **kwargs: Any): super().__init__(*args, **kwargs) self._package = package self._bar = Progress()
[docs] def on_mount(self) -> None: self.set_interval(1 / 60, lambda: self.update(self._bar)) self.run_worker(self.update_package())
[docs] async def update_package(self): # TODO: This is a mock of actual package update with self._bar as bar: total_time, time_step = 2, 0.2 task = bar.add_task("", total=int(total_time / time_step)) while not bar.finished: bar.update(task, advance=1) await asyncio.sleep(time_step) self._package.update_available = False self.screen.dismiss(True) # Return a value to trigger the callback
[docs] class ShellCommandProgress(Static): def __init__(self, *commands: str, **kwargs: Any): super().__init__(**kwargs) self._bar = Progress( TextColumn("[progress.description]{task.description}"), BarColumn(), TaskProgressColumn(), )
[docs] def on_mount(self) -> None: self.set_interval(1 / 60, lambda: self.update(self._bar))
[docs] async def run_command(self, command: list[str], log: Log): # Remove any existing tasks for task_id in self._bar.task_ids: self._bar.remove_task(task_id) with self._bar as bar: description = ( f"Running command: [cyan bold]{' '.join(command)}[/cyan bold]:" ) task = bar.add_task(description, total=None) with tempfile.TemporaryDirectory() as tmp_dir: tmp_path = Path(tmp_dir, "tmp.log") # Here, the subprocess writes to the temporary file, and then # the polling writes to the log widget. We do it this way so # it is not blocking. The sleep call is important because it # allows the event loop to be used by the other UI threads. with tmp_path.open("w") as writer, tmp_path.open("r", 1) as reader: process = subprocess.Popen(command, stdout=writer, stderr=writer) while process.poll() is None: log.write(reader.read()) await asyncio.sleep(0.1) # Write any remaining characters log.write(reader.read()) log.write(f"\nFinished with status code {process.returncode}") bar.update(task, total=1, completed=True)