diff --git a/Makefile b/Makefile index db8b32c..f710c6c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,8 @@ VERSION := $(shell grep -m 1 version pyproject.toml | tr -s ' ' | tr -d '"' | tr -d "'" | cut -d' ' -f3) +PATH := "/opt/bin:/opt/sbin:/home/root/.local/bin:/opt/bin:/opt/sbin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin" define SCRIPT +export PATH=${PATH} if ! type pip &> /dev/null; then if ! type opkg &> /dev/null; then echo "Opkg not found, please install toltec" @@ -29,6 +31,8 @@ install: deploy echo -e "$$SCRIPT" | ssh root@10.11.99.1 bash -le test: install - cat test.py | ssh root@10.11.99.1 /opt/bin/python -u + cat test.py \ + | ssh root@10.11.99.1 \ + "bash -ec 'PATH=${PATH} /opt/bin/python -u'" .PHONY: clean install test deploy diff --git a/README.md b/README.md index 423ea82..02af2ea 100644 --- a/README.md +++ b/README.md @@ -15,4 +15,18 @@ Usage ```python import launcherctl + +if ( + launcherctl.launchers.current.name != "oxide" + and "oxide" in launcherctl.launchers +): + launcherctl.launchers.switch("oxide", start=True) + # or + launcherctl.launchers["oxide"].enable(start=True) + +if ( + "calculator" in launcherctl.apps + and "calculator" not in launcherctl.apps.running.keys() +): + launcherctl.apps["calculator"].start() ``` diff --git a/launcherctl/__init__.py b/launcherctl/__init__.py index 56633e1..c069740 100644 --- a/launcherctl/__init__.py +++ b/launcherctl/__init__.py @@ -1,2 +1,8 @@ -import subprocess -import sys +from ._app import App +from ._app import api as apps + +from ._launcher import Launcher +from ._launcher import api as launchers + +from ._util import LauncherCtlException +from ._util import launcherctl diff --git a/launcherctl/_app.py b/launcherctl/_app.py new file mode 100644 index 0000000..6661c83 --- /dev/null +++ b/launcherctl/_app.py @@ -0,0 +1,61 @@ +from ._util import launcherctl + + +class App: + def __init__(self, name: str): + self.name = name + + @property + def is_running(self) -> bool: + return self.name in api.running.keys() + + @property + def is_paused(self) -> bool: + return self.name in api.paused.keys() + + def start(self) -> None: + launcherctl("start-app", self.name) + + def stop(self) -> None: + launcherctl("stop-app", self.name) + + def pause(self) -> None: + launcherctl("pause-app", self.name) + + def resume(self) -> None: + launcherctl("resume-app", self.name) + + +class API: + def keys(self) -> list[str]: + return [x.decode("utf-8") for x in launcherctl("list-apps").splitlines()] + + def __contains__(self, key: str) -> bool: + return key in self.keys() + + def __getitem__(self, key: str) -> App: + if key not in self: + raise KeyError() + + return App(key) + + @property + def running(self) -> dict[App]: + return { + x: App(x) + for x in [ + x.decode("utf-8") for x in launcherctl("list-running-apps").splitlines() + ] + } + + @property + def paused(self) -> dict[App]: + return { + x: App(x) + for x in [ + x.decode("utf-8") for x in launcherctl("list-paused-apps").splitlines() + ] + } + + +api = API() diff --git a/launcherctl/_launcher.py b/launcherctl/_launcher.py new file mode 100644 index 0000000..6205b1f --- /dev/null +++ b/launcherctl/_launcher.py @@ -0,0 +1,76 @@ +import subprocess + +from typing import Callable + +from ._app import App +from ._util import launcherctl +from ._util import LauncherCtlException + + +class Launcher: + def __init__(self, name: str): + self.name = name + + def logs(self, onlogline: Callable[[str], None] = None) -> list[str] | None: + pass + + def start(self): + launcherctl("start-launcher", self.name) + + def stop(self): + launcherctl("stop-launcher", self.name) + + def enable(self, start: bool = False): + if start: + launcherctl("switch-launcher", "--start", self.name) + + else: + launcherctl("switch-launcher", self.name) + + @property + def is_current(self) -> bool: + return ( + subprocess.call(["/opt/bin/launcherctl", "is-current-launcher", self.name]) + == 0 + ) + + @property + def is_enabled(self) -> bool: + return ( + subprocess.call(["/opt/bin/launcherctl", "is-enabled-launcher", self.name]) + == 0 + ) + + @property + def is_active(self) -> bool: + return ( + subprocess.call(["/opt/bin/launcherctl", "is-active-launcher", self.name]) + == 0 + ) + + +class API: + def keys(self) -> list[str]: + return [x.decode("utf-8") for x in launcherctl("list-launchers").splitlines()] + + def __contains__(self, key: str) -> bool: + return key in self.keys() + + def __getitem__(self, key: str) -> App: + if key not in self: + raise KeyError() + + return Launcher(key) + + @property + def current(self): + return Launcher(launcherctl("status").splitlines()[0][14:-4].decode("utf-8")) + + def switch(launcher: Launcher | str, start: bool = False): + if not isinstance(Launcher, launcher): + launcher = Launcher(launcher) + + launcher.enable(start) + + +api = API() diff --git a/launcherctl/_util.py b/launcherctl/_util.py new file mode 100644 index 0000000..d2e8a00 --- /dev/null +++ b/launcherctl/_util.py @@ -0,0 +1,13 @@ +import subprocess + + +def LauncherCtlException(Exception): + pass + + +def launcherctl(*args) -> str | None: + try: + return subprocess.check_output(["/opt/bin/launcherctl"] + list(args)) + except subprocess.CalledProcessError as e: + stdout = e.output.decode("utf-8") + raise LauncherCtlException(stdout) from e diff --git a/pyproject.toml b/pyproject.toml index afa89f1..fd73633 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ name = "launcherctl" description = "Python wrapper around launcherctl." readme = "README.md" -version = "0.0.1" +version = "1.0.0" requires-python = ">= 3.11" authors = [ {name = "Nathaniel van Diepen", email = "eeems@eeems.email"}, diff --git a/test.py b/test.py index 432b2ce..ecfac58 100644 --- a/test.py +++ b/test.py @@ -1 +1,33 @@ import launcherctl + +print(launcherctl.launchers.current.name) +print([x for x in launcherctl.launchers.keys()]) +if "oxide" in launcherctl.launchers: + print("oxide:") + oxide = launcherctl.launchers["oxide"] + print(f" current: {oxide.is_current}") + print(f" enabled: {oxide.is_enabled}") + print(f" active: {oxide.is_active}") + +if "xochitl" in launcherctl.launchers: + print("xochitl:") + xochitl = launcherctl.launchers["xochitl"] + print(f" current: {xochitl.is_current}") + print(f" enabled: {xochitl.is_enabled}") + print(f" active: {xochitl.is_active}") + +launcherctl.launchers["xochitl"].is_current +print([x for x in launcherctl.apps.keys()]) +print([x for x in launcherctl.apps.running.keys()]) +print([x for x in launcherctl.apps.paused.keys()]) +if "calculator" in launcherctl.apps: + calculator = launcherctl.apps["calculator"] + print("calculator:") + print(f" running: {calculator.is_running}") + print(f" paused: {calculator.is_paused}") + +if "xochitl" in launcherctl.apps: + xochitl = launcherctl.apps["xochitl"] + print("xochitl:") + print(f" running: {xochitl.is_running}") + print(f" paused: {xochitl.is_paused}")