]> git.scottworley.com Git - nix-env-apps/blob - apps.py
155671490fdbbecf10fc313e852aadf2ba7e8b99
[nix-env-apps] / apps.py
1 import os
2 import subprocess
3 from typing import Any, Callable
4
5 import gi
6 gi.require_version("Gtk", "4.0")
7 from gi.repository import Gtk # nopep8 pylint: disable=wrong-import-position
8
9
10 def on_edit(_: Any) -> None:
11 config_dir = os.path.join(
12 os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')),
13 'nixpkgs',
14 'overlays')
15 os.makedirs(config_dir, exist_ok=True)
16 config_file = os.path.join(config_dir, 'userPackages.nix')
17 try:
18 with open(config_file, mode="x", encoding='utf-8') as f:
19 f.write('''final: prev: {
20 userPackages = final.buildEnv {
21 name = "userPackages";
22 paths = (with final; [
23
24
25
26 ];
27 };
28 }
29 ''')
30 except FileExistsError:
31 pass
32 subprocess.run(['xdg-open', config_file], check=True)
33
34
35 def try_exec_terminal(terminal: str, args: list[str]) -> None:
36 try:
37 os.execvp(terminal, [terminal] + args)
38 except FileNotFoundError:
39 pass
40
41
42 def on_apply(_: Any) -> None:
43 command = ['nix-env', '-riA', 'nixos.userPackages']
44 command_string = ' '.join(command)
45 close_string = (
46 ''' && read -p "SUCCESS: Press ENTER to close this window"''' +
47 ''' || read -p "FAILURE: Press ENTER to close this window"''')
48 # This should be a simple `xdg-terminal` invocation, but as of 2025,
49 # xdg-terminal is extremely broken in Gnome:
50 # * It doesn't cause a terminal window to appear
51 # * It doesn't run the given command
52 # * It exits with status 0, so you can't even tell that it failed
53 # * There's no way for the user to configure their preferred terminal?
54 # So we just try launching a whole bunch of terminals until we find one
55 # that works
56 if os.fork() == 0:
57 try_exec_terminal('kitty', ['sh', '-c', command_string + close_string])
58 try_exec_terminal(
59 'alactritty', [
60 '-e', 'sh', '-c', command_string + close_string])
61 try_exec_terminal('kgx', ['--'] + command)
62 try_exec_terminal(
63 'konsole', [
64 '-e', 'sh', '-c', command_string + close_string])
65 try_exec_terminal('xfce4-terminal', ['--hold', '-e', command_string])
66 try_exec_terminal('st', ['sh', '-c', command_string + close_string])
67 try_exec_terminal(
68 'urxvt', [
69 '-e', 'sh', '-c', command_string + close_string])
70 try_exec_terminal(
71 'xterm', [
72 '-e', 'sh', '-c', command_string + close_string])
73
74 # Don't even try gnome-terminal. Sometimes it will start, but not run the command,
75 # and exit with status 0 so we wouldn't even be able to tell that there was a problem.
76 # try_exec_terminal('gnome-terminal', ['--', 'sh', '-c', command_string + close_string])
77
78 # As a last resort, run the command directly, without a terminal, where
79 # the user probably can't see it. :(
80 os.execvp(command[0], command)
81
82
83 def make_button(label: str, action: Callable[[Any], None]) -> Gtk.Button:
84 button = Gtk.Button(label=label)
85 button.connect('clicked', action)
86 button.set_margin_top(10)
87 button.set_margin_start(10)
88 button.set_margin_end(10)
89 button.set_margin_bottom(10)
90 return button
91
92
93 def on_activate(app: Gtk.Application) -> None:
94 win = Gtk.ApplicationWindow(application=app)
95 win.set_title('Apps')
96 box = Gtk.Box()
97 box.set_orientation(Gtk.Orientation.VERTICAL)
98 edit = make_button("Edit Configuration", on_edit)
99 apply = make_button("Apply Configuration", on_apply)
100 box.append(edit)
101 box.append(apply)
102 win.set_child(box)
103 win.present()
104
105
106 def main() -> None:
107 app = Gtk.Application(application_id='net.chkno.nix-env-apps')
108 app.connect('activate', on_activate)
109 app.run(None)
110
111
112 if __name__ == '__main__':
113 main()