diff --git a/docs/contributing.md b/docs/contributing.md
index 91e44acf1..342d9eddf 100644
--- a/docs/contributing.md
+++ b/docs/contributing.md
@@ -78,8 +78,7 @@ Let's get your development environment up and running:
```
- Wait for the frontend to build.
- NOTE: If you have the error "@clan/colors.json" you executed `npm install`, please do not do that. `direnv reload` will handle dependency management. Please delete node_modules with `rm -rf node_modules`.
-
+ NOTE: If you have the error "@clan/colors.json" you executed `npm install`, please do not do that. `direnv reload` will handle dependency management. Please delete node_modules with `rm -rf node_modules`.
9. **Start the Frontend**:
- To start the frontend, execute:
diff --git a/pkgs/clan-cli/clan_cli/__init__.py b/pkgs/clan-cli/clan_cli/__init__.py
index 597955023..bca16c4ce 100644
--- a/pkgs/clan-cli/clan_cli/__init__.py
+++ b/pkgs/clan-cli/clan_cli/__init__.py
@@ -5,7 +5,7 @@ from pathlib import Path
from types import ModuleType
from typing import Any, Optional, Sequence
-from . import config, flakes, machines, secrets, vms, webui
+from . import config, flakes, gtkui, machines, secrets, vms, webui
from .custom_logger import setup_logging
from .dirs import get_clan_flake_toplevel
from .ssh import cli as ssh_cli
@@ -64,6 +64,9 @@ def create_parser(prog: Optional[str] = None) -> argparse.ArgumentParser:
subparsers = parser.add_subparsers()
+ parser_gtkui = subparsers.add_parser("gtkui", help="start gtkui")
+ gtkui.register_parser(parser_gtkui)
+
parser_flake = subparsers.add_parser(
"flakes", help="create a clan flake inside the current directory"
)
diff --git a/pkgs/clan-cli/clan_cli/async_cmd.py b/pkgs/clan-cli/clan_cli/async_cmd.py
index 96f4b2a08..462b2000f 100644
--- a/pkgs/clan-cli/clan_cli/async_cmd.py
+++ b/pkgs/clan-cli/clan_cli/async_cmd.py
@@ -1,9 +1,8 @@
import asyncio
import logging
-import deal
import shlex
from pathlib import Path
-from typing import Any, Callable, Coroutine, Dict, NamedTuple, Optional, Awaitable
+from typing import Any, Callable, Coroutine, Dict, NamedTuple, Optional
from .custom_logger import get_caller
from .errors import ClanError
@@ -16,8 +15,8 @@ class CmdOut(NamedTuple):
stderr: str
cwd: Optional[Path] = None
-@deal.raises(ClanError)
-async def run(cmd: list[str], cwd: Optional[Path] = None) -> Awaitable[CmdOut]:
+
+async def run(cmd: list[str], cwd: Optional[Path] = None) -> CmdOut:
cwd_res = None
if cwd is not None:
if not cwd.exists():
@@ -52,7 +51,6 @@ stdout:
return CmdOut(stdout.decode("utf-8"), stderr.decode("utf-8"), cwd=cwd)
-@deal.raises(ClanError)
def runforcli(
func: Callable[..., Coroutine[Any, Any, Dict[str, CmdOut]]], *args: Any
) -> None:
diff --git a/pkgs/clan-cli/clan_cli/gtkui/__init__.py b/pkgs/clan-cli/clan_cli/gtkui/__init__.py
new file mode 100644
index 000000000..f634e0604
--- /dev/null
+++ b/pkgs/clan-cli/clan_cli/gtkui/__init__.py
@@ -0,0 +1,10 @@
+import argparse
+from typing import Callable, Optional
+
+start_app: Optional[Callable] = None
+
+from .app import start_app
+
+
+def register_parser(parser: argparse.ArgumentParser) -> None:
+ parser.set_defaults(func=start_app)
diff --git a/pkgs/clan-cli/clan_cli/gtkui/app.glade b/pkgs/clan-cli/clan_cli/gtkui/app.glade
new file mode 100644
index 000000000..65a645d0a
--- /dev/null
+++ b/pkgs/clan-cli/clan_cli/gtkui/app.glade
@@ -0,0 +1,49 @@
+
+
+
+
+
+
diff --git a/pkgs/clan-cli/clan_cli/gtkui/app.glade~ b/pkgs/clan-cli/clan_cli/gtkui/app.glade~
new file mode 100644
index 000000000..65a645d0a
--- /dev/null
+++ b/pkgs/clan-cli/clan_cli/gtkui/app.glade~
@@ -0,0 +1,49 @@
+
+
+
+
+
+ False
+
+
+ asdasd
+ True
+ False
+
+
+ May I help you?
+ asdasd
+ 100
+ 80
+ True
+ True
+ True
+ top
+
+
+
+ 21
+ 21
+
+
+
+
+ 100
+ 80
+ True
+ False
+ Get me some coffe!
+ 0
+
+
+ 178
+ 120
+
+
+
+
+
+
+
diff --git a/pkgs/clan-cli/clan_cli/gtkui/app.py b/pkgs/clan-cli/clan_cli/gtkui/app.py
new file mode 100644
index 000000000..0122b9df3
--- /dev/null
+++ b/pkgs/clan-cli/clan_cli/gtkui/app.py
@@ -0,0 +1,19 @@
+# !/usr/bin/env python3
+
+import argparse # noqa
+from pathlib import Path # noqa
+
+import gi # noqa
+
+gi.require_version("Gtk", "3.0") # noqa
+from gi.repository import Gtk # noqa
+
+
+def start_app(args: argparse.Namespace) -> None:
+ builder = Gtk.Builder()
+ glade_file = Path(__file__).parent / "app.glade"
+ builder.add_from_file(str(glade_file))
+ window = builder.get_object("main-window")
+ window.show_all()
+
+ Gtk.main()
diff --git a/pkgs/clan-cli/clan_cli/nix.py b/pkgs/clan-cli/clan_cli/nix.py
index 6776dd05d..c913928a5 100644
--- a/pkgs/clan-cli/clan_cli/nix.py
+++ b/pkgs/clan-cli/clan_cli/nix.py
@@ -2,11 +2,14 @@ import json
import os
import subprocess
import tempfile
-import deal
from pathlib import Path
from typing import Any
+import deal
+
from .dirs import nixpkgs_flake, nixpkgs_source
+from .errors import ClanError
+
@deal.raises(ClanError)
def nix_command(flags: list[str]) -> list[str]:
@@ -25,6 +28,7 @@ def nix_flake_show(flake_url: str | Path) -> list[str]:
]
)
+
@deal.raises(ClanError)
def nix_build(
flags: list[str],
@@ -41,6 +45,7 @@ def nix_build(
+ flags
)
+
@deal.raises(ClanError)
def nix_config() -> dict[str, Any]:
cmd = nix_command(["show-config", "--json"])
@@ -51,6 +56,7 @@ def nix_config() -> dict[str, Any]:
config[key] = value["value"]
return config
+
@deal.raises(ClanError)
def nix_eval(flags: list[str]) -> list[str]:
default_flags = nix_command(
@@ -78,6 +84,7 @@ def nix_eval(flags: list[str]) -> list[str]:
)
return default_flags + flags
+
@deal.raises(ClanError)
def nix_shell(packages: list[str], cmd: list[str]) -> list[str]:
# we cannot use nix-shell inside the nix sandbox
diff --git a/pkgs/clan-cli/clan_cli/task_manager.py b/pkgs/clan-cli/clan_cli/task_manager.py
index edadef5cb..451e0b1fb 100644
--- a/pkgs/clan-cli/clan_cli/task_manager.py
+++ b/pkgs/clan-cli/clan_cli/task_manager.py
@@ -186,6 +186,7 @@ def get_task(uuid: UUID) -> BaseTask:
T = TypeVar("T", bound="BaseTask")
+
@deal.raises(ClanError)
def create_task(task_type: Type[T], *args: Any) -> T:
global POOL
diff --git a/pkgs/clan-cli/default.nix b/pkgs/clan-cli/default.nix
index 263812fe0..2db7105d6 100644
--- a/pkgs/clan-cli/default.nix
+++ b/pkgs/clan-cli/default.nix
@@ -36,12 +36,17 @@
, deal
, rope
, clan-core-path
-, schemathesis
+, schemathesis ? null
}:
let
dependencies = [
argcomplete # optional dependency: if not enabled, shell completion will not work
+ wrapGAppsHook
+ gtk3
+ glib
+ gobject-introspection
+ pygobject3
];
pytestDependencies = runtimeDependencies ++ dependencies ++ [
diff --git a/pkgs/clan-cli/pyproject.toml b/pkgs/clan-cli/pyproject.toml
index 927de1d01..0979e0180 100644
--- a/pkgs/clan-cli/pyproject.toml
+++ b/pkgs/clan-cli/pyproject.toml
@@ -38,6 +38,11 @@ exclude = "clan_cli.nixpkgs"
module = "argcomplete.*"
ignore_missing_imports = true
+[[tool.mypy.overrides]]
+module = "gi.*"
+ignore_missing_imports = true
+
+
[[tool.mypy.overrides]]
module = "jsonschema.*"
ignore_missing_imports = true
@@ -58,4 +63,4 @@ ignore_missing_imports = true
line-length = 88
select = [ "E", "F", "I", "N"]
-ignore = [ "E501" ]
+ignore = [ "E501", "E402" ]
diff --git a/pkgs/clan-cli/tests/test_with_deal.py b/pkgs/clan-cli/tests/test_with_deal.py
index d471e2cba..8d1637901 100644
--- a/pkgs/clan-cli/tests/test_with_deal.py
+++ b/pkgs/clan-cli/tests/test_with_deal.py
@@ -1,13 +1,13 @@
import deal
-from clan_cli import task_manager
-from clan_cli import async_cmd
-from clan_cli import nix
+from clan_cli import nix, task_manager
+
@deal.cases(task_manager.get_task)
def test_get_task(case: deal.TestCase) -> None:
case()
+
@deal.cases(task_manager.create_task)
def test_create_task(case: deal.TestCase) -> None:
case()
@@ -17,18 +17,22 @@ def test_create_task(case: deal.TestCase) -> None:
def test_nix_command(case: deal.TestCase) -> None:
case()
+
@deal.cases(nix.nix_build)
def test_nix_build(case: deal.TestCase) -> None:
case()
+
@deal.cases(nix.nix_config)
def test_nix_config(case: deal.TestCase) -> None:
case()
+
@deal.cases(nix.nix_eval)
def test_nix_eval(case: deal.TestCase) -> None:
case()
+
@deal.cases(nix.nix_shell)
def test_nix_shell(case: deal.TestCase) -> None:
- case()
\ No newline at end of file
+ case()