···3132- [Bazecor](https://github.com/Dygmalab/Bazecor), the graphical configurator for Dygma Products.
330034- [scanservjs](https://github.com/sbs20/scanservjs/), a web UI for SANE scanners. Available at [services.scanservjs](#opt-services.scanservjs.enable).
3536- [Kimai](https://www.kimai.org/), a web-based multi-user time-tracking application. Available as [services.kimai](options.html#opt-services.kimai).
···38- [Omnom](https://github.com/asciimoo/omnom), a webpage bookmarking and snapshotting service. Available as [services.omnom](options.html#opt-services.omnom.enable).
3940- [MaryTTS](https://github.com/marytts/marytts), an open-source, multilingual text-to-speech synthesis system written in pure Java. Available as [services.marytts](options.html#opt-services.marytts).
004142- [Conduwuit](https://conduwuit.puppyirl.gay/), a federated chat server implementing the Matrix protocol, forked from Conduit. Available as [services.conduwuit](#opt-services.conduwuit.enable).
43···60- [mqtt-exporter](https://github.com/kpetremann/mqtt-exporter/), a Prometheus exporter for exposing messages from MQTT. Available as [services.prometheus.exporters.mqtt](#opt-services.prometheus.exporters.mqtt.enable).
6162- [nvidia-gpu](https://github.com/utkuozdemir/nvidia_gpu_exporter), a Prometheus exporter that scrapes `nvidia-smi` for GPU metrics. Available as [services.prometheus.exporters.nvidia-gpu](#opt-services.prometheus.exporters.nvidia-gpu.enable).
006364- [Buffyboard](https://gitlab.postmarketos.org/postmarketOS/buffybox/-/tree/master/buffyboard), a framebuffer on-screen keyboard. Available as [services.buffyboard](option.html#opt-services.buffyboard).
65
···3132- [Bazecor](https://github.com/Dygmalab/Bazecor), the graphical configurator for Dygma Products.
3334+- [Bonsai](https://git.sr.ht/~stacyharper/bonsai), a general-purpose event mapper/state machine primarily used to create complex key shortcuts, and as part of the [SXMO](https://sxmo.org/) desktop environment. Available as [services.bonsaid](#opt-services.bonsaid.enable).
35+36- [scanservjs](https://github.com/sbs20/scanservjs/), a web UI for SANE scanners. Available at [services.scanservjs](#opt-services.scanservjs.enable).
3738- [Kimai](https://www.kimai.org/), a web-based multi-user time-tracking application. Available as [services.kimai](options.html#opt-services.kimai).
···40- [Omnom](https://github.com/asciimoo/omnom), a webpage bookmarking and snapshotting service. Available as [services.omnom](options.html#opt-services.omnom.enable).
4142- [MaryTTS](https://github.com/marytts/marytts), an open-source, multilingual text-to-speech synthesis system written in pure Java. Available as [services.marytts](options.html#opt-services.marytts).
43+44+- [networking.modemmanager](options.html#opt-networking.modemmanager) has been split out of [networking.networkmanager](options.html#opt-networking.networkmanager). NetworkManager still enables ModemManager by default, but options exist now to run NetworkManager without ModemManager.
4546- [Conduwuit](https://conduwuit.puppyirl.gay/), a federated chat server implementing the Matrix protocol, forked from Conduit. Available as [services.conduwuit](#opt-services.conduwuit.enable).
47···64- [mqtt-exporter](https://github.com/kpetremann/mqtt-exporter/), a Prometheus exporter for exposing messages from MQTT. Available as [services.prometheus.exporters.mqtt](#opt-services.prometheus.exporters.mqtt.enable).
6566- [nvidia-gpu](https://github.com/utkuozdemir/nvidia_gpu_exporter), a Prometheus exporter that scrapes `nvidia-smi` for GPU metrics. Available as [services.prometheus.exporters.nvidia-gpu](#opt-services.prometheus.exporters.nvidia-gpu.enable).
67+68+- [InputPlumber](https://github.com/ShadowBlip/InputPlumber/), an open source input router and remapper daemon for Linux. Available as [services.inputplumber](#opt-services.inputplumber.enable).
6970- [Buffyboard](https://gitlab.postmarketos.org/postmarketOS/buffybox/-/tree/master/buffyboard), a framebuffer on-screen keyboard. Available as [services.buffyboard](option.html#opt-services.buffyboard).
71
···1+{
2+ config,
3+ lib,
4+ pkgs,
5+ ...
6+}:
7+let
8+ json = pkgs.formats.json { };
9+ transitionType = lib.types.submodule {
10+ freeformType = json.type;
11+ options.type = lib.mkOption {
12+ type = lib.types.enum [
13+ "delay"
14+ "event"
15+ "exec"
16+ ];
17+ description = ''
18+ Type of transition. Determines how bonsaid interprets the other options in this transition.
19+ '';
20+ };
21+ options.command = lib.mkOption {
22+ type = lib.types.nullOr (lib.types.listOf lib.types.str);
23+ default = null;
24+ description = ''
25+ Command to run when this transition is taken.
26+ This is executed inline by `bonsaid` and blocks handling of any other events until completion.
27+ To perform the command asynchronously, specify it like `[ "setsid" "-f" "my-command" ]`.
28+29+ Only effects transitions with `type = "exec"`.
30+ '';
31+ };
32+ options.delay_duration = lib.mkOption {
33+ type = lib.types.nullOr lib.types.int;
34+ default = null;
35+ description = ''
36+ Nanoseconds to wait after the previous state change before performing this transition.
37+ This can be placed at the same level as a `type = "event"` transition to achieve a
38+ timeout mechanism.
39+40+ Only effects transitions with `type = "delay"`.
41+ '';
42+ };
43+ options.event_name = lib.mkOption {
44+ type = lib.types.nullOr lib.types.str;
45+ default = null;
46+ description = ''
47+ Name of the event which should trigger this transition when received by `bonsaid`.
48+ Events are sent to `bonsaid` by running `bonsaictl -e <event_name>`.
49+50+ Only effects transitions with `type = "event"`.
51+ '';
52+ };
53+ options.transitions = lib.mkOption {
54+ type = lib.types.listOf transitionType;
55+ default = [ ];
56+ description = ''
57+ List of transitions out of this state.
58+ If left empty, then this state is considered a terminal state and entering it will
59+ trigger an immediate transition back to the root state (after processing side effects).
60+ '';
61+ visible = "shallow";
62+ };
63+ };
64+ cfg = config.services.bonsaid;
65+in
66+{
67+ meta.maintainers = [ lib.maintainers.colinsane ];
68+69+ options.services.bonsaid = {
70+ enable = lib.mkEnableOption "bonsaid";
71+ package = lib.mkPackageOption pkgs "bonsai" { };
72+ extraFlags = lib.mkOption {
73+ type = lib.types.listOf lib.types.str;
74+ default = [ ];
75+ description = ''
76+ Extra flags to pass to `bonsaid`, such as `[ "-v" ]` to enable verbose logging.
77+ '';
78+ };
79+ settings = lib.mkOption {
80+ type = lib.types.listOf transitionType;
81+ description = ''
82+ State transition definitions. See the upstream [README](https://git.sr.ht/~stacyharper/bonsai)
83+ for extended documentation and a more complete example.
84+ '';
85+ example = [
86+ {
87+ type = "event";
88+ event_name = "power_button_pressed";
89+ transitions = [
90+ {
91+ # Hold power button for 600ms to trigger a command
92+ type = "delay";
93+ delay_duration = 600000000;
94+ transitions = [
95+ {
96+ type = "exec";
97+ command = [
98+ "swaymsg"
99+ "--"
100+ "output"
101+ "*"
102+ "power"
103+ "off"
104+ ];
105+ # `transitions = []` marks this as a terminal state,
106+ # so bonsai will return to the root state immediately after executing the above command.
107+ transitions = [ ];
108+ }
109+ ];
110+ }
111+ {
112+ # If the power button is released before the 600ms elapses, return to the root state.
113+ type = "event";
114+ event_name = "power_button_released";
115+ transitions = [ ];
116+ }
117+ ];
118+ }
119+ ];
120+ };
121+ configFile = lib.mkOption {
122+ type = lib.types.path;
123+ description = ''
124+ Path to a .json file specifying the state transitions.
125+ You don't need to set this unless you prefer to provide the json file
126+ yourself instead of using the `settings` option.
127+ '';
128+ };
129+ };
130+131+ config = lib.mkIf cfg.enable {
132+ services.bonsaid.configFile =
133+ let
134+ filterNulls =
135+ v:
136+ if lib.isAttrs v then
137+ lib.mapAttrs (_: filterNulls) (lib.filterAttrs (_: a: a != null) v)
138+ else if lib.isList v then
139+ lib.map filterNulls (lib.filter (a: a != null) v)
140+ else
141+ v;
142+ in
143+ lib.mkDefault (json.generate "bonsai_tree.json" (filterNulls cfg.settings));
144+145+ # bonsaid is controlled by bonsaictl, so place the latter in the environment by default.
146+ # bonsaictl is typically invoked by scripts or a DE so this isn't strictly necesssary,
147+ # but it's helpful while administering the service generally.
148+ environment.systemPackages = [ cfg.package ];
149+150+ systemd.user.services.bonsaid = {
151+ description = "Bonsai Finite State Machine daemon";
152+ documentation = [ "https://git.sr.ht/~stacyharper/bonsai" ];
153+ wantedBy = [ "multi-user.target" ];
154+ serviceConfig = {
155+ ExecStart = lib.escapeShellArgs (
156+ [
157+ (lib.getExe' cfg.package "bonsaid")
158+ "-t"
159+ cfg.configFile
160+ ]
161+ ++ cfg.extraFlags
162+ );
163+ Restart = "on-failure";
164+ RestartSec = "5s";
165+ };
166+ };
167+ };
168+}
···60 };
6162 buildType = "production";
63-64- cargoBuildFlags = [
65- "-p"
66- "polkadot"
67- "-p"
68- "polkadot-omni-node"
69- "-p"
70- "polkadot-parachain-bin"
71- ];
7273 # NOTE: tests currently fail to compile due to an issue with cargo-auditable
74 # and resolution of features flags, potentially related to this:
···100 ROCKSDB_LIB_DIR = "${rocksdb}/lib";
101102 meta = with lib; {
103- description = "Polkadot Node Implementation";
104- homepage = "https://polkadot.network";
105 license = licenses.gpl3Only;
106 maintainers = with maintainers; [
107 akru
···60 };
6162 buildType = "production";
63+ buildAndTestSubdir = "polkadot";
000000006465 # NOTE: tests currently fail to compile due to an issue with cargo-auditable
66 # and resolution of features flags, potentially related to this:
···92 ROCKSDB_LIB_DIR = "${rocksdb}/lib";
9394 meta = with lib; {
95+ description = "Implementation of a https://polkadot.network node in Rust based on the Substrate framework";
96+ homepage = "https://github.com/paritytech/polkadot-sdk";
97 license = licenses.gpl3Only;
98 maintainers = with maintainers; [
99 akru
···276 build_attr = BuildAttr.from_arg(args.attr, args.file)
277 drv = nix.build(attr, build_attr, **build_flags, no_out_link=True)
278 except CalledProcessError:
279- logger.warning("could not build a newer version of nixos-rebuild")
000280281 if drv:
282 new = drv / f"bin/{EXECUTABLE}"
···284 if new != current:
285 logging.debug(
286 "detected newer version of script, re-exec'ing, current=%s, new=%s",
287- argv[0],
288 new,
289 )
290 # Manually call clean-up functions since os.execve() will replace
291 # the process immediately
292 cleanup_ssh()
293 tmpdir.TMPDIR.cleanup()
294- os.execve(new, argv, os.environ | {"_NIXOS_REBUILD_REEXEC": "1"})
0000000000000295296297def execute(argv: list[str]) -> None:
···276 build_attr = BuildAttr.from_arg(args.attr, args.file)
277 drv = nix.build(attr, build_attr, **build_flags, no_out_link=True)
278 except CalledProcessError:
279+ logger.warning(
280+ "could not build a newer version of nixos-rebuild, "
281+ + "using current version"
282+ )
283284 if drv:
285 new = drv / f"bin/{EXECUTABLE}"
···287 if new != current:
288 logging.debug(
289 "detected newer version of script, re-exec'ing, current=%s, new=%s",
290+ current,
291 new,
292 )
293 # Manually call clean-up functions since os.execve() will replace
294 # the process immediately
295 cleanup_ssh()
296 tmpdir.TMPDIR.cleanup()
297+ try:
298+ os.execve(new, argv, os.environ | {"_NIXOS_REBUILD_REEXEC": "1"})
299+ except Exception:
300+ # Possible errors that we can have here:
301+ # - Missing the binary
302+ # - Exec format error (e.g.: another OS/CPU arch)
303+ logger.warning(
304+ "could not re-exec in a newer version of nixos-rebuild, "
305+ + "using current version"
306+ )
307+ logger.debug("re-exec exception", exc_info=True)
308+ # We already run clean-up, let's re-exec in the current version
309+ # to avoid issues
310+ os.execve(current, argv, os.environ | {"_NIXOS_REBUILD_REEXEC": "1"})
311312313def execute(argv: list[str]) -> None: