diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/foucault/__pycache__/__init__.cpython-313.pyc b/foucault/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 8513b21..0000000 Binary files a/foucault/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/foucault/__pycache__/gui.cpython-313.pyc b/foucault/__pycache__/gui.cpython-313.pyc deleted file mode 100644 index 51e83fa..0000000 Binary files a/foucault/__pycache__/gui.cpython-313.pyc and /dev/null differ diff --git a/foucault/gui.py b/foucault/gui.py index c890b3b..18d06a5 100644 --- a/foucault/gui.py +++ b/foucault/gui.py @@ -86,6 +86,7 @@ class SubprocessController(): @classmethod def from_toml(cls, filename: os.PathLike): + logger.info(f"Load from TOML {filename}") path = pathlib.Path(filename) name = path.stem args = [] @@ -93,7 +94,7 @@ class SubprocessController(): data = tomllib.load(fp) print(data) - for arg in data['arguments']: + for arg in data.get('arguments', []): args.append(Argument.from_dict(arg)) sc = cls( @@ -198,10 +199,34 @@ class Foucault(): def __init__(self): self.processes: list[SubprocessController] = [] self.uis: list[SubprocessUI] = [] + self.directories: list[pathlib.Path] = [] def add_process(self, sc: SubprocessController): + logger.info(f"add process {sc.as_bash_string()}") self.processes.append(sc) self.uis.append(SubprocessUI(sc)) + self.ui.refresh() + + def watch(self, path: os.PathLike): + path = pathlib.Path(path).resolve() + if path.is_dir(): + if path in self.directories: + logger.warning(f"Path already watched {path}") + self.directories.append(path) + self.update_watched() + elif path.suffix == 'toml': + self.add_process(SubprocessController.from_toml(path)) + else: + raise RuntimeError(f"Not a valid path {path}") + + def update_watched(self): + # TODO)) It would be great to use e.g. Watchdog + fns = [scu.sc.filename for scu in self.uis] + for d in self.directories: + config_files = d.glob("**/*.toml") + for path in config_files: + if path not in fns: + self.add_process(SubprocessController.from_toml(path)) def run_all(self): for p in self.processes: @@ -217,6 +242,7 @@ class Foucault(): self.stop_all() self.run_all() + @ui.refreshable_method def ui(self): with ui.row(): ui.button('▶', on_click=self.run_all) @@ -248,6 +274,7 @@ class Foucault(): i+=1 # if we're only interested in running, we can use os.waitpid(), but we also check config changes time.sleep(.3) + self.update_watched() for proc_ui in self.uis: state = proc_ui.sc.state() if state != states[proc_ui.sc]: @@ -262,7 +289,7 @@ class SubprocessUI: @ui.refreshable_method def ui(self): - card_class = "bg-teal" if self.sc.is_running() else ("bg-warning" if self.sc.return_code() else "bg-gray") + card_class = "bg-teal" if self.sc.is_running() else ("bg-warning" if self.sc.return_code() and math.abs(self.sc.return_code()) != 15 else "bg-gray") with ui.card().classes(card_class): with ui.row(align_items="stretch").classes('w-full'): if self.sc.return_code(): @@ -276,7 +303,7 @@ class SubprocessUI: ui.button('↺', on_click=self.sc.restart, color='red' if self.sc.is_stale() else "primary") - ui.label(f'Running: {self.sc.is_running()}') + ui.label(f'Running: {self.sc.is_running()}' + f"({self.sc.return_code()})") ui.code(f'{" ".join(self.sc.cmd)}') ui.code(self.sc.as_bash_string()) ui.separator() diff --git a/main.py b/main.py index 2e24fb4..ab8c673 100644 --- a/main.py +++ b/main.py @@ -2,21 +2,9 @@ from pathlib import Path from foucault.gui import * -# print(sc) - logging.basicConfig(level=logging.INFO) conductofconduct = Foucault() -sc = SubprocessController.from_toml(Path('processes/tail.toml')) -sc2 = SubprocessController.from_toml(Path('processes/tail2.toml')) -sc3 = SubprocessController.from_toml(Path('processes/tail.toml')) -conductofconduct.add_process(sc) -conductofconduct.add_process(sc2) -conductofconduct.add_process(sc3) -# conductofconduct.add_process(SubprocessController("test1" , ["tail"], ['-f', "gui.py"])) -# conductofconduct.add_process(SubprocessController("test2" , ["tail"], ['-f', "gui.py"])) -# conductofconduct.add_process(SubprocessController("test3 broken" , ["tail"], ['-f', "nonexistent.py"])) -# conductofconduct.add_process(SubprocessController("system status" , ["uv run status.py"], ['-f', "nonexistent.py"])) - +conductofconduct.watch("processes") conductofconduct.run()