mirror of
https://github.com/nix-community/home-manager.git
synced 2026-01-11 17:39:37 +08:00
Compare commits
97 Commits
putter-poc
...
4e8b7bef66
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e8b7bef66 | ||
|
|
6e94d8157c | ||
|
|
6e3931c01f | ||
|
|
c91dbdf61a | ||
|
|
38e187fd2f | ||
|
|
9bfca5b3a7 | ||
|
|
bfaba198af | ||
|
|
b1421bdfe5 | ||
|
|
4cd7ae4cd4 | ||
|
|
e43f7c3321 | ||
|
|
6841643203 | ||
|
|
a755d94ab0 | ||
|
|
33fe25dbe5 | ||
|
|
337d3602c0 | ||
|
|
5d814af6af | ||
|
|
787784fb6f | ||
|
|
2379f704b0 | ||
|
|
a26335db1b | ||
|
|
d016674f6a | ||
|
|
c2d3a75ebe | ||
|
|
93af99ec02 | ||
|
|
c8b68aafed | ||
|
|
bca7415de4 | ||
|
|
d070d83048 | ||
|
|
048104c098 | ||
|
|
af894fbbc7 | ||
|
|
53084c95ce | ||
|
|
a65c04965c | ||
|
|
c4eabb884b | ||
|
|
156b698b75 | ||
|
|
9d1c71f390 | ||
|
|
47e195783e | ||
|
|
f894bc4ffd | ||
|
|
73f5a5ecc9 | ||
|
|
7d5927b63c | ||
|
|
8f7d6bacb6 | ||
|
|
12cc14271b | ||
|
|
c211298f7e | ||
|
|
1cfa305fba | ||
|
|
3e87b442b5 | ||
|
|
99a037de18 | ||
|
|
3b3164dfe3 | ||
|
|
bc43546503 | ||
|
|
78a8fae57f | ||
|
|
b558d54215 | ||
|
|
9ef24320f1 | ||
|
|
18f9d668aa | ||
|
|
2f06b72606 | ||
|
|
d4e4d5cfa3 | ||
|
|
e4e78a2cbe | ||
|
|
ae1ea768ef | ||
|
|
365cbc13c4 | ||
|
|
d99b4ca5de | ||
|
|
64f4dadb80 | ||
|
|
7a7b43c723 | ||
|
|
a84cccefd4 | ||
|
|
9d32c214db | ||
|
|
87785ddbc7 | ||
|
|
113b155fe8 | ||
|
|
398bc87bc8 | ||
|
|
3613abcbd7 | ||
|
|
d7e794fe12 | ||
|
|
8969535f1c | ||
|
|
80cca72314 | ||
|
|
d2e0458d65 | ||
|
|
b3ae822959 | ||
|
|
d761c0ce89 | ||
|
|
f84f474c1b | ||
|
|
ea6dfabe3c | ||
|
|
5432dc5bc4 | ||
|
|
bec08ef6e3 | ||
|
|
4067ca1ffb | ||
|
|
2d36a6de2f | ||
|
|
91cdb0e2d5 | ||
|
|
7eca7f7081 | ||
|
|
20728df08f | ||
|
|
af3c24de76 | ||
|
|
624c7e80fb | ||
|
|
9c790e687e | ||
|
|
527ad07e66 | ||
|
|
57a02fd7d9 | ||
|
|
3fe66908e0 | ||
|
|
61fcc9de76 | ||
|
|
7b73a6e98f | ||
|
|
4dc3c91c50 | ||
|
|
a7d6bba358 | ||
|
|
bdb807dc28 | ||
|
|
0a583021ea | ||
|
|
ab01ea24b2 | ||
|
|
c764a377a0 | ||
|
|
28b3622b80 | ||
|
|
c848303f1e | ||
|
|
bb35f07cc9 | ||
|
|
9bf54edf10 | ||
|
|
89c9508bbe | ||
|
|
22202ff0d8 | ||
|
|
2f93d7333e |
@@ -1097,19 +1097,6 @@
|
||||
name = "Hoang Nguyen";
|
||||
source = "home-manager";
|
||||
};
|
||||
foo-dogsquared = {
|
||||
email = "foodogsquared@foodogsquared.one";
|
||||
github = "foo-dogsquared";
|
||||
githubId = 34962634;
|
||||
keys = [
|
||||
{
|
||||
fingerprint = "DDD7 D0BD 602E 564B AA04 FC35 1431 0D91 4115 2B92";
|
||||
}
|
||||
];
|
||||
matrix = "@foodogsquared:matrix.org";
|
||||
name = "Gabriel Arazas";
|
||||
source = "nixpkgs";
|
||||
};
|
||||
fpob = {
|
||||
email = "fpob@proton.me";
|
||||
github = "fpob";
|
||||
@@ -2078,7 +2065,7 @@
|
||||
source = "nixpkgs";
|
||||
};
|
||||
shikanime = {
|
||||
email = "deva.shikanime@protonmail.com";
|
||||
email = "william.phetsinorath@shikanime.studio";
|
||||
github = "shikanime";
|
||||
githubId = 22115108;
|
||||
name = "William Phetsinorath";
|
||||
|
||||
@@ -57,3 +57,9 @@ changes are only active if the `home.stateVersion` option is set to
|
||||
|
||||
now default to `true` which is consistent with the default values
|
||||
for those options used by `i3` and `sway`.
|
||||
|
||||
- The [](#opt-programs.swaylock.enable) option now defaults to `false`
|
||||
and must be explicitly enabled. Previously, it would be implicitly
|
||||
enabled when `programs.swaylock.settings` was non-empty. Users with
|
||||
`home.stateVersion` set to earlier versions will continue to get the
|
||||
old implicit behavior.
|
||||
|
||||
@@ -27,4 +27,8 @@ The state version in this release includes the changes below. These
|
||||
changes are only active if the `home.stateVersion` option is set to
|
||||
\"25.05\" or later.
|
||||
|
||||
- No changes.
|
||||
- The [](#opt-programs.git.signing.format) option no longer defaults to
|
||||
`"openpgp"`. Users who use Git signing with GPG should explicitly set
|
||||
this option to `"openpgp"` to maintain the previous behavior. Users
|
||||
with `home.stateVersion` set to earlier versions will continue to get
|
||||
the `"openpgp"` default for backwards compatibility.
|
||||
|
||||
@@ -80,3 +80,10 @@ changes are only active if the `home.stateVersion` option is set to
|
||||
`{ PASSWORD_STORE_DIR = $XDG_DATA_HOME/password-store; }` anymore by its
|
||||
default value. This will revert to the default behaviour of the program,
|
||||
namely `$HOME/.password-store` to be used as the store path.
|
||||
|
||||
- On macOS, [](#opt-targets.darwin.copyApps.enable) is now enabled by
|
||||
default instead of [](#opt-targets.darwin.linkApps.enable). This means
|
||||
applications from `home.packages` will be copied to
|
||||
`~/Applications/Home Manager Apps` rather than symlinked, making them
|
||||
work properly with Spotlight. Users with `home.stateVersion` set to
|
||||
earlier versions will continue to use `linkApps` by default.
|
||||
|
||||
@@ -7,11 +7,19 @@ section is therefore not final.
|
||||
|
||||
This release has the following notable changes:
|
||||
|
||||
- The [](#opt-programs.anki.uiScale) option now expects a value in the
|
||||
range 1.0–2.0, previously it erroneously expected values in the
|
||||
range `0.0–1.0`.
|
||||
|
||||
## State Version Changes {#sec-release-26.05-state-version-changes}
|
||||
|
||||
The state version in this release includes the changes below. These
|
||||
changes are only active if the `home.stateVersion` option is set to
|
||||
\"26.05\" or later.
|
||||
|
||||
- The `gtk.gtk4.theme` option does not mirror `gtk.theme` by default
|
||||
anymore.
|
||||
- The [](#opt-gtk.gtk4.theme) option does not mirror
|
||||
[](#opt-gtk.theme) by default anymore.
|
||||
|
||||
- The [](#opt-programs.zsh.dotDir) option now defaults to the XDG
|
||||
configuration directory (usually `~/.config/zsh`) when
|
||||
[](#opt-xdg.enable) is true.
|
||||
|
||||
6
flake.lock
generated
6
flake.lock
generated
@@ -2,11 +2,11 @@
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1765472234,
|
||||
"narHash": "sha256-9VvC20PJPsleGMewwcWYKGzDIyjckEz8uWmT0vCDYK0=",
|
||||
"lastModified": 1766902085,
|
||||
"narHash": "sha256-coBu0ONtFzlwwVBzmjacUQwj3G+lybcZ1oeNSQkgC0M=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "2fbfb1d73d239d2402a8fe03963e37aab15abe8b",
|
||||
"rev": "c0b0e0fddf73fd517c3471e546c0df87a42d53f4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: Home Manager\n"
|
||||
"Report-Msgid-Bugs-To: https://github.com/nix-community/home-manager/issues\n"
|
||||
"POT-Creation-Date: 2025-07-22 10:59+0200\n"
|
||||
"PO-Revision-Date: 2025-12-04 04:17+0000\n"
|
||||
"PO-Revision-Date: 2025-12-04 09:16+0000\n"
|
||||
"Last-Translator: \"Urocissa Caerulea.Tw\" <urocissa.tw@proton.me>\n"
|
||||
"Language-Team: Chinese (Traditional Han script) <https://hosted.weblate.org/"
|
||||
"projects/home-manager/cli/zh_Hant/>\n"
|
||||
@@ -215,7 +215,7 @@ msgstr "沒有即將過期的世代"
|
||||
|
||||
#: home-manager/home-manager:877
|
||||
msgid "No home-manager packages seem to be installed."
|
||||
msgstr "似乎沒有安裝 home-manager 軟體包。"
|
||||
msgstr "似乎沒有安裝 home-manager 套件。"
|
||||
|
||||
#: home-manager/home-manager:962
|
||||
msgid "Unknown argument %s"
|
||||
@@ -223,11 +223,11 @@ msgstr "未知引數 %s"
|
||||
|
||||
#: home-manager/home-manager:987
|
||||
msgid "This will remove Home Manager from your system."
|
||||
msgstr "這將會從系統中移除 Home Manager。"
|
||||
msgstr "這將會從您的系統中移除 Home Manager。"
|
||||
|
||||
#: home-manager/home-manager:990
|
||||
msgid "This is a dry run, nothing will actually be uninstalled."
|
||||
msgstr "這是試執行結果,沒有實際解除安裝任何軟體包。"
|
||||
msgstr "這是模擬執行,實際上並不會解除安裝任何內容。"
|
||||
|
||||
#: home-manager/home-manager:994
|
||||
msgid "Really uninstall Home Manager?"
|
||||
@@ -235,27 +235,27 @@ msgstr "確定要解除安裝 Home Manager 嗎?"
|
||||
|
||||
#: home-manager/home-manager:1000
|
||||
msgid "Switching to empty Home Manager configuration..."
|
||||
msgstr "正在切換至空的 Home Manager 配置 ..."
|
||||
msgstr "正在切換至空的 Home Manager 設定..."
|
||||
|
||||
#: home-manager/home-manager:1015
|
||||
msgid "Yay!"
|
||||
msgstr "好耶!"
|
||||
msgstr "太好了!"
|
||||
|
||||
#: home-manager/home-manager:1020
|
||||
msgid "Home Manager is uninstalled but your home.nix is left untouched."
|
||||
msgstr "Home Manager 已解除安裝,但未改動您的 home.nix 配置檔案。"
|
||||
msgstr "Home Manager 已解除安裝,但您的 home.nix 保持不變。"
|
||||
|
||||
#: home-manager/home-manager:1285
|
||||
msgid "expire-generations expects one argument, got %d."
|
||||
msgstr "expire-generations 須要一個引數,但獲取到了 %d 個。"
|
||||
msgstr "expire-generations 預期一個引數,但得到了 %d 個。"
|
||||
|
||||
#: home-manager/home-manager:1310
|
||||
msgid "Unknown command: %s"
|
||||
msgstr "未知命令:%s"
|
||||
msgstr "未知指令:%s"
|
||||
|
||||
#: home-manager/install.nix:21
|
||||
msgid "This derivation is not buildable, please run it using nix-shell."
|
||||
msgstr "此配置檔案/變體不可構建,請在 nix-shell 中執行它。"
|
||||
msgstr "此 derivation 無法建置,請使用 nix-shell 執行。"
|
||||
|
||||
#, sh-format
|
||||
#~ msgid "Please set the $EDITOR environment variable"
|
||||
|
||||
@@ -270,9 +270,7 @@ in
|
||||
setupLaunchAgents
|
||||
|
||||
# Restore errexit
|
||||
if [[ -o errexit ]]; then
|
||||
set -e
|
||||
fi
|
||||
set -e
|
||||
'';
|
||||
})
|
||||
];
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
isList
|
||||
mapAttrsToList
|
||||
replicate
|
||||
attrNames
|
||||
;
|
||||
|
||||
initialIndent = concatStrings (replicate indentLevel " ");
|
||||
@@ -28,31 +29,36 @@
|
||||
toHyprconf' =
|
||||
indent: attrs:
|
||||
let
|
||||
sections = filterAttrs (n: v: isAttrs v || (isList v && all isAttrs v)) attrs;
|
||||
isImportantField =
|
||||
n: _: foldl (acc: prev: if hasPrefix prev n then true else acc) false importantPrefixes;
|
||||
importantFields = filterAttrs isImportantField attrs;
|
||||
withoutImportantFields = fields: removeAttrs fields (attrNames importantFields);
|
||||
|
||||
allSections = filterAttrs (n: v: isAttrs v || isList v) attrs;
|
||||
sections = withoutImportantFields allSections;
|
||||
|
||||
mkSection =
|
||||
n: attrs:
|
||||
if lib.isList attrs then
|
||||
(concatMapStringsSep "\n" (a: mkSection n a) attrs)
|
||||
else
|
||||
if isList attrs then
|
||||
let
|
||||
separator = if all isAttrs attrs then "\n" else "";
|
||||
in
|
||||
(concatMapStringsSep separator (a: mkSection n a) attrs)
|
||||
else if isAttrs attrs then
|
||||
''
|
||||
${indent}${n} {
|
||||
${toHyprconf' " ${indent}" attrs}${indent}}
|
||||
'';
|
||||
''
|
||||
else
|
||||
toHyprconf' indent { ${n} = attrs; };
|
||||
|
||||
mkFields = generators.toKeyValue {
|
||||
listsAsDuplicateKeys = true;
|
||||
inherit indent;
|
||||
};
|
||||
|
||||
allFields = filterAttrs (n: v: !(isAttrs v || (isList v && all isAttrs v))) attrs;
|
||||
|
||||
isImportantField =
|
||||
n: _: foldl (acc: prev: if hasPrefix prev n then true else acc) false importantPrefixes;
|
||||
|
||||
importantFields = filterAttrs isImportantField allFields;
|
||||
|
||||
fields = builtins.removeAttrs allFields (mapAttrsToList (n: _: n) importantFields);
|
||||
allFields = filterAttrs (n: v: !(isAttrs v || isList v)) attrs;
|
||||
fields = withoutImportantFields allFields;
|
||||
in
|
||||
mkFields importantFields
|
||||
+ concatStringsSep "\n" (mapAttrsToList mkSection sections)
|
||||
|
||||
20
modules/misc/news/2025/12/2025-12-27_13-32-14.nix
Normal file
20
modules/misc/news/2025/12/2025-12-27_13-32-14.nix
Normal file
@@ -0,0 +1,20 @@
|
||||
{ config, ... }:
|
||||
{
|
||||
time = "2025-12-27T19:00:00+00:00";
|
||||
condition = config.programs.zsh.enable;
|
||||
|
||||
message = ''
|
||||
The default value of `programs.zsh.dotDir` has changed.
|
||||
|
||||
When `home.stateVersion` is set to "26.05" or later, and `xdg.enable` is
|
||||
`true` (the default), `programs.zsh.dotDir` now defaults to
|
||||
`''${config.xdg.configHome}/zsh`. Previously, it defaulted to the home
|
||||
directory.
|
||||
|
||||
This means your Zsh configuration files (`.zshrc`, `.zshenv`, etc.) will be
|
||||
moved to `~/.config/zsh` (or your configured XDG config home).
|
||||
|
||||
If you prefer the old behavior, you can explicitly set:
|
||||
`programs.zsh.dotDir = config.home.homeDirectory;`
|
||||
'';
|
||||
}
|
||||
10
modules/misc/news/2026/01/2026-01-02_00-03-48.nix
Normal file
10
modules/misc/news/2026/01/2026-01-02_00-03-48.nix
Normal file
@@ -0,0 +1,10 @@
|
||||
{ config, ... }:
|
||||
{
|
||||
time = "2026-01-02T00:03:48+00:00";
|
||||
condition = config.services.mpd.enable;
|
||||
message = ''
|
||||
`MPD_HOST` and `MPD_PORT` environment variables are now set automatically.
|
||||
|
||||
This can be disabled with `services.mpd.enableSessionVariables = false`.
|
||||
'';
|
||||
}
|
||||
@@ -136,7 +136,7 @@ in
|
||||
xdg.stateHome = mkOptionDefault defaultStateHome;
|
||||
|
||||
home.sessionVariables = variables;
|
||||
systemd.user.sessionVariables = mkIf pkgs.stdenv.hostPlatform.isLinux variables;
|
||||
systemd.user.sessionVariables = variables;
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ in
|
||||
home.activation.xfconfSettings = lib.hm.dag.entryAfter [ "installPackages" ] (
|
||||
let
|
||||
mkCommand = channel: property: value: ''
|
||||
run ${pkgs.xfce.xfconf}/bin/xfconf-query \
|
||||
run ${pkgs.xfconf}/bin/xfconf-query \
|
||||
${lib.escapeShellArgs (
|
||||
[
|
||||
"-c"
|
||||
|
||||
@@ -82,7 +82,7 @@ in
|
||||
};
|
||||
|
||||
uiScale = lib.mkOption {
|
||||
type = with lib.types; nullOr (numbers.between 0.0 1.0);
|
||||
type = with lib.types; nullOr (numbers.between 1.0 2.0);
|
||||
default = null;
|
||||
example = 1.0;
|
||||
description = "User interface scale.";
|
||||
|
||||
@@ -112,7 +112,7 @@ let
|
||||
|
||||
answer_keys: tuple[tuple[int, str], ...] = (${
|
||||
lib.strings.concatMapStringsSep ", " (val: "(${toString val.ease}, '${val.key}')") cfg.answerKeys
|
||||
})
|
||||
}${if cfg.answerKeys != [ ] then "," else ""})
|
||||
for ease, key in answer_keys:
|
||||
profile_manager.set_answer_key(ease, key)
|
||||
|
||||
|
||||
@@ -185,7 +185,7 @@ in
|
||||
|
||||
extraCss = mkOption {
|
||||
type = nullOr lines;
|
||||
default = "";
|
||||
default = null;
|
||||
description = ''
|
||||
Extra CSS lines to add to {file}`~/.config/anyrun/style.css`.
|
||||
'';
|
||||
|
||||
@@ -11,7 +11,6 @@ let
|
||||
tomlFormat = pkgs.formats.toml { };
|
||||
|
||||
inherit (lib) mkIf mkOption types;
|
||||
inherit (pkgs.stdenv) isLinux isDarwin;
|
||||
in
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [
|
||||
@@ -221,98 +220,82 @@ in
|
||||
};
|
||||
}
|
||||
|
||||
(mkIf daemonCfg.enable (
|
||||
lib.mkMerge [
|
||||
(mkIf daemonCfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertions = [
|
||||
{
|
||||
assertion = lib.versionAtLeast cfg.package.version "18.2.0";
|
||||
message = ''
|
||||
The Atuin daemon requires at least version 18.2.0 or later.
|
||||
'';
|
||||
}
|
||||
{
|
||||
assertion = isLinux || isDarwin;
|
||||
message = "The Atuin daemon can only be configured on either Linux or macOS.";
|
||||
}
|
||||
];
|
||||
|
||||
programs.atuin.settings = {
|
||||
daemon = {
|
||||
enabled = true;
|
||||
};
|
||||
};
|
||||
assertion = lib.versionAtLeast cfg.package.version "18.2.0";
|
||||
message = ''
|
||||
The Atuin daemon requires at least version 18.2.0 or later.
|
||||
'';
|
||||
}
|
||||
(mkIf isLinux {
|
||||
programs.atuin.settings = {
|
||||
daemon = {
|
||||
systemd_socket = true;
|
||||
};
|
||||
};
|
||||
{
|
||||
assertion = config.systemd.user.enable || config.launchd.enable;
|
||||
message = "The Atuin daemon can only be configured on systems with systemd or launchd.";
|
||||
}
|
||||
];
|
||||
|
||||
systemd.user.services.atuin-daemon = {
|
||||
Unit = {
|
||||
Description = "Atuin daemon";
|
||||
Requires = [ "atuin-daemon.socket" ];
|
||||
};
|
||||
Install = {
|
||||
Also = [ "atuin-daemon.socket" ];
|
||||
WantedBy = [ "default.target" ];
|
||||
};
|
||||
Service = {
|
||||
ExecStart = "${lib.getExe cfg.package} daemon";
|
||||
Environment = lib.optionals (daemonCfg.logLevel != null) [ "ATUIN_LOG=${daemonCfg.logLevel}" ];
|
||||
Restart = "on-failure";
|
||||
RestartSteps = 3;
|
||||
RestartMaxDelaySec = 6;
|
||||
};
|
||||
};
|
||||
programs.atuin.settings.daemon = {
|
||||
enabled = true;
|
||||
systemd_socket = config.systemd.user.enable;
|
||||
socket_path = lib.mkIf (!config.systemd.user.enable) (
|
||||
lib.mkDefault "${config.xdg.dataHome}/atuin/daemon.sock"
|
||||
);
|
||||
};
|
||||
|
||||
systemd.user.sockets.atuin-daemon =
|
||||
let
|
||||
socket_dir = if lib.versionAtLeast cfg.package.version "18.4.0" then "%t" else "%D/atuin";
|
||||
in
|
||||
{
|
||||
Unit = {
|
||||
Description = "Atuin daemon socket";
|
||||
};
|
||||
Install = {
|
||||
WantedBy = [ "sockets.target" ];
|
||||
};
|
||||
Socket = {
|
||||
ListenStream = "${socket_dir}/atuin.sock";
|
||||
SocketMode = "0600";
|
||||
RemoveOnStop = true;
|
||||
};
|
||||
};
|
||||
})
|
||||
(mkIf isDarwin {
|
||||
programs.atuin.settings = {
|
||||
daemon = {
|
||||
socket_path = lib.mkDefault "${config.xdg.dataHome}/atuin/daemon.sock";
|
||||
};
|
||||
};
|
||||
systemd.user.services.atuin-daemon = {
|
||||
Unit = {
|
||||
Description = "Atuin daemon";
|
||||
Requires = [ "atuin-daemon.socket" ];
|
||||
};
|
||||
Install = {
|
||||
Also = [ "atuin-daemon.socket" ];
|
||||
WantedBy = [ "default.target" ];
|
||||
};
|
||||
Service = {
|
||||
ExecStart = "${lib.getExe cfg.package} daemon";
|
||||
Environment = lib.optionals (daemonCfg.logLevel != null) [ "ATUIN_LOG=${daemonCfg.logLevel}" ];
|
||||
Restart = "on-failure";
|
||||
RestartSteps = 3;
|
||||
RestartMaxDelaySec = 6;
|
||||
};
|
||||
};
|
||||
|
||||
launchd.agents.atuin-daemon = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
"${lib.getExe cfg.package}"
|
||||
"daemon"
|
||||
];
|
||||
EnvironmentVariables = lib.optionalAttrs (daemonCfg.logLevel != null) {
|
||||
ATUIN_LOG = daemonCfg.logLevel;
|
||||
};
|
||||
KeepAlive = {
|
||||
Crashed = true;
|
||||
SuccessfulExit = false;
|
||||
};
|
||||
ProcessType = "Background";
|
||||
};
|
||||
systemd.user.sockets.atuin-daemon =
|
||||
let
|
||||
socket_dir = if lib.versionAtLeast cfg.package.version "18.4.0" then "%t" else "%D/atuin";
|
||||
in
|
||||
{
|
||||
Unit = {
|
||||
Description = "Atuin daemon socket";
|
||||
};
|
||||
})
|
||||
]
|
||||
))
|
||||
Install = {
|
||||
WantedBy = [ "sockets.target" ];
|
||||
};
|
||||
Socket = {
|
||||
ListenStream = "${socket_dir}/atuin.sock";
|
||||
SocketMode = "0600";
|
||||
RemoveOnStop = true;
|
||||
};
|
||||
};
|
||||
|
||||
launchd.agents.atuin-daemon = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
"${lib.getExe cfg.package}"
|
||||
"daemon"
|
||||
];
|
||||
EnvironmentVariables = lib.optionalAttrs (daemonCfg.logLevel != null) {
|
||||
ATUIN_LOG = daemonCfg.logLevel;
|
||||
};
|
||||
KeepAlive = {
|
||||
Crashed = true;
|
||||
SuccessfulExit = false;
|
||||
};
|
||||
ProcessType = "Background";
|
||||
};
|
||||
};
|
||||
})
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ let
|
||||
cfg = config.programs.bashmount;
|
||||
in
|
||||
{
|
||||
meta.maintainers = [ lib.maintainers.AndersonTorres ];
|
||||
meta.maintainers = [ ];
|
||||
|
||||
options.programs.bashmount = {
|
||||
enable = lib.mkEnableOption "bashmount";
|
||||
|
||||
@@ -197,6 +197,47 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
rules = lib.mkOption {
|
||||
type = lib.types.attrsOf (lib.types.either lib.types.lines lib.types.path);
|
||||
default = { };
|
||||
description = ''
|
||||
Modular rule files for Claude Code.
|
||||
The attribute name becomes the rule filename, and the value is either:
|
||||
- Inline content as a string
|
||||
- A path to a file containing the rule content
|
||||
Rules are stored in .claude/rules/ directory.
|
||||
All markdown files in .claude/rules/ are automatically loaded as project memory.
|
||||
'';
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
code-style = '''
|
||||
# Code Style Guidelines
|
||||
|
||||
- Use consistent formatting
|
||||
- Follow language conventions
|
||||
''';
|
||||
testing = '''
|
||||
# Testing Conventions
|
||||
|
||||
- Write tests for all new features
|
||||
- Maintain test coverage above 80%
|
||||
''';
|
||||
security = ./rules/security.md;
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
rulesDir = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
default = null;
|
||||
description = ''
|
||||
Path to a directory containing rule files for Claude Code.
|
||||
Rule files from this directory will be symlinked to .claude/rules/.
|
||||
All markdown files in this directory are automatically loaded as project memory.
|
||||
'';
|
||||
example = lib.literalExpression "./rules";
|
||||
};
|
||||
|
||||
agentsDir = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
default = null;
|
||||
@@ -325,6 +366,10 @@ in
|
||||
assertion = !(cfg.memory.text != null && cfg.memory.source != null);
|
||||
message = "Cannot specify both `programs.claude-code.memory.text` and `programs.claude-code.memory.source`";
|
||||
}
|
||||
{
|
||||
assertion = !(cfg.rules != { } && cfg.rulesDir != null);
|
||||
message = "Cannot specify both `programs.claude-code.rules` and `programs.claude-code.rulesDir`";
|
||||
}
|
||||
{
|
||||
assertion = !(cfg.agents != { } && cfg.agentsDir != null);
|
||||
message = "Cannot specify both `programs.claude-code.agents` and `programs.claude-code.agentsDir`";
|
||||
@@ -386,6 +431,11 @@ in
|
||||
if cfg.memory.text != null then { text = cfg.memory.text; } else { source = cfg.memory.source; }
|
||||
);
|
||||
|
||||
".claude/rules" = lib.mkIf (cfg.rulesDir != null) {
|
||||
source = cfg.rulesDir;
|
||||
recursive = true;
|
||||
};
|
||||
|
||||
".claude/agents" = lib.mkIf (cfg.agentsDir != null) {
|
||||
source = cfg.agentsDir;
|
||||
recursive = true;
|
||||
@@ -406,6 +456,12 @@ in
|
||||
recursive = true;
|
||||
};
|
||||
}
|
||||
// lib.mapAttrs' (
|
||||
name: content:
|
||||
lib.nameValuePair ".claude/rules/${name}.md" (
|
||||
if lib.isPath content then { source = content; } else { text = content; }
|
||||
)
|
||||
) cfg.rules
|
||||
// lib.mapAttrs' (
|
||||
name: content:
|
||||
lib.nameValuePair ".claude/agents/${name}.md" (
|
||||
|
||||
@@ -21,14 +21,19 @@ in
|
||||
settings = lib.mkOption {
|
||||
inherit (jsonFormat) type;
|
||||
default = { };
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
"theme": "Default",
|
||||
"vimMode": true,
|
||||
"preferredEditor": "nvim",
|
||||
"autoAccept": true
|
||||
}
|
||||
'';
|
||||
example = {
|
||||
ui.theme = "Default";
|
||||
general = {
|
||||
vimMode = true;
|
||||
preferredEditor = "nvim";
|
||||
previewFeatures = true;
|
||||
};
|
||||
ide.enabled = true;
|
||||
privacy.usageStatisticsEnabled = false;
|
||||
tools.autoAccept = false;
|
||||
context.loadMemoryFromIncludeDirectories = true;
|
||||
security.auth.selectedType = "oauth-personal";
|
||||
};
|
||||
description = "JSON config for gemini-cli";
|
||||
};
|
||||
|
||||
@@ -81,12 +86,12 @@ in
|
||||
};
|
||||
|
||||
defaultModel = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "gemini-2.5-pro";
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
example = "gemini-2.5-flash";
|
||||
description = ''
|
||||
The default model to use for the CLI.
|
||||
Will be set as $GEMINI_MODEL.
|
||||
Will be set as $GEMINI_MODEL when configured.
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -138,7 +143,9 @@ in
|
||||
file.".gemini/settings.json" = lib.mkIf (cfg.settings != { }) {
|
||||
source = jsonFormat.generate "gemini-cli-settings.json" cfg.settings;
|
||||
};
|
||||
sessionVariables.GEMINI_MODEL = cfg.defaultModel;
|
||||
sessionVariables = lib.mkIf (cfg.defaultModel != null) {
|
||||
GEMINI_MODEL = cfg.defaultModel;
|
||||
};
|
||||
};
|
||||
}
|
||||
{
|
||||
|
||||
@@ -224,8 +224,15 @@ in
|
||||
message = "Ghostty systemd integration cannot be enabled for non-linux platforms";
|
||||
}
|
||||
];
|
||||
|
||||
xdg.configFile."systemd/user/app-com.mitchellh.ghostty.service".source =
|
||||
"${cfg.package}/share/systemd/user/app-com.mitchellh.ghostty.service";
|
||||
|
||||
xdg.configFile."systemd/user/app-com.mitchellh.ghostty.service.d/overrides.conf".text = ''
|
||||
[Unit]
|
||||
X-SwitchMethod=keep-old
|
||||
'';
|
||||
|
||||
dbus.packages = [ cfg.package ];
|
||||
})
|
||||
|
||||
|
||||
@@ -16,18 +16,13 @@ let
|
||||
|
||||
cfg = config.programs.gpg;
|
||||
|
||||
mkKeyValue =
|
||||
key: value: if lib.isString value then "${key} ${value}" else lib.optionalString value key;
|
||||
|
||||
cfgText = lib.generators.toKeyValue {
|
||||
inherit mkKeyValue;
|
||||
listsAsDuplicateKeys = true;
|
||||
} cfg.settings;
|
||||
|
||||
scdaemonCfgText = lib.generators.toKeyValue {
|
||||
inherit mkKeyValue;
|
||||
listsAsDuplicateKeys = true;
|
||||
} cfg.scdaemonSettings;
|
||||
toKeyValue =
|
||||
settings:
|
||||
lib.generators.toKeyValue {
|
||||
mkKeyValue =
|
||||
key: value: if lib.isString value then "${key} ${value}" else lib.optionalString value key;
|
||||
listsAsDuplicateKeys = true;
|
||||
} settings;
|
||||
|
||||
primitiveType = types.oneOf [
|
||||
types.str
|
||||
@@ -193,6 +188,7 @@ in
|
||||
|
||||
scdaemonSettings = mkOption {
|
||||
type = types.attrsOf (types.either primitiveType (types.listOf types.str));
|
||||
default = { };
|
||||
example = literalExpression ''
|
||||
{
|
||||
disable-ccid = true;
|
||||
@@ -207,6 +203,41 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
dirmngrSettings = mkOption {
|
||||
type = types.attrsOf (types.either primitiveType (types.listOf types.str));
|
||||
default = { };
|
||||
example = literalExpression ''
|
||||
{
|
||||
allow-version-check = true;
|
||||
keyserver = "ldaps://ldap.example.com";
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Dirmngr configuration options. Available options are described
|
||||
in
|
||||
[
|
||||
{manpage}`dirmngr(1)`
|
||||
](https://www.gnupg.org/documentation/manuals/gnupg/Dirmngr-Options.html)
|
||||
'';
|
||||
};
|
||||
|
||||
gpgsmSettings = mkOption {
|
||||
type = types.attrsOf (types.either primitiveType (types.listOf types.str));
|
||||
default = { };
|
||||
example = literalExpression ''
|
||||
{
|
||||
with-key-data = true;
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
GPGSM configuration options. Available options are described
|
||||
in
|
||||
[
|
||||
{manpage}`gpgsm(1)`
|
||||
](https://www.gnupg.org/documentation/manuals/gnupg/GPGSM-Options.html)
|
||||
'';
|
||||
};
|
||||
|
||||
homedir = mkOption {
|
||||
type = types.path;
|
||||
example = literalExpression ''"''${config.xdg.dataHome}/gnupg"'';
|
||||
@@ -267,8 +298,7 @@ in
|
||||
cert-digest-algo = mkDefault "SHA512";
|
||||
s2k-digest-algo = mkDefault "SHA512";
|
||||
s2k-cipher-algo = mkDefault "AES256";
|
||||
charset = mkDefault "utf-8";
|
||||
fixed-list-mode = mkDefault true;
|
||||
display-charset = mkDefault "utf-8";
|
||||
no-comments = mkDefault true;
|
||||
no-emit-version = mkDefault true;
|
||||
keyid-format = mkDefault "0xlong";
|
||||
@@ -277,11 +307,6 @@ in
|
||||
with-fingerprint = mkDefault true;
|
||||
require-cross-certification = mkDefault true;
|
||||
no-symkey-cache = mkDefault true;
|
||||
use-agent = mkDefault true;
|
||||
};
|
||||
|
||||
programs.gpg.scdaemonSettings = {
|
||||
# no defaults for scdaemon
|
||||
};
|
||||
|
||||
home.packages = [ cfg.package ];
|
||||
@@ -289,9 +314,21 @@ in
|
||||
GNUPGHOME = cfg.homedir;
|
||||
};
|
||||
|
||||
home.file."${cfg.homedir}/gpg.conf".text = cfgText;
|
||||
home.file."${cfg.homedir}/gpg.conf" = mkIf (cfg.settings != { }) {
|
||||
text = toKeyValue cfg.settings;
|
||||
};
|
||||
|
||||
home.file."${cfg.homedir}/scdaemon.conf".text = scdaemonCfgText;
|
||||
home.file."${cfg.homedir}/scdaemon.conf" = mkIf (cfg.scdaemonSettings != { }) {
|
||||
text = toKeyValue cfg.scdaemonSettings;
|
||||
};
|
||||
|
||||
home.file."${cfg.homedir}/dirmngr.conf" = mkIf (cfg.dirmngrSettings != { }) {
|
||||
text = toKeyValue cfg.dirmngrSettings;
|
||||
};
|
||||
|
||||
home.file."${cfg.homedir}/gpgsm.conf" = mkIf (cfg.gpgsmSettings != { }) {
|
||||
text = toKeyValue cfg.gpgsmSettings;
|
||||
};
|
||||
|
||||
# Link keyring if keys are not mutable
|
||||
home.file."${cfg.homedir}/pubring.kbx" = mkIf (!cfg.mutableKeys && cfg.publicKeys != [ ]) {
|
||||
|
||||
@@ -9,7 +9,7 @@ let
|
||||
iniFormat = pkgs.formats.ini { };
|
||||
in
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [ AndersonTorres ];
|
||||
meta.maintainers = with lib.maintainers; [ ];
|
||||
|
||||
options.programs.havoc = {
|
||||
enable = lib.mkEnableOption "Havoc terminal";
|
||||
|
||||
@@ -62,8 +62,15 @@ in
|
||||
Configuration written to
|
||||
{file}`$XDG_CONFIG_HOME/keepassxc/keepassxc.ini`.
|
||||
|
||||
See <https://github.com/keepassxreboot/keepassxc/blob/647272e9c5542297d3fcf6502e6173c96f12a9a0/src/core/Config.cpp#L49-L223>
|
||||
See <https://github.com/keepassxreboot/keepassxc/blob/develop/src/core/Config.cpp>
|
||||
for the full list of options.
|
||||
|
||||
::: {.note}
|
||||
When the settings are non-empty, the configuration file will be linked
|
||||
into the Nix store and KeePassXC will report an access error for its
|
||||
configuration file. This is expected and can not be fixed in a way that
|
||||
aligns with Home Manager's principles. See [#8257](https://github.com/nix-community/home-manager/issues/8257) for more details.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
@@ -24,7 +24,8 @@ let
|
||||
meliAccounts = (lib.attrsets.mapAttrs (name: value: (mkMeliAccounts name value)) enabledAccounts);
|
||||
|
||||
mkMeliAccounts = (
|
||||
name: account: {
|
||||
name: account:
|
||||
{
|
||||
root_mailbox = "${config.accounts.email.maildirBasePath}/${account.maildir.path}";
|
||||
format = "Maildir";
|
||||
identity = account.address;
|
||||
@@ -33,6 +34,14 @@ let
|
||||
send_mail = mkSmtp account;
|
||||
mailboxes = account.meli.mailboxAliases;
|
||||
}
|
||||
// lib.optionalAttrs (account.flavor == "fastmail.com") {
|
||||
server_username = account.userName;
|
||||
server_password_command = lib.concatMapStringsSep " " lib.escapeShellArg account.passwordCommand;
|
||||
format = "jmap";
|
||||
server_url = "https://api.fastmail.com/jmap/session";
|
||||
use_token = true;
|
||||
}
|
||||
// account.meli.settings
|
||||
);
|
||||
|
||||
mkSmtp = account: {
|
||||
@@ -153,6 +162,14 @@ in
|
||||
};
|
||||
description = "Folder display name";
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
type = types.submodule {
|
||||
freeformType = tomlFormat.type;
|
||||
};
|
||||
default = { };
|
||||
description = "Account specific meli configuration";
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
@@ -160,6 +177,15 @@ in
|
||||
};
|
||||
};
|
||||
config = mkIf config.programs.meli.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.settings ? accounts == false;
|
||||
message = ''
|
||||
programs.meli.settings.accounts override the accounts.email values.
|
||||
Use per-email accounts.email.<ACCOUNT>.meli.settings instead'';
|
||||
}
|
||||
];
|
||||
|
||||
home.packages = [ config.programs.meli.package ];
|
||||
|
||||
# Generate meli configuration from email accounts
|
||||
|
||||
@@ -7,121 +7,46 @@
|
||||
|
||||
let
|
||||
inherit (lib)
|
||||
concatMapStringsSep
|
||||
literalExpression
|
||||
mkEnableOption
|
||||
mkIf
|
||||
mkOption
|
||||
mkRemovedOptionModule
|
||||
mkPackageOption
|
||||
optionals
|
||||
types
|
||||
;
|
||||
|
||||
cfg = config.programs.neovim;
|
||||
|
||||
fileType =
|
||||
(import ../lib/file-type.nix {
|
||||
inherit (config.home) homeDirectory;
|
||||
inherit lib pkgs;
|
||||
}).fileType;
|
||||
inherit
|
||||
(
|
||||
(import ../lib/file-type.nix {
|
||||
inherit (config.home) homeDirectory;
|
||||
inherit lib pkgs;
|
||||
})
|
||||
)
|
||||
fileType
|
||||
;
|
||||
|
||||
jsonFormat = pkgs.formats.json { };
|
||||
|
||||
pluginWithConfigType = types.submodule {
|
||||
options = {
|
||||
config = mkOption {
|
||||
type = types.nullOr types.lines;
|
||||
description = "Script to configure this plugin. The scripting language should match type.";
|
||||
default = null;
|
||||
};
|
||||
|
||||
type = mkOption {
|
||||
type = types.either (types.enum [
|
||||
"lua"
|
||||
"viml"
|
||||
"teal"
|
||||
"fennel"
|
||||
]) types.str;
|
||||
description = "Language used in config. Configurations are aggregated per-language.";
|
||||
default = "viml";
|
||||
};
|
||||
|
||||
optional = mkEnableOption "optional" // {
|
||||
description = "Don't load by default (load with :packadd)";
|
||||
};
|
||||
|
||||
plugin = lib.mkPackageOption pkgs.vimPlugins "plugin" {
|
||||
default = null;
|
||||
example = "pkgs.vimPlugins.nvim-treesitter";
|
||||
pkgsText = "pkgs.vimPlugins";
|
||||
};
|
||||
|
||||
runtime = mkOption {
|
||||
default = { };
|
||||
# passing actual "${xdg.configHome}/nvim" as basePath was a bit tricky
|
||||
# due to how fileType.target is implemented
|
||||
type = fileType "programs.neovim.plugins._.runtime" "{var}`xdg.configHome/nvim`" "nvim";
|
||||
example = literalExpression ''
|
||||
{ "ftplugin/c.vim".text = "setlocal omnifunc=v:lua.vim.lsp.omnifunc"; }
|
||||
'';
|
||||
description = ''
|
||||
Set of files that have to be linked in nvim config folder.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
allPlugins =
|
||||
cfg.plugins
|
||||
++ lib.optional cfg.coc.enable {
|
||||
type = "viml";
|
||||
plugin = cfg.coc.package;
|
||||
config = cfg.coc.pluginConfig;
|
||||
optional = false;
|
||||
};
|
||||
|
||||
luaPackages = cfg.finalPackage.unwrapped.lua.pkgs;
|
||||
resolvedExtraLuaPackages = cfg.extraLuaPackages luaPackages;
|
||||
|
||||
extraMakeWrapperArgs = lib.optionalString (
|
||||
cfg.extraPackages != [ ]
|
||||
) ''--suffix PATH : "${lib.makeBinPath cfg.extraPackages}"'';
|
||||
extraMakeWrapperLuaCArgs =
|
||||
lib.optionalString (resolvedExtraLuaPackages != [ ])
|
||||
''--suffix LUA_CPATH ";" "${
|
||||
lib.concatMapStringsSep ";" luaPackages.getLuaCPath resolvedExtraLuaPackages
|
||||
}"'';
|
||||
extraMakeWrapperLuaArgs =
|
||||
lib.optionalString (resolvedExtraLuaPackages != [ ])
|
||||
''--suffix LUA_PATH ";" "${
|
||||
lib.concatMapStringsSep ";" luaPackages.getLuaPath resolvedExtraLuaPackages
|
||||
}"'';
|
||||
in
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [ khaneliman ];
|
||||
|
||||
imports = [
|
||||
(mkRemovedOptionModule [
|
||||
"programs"
|
||||
"neovim"
|
||||
"withPython"
|
||||
] "Python2 support has been removed from neovim.")
|
||||
(mkRemovedOptionModule [
|
||||
"programs"
|
||||
"neovim"
|
||||
"extraPythonPackages"
|
||||
] "Python2 support has been removed from neovim.")
|
||||
(mkRemovedOptionModule [ "programs" "neovim" "configure" ] ''
|
||||
programs.neovim.configure is deprecated.
|
||||
Other programs.neovim options can override its settings or ignore them.
|
||||
Please use the other options at your disposal:
|
||||
configure.packages.*.opt -> programs.neovim.plugins = [ { plugin = ...; optional = true; }]
|
||||
configure.packages.*.start -> programs.neovim.plugins = [ { plugin = ...; }]
|
||||
configure.customRC -> programs.neovim.extraConfig
|
||||
'')
|
||||
];
|
||||
options = {
|
||||
programs.neovim = {
|
||||
enable = mkEnableOption "Neovim";
|
||||
|
||||
package = mkPackageOption pkgs "neovim" { default = "neovim-unwrapped"; };
|
||||
|
||||
finalPackage = mkOption {
|
||||
type = types.package;
|
||||
readOnly = true;
|
||||
description = "Resulting customized neovim package.";
|
||||
};
|
||||
|
||||
# Aliases
|
||||
viAlias = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
@@ -146,6 +71,17 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
defaultEditor = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to configure {command}`nvim` as the default
|
||||
editor using the {env}`EDITOR` and {env}`VISUAL`
|
||||
environment variables.
|
||||
'';
|
||||
};
|
||||
|
||||
# Providers & Runtimes
|
||||
withNodeJs = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
@@ -155,11 +91,12 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
withRuby = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = true;
|
||||
withPerl = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Enable ruby provider.
|
||||
Enable perl provider. Set to `true` to
|
||||
use Perl plugins.
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -172,21 +109,16 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
withRuby = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Enable ruby provider.
|
||||
'';
|
||||
};
|
||||
|
||||
extraPython3Packages = mkOption {
|
||||
# In case we get a plain list, we need to turn it into a function,
|
||||
# as expected by the function in nixpkgs.
|
||||
# The only way to do so is to call `const`, which will ignore its input.
|
||||
type =
|
||||
let
|
||||
fromType = types.listOf types.package;
|
||||
in
|
||||
types.coercedTo fromType (lib.flip lib.warn lib.const ''
|
||||
Assigning a plain list to extraPython3Packages is deprecated.
|
||||
Please assign a function taking a package set as argument, so
|
||||
extraPython3Packages = [ pkgs.python3Packages.xxx ];
|
||||
should become
|
||||
extraPython3Packages = ps: [ ps.xxx ];
|
||||
'') (types.functionTo fromType);
|
||||
type = types.functionTo (types.listOf types.package);
|
||||
default = _: [ ];
|
||||
defaultText = literalExpression "ps: [ ]";
|
||||
example = literalExpression "pyPkgs: with pyPkgs; [ python-language-server ]";
|
||||
@@ -198,21 +130,8 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
# We get the Lua package from the final package and use its
|
||||
# Lua packageset to evaluate the function that this option was set to.
|
||||
# This ensures that we always use the same Lua version as the Neovim package.
|
||||
extraLuaPackages = mkOption {
|
||||
type =
|
||||
let
|
||||
fromType = types.listOf types.package;
|
||||
in
|
||||
types.coercedTo fromType (lib.flip lib.warn lib.const ''
|
||||
Assigning a plain list to extraLuaPackages is deprecated.
|
||||
Please assign a function taking a package set as argument, so
|
||||
extraLuaPackages = [ pkgs.lua51Packages.xxx ];
|
||||
should become
|
||||
extraLuaPackages = ps: [ ps.xxx ];
|
||||
'') (types.functionTo fromType);
|
||||
type = types.functionTo (types.listOf types.package);
|
||||
default = _: [ ];
|
||||
defaultText = literalExpression "ps: [ ]";
|
||||
example = literalExpression "luaPkgs: with luaPkgs; [ luautf8 ]";
|
||||
@@ -224,8 +143,34 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
# Wrapper Configuration
|
||||
extraName = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = ''
|
||||
Extra name appended to the wrapper package name.
|
||||
'';
|
||||
};
|
||||
|
||||
autowrapRuntimeDeps = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to automatically wrap the binary with the runtime dependencies of the plugins.
|
||||
'';
|
||||
};
|
||||
|
||||
waylandSupport = mkOption {
|
||||
type = types.bool;
|
||||
default = pkgs.stdenv.isLinux;
|
||||
defaultText = literalExpression "pkgs.stdenv.isLinux";
|
||||
description = ''
|
||||
Whether to enable Wayland clipboard support.
|
||||
'';
|
||||
};
|
||||
|
||||
extraWrapperArgs = mkOption {
|
||||
type = with types; listOf str;
|
||||
type = types.listOf types.str;
|
||||
default = [ ];
|
||||
example = literalExpression ''
|
||||
[
|
||||
@@ -246,54 +191,14 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
generatedConfigViml = mkOption {
|
||||
type = types.lines;
|
||||
visible = true;
|
||||
readOnly = true;
|
||||
description = ''
|
||||
Generated vimscript config.
|
||||
'';
|
||||
};
|
||||
|
||||
generatedConfigs = mkOption {
|
||||
type = types.attrsOf types.lines;
|
||||
visible = true;
|
||||
readOnly = true;
|
||||
example = literalExpression ''
|
||||
{
|
||||
viml = '''
|
||||
" Generated by home-manager
|
||||
map <leader> ,
|
||||
''';
|
||||
|
||||
lua = '''
|
||||
-- Generated by home-manager
|
||||
vim.opt.background = "dark"
|
||||
''';
|
||||
}'';
|
||||
description = ''
|
||||
Generated configurations with as key their language (set via type).
|
||||
'';
|
||||
};
|
||||
|
||||
package = lib.mkPackageOption pkgs "neovim" { default = "neovim-unwrapped"; };
|
||||
|
||||
finalPackage = mkOption {
|
||||
type = types.package;
|
||||
readOnly = true;
|
||||
description = "Resulting customized neovim package.";
|
||||
};
|
||||
|
||||
defaultEditor = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to configure {command}`nvim` as the default
|
||||
editor using the {env}`EDITOR` and {env}`VISUAL`
|
||||
environment variables.
|
||||
'';
|
||||
extraPackages = mkOption {
|
||||
type = types.listOf types.package;
|
||||
default = [ ];
|
||||
example = literalExpression "[ pkgs.shfmt ]";
|
||||
description = "Extra packages available to nvim.";
|
||||
};
|
||||
|
||||
# Configuration & Plugins
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
@@ -308,45 +213,92 @@ in
|
||||
extraLuaConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
example = ''
|
||||
vim.opt.nobackup = true
|
||||
example = lib.literalExpression ''
|
||||
let
|
||||
nvimEarlyInit = lib.mkOrder 500 "set rtp+=vim.opt.rtp:prepend('/home/user/myplugin')";
|
||||
nvimLateInit = lib.mkAfter "vim.opt.signcolumn = 'auto:1-3'";
|
||||
in
|
||||
lib.mkMerge [ nvimEarlyInit nvimLateInit ];
|
||||
'';
|
||||
description = ''
|
||||
Custom lua lines.
|
||||
Content to be added to {file}`init.lua`.
|
||||
|
||||
To specify the order, use `lib.mkOrder`, `lib.mkBefore`, `lib.mkAfter`.
|
||||
'';
|
||||
};
|
||||
|
||||
extraPackages = mkOption {
|
||||
type = with types; listOf package;
|
||||
default = [ ];
|
||||
example = literalExpression "[ pkgs.shfmt ]";
|
||||
description = "Extra packages available to nvim.";
|
||||
};
|
||||
plugins =
|
||||
let
|
||||
pluginWithConfigType = types.submodule {
|
||||
options = {
|
||||
config = mkOption {
|
||||
type = types.nullOr types.lines;
|
||||
description = "Script to configure this plugin. The scripting language should match type.";
|
||||
default = null;
|
||||
};
|
||||
|
||||
plugins = mkOption {
|
||||
type = with types; listOf (either package pluginWithConfigType);
|
||||
default = [ ];
|
||||
example = literalExpression ''
|
||||
with pkgs.vimPlugins; [
|
||||
yankring
|
||||
vim-nix
|
||||
{ plugin = vim-startify;
|
||||
config = "let g:startify_change_to_vcs_root = 0";
|
||||
}
|
||||
]
|
||||
'';
|
||||
description = ''
|
||||
List of vim plugins to install optionally associated with
|
||||
configuration to be placed in init.vim.
|
||||
type = mkOption {
|
||||
type = types.either (types.enum [
|
||||
"lua"
|
||||
"viml"
|
||||
"teal"
|
||||
"fennel"
|
||||
]) types.str;
|
||||
description = "Language used in config. Configurations are aggregated per-language.";
|
||||
default = "viml";
|
||||
};
|
||||
|
||||
This option is mutually exclusive with {var}`configure`.
|
||||
'';
|
||||
};
|
||||
optional = mkEnableOption "optional" // {
|
||||
description = "Don't load by default (load with :packadd)";
|
||||
};
|
||||
|
||||
plugin = mkPackageOption pkgs.vimPlugins "plugin" {
|
||||
default = null;
|
||||
example = "pkgs.vimPlugins.nvim-treesitter";
|
||||
pkgsText = "pkgs.vimPlugins";
|
||||
};
|
||||
|
||||
runtime = mkOption {
|
||||
default = { };
|
||||
# passing actual "${xdg.configHome}/nvim" as basePath was a bit tricky
|
||||
# due to how fileType.target is implemented
|
||||
type = fileType "programs.neovim.plugins._.runtime" "{var}`xdg.configHome/nvim`" "nvim";
|
||||
example = literalExpression ''
|
||||
{ "ftplugin/c.vim".text = "setlocal omnifunc=v:lua.vim.lsp.omnifunc"; }
|
||||
'';
|
||||
description = ''
|
||||
Set of files that have to be linked in nvim config folder.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
in
|
||||
mkOption {
|
||||
type = types.listOf (types.either types.package pluginWithConfigType);
|
||||
default = [ ];
|
||||
example = literalExpression ''
|
||||
with pkgs.vimPlugins;
|
||||
[
|
||||
yankring
|
||||
vim-nix
|
||||
{ plugin = vim-startify;
|
||||
config = "let g:startify_change_to_vcs_root = 0";
|
||||
}
|
||||
]
|
||||
'';
|
||||
description = ''
|
||||
List of vim plugins to install optionally associated with
|
||||
configuration to be placed in init.vim.
|
||||
|
||||
This option is mutually exclusive with {var}`configure`.
|
||||
'';
|
||||
};
|
||||
|
||||
coc = {
|
||||
enable = mkEnableOption "Coc";
|
||||
|
||||
package = lib.mkPackageOption pkgs "coc-nvim" {
|
||||
package = mkPackageOption pkgs "coc-nvim" {
|
||||
default = [
|
||||
"vimPlugins"
|
||||
"coc-nvim"
|
||||
@@ -376,7 +328,7 @@ in
|
||||
filetypes = [ "haskell" "lhaskell" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Extra configuration lines to add to
|
||||
@@ -393,11 +345,52 @@ in
|
||||
description = "Script to configure CoC. Must be viml.";
|
||||
};
|
||||
};
|
||||
|
||||
# Generated / Read-Only
|
||||
generatedConfigViml = mkOption {
|
||||
type = types.lines;
|
||||
visible = true;
|
||||
readOnly = true;
|
||||
description = ''
|
||||
Generated vimscript config.
|
||||
'';
|
||||
};
|
||||
|
||||
generatedConfigs = mkOption {
|
||||
type = types.attrsOf types.lines;
|
||||
visible = true;
|
||||
readOnly = true;
|
||||
example = literalExpression ''
|
||||
{
|
||||
viml = '''
|
||||
" Generated by home-manager
|
||||
map <leader> ,
|
||||
''';
|
||||
|
||||
lua = '''
|
||||
-- Generated by home-manager
|
||||
vim.opt.background = "dark"
|
||||
''';
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Generated configurations with as key their language (set via type).
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config =
|
||||
config = mkIf cfg.enable (
|
||||
let
|
||||
allPlugins =
|
||||
cfg.plugins
|
||||
++ lib.optional cfg.coc.enable {
|
||||
type = "viml";
|
||||
plugin = cfg.coc.package;
|
||||
config = cfg.coc.pluginConfig;
|
||||
optional = false;
|
||||
};
|
||||
|
||||
defaultPlugin = {
|
||||
type = "viml";
|
||||
plugin = null;
|
||||
@@ -413,81 +406,100 @@ in
|
||||
|
||||
suppressNotVimlConfig = p: if p.type != "viml" then p // { config = null; } else p;
|
||||
|
||||
neovimConfig = pkgs.neovimUtils.makeNeovimConfig {
|
||||
# Lua & Python Package Resolution
|
||||
luaPackages = cfg.finalPackage.unwrapped.lua.pkgs;
|
||||
resolvedExtraLuaPackages = cfg.extraLuaPackages luaPackages;
|
||||
|
||||
# Wrapper Arguments Construction
|
||||
extraMakeWrapperArgs = optionals (cfg.extraPackages != [ ]) [
|
||||
"--suffix"
|
||||
"PATH"
|
||||
":"
|
||||
(lib.makeBinPath cfg.extraPackages)
|
||||
];
|
||||
|
||||
extraMakeWrapperLuaCArgs = optionals (resolvedExtraLuaPackages != [ ]) [
|
||||
"--suffix"
|
||||
"LUA_CPATH"
|
||||
";"
|
||||
(concatMapStringsSep ";" luaPackages.getLuaCPath resolvedExtraLuaPackages)
|
||||
];
|
||||
|
||||
extraMakeWrapperLuaArgs = optionals (resolvedExtraLuaPackages != [ ]) [
|
||||
"--suffix"
|
||||
"LUA_PATH"
|
||||
";"
|
||||
(concatMapStringsSep ";" luaPackages.getLuaPath resolvedExtraLuaPackages)
|
||||
];
|
||||
|
||||
wrappedNeovim' = pkgs.wrapNeovimUnstable cfg.package {
|
||||
withNodeJs = cfg.withNodeJs || cfg.coc.enable;
|
||||
plugins = map suppressNotVimlConfig pluginsNormalized;
|
||||
|
||||
inherit (cfg)
|
||||
extraPython3Packages
|
||||
withPython3
|
||||
withRuby
|
||||
withPerl
|
||||
viAlias
|
||||
vimAlias
|
||||
extraName
|
||||
autowrapRuntimeDeps
|
||||
waylandSupport
|
||||
;
|
||||
withNodeJs = cfg.withNodeJs || cfg.coc.enable;
|
||||
plugins = map suppressNotVimlConfig pluginsNormalized;
|
||||
customRC = cfg.extraConfig;
|
||||
neovimRcContent = cfg.extraConfig;
|
||||
wrapperArgs =
|
||||
cfg.extraWrapperArgs ++ extraMakeWrapperArgs ++ extraMakeWrapperLuaCArgs ++ extraMakeWrapperLuaArgs;
|
||||
wrapRc = false;
|
||||
};
|
||||
|
||||
wrappedNeovim' = pkgs.wrapNeovimUnstable cfg.package (
|
||||
neovimConfig
|
||||
// {
|
||||
wrapperArgs =
|
||||
(lib.escapeShellArgs (neovimConfig.wrapperArgs ++ cfg.extraWrapperArgs))
|
||||
+ " "
|
||||
+ extraMakeWrapperArgs
|
||||
+ " "
|
||||
+ extraMakeWrapperLuaCArgs
|
||||
+ " "
|
||||
+ extraMakeWrapperLuaArgs;
|
||||
wrapRc = false;
|
||||
}
|
||||
);
|
||||
in
|
||||
mkIf cfg.enable {
|
||||
{
|
||||
programs.neovim = {
|
||||
generatedConfigViml = cfg.extraConfig;
|
||||
|
||||
programs.neovim.generatedConfigViml = neovimConfig.neovimRcContent;
|
||||
generatedConfigs =
|
||||
let
|
||||
grouped = lib.groupBy (x: x.type) pluginsNormalized;
|
||||
configsOnly = lib.foldl (acc: p: if p.config != null then acc ++ [ p.config ] else acc) [ ];
|
||||
in
|
||||
lib.mapAttrs (_name: vals: lib.concatStringsSep "\n" (configsOnly vals)) grouped;
|
||||
|
||||
programs.neovim.generatedConfigs =
|
||||
let
|
||||
grouped = lib.lists.groupBy (x: x.type) pluginsNormalized;
|
||||
configsOnly = lib.foldl (acc: p: if p.config != null then acc ++ [ p.config ] else acc) [ ];
|
||||
in
|
||||
lib.mapAttrs (name: vals: lib.concatStringsSep "\n" (configsOnly vals)) grouped;
|
||||
|
||||
home.packages = [ cfg.finalPackage ];
|
||||
|
||||
home.sessionVariables = mkIf cfg.defaultEditor {
|
||||
EDITOR = "nvim";
|
||||
VISUAL = "nvim";
|
||||
finalPackage = wrappedNeovim';
|
||||
};
|
||||
|
||||
home.shellAliases = mkIf cfg.vimdiffAlias { vimdiff = "nvim -d"; };
|
||||
home = {
|
||||
packages = [ cfg.finalPackage ];
|
||||
|
||||
xdg.configFile =
|
||||
let
|
||||
hasLuaConfig = lib.hasAttr "lua" config.programs.neovim.generatedConfigs;
|
||||
in
|
||||
lib.mkMerge (
|
||||
# writes runtime
|
||||
(map (x: x.runtime) pluginsNormalized)
|
||||
++ [
|
||||
{
|
||||
"nvim/init.lua" =
|
||||
let
|
||||
luaRcContent =
|
||||
lib.optionalString (
|
||||
wrappedNeovim'.initRc != ""
|
||||
) "vim.cmd [[source ${pkgs.writeText "nvim-init-home-manager.vim" wrappedNeovim'.initRc}]]\n"
|
||||
+ config.programs.neovim.extraLuaConfig
|
||||
+ lib.optionalString hasLuaConfig config.programs.neovim.generatedConfigs.lua;
|
||||
in
|
||||
mkIf (luaRcContent != "") { text = luaRcContent; };
|
||||
sessionVariables = mkIf cfg.defaultEditor {
|
||||
EDITOR = "nvim";
|
||||
VISUAL = "nvim";
|
||||
};
|
||||
|
||||
"nvim/coc-settings.json" = mkIf cfg.coc.enable {
|
||||
source = jsonFormat.generate "coc-settings.json" cfg.coc.settings;
|
||||
};
|
||||
}
|
||||
]
|
||||
);
|
||||
shellAliases = mkIf cfg.vimdiffAlias { vimdiff = "nvim -d"; };
|
||||
};
|
||||
|
||||
programs.neovim.finalPackage = wrappedNeovim';
|
||||
};
|
||||
programs.neovim.extraLuaConfig = lib.mkMerge [
|
||||
(lib.mkIf (wrappedNeovim'.initRc != "") (
|
||||
lib.mkBefore "vim.cmd [[source ${pkgs.writeText "nvim-init-home-manager.vim" wrappedNeovim'.initRc}]]"
|
||||
))
|
||||
(lib.mkIf (lib.hasAttr "lua" cfg.generatedConfigs) (lib.mkAfter cfg.generatedConfigs.lua))
|
||||
];
|
||||
|
||||
xdg.configFile = lib.mkMerge (
|
||||
# writes runtime
|
||||
(map (x: x.runtime) pluginsNormalized)
|
||||
++ [
|
||||
{
|
||||
"nvim/init.lua" = mkIf (cfg.extraLuaConfig != "") {
|
||||
text = cfg.extraLuaConfig;
|
||||
};
|
||||
|
||||
"nvim/coc-settings.json" = mkIf cfg.coc.enable {
|
||||
source = jsonFormat.generate "coc-settings.json" cfg.coc.settings;
|
||||
};
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ in
|
||||
lib.optional (cfg.clean.enable && config.nix.gc.automatic)
|
||||
"programs.nh.clean.enable and nix.gc.automatic (Home-Manager) are both enabled. Please use one or the other to avoid conflict.";
|
||||
|
||||
assertions = lib.optionals pkgs.stdenv.isDarwin [
|
||||
assertions = [
|
||||
(lib.hm.darwin.assertInterval "programs.nh.clean.dates" cfg.clean.dates pkgs)
|
||||
];
|
||||
|
||||
@@ -131,30 +131,25 @@ in
|
||||
];
|
||||
};
|
||||
|
||||
systemd.user = lib.mkIf (cfg.clean.enable && pkgs.stdenv.isLinux) {
|
||||
systemd.user = lib.mkIf cfg.clean.enable {
|
||||
services.nh-clean = {
|
||||
Unit.Description = "Nh clean (user)";
|
||||
|
||||
Service = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${lib.getExe cfg.package} clean user ${cfg.clean.extraArgs}";
|
||||
};
|
||||
};
|
||||
|
||||
timers.nh-clean = {
|
||||
Unit.Description = "Run nh clean";
|
||||
|
||||
Timer = {
|
||||
OnCalendar = cfg.clean.dates;
|
||||
Persistent = true;
|
||||
};
|
||||
|
||||
Install.WantedBy = [ "timers.target" ];
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
launchd.agents.nh-clean = lib.mkIf (cfg.clean.enable && pkgs.stdenv.isDarwin) {
|
||||
launchd.agents.nh-clean = lib.mkIf cfg.clean.enable {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
@@ -163,9 +158,7 @@ in
|
||||
"user"
|
||||
]
|
||||
++ lib.optional (cfg.clean.extraArgs != "") cfg.clean.extraArgs;
|
||||
|
||||
StartCalendarInterval = lib.hm.darwin.mkCalendarInterval cfg.clean.dates;
|
||||
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -66,10 +66,7 @@ in
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = pkgs.stdenv.hostPlatform.isLinux;
|
||||
message = "niriswitcher is only available on Linux.";
|
||||
}
|
||||
(lib.hm.assertions.assertPlatform "programs.niriswitcher" pkgs lib.platforms.linux)
|
||||
];
|
||||
|
||||
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||
|
||||
@@ -133,7 +133,7 @@ in
|
||||
The attribute name becomes the command filename, and the value is either:
|
||||
- Inline content as a string
|
||||
- A path to a file containing the command content
|
||||
Commands are stored in {file}`$XDG_CONFIG_HOME/.config/opencode/command/` directory.
|
||||
Commands are stored in {file}`$XDG_CONFIG_HOME/opencode/command/` directory.
|
||||
'';
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
@@ -162,7 +162,7 @@ in
|
||||
The attribute name becomes the agent filename, and the value is either:
|
||||
- Inline content as a string
|
||||
- A path to a file containing the agent content
|
||||
Agents are stored in {file}`$XDG_CONFIG_HOME/.config/opencode/agent/` directory.
|
||||
Agents are stored in {file}`$XDG_CONFIG_HOME/opencode/agent/` directory.
|
||||
'';
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
@@ -183,6 +183,49 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
skills = lib.mkOption {
|
||||
type = lib.types.either (lib.types.attrsOf (lib.types.either lib.types.lines lib.types.path)) lib.types.path;
|
||||
default = { };
|
||||
description = ''
|
||||
Custom agent skills for opencode.
|
||||
|
||||
This option can either be:
|
||||
- An attribute set defining skills
|
||||
- A path to a directory containing multiple skill folders
|
||||
|
||||
If an attribute set is used, the attribute name becomes the skill directory name,
|
||||
and the value is either:
|
||||
- Inline content as a string (creates `opencode/skill/<name>/SKILL.md`)
|
||||
- A path to a file (creates `opencode/skill/<name>/SKILL.md`)
|
||||
- A path to a directory (creates `opencode/skill/<name>/` with all files)
|
||||
|
||||
If a path is used, it is expected to contain one folder per skill name, each
|
||||
containing a {file}`SKILL.md`. The directory is symlinked to
|
||||
{file}`$XDG_CONFIG_HOME/opencode/skill/`.
|
||||
|
||||
See <https://opencode.ai/docs/skills/> for the documentation.
|
||||
'';
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
git-release = '''
|
||||
---
|
||||
name: git-release
|
||||
description: Create consistent releases and changelogs
|
||||
---
|
||||
|
||||
## What I do
|
||||
|
||||
- Draft release notes from merged PRs
|
||||
- Propose a version bump
|
||||
- Provide a copy-pasteable `gh release create` command
|
||||
''';
|
||||
|
||||
# A skill can also be a directory containing SKILL.md and other files.
|
||||
data-analysis = ./skills/data-analysis;
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
themes = mkOption {
|
||||
type = lib.types.attrsOf (lib.types.either jsonFormat.type lib.types.path);
|
||||
default = { };
|
||||
@@ -199,6 +242,13 @@ in
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = !lib.isPath cfg.skills || lib.pathIsDirectory cfg.skills;
|
||||
message = "`programs.opencode.skills` must be a directory when set to a path";
|
||||
}
|
||||
];
|
||||
|
||||
home.packages = mkIf (cfg.package != null) [ cfg.package ];
|
||||
|
||||
xdg.configFile = {
|
||||
@@ -227,6 +277,11 @@ in
|
||||
text = cfg.rules;
|
||||
})
|
||||
);
|
||||
|
||||
"opencode/skill" = mkIf (lib.isPath cfg.skills) {
|
||||
source = cfg.skills;
|
||||
recursive = true;
|
||||
};
|
||||
}
|
||||
// lib.mapAttrs' (
|
||||
name: content:
|
||||
@@ -240,6 +295,18 @@ in
|
||||
if lib.isPath content then { source = content; } else { text = content; }
|
||||
)
|
||||
) cfg.agents
|
||||
// lib.mapAttrs' (
|
||||
name: content:
|
||||
if lib.isPath content && lib.pathIsDirectory content then
|
||||
lib.nameValuePair "opencode/skill/${name}" {
|
||||
source = content;
|
||||
recursive = true;
|
||||
}
|
||||
else
|
||||
lib.nameValuePair "opencode/skill/${name}/SKILL.md" (
|
||||
if lib.isPath content then { source = content; } else { text = content; }
|
||||
)
|
||||
) (if builtins.isAttrs cfg.skills then cfg.skills else { })
|
||||
// lib.mapAttrs' (
|
||||
name: content:
|
||||
lib.nameValuePair "opencode/themes/${name}.json" (
|
||||
|
||||
@@ -30,44 +30,42 @@ let
|
||||
mapAttrsToList (name: value: ''${name}="${lib.escape [ ''"'' "\\" ] (toString value)}"'') envStr
|
||||
);
|
||||
|
||||
bindOptions = {
|
||||
address = mkOption {
|
||||
type = types.str;
|
||||
default = "localhost";
|
||||
example = "example.org";
|
||||
description = "The address where to bind the port.";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.nullOr types.port;
|
||||
default = null;
|
||||
example = 8080;
|
||||
description = "Specifies port number to bind on bind address.";
|
||||
};
|
||||
};
|
||||
|
||||
dynamicForwardModule = types.submodule { options = bindOptions; };
|
||||
|
||||
forwardModule = types.submodule {
|
||||
options = {
|
||||
bind = bindOptions;
|
||||
|
||||
host = {
|
||||
mkAddressPortModule =
|
||||
{
|
||||
actionType,
|
||||
nullableAddress ? actionType == "forward",
|
||||
}:
|
||||
types.submodule {
|
||||
options = {
|
||||
address = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
type = if nullableAddress then types.nullOr types.str else types.str;
|
||||
default = if nullableAddress then null else "localhost";
|
||||
example = "example.org";
|
||||
description = "The address where to forward the traffic to.";
|
||||
description = "The address to ${actionType} to.";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.nullOr types.port;
|
||||
default = null;
|
||||
example = 80;
|
||||
description = "Specifies port number to forward the traffic to.";
|
||||
example = 8080;
|
||||
description = "Specifies port number to ${actionType} to.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
dynamicForwardModule = mkAddressPortModule { actionType = "bind"; };
|
||||
|
||||
forwardModule = types.submodule {
|
||||
options = {
|
||||
bind = mkOption {
|
||||
type = mkAddressPortModule { actionType = "bind"; };
|
||||
description = "Local port binding options";
|
||||
};
|
||||
host = mkOption {
|
||||
type = mkAddressPortModule { actionType = "forward"; };
|
||||
description = "Host port binding options";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
matchBlockModule = types.submodule {
|
||||
@@ -383,6 +381,18 @@ let
|
||||
example = "10m";
|
||||
description = "Whether control socket should remain open in the background.";
|
||||
};
|
||||
|
||||
kexAlgorithms = mkOption {
|
||||
type = types.nullOr (types.listOf types.str);
|
||||
default = null;
|
||||
example = [
|
||||
"curve25519-sha256@libssh.org"
|
||||
"diffie-hellman-group-exchange-sha256"
|
||||
];
|
||||
description = ''
|
||||
Specifies the available KEX (Key Exchange) algorithms.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
# config.host = mkDefault dagName;
|
||||
@@ -430,6 +440,9 @@ let
|
||||
++ map (f: " LocalForward" + addressPort f.bind + addressPort f.host) cf.localForwards
|
||||
++ map (f: " RemoteForward" + addressPort f.bind + addressPort f.host) cf.remoteForwards
|
||||
++ map (f: " DynamicForward" + addressPort f) cf.dynamicForwards
|
||||
++ optional (
|
||||
cf.kexAlgorithms != null
|
||||
) " KexAlgorithms ${builtins.concatStringsSep "," cf.kexAlgorithms}"
|
||||
++ [
|
||||
(lib.generators.toKeyValue {
|
||||
mkKeyValue = lib.generators.mkKeyValueDefault { } " ";
|
||||
|
||||
@@ -106,13 +106,13 @@ in
|
||||
];
|
||||
|
||||
programs.bash.initExtra = lib.mkIf cfg.enableBashIntegration ''
|
||||
eval "$(${lib.getExe cfg.package} init bash)"
|
||||
source ${cfg.package}/share/television/completion.bash
|
||||
'';
|
||||
programs.zsh.initContent = lib.mkIf cfg.enableZshIntegration ''
|
||||
eval "$(${lib.getExe cfg.package} init zsh)"
|
||||
source ${cfg.package}/share/television/completion.zsh
|
||||
'';
|
||||
programs.fish.interactiveShellInit = lib.mkIf cfg.enableFishIntegration ''
|
||||
${lib.getExe cfg.package} init fish | source
|
||||
source ${cfg.package}/share/television/completion.fish
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ let
|
||||
|
||||
packageVersion = if cfg.package != null then lib.getVersion cfg.package else null;
|
||||
themeIsToml = lib.versionAtLeast packageVersion "0.15.0";
|
||||
versionPost0_17 = lib.versionAtLeast packageVersion "0.17.0";
|
||||
in
|
||||
{
|
||||
meta.maintainers = [ lib.maintainers.leiserfg ];
|
||||
@@ -43,7 +44,12 @@ in
|
||||
useLayerShell = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = "If vicinae should use the layer shell";
|
||||
description = ''
|
||||
Whether vicinae should use the layer shell.
|
||||
If you are using version 0.17 or newer, you should use
|
||||
{option}.programs.vicinae.settings.launcher_window.layer_shell.enabled = false
|
||||
instead.
|
||||
'';
|
||||
};
|
||||
|
||||
extensions = lib.mkOption {
|
||||
@@ -127,27 +133,22 @@ in
|
||||
settings = lib.mkOption {
|
||||
inherit (jsonFormat) type;
|
||||
default = { };
|
||||
description = "Settings written as JSON to `~/.config/vicinae/vicinae.json.";
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
faviconService = "twenty";
|
||||
font = {
|
||||
size = 10;
|
||||
};
|
||||
popToRootOnClose = false;
|
||||
rootSearch = {
|
||||
searchFiles = false;
|
||||
};
|
||||
favicon_service = "twenty";
|
||||
font.normal.size = 10;
|
||||
pop_to_root_on_close=false;
|
||||
search_files_in_root= false;
|
||||
theme = {
|
||||
name = "vicinae-dark";
|
||||
};
|
||||
window = {
|
||||
csd = true;
|
||||
opacity = 0.95;
|
||||
rounding = 10;
|
||||
dark.name = "vicinae-dark";
|
||||
light.name = "vicinae-light";
|
||||
};
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Settings written as JSON to {file}`~/.config/vicinae/settings.json`.
|
||||
See {command}`vicinae config default`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
@@ -158,6 +159,10 @@ in
|
||||
assertion = cfg.systemd.enable -> cfg.package != null;
|
||||
message = "{option}programs.vicinae.systemd.enable requires non null {option}programs.vicinae.package";
|
||||
}
|
||||
{
|
||||
assertion = !cfg.useLayerShell -> !versionPost0_17;
|
||||
message = ''After version 0.17, if you want to explicitly disable the use of layer shell, you need to set {option}.programs.vicinae.settings.launcher_window.layer_shell.enabled = false.'';
|
||||
}
|
||||
];
|
||||
lib.vicinae.mkExtension = (
|
||||
{
|
||||
@@ -223,10 +228,11 @@ in
|
||||
source = themeFormat.generate "vicinae-${name}-theme" theme;
|
||||
}
|
||||
) cfg.themes;
|
||||
settingsPath = if versionPost0_17 then "vicinae/settings.json" else "vicinae/vicinae.json";
|
||||
in
|
||||
{
|
||||
configFile = {
|
||||
"vicinae/vicinae.json" = lib.mkIf (cfg.settings != { }) {
|
||||
"${settingsPath}" = lib.mkIf (cfg.settings != { }) {
|
||||
source = jsonFormat.generate "vicinae-settings" cfg.settings;
|
||||
};
|
||||
}
|
||||
@@ -250,14 +256,16 @@ in
|
||||
PartOf = [ cfg.systemd.target ];
|
||||
};
|
||||
Service = {
|
||||
EnvironmentFile = pkgs.writeText "vicinae-env" ''
|
||||
USE_LAYER_SHELL=${if cfg.useLayerShell then builtins.toString 1 else builtins.toString 0}
|
||||
'';
|
||||
Type = "simple";
|
||||
ExecStart = "${lib.getExe' cfg.package "vicinae"} server";
|
||||
Restart = "always";
|
||||
RestartSec = 5;
|
||||
KillMode = "process";
|
||||
EnvironmentFile = lib.mkIf (!versionPost0_17) (
|
||||
pkgs.writeText "vicinae-env" ''
|
||||
USE_LAYER_SHELL=${if cfg.useLayerShell then builtins.toString 1 else builtins.toString 0}
|
||||
''
|
||||
);
|
||||
};
|
||||
Install = lib.mkIf cfg.systemd.autoStart {
|
||||
WantedBy = [ cfg.systemd.target ];
|
||||
|
||||
@@ -9,12 +9,27 @@ let
|
||||
|
||||
cfg = config.programs.yt-dlp;
|
||||
|
||||
renderSettings = lib.mapAttrsToList (
|
||||
configAtom =
|
||||
with types;
|
||||
oneOf [
|
||||
bool
|
||||
int
|
||||
str
|
||||
];
|
||||
|
||||
renderSingleOption =
|
||||
name: value:
|
||||
if lib.isBool value then
|
||||
if value then "--${name}" else "--no-${name}"
|
||||
else
|
||||
"--${name} ${toString value}"
|
||||
"--${name} ${toString value}";
|
||||
|
||||
renderSettings = lib.mapAttrsToList (
|
||||
name: value:
|
||||
if lib.isList value then
|
||||
lib.concatStringsSep "\n" (map (renderSingleOption name) value)
|
||||
else
|
||||
renderSingleOption name value
|
||||
);
|
||||
|
||||
in
|
||||
@@ -27,13 +42,7 @@ in
|
||||
package = lib.mkPackageOption pkgs "yt-dlp" { };
|
||||
|
||||
settings = mkOption {
|
||||
type =
|
||||
with types;
|
||||
attrsOf (oneOf [
|
||||
bool
|
||||
int
|
||||
str
|
||||
]);
|
||||
type = with types; attrsOf (either configAtom (listOf configAtom));
|
||||
default = { };
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
@@ -42,6 +51,10 @@ in
|
||||
sub-langs = "all";
|
||||
downloader = "aria2c";
|
||||
downloader-args = "aria2c:'-c -x8 -s8 -k1M'";
|
||||
color = [
|
||||
"stdout:no_color"
|
||||
"stderr:always"
|
||||
];
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
options,
|
||||
...
|
||||
}:
|
||||
let
|
||||
@@ -100,9 +101,18 @@ in
|
||||
};
|
||||
|
||||
dotDir = mkOption {
|
||||
default = homeDir;
|
||||
defaultText = "`config.home.homeDirectory`";
|
||||
example = "`\${config.xdg.configHome}/zsh`";
|
||||
default =
|
||||
if config.xdg.enable && lib.versionAtLeast config.home.stateVersion "26.05" then
|
||||
"${config.xdg.configHome}/zsh"
|
||||
else
|
||||
homeDir;
|
||||
defaultText = lib.literalExpression ''
|
||||
if config.xdg.enable && lib.versionAtLeast config.home.stateVersion "26.05" then
|
||||
"''${config.xdg.configHome}/zsh"
|
||||
else
|
||||
config.home.homeDirectory
|
||||
'';
|
||||
example = literalExpression ''"''${config.xdg.configHome}/zsh"'';
|
||||
description = ''
|
||||
Directory where the zsh configuration and more should be located,
|
||||
relative to the users home directory. The default is the home
|
||||
@@ -391,7 +401,24 @@ in
|
||||
- config.xdg.dataHome (XDG data directory)
|
||||
- config.xdg.cacheHome (XDG cache directory)
|
||||
''
|
||||
];
|
||||
]
|
||||
++
|
||||
lib.optionals
|
||||
(
|
||||
config.xdg.enable
|
||||
&& !lib.versionAtLeast config.home.stateVersion "26.05"
|
||||
&& options.programs.zsh.dotDir.highestPrio >= 1500
|
||||
)
|
||||
[
|
||||
''
|
||||
The default value of `programs.zsh.dotDir` will change in future versions.
|
||||
You are currently using the legacy default (home directory) because `home.stateVersion` is less than "26.05".
|
||||
To silence this warning and lock in the current behavior, set:
|
||||
programs.zsh.dotDir = config.home.homeDirectory;
|
||||
To adopt the new behavior (XDG config directory), set:
|
||||
programs.zsh.dotDir = "''${config.xdg.configHome}/zsh";
|
||||
''
|
||||
];
|
||||
}
|
||||
|
||||
(mkIf (cfg.envExtra != "") {
|
||||
@@ -412,7 +439,7 @@ in
|
||||
|
||||
(mkIf (dotDirAbs != homeDir) {
|
||||
home.file."${dotDirRel}/.zshenv".text = ''
|
||||
export ZDOTDIR=${dotDirAbs}
|
||||
${config.lib.zsh.export "ZDOTDIR" dotDirAbs}
|
||||
'';
|
||||
|
||||
# When dotDir is set, only use ~/.zshenv to source ZDOTDIR/.zshenv,
|
||||
@@ -420,7 +447,7 @@ in
|
||||
# already set correctly (by e.g. spawning a zsh inside a zsh), all env
|
||||
# vars still get exported
|
||||
home.file.".zshenv".text = ''
|
||||
source ${dotDirAbs}/.zshenv
|
||||
source ${lib.escapeShellArg "${dotDirAbs}/.zshenv"}
|
||||
'';
|
||||
})
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
{ config, lib, ... }:
|
||||
let
|
||||
cfg = config.programs.zsh;
|
||||
|
||||
stripSlash = lib.removeSuffix "/";
|
||||
in
|
||||
rec {
|
||||
homeDir = config.home.homeDirectory;
|
||||
# Raw home directory, no trailing slash.
|
||||
homeDir = stripSlash config.home.homeDirectory;
|
||||
|
||||
/*
|
||||
Escape a path string for shell usage and remove trailing slashes.
|
||||
@@ -18,10 +21,11 @@ rec {
|
||||
cleanPathStr "/path/to/dir/" => "'/path/to/dir'"
|
||||
cleanPathStr "path with spaces" => "'path with spaces'"
|
||||
*/
|
||||
cleanPathStr = pathStr: lib.escapeShellArg (lib.removeSuffix "/" pathStr);
|
||||
cleanPathStr = pathStr: lib.escapeShellArg (stripSlash pathStr);
|
||||
|
||||
/*
|
||||
Convert an absolute path to a relative path by stripping the home directory prefix.
|
||||
Returns the raw path (unescaped) for use in home.file keys.
|
||||
|
||||
This function converts absolute paths within the home directory to relative paths
|
||||
by removing the home directory prefix. Paths already relative are returned as-is.
|
||||
@@ -30,19 +34,22 @@ rec {
|
||||
Type: String -> String
|
||||
|
||||
Example:
|
||||
mkRelPathStr "/home/user/config" => "'config'"
|
||||
mkRelPathStr "config" => "'config'"
|
||||
mkRelPathStr "/home/user/config" => "config"
|
||||
mkRelPathStr "config" => "config"
|
||||
mkRelPathStr "/home/user" => "."
|
||||
mkRelPathStr "/etc/config" => <error>
|
||||
*/
|
||||
mkRelPathStr =
|
||||
pathStr:
|
||||
# is already a relative path
|
||||
if (!lib.hasPrefix "/" pathStr) then
|
||||
cleanPathStr pathStr
|
||||
# is an absolute path within home dir
|
||||
else if (lib.hasPrefix homeDir pathStr) then
|
||||
cleanPathStr (lib.removePrefix "${homeDir}/" pathStr)
|
||||
# is an absolute path not in home dir
|
||||
let
|
||||
normPath = stripSlash pathStr;
|
||||
in
|
||||
if (!lib.hasPrefix "/" normPath) then
|
||||
normPath
|
||||
else if normPath == homeDir then
|
||||
"."
|
||||
else if (lib.hasPrefix "${homeDir}/" normPath) then
|
||||
lib.removePrefix "${homeDir}/" normPath
|
||||
else
|
||||
throw ''
|
||||
Attempted to convert an absolute path not within home directory to a
|
||||
@@ -54,47 +61,47 @@ rec {
|
||||
'';
|
||||
|
||||
/*
|
||||
Convert a relative path to an absolute path by prepending the home directory.
|
||||
Convert a relative path to an absolute path.
|
||||
Returns RAW path (unescaped).
|
||||
|
||||
This function ensures paths are absolute by prepending the home directory
|
||||
to relative paths. Already absolute paths are returned unchanged (after cleaning).
|
||||
This function does NOT support shell variables.
|
||||
|
||||
Type: String -> String
|
||||
|
||||
Example:
|
||||
mkAbsPathStr "config" => "'/home/user/config'"
|
||||
mkAbsPathStr "/absolute/path" => "'/absolute/path'"
|
||||
mkAbsPathStr "config" => "/home/user/config"
|
||||
mkAbsPathStr "/absolute/path" => "/absolute/path"
|
||||
*/
|
||||
mkAbsPathStr =
|
||||
pathStr: cleanPathStr ((lib.optionalString (!lib.hasPrefix "/" pathStr) "${homeDir}/") + pathStr);
|
||||
pathStr:
|
||||
let
|
||||
normPath = stripSlash pathStr;
|
||||
in
|
||||
if lib.hasPrefix "/" normPath then normPath else "${homeDir}/${normPath}";
|
||||
|
||||
/*
|
||||
Convert a path to absolute form while preserving shell variables for runtime expansion.
|
||||
Convert a path to absolute form while preserving shell variables.
|
||||
Returns RAW path (unescaped) unless vars are present (then preserves vars).
|
||||
|
||||
This function handles both literal paths and shell variable expressions.
|
||||
Shell variables (containing '$') are preserved unescaped to allow runtime expansion.
|
||||
Literal paths are made absolute and properly escaped for shell usage.
|
||||
Literal paths are made absolute.
|
||||
|
||||
Type: String -> String
|
||||
|
||||
Example:
|
||||
mkShellVarPathStr "config" => "'/home/user/config'"
|
||||
mkShellVarPathStr "config" => "/home/user/config"
|
||||
mkShellVarPathStr "$HOME/config" => "$HOME/config"
|
||||
mkShellVarPathStr "\${XDG_CONFIG_HOME:-$HOME/.config}/app" => "\${XDG_CONFIG_HOME:-$HOME/.config}/app"
|
||||
*/
|
||||
mkShellVarPathStr =
|
||||
pathStr:
|
||||
let
|
||||
cleanPath = lib.removeSuffix "/" pathStr;
|
||||
hasShellVars = lib.hasInfix "$" cleanPath;
|
||||
normPath = stripSlash pathStr;
|
||||
hasShellVars = lib.hasInfix "$" normPath;
|
||||
in
|
||||
if hasShellVars then
|
||||
# Does not escape shell variables, allowing them to be expanded at runtime
|
||||
cleanPath
|
||||
else
|
||||
# For literal paths, make them absolute if needed and escape them
|
||||
cleanPathStr ((lib.optionalString (!lib.hasPrefix "/" cleanPath) "${homeDir}/") + cleanPath);
|
||||
if hasShellVars then normPath else mkAbsPathStr normPath;
|
||||
|
||||
dotDirAbs = mkAbsPathStr cfg.dotDir;
|
||||
dotDirRel = mkRelPathStr cfg.dotDir;
|
||||
@@ -107,5 +114,5 @@ rec {
|
||||
|
||||
Type: String
|
||||
*/
|
||||
pluginsDir = dotDirAbs + (lib.optionalString (homeDir == dotDirAbs) "/.zsh") + "/plugins";
|
||||
pluginsDir = dotDirAbs + (lib.optionalString (mkRelPathStr cfg.dotDir == ".") "/.zsh") + "/plugins";
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ let
|
||||
);
|
||||
in
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [ foo-dogsquared ];
|
||||
meta.maintainers = [ ];
|
||||
|
||||
options.services.activitywatch = {
|
||||
enable = lib.mkEnableOption "ActivityWatch, an automated time tracker";
|
||||
|
||||
@@ -32,78 +32,72 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf serviceConfig.enable (
|
||||
lib.mkMerge [
|
||||
(lib.mkIf pkgs.stdenv.isLinux {
|
||||
systemd.user = {
|
||||
services.borgmatic = {
|
||||
Unit = {
|
||||
Description = "borgmatic backup";
|
||||
# Prevent borgmatic from running unless the machine is
|
||||
# plugged into power:
|
||||
ConditionACPower = true;
|
||||
};
|
||||
Service = {
|
||||
Type = "oneshot";
|
||||
|
||||
# Lower CPU and I/O priority:
|
||||
Nice = 19;
|
||||
IOSchedulingClass = "best-effort";
|
||||
IOSchedulingPriority = 7;
|
||||
IOWeight = 100;
|
||||
|
||||
Restart = "no";
|
||||
LogRateLimitIntervalSec = 0;
|
||||
|
||||
# Delay start to prevent backups running during boot:
|
||||
ExecStartPre = "${pkgs.coreutils}/bin/sleep 3m";
|
||||
|
||||
ExecStart = ''
|
||||
${pkgs.systemd}/bin/systemd-inhibit \
|
||||
--who="borgmatic" \
|
||||
--what="sleep:shutdown" \
|
||||
--why="Prevent interrupting scheduled backup" \
|
||||
${programConfig.package}/bin/borgmatic \
|
||||
--stats \
|
||||
--verbosity -1 \
|
||||
--list \
|
||||
--syslog-verbosity 1
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
timers.borgmatic = {
|
||||
Unit.Description = "Run borgmatic backup";
|
||||
Timer = {
|
||||
OnCalendar = serviceConfig.frequency;
|
||||
Persistent = true;
|
||||
RandomizedDelaySec = "10m";
|
||||
};
|
||||
Install.WantedBy = [ "timers.target" ];
|
||||
};
|
||||
config = lib.mkIf serviceConfig.enable {
|
||||
systemd.user = {
|
||||
services.borgmatic = {
|
||||
Unit = {
|
||||
Description = "borgmatic backup";
|
||||
# Prevent borgmatic from running unless the machine is
|
||||
# plugged into power:
|
||||
ConditionACPower = true;
|
||||
};
|
||||
})
|
||||
Service = {
|
||||
Type = "oneshot";
|
||||
|
||||
(lib.mkIf pkgs.stdenv.isDarwin {
|
||||
assertions = [
|
||||
(lib.hm.darwin.assertInterval "services.borgmatic.frequency" serviceConfig.frequency pkgs)
|
||||
# Lower CPU and I/O priority:
|
||||
Nice = 19;
|
||||
IOSchedulingClass = "best-effort";
|
||||
IOSchedulingPriority = 7;
|
||||
IOWeight = 100;
|
||||
|
||||
Restart = "no";
|
||||
LogRateLimitIntervalSec = 0;
|
||||
|
||||
# Delay start to prevent backups running during boot:
|
||||
ExecStartPre = "${pkgs.coreutils}/bin/sleep 3m";
|
||||
|
||||
ExecStart = ''
|
||||
${pkgs.systemd}/bin/systemd-inhibit \
|
||||
--who="borgmatic" \
|
||||
--what="sleep:shutdown" \
|
||||
--why="Prevent interrupting scheduled backup" \
|
||||
${programConfig.package}/bin/borgmatic \
|
||||
--stats \
|
||||
--verbosity -1 \
|
||||
--list \
|
||||
--syslog-verbosity 1
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
timers.borgmatic = {
|
||||
Unit.Description = "Run borgmatic backup";
|
||||
Timer = {
|
||||
OnCalendar = serviceConfig.frequency;
|
||||
Persistent = true;
|
||||
RandomizedDelaySec = "10m";
|
||||
};
|
||||
Install.WantedBy = [ "timers.target" ];
|
||||
};
|
||||
};
|
||||
|
||||
assertions = [
|
||||
(lib.hm.darwin.assertInterval "services.borgmatic.frequency" serviceConfig.frequency pkgs)
|
||||
];
|
||||
|
||||
launchd.agents.borgmatic = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
(lib.getExe programConfig.package)
|
||||
"--stats"
|
||||
"--list"
|
||||
];
|
||||
|
||||
launchd.agents.borgmatic = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
(lib.getExe programConfig.package)
|
||||
"--stats"
|
||||
"--list"
|
||||
];
|
||||
ProcessType = "Background";
|
||||
StartCalendarInterval = lib.hm.darwin.mkCalendarInterval serviceConfig.frequency;
|
||||
StandardOutPath = "${config.home.homeDirectory}/Library/Logs/borgmatic/launchd-stdout.log";
|
||||
StandardErrorPath = "${config.home.homeDirectory}/Library/Logs/borgmatic/launchd-stderr.log";
|
||||
};
|
||||
};
|
||||
})
|
||||
]
|
||||
);
|
||||
ProcessType = "Background";
|
||||
StartCalendarInterval = lib.hm.darwin.mkCalendarInterval serviceConfig.frequency;
|
||||
StandardOutPath = "${config.home.homeDirectory}/Library/Logs/borgmatic/launchd-stdout.log";
|
||||
StandardErrorPath = "${config.home.homeDirectory}/Library/Logs/borgmatic/launchd-stderr.log";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ in
|
||||
|
||||
xdg.configFile."clipse/custom_theme.json".source = jsonFormat.generate "theme" cfg.theme;
|
||||
|
||||
systemd.user.services.clipse = lib.mkIf (pkgs.stdenv.isLinux && (cfg.package != null)) {
|
||||
systemd.user.services.clipse = lib.mkIf (cfg.package != null) {
|
||||
Unit = {
|
||||
Description = "Clipse listener";
|
||||
PartOf = [ "graphical-session.target" ];
|
||||
|
||||
@@ -163,7 +163,7 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable ({
|
||||
config = lib.mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = (lib.count (p: p.isActive) (lib.attrValues cfg.profiles)) <= 1;
|
||||
@@ -189,78 +189,74 @@ in
|
||||
if activeProfile.name != "default" then "colima-${activeProfile.name}" else "colima"
|
||||
);
|
||||
|
||||
launchd.agents = lib.mkIf pkgs.stdenv.isDarwin (
|
||||
lib.mapAttrs' (
|
||||
name: profile:
|
||||
lib.nameValuePair "colima-${name}" {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
"${lib.getExe cfg.package}"
|
||||
"start"
|
||||
name
|
||||
"-f"
|
||||
"--activate=${if profile.isActive then "true" else "false"}"
|
||||
"--save-config=false"
|
||||
];
|
||||
KeepAlive = true;
|
||||
RunAtLoad = true;
|
||||
EnvironmentVariables.PATH = lib.makeBinPath [
|
||||
cfg.package
|
||||
cfg.perlPackage
|
||||
cfg.dockerPackage
|
||||
cfg.sshPackage
|
||||
cfg.coreutilsPackage
|
||||
cfg.curlPackage
|
||||
cfg.bashPackage
|
||||
pkgs.darwin.DarwinTools
|
||||
];
|
||||
StandardOutPath = profile.logFile;
|
||||
StandardErrorPath = profile.logFile;
|
||||
};
|
||||
}
|
||||
) (lib.filterAttrs (_: p: p.isService) cfg.profiles)
|
||||
);
|
||||
launchd.agents = lib.mapAttrs' (
|
||||
name: profile:
|
||||
lib.nameValuePair "colima-${name}" {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
"${lib.getExe cfg.package}"
|
||||
"start"
|
||||
name
|
||||
"-f"
|
||||
"--activate=${if profile.isActive then "true" else "false"}"
|
||||
"--save-config=false"
|
||||
];
|
||||
KeepAlive = true;
|
||||
RunAtLoad = true;
|
||||
EnvironmentVariables.PATH = lib.makeBinPath [
|
||||
cfg.package
|
||||
cfg.perlPackage
|
||||
cfg.dockerPackage
|
||||
cfg.sshPackage
|
||||
cfg.coreutilsPackage
|
||||
cfg.curlPackage
|
||||
cfg.bashPackage
|
||||
pkgs.darwin.DarwinTools
|
||||
];
|
||||
StandardOutPath = profile.logFile;
|
||||
StandardErrorPath = profile.logFile;
|
||||
};
|
||||
}
|
||||
) (lib.filterAttrs (_: p: p.isService) cfg.profiles);
|
||||
|
||||
systemd.user.services = lib.mkIf pkgs.stdenv.isLinux (
|
||||
lib.mapAttrs' (
|
||||
name: profile:
|
||||
lib.nameValuePair "colima-${name}" {
|
||||
Unit = {
|
||||
Description = "Colima container runtime (${name} profile)";
|
||||
After = [ "network-online.target" ];
|
||||
Wants = [ "network-online.target" ];
|
||||
};
|
||||
Service = {
|
||||
ExecStart = ''
|
||||
${lib.getExe cfg.package} start ${name} \
|
||||
-f \
|
||||
--activate=${if profile.isActive then "true" else "false"} \
|
||||
--save-config=false
|
||||
'';
|
||||
Restart = "always";
|
||||
RestartSec = 2;
|
||||
Environment = [
|
||||
"PATH=${
|
||||
lib.makeBinPath [
|
||||
cfg.package
|
||||
cfg.perlPackage
|
||||
cfg.dockerPackage
|
||||
cfg.sshPackage
|
||||
cfg.coreutilsPackage
|
||||
cfg.curlPackage
|
||||
cfg.bashPackage
|
||||
]
|
||||
}"
|
||||
];
|
||||
StandardOutput = "append:${profile.logFile}";
|
||||
StandardError = "append:${profile.logFile}";
|
||||
};
|
||||
Install = {
|
||||
WantedBy = [ "default.target" ];
|
||||
};
|
||||
}
|
||||
) (lib.filterAttrs (_: p: p.isService) cfg.profiles)
|
||||
);
|
||||
});
|
||||
systemd.user.services = lib.mapAttrs' (
|
||||
name: profile:
|
||||
lib.nameValuePair "colima-${name}" {
|
||||
Unit = {
|
||||
Description = "Colima container runtime (${name} profile)";
|
||||
After = [ "network-online.target" ];
|
||||
Wants = [ "network-online.target" ];
|
||||
};
|
||||
Service = {
|
||||
ExecStart = ''
|
||||
${lib.getExe cfg.package} start ${name} \
|
||||
-f \
|
||||
--activate=${if profile.isActive then "true" else "false"} \
|
||||
--save-config=false
|
||||
'';
|
||||
Restart = "always";
|
||||
RestartSec = 2;
|
||||
Environment = [
|
||||
"PATH=${
|
||||
lib.makeBinPath [
|
||||
cfg.package
|
||||
cfg.perlPackage
|
||||
cfg.dockerPackage
|
||||
cfg.sshPackage
|
||||
cfg.coreutilsPackage
|
||||
cfg.curlPackage
|
||||
cfg.bashPackage
|
||||
]
|
||||
}"
|
||||
];
|
||||
StandardOutput = "append:${profile.logFile}";
|
||||
StandardError = "append:${profile.logFile}";
|
||||
};
|
||||
Install = {
|
||||
WantedBy = [ "default.target" ];
|
||||
};
|
||||
}
|
||||
) (lib.filterAttrs (_: p: p.isService) cfg.profiles);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -117,6 +117,8 @@ in
|
||||
systemd.user.services.easyeffects = {
|
||||
Unit = {
|
||||
Description = "Easyeffects daemon";
|
||||
After = [ "graphical-session.target" ];
|
||||
PartOf = [ "graphical-session.target" ];
|
||||
};
|
||||
|
||||
Install.WantedBy = [ "graphical-session.target" ];
|
||||
|
||||
@@ -107,10 +107,10 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
defaultEditor = mkOption rec {
|
||||
defaultEditor = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
example = !default;
|
||||
example = true;
|
||||
description = ''
|
||||
Whether to configure {command}`emacsclient` as the default
|
||||
editor using the {env}`EDITOR` and {env}`VISUAL`
|
||||
@@ -119,127 +119,117 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable (
|
||||
lib.mkMerge [
|
||||
{
|
||||
home.sessionVariables =
|
||||
let
|
||||
editorBin = lib.getBin (
|
||||
pkgs.writeShellScript "editor" ''exec ${lib.getBin cfg.package}/bin/emacsclient "''${@:---create-frame}"''
|
||||
);
|
||||
in
|
||||
mkIf cfg.defaultEditor {
|
||||
EDITOR = editorBin;
|
||||
VISUAL = editorBin;
|
||||
};
|
||||
config = mkIf cfg.enable {
|
||||
home.sessionVariables =
|
||||
let
|
||||
editorBin = lib.getBin (
|
||||
pkgs.writeShellScript "editor" ''exec ${lib.getBin cfg.package}/bin/emacsclient "''${@:---create-frame}"''
|
||||
);
|
||||
in
|
||||
mkIf cfg.defaultEditor {
|
||||
EDITOR = editorBin;
|
||||
VISUAL = editorBin;
|
||||
};
|
||||
|
||||
home.packages = optional (cfg.client.enable && pkgs.stdenv.isLinux) (lib.hiPrio clientDesktopItem);
|
||||
|
||||
systemd.user.services.emacs = {
|
||||
Unit = {
|
||||
Description = "Emacs text editor";
|
||||
Documentation = "info:emacs man:emacs(1) https://gnu.org/software/emacs/";
|
||||
|
||||
After = optional (cfg.startWithUserSession == "graphical") "graphical-session.target";
|
||||
PartOf = optional (cfg.startWithUserSession == "graphical") "graphical-session.target";
|
||||
|
||||
# Avoid killing the Emacs session, which may be full of
|
||||
# unsaved buffers.
|
||||
X-RestartIfChanged = false;
|
||||
}
|
||||
// optionalAttrs needsSocketWorkaround {
|
||||
# Emacs deletes its socket when shutting down, which systemd doesn't
|
||||
# handle, resulting in a server without a socket.
|
||||
# See https://github.com/nix-community/home-manager/issues/2018
|
||||
RefuseManualStart = true;
|
||||
};
|
||||
|
||||
(mkIf pkgs.stdenv.isLinux {
|
||||
systemd.user.services.emacs = {
|
||||
Unit = {
|
||||
Description = "Emacs text editor";
|
||||
Documentation = "info:emacs man:emacs(1) https://gnu.org/software/emacs/";
|
||||
Service = {
|
||||
Type = "notify";
|
||||
|
||||
After = optional (cfg.startWithUserSession == "graphical") "graphical-session.target";
|
||||
PartOf = optional (cfg.startWithUserSession == "graphical") "graphical-session.target";
|
||||
# We wrap ExecStart in a login shell so Emacs starts with the user's
|
||||
# environment, most importantly $PATH and $NIX_PROFILES. It may be
|
||||
# worth investigating a more targeted approach for user services to
|
||||
# import the user environment.
|
||||
ExecStart = ''${pkgs.runtimeShell} -l -c "${emacsBinPath}/emacs --fg-daemon${
|
||||
# In case the user sets 'server-directory' or 'server-name' in
|
||||
# their Emacs config, we want to specify the socket path explicitly
|
||||
# so launching 'emacs.service' manually doesn't break emacsclient
|
||||
# when using socket activation.
|
||||
lib.optionalString cfg.socketActivation.enable "=${lib.escapeShellArg socketPath}"
|
||||
} ${lib.escapeShellArgs cfg.extraOptions}"'';
|
||||
|
||||
# Avoid killing the Emacs session, which may be full of
|
||||
# unsaved buffers.
|
||||
X-RestartIfChanged = false;
|
||||
}
|
||||
// optionalAttrs needsSocketWorkaround {
|
||||
# Emacs deletes its socket when shutting down, which systemd doesn't
|
||||
# handle, resulting in a server without a socket.
|
||||
# See https://github.com/nix-community/home-manager/issues/2018
|
||||
RefuseManualStart = true;
|
||||
};
|
||||
# Emacs will exit with status 15 after having received SIGTERM, which
|
||||
# is the default "KillSignal" value systemd uses to stop services.
|
||||
SuccessExitStatus = 15;
|
||||
|
||||
Service = {
|
||||
Type = "notify";
|
||||
Restart = "on-failure";
|
||||
}
|
||||
// optionalAttrs needsSocketWorkaround {
|
||||
# Use read-only directory permissions to prevent emacs from
|
||||
# deleting systemd's socket file before exiting.
|
||||
ExecStartPost = "${pkgs.coreutils}/bin/chmod --changes -w ${socketDir}";
|
||||
ExecStopPost = "${pkgs.coreutils}/bin/chmod --changes +w ${socketDir}";
|
||||
};
|
||||
}
|
||||
// optionalAttrs (cfg.startWithUserSession != false) {
|
||||
Install = {
|
||||
WantedBy = [
|
||||
(if cfg.startWithUserSession == true then "default.target" else "graphical-session.target")
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# We wrap ExecStart in a login shell so Emacs starts with the user's
|
||||
# environment, most importantly $PATH and $NIX_PROFILES. It may be
|
||||
# worth investigating a more targeted approach for user services to
|
||||
# import the user environment.
|
||||
ExecStart = ''${pkgs.runtimeShell} -l -c "${emacsBinPath}/emacs --fg-daemon${
|
||||
# In case the user sets 'server-directory' or 'server-name' in
|
||||
# their Emacs config, we want to specify the socket path explicitly
|
||||
# so launching 'emacs.service' manually doesn't break emacsclient
|
||||
# when using socket activation.
|
||||
lib.optionalString cfg.socketActivation.enable "=${lib.escapeShellArg socketPath}"
|
||||
} ${lib.escapeShellArgs cfg.extraOptions}"'';
|
||||
systemd.user.sockets.emacs = mkIf cfg.socketActivation.enable {
|
||||
Unit = {
|
||||
Description = "Emacs text editor";
|
||||
Documentation = "info:emacs man:emacs(1) https://gnu.org/software/emacs/";
|
||||
};
|
||||
|
||||
# Emacs will exit with status 15 after having received SIGTERM, which
|
||||
# is the default "KillSignal" value systemd uses to stop services.
|
||||
SuccessExitStatus = 15;
|
||||
Socket = {
|
||||
ListenStream = socketPath;
|
||||
FileDescriptorName = "server";
|
||||
SocketMode = "0600";
|
||||
DirectoryMode = "0700";
|
||||
# This prevents the service from immediately starting again
|
||||
# after being stopped, due to the function
|
||||
# `server-force-stop' present in `kill-emacs-hook', which
|
||||
# calls `server-running-p', which opens the socket file.
|
||||
FlushPending = true;
|
||||
};
|
||||
|
||||
Restart = "on-failure";
|
||||
}
|
||||
// optionalAttrs needsSocketWorkaround {
|
||||
# Use read-only directory permissions to prevent emacs from
|
||||
# deleting systemd's socket file before exiting.
|
||||
ExecStartPost = "${pkgs.coreutils}/bin/chmod --changes -w ${socketDir}";
|
||||
ExecStopPost = "${pkgs.coreutils}/bin/chmod --changes +w ${socketDir}";
|
||||
};
|
||||
}
|
||||
// optionalAttrs (cfg.startWithUserSession != false) {
|
||||
Install = {
|
||||
WantedBy = [
|
||||
(if cfg.startWithUserSession == true then "default.target" else "graphical-session.target")
|
||||
];
|
||||
};
|
||||
Install = {
|
||||
WantedBy = [ "sockets.target" ];
|
||||
# Adding this Requires= dependency ensures that systemd
|
||||
# manages the socket file, in the case where the service is
|
||||
# started when the socket is stopped.
|
||||
# The socket unit is implicitly ordered before the service.
|
||||
RequiredBy = [ "emacs.service" ];
|
||||
};
|
||||
};
|
||||
|
||||
launchd.agents.emacs = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
"${cfg.package}/bin/emacs"
|
||||
"--fg-daemon"
|
||||
]
|
||||
++ cfg.extraOptions;
|
||||
RunAtLoad = true;
|
||||
KeepAlive = {
|
||||
Crashed = true;
|
||||
SuccessfulExit = false;
|
||||
};
|
||||
|
||||
home.packages = optional cfg.client.enable (lib.hiPrio clientDesktopItem);
|
||||
})
|
||||
|
||||
(mkIf (cfg.socketActivation.enable && pkgs.stdenv.isLinux) {
|
||||
systemd.user.sockets.emacs = {
|
||||
Unit = {
|
||||
Description = "Emacs text editor";
|
||||
Documentation = "info:emacs man:emacs(1) https://gnu.org/software/emacs/";
|
||||
};
|
||||
|
||||
Socket = {
|
||||
ListenStream = socketPath;
|
||||
FileDescriptorName = "server";
|
||||
SocketMode = "0600";
|
||||
DirectoryMode = "0700";
|
||||
# This prevents the service from immediately starting again
|
||||
# after being stopped, due to the function
|
||||
# `server-force-stop' present in `kill-emacs-hook', which
|
||||
# calls `server-running-p', which opens the socket file.
|
||||
FlushPending = true;
|
||||
};
|
||||
|
||||
Install = {
|
||||
WantedBy = [ "sockets.target" ];
|
||||
# Adding this Requires= dependency ensures that systemd
|
||||
# manages the socket file, in the case where the service is
|
||||
# started when the socket is stopped.
|
||||
# The socket unit is implicitly ordered before the service.
|
||||
RequiredBy = [ "emacs.service" ];
|
||||
};
|
||||
};
|
||||
})
|
||||
|
||||
(mkIf pkgs.stdenv.isDarwin {
|
||||
launchd.agents.emacs = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
"${cfg.package}/bin/emacs"
|
||||
"--fg-daemon"
|
||||
]
|
||||
++ cfg.extraOptions;
|
||||
RunAtLoad = true;
|
||||
KeepAlive = {
|
||||
Crashed = true;
|
||||
SuccessfulExit = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
})
|
||||
]
|
||||
);
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -15,49 +15,12 @@ let
|
||||
|
||||
cfg = config.services.git-sync;
|
||||
|
||||
mkUnit = name: repo: {
|
||||
Unit.Description = "Git Sync ${name}";
|
||||
|
||||
Install.WantedBy = [ "default.target" ];
|
||||
|
||||
Service = {
|
||||
Environment = [
|
||||
"PATH=${
|
||||
lib.makeBinPath (
|
||||
with pkgs;
|
||||
[
|
||||
openssh
|
||||
git
|
||||
]
|
||||
++ repo.extraPackages
|
||||
)
|
||||
}"
|
||||
"GIT_SYNC_DIRECTORY=${lib.strings.escapeShellArg repo.path}"
|
||||
"GIT_SYNC_COMMAND=${cfg.package}/bin/git-sync"
|
||||
"GIT_SYNC_REPOSITORY=${lib.strings.escapeShellArg repo.uri}"
|
||||
"GIT_SYNC_INTERVAL=${toString repo.interval}"
|
||||
];
|
||||
ExecStart = "${cfg.package}/bin/git-sync-on-inotify";
|
||||
Restart = "on-abort";
|
||||
};
|
||||
};
|
||||
|
||||
mkAgent = name: repo: {
|
||||
enable = true;
|
||||
config = {
|
||||
StartInterval = repo.interval;
|
||||
ProcessType = "Background";
|
||||
WorkingDirectory = "${repo.path}";
|
||||
WatchPaths = [ "${repo.path}" ];
|
||||
ProgramArguments = [ "${cfg.package}/bin/git-sync" ];
|
||||
};
|
||||
};
|
||||
|
||||
mkService = if pkgs.stdenv.isLinux then mkUnit else mkAgent;
|
||||
services = lib.mapAttrs' (name: repo: {
|
||||
name = "git-sync-${name}";
|
||||
value = mkService name repo;
|
||||
}) cfg.repositories;
|
||||
services =
|
||||
mkService:
|
||||
lib.mapAttrs' (name: repo: {
|
||||
name = "git-sync-${name}";
|
||||
value = mkService name repo;
|
||||
}) cfg.repositories;
|
||||
|
||||
repositoryType = types.submodule (
|
||||
{ name, ... }:
|
||||
@@ -141,11 +104,48 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable (
|
||||
lib.mkMerge [
|
||||
(mkIf pkgs.stdenv.isLinux { systemd.user.services = services; })
|
||||
(mkIf pkgs.stdenv.isDarwin { launchd.agents = services; })
|
||||
]
|
||||
);
|
||||
config = mkIf cfg.enable {
|
||||
launchd.agents = services (
|
||||
name: repo: {
|
||||
enable = true;
|
||||
config = {
|
||||
StartInterval = repo.interval;
|
||||
ProcessType = "Background";
|
||||
WorkingDirectory = "${repo.path}";
|
||||
WatchPaths = [ "${repo.path}" ];
|
||||
ProgramArguments = [ "${cfg.package}/bin/git-sync" ];
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
systemd.user.services = services (
|
||||
name: repo: {
|
||||
Unit.Description = "Git Sync ${name}";
|
||||
|
||||
Install.WantedBy = [ "default.target" ];
|
||||
|
||||
Service = {
|
||||
Environment = [
|
||||
"PATH=${
|
||||
lib.makeBinPath (
|
||||
with pkgs;
|
||||
[
|
||||
openssh
|
||||
git
|
||||
]
|
||||
++ repo.extraPackages
|
||||
)
|
||||
}"
|
||||
"GIT_SYNC_DIRECTORY=${lib.strings.escapeShellArg repo.path}"
|
||||
"GIT_SYNC_COMMAND=${cfg.package}/bin/git-sync"
|
||||
"GIT_SYNC_REPOSITORY=${lib.strings.escapeShellArg repo.uri}"
|
||||
"GIT_SYNC_INTERVAL=${toString repo.interval}"
|
||||
];
|
||||
ExecStart = "${cfg.package}/bin/git-sync-on-inotify";
|
||||
Restart = "on-abort";
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -344,125 +344,115 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable (
|
||||
lib.mkMerge [
|
||||
{
|
||||
# Grab the default binary name and fallback to expected value if `meta.mainProgram` not set
|
||||
services.gpg-agent.pinentry.program = lib.mkOptionDefault (
|
||||
cfg.pinentry.package.meta.mainProgram or "pinentry"
|
||||
);
|
||||
config = mkIf cfg.enable {
|
||||
# Grab the default binary name and fallback to expected value if `meta.mainProgram` not set
|
||||
services.gpg-agent.pinentry.program = lib.mkOptionDefault (
|
||||
cfg.pinentry.package.meta.mainProgram or "pinentry"
|
||||
);
|
||||
|
||||
home.file."${homedir}/gpg-agent.conf".text = lib.concatStringsSep "\n" (
|
||||
optional cfg.enableSshSupport "enable-ssh-support"
|
||||
++ optional cfg.grabKeyboardAndMouse "grab"
|
||||
++ optional (!cfg.enableScDaemon) "disable-scdaemon"
|
||||
++ optional cfg.noAllowExternalCache "no-allow-external-cache"
|
||||
++ optional (cfg.defaultCacheTtl != null) "default-cache-ttl ${toString cfg.defaultCacheTtl}"
|
||||
++ optional (
|
||||
cfg.defaultCacheTtlSsh != null
|
||||
) "default-cache-ttl-ssh ${toString cfg.defaultCacheTtlSsh}"
|
||||
++ optional (cfg.maxCacheTtl != null) "max-cache-ttl ${toString cfg.maxCacheTtl}"
|
||||
++ optional (cfg.maxCacheTtlSsh != null) "max-cache-ttl-ssh ${toString cfg.maxCacheTtlSsh}"
|
||||
++ optional (
|
||||
cfg.pinentry.package != null
|
||||
) "pinentry-program ${lib.getExe' cfg.pinentry.package cfg.pinentry.program}"
|
||||
++ [ cfg.extraConfig ]
|
||||
);
|
||||
home.file."${homedir}/gpg-agent.conf".text = lib.concatStringsSep "\n" (
|
||||
optional cfg.enableSshSupport "enable-ssh-support"
|
||||
++ optional cfg.grabKeyboardAndMouse "grab"
|
||||
++ optional (!cfg.enableScDaemon) "disable-scdaemon"
|
||||
++ optional cfg.noAllowExternalCache "no-allow-external-cache"
|
||||
++ optional (cfg.defaultCacheTtl != null) "default-cache-ttl ${toString cfg.defaultCacheTtl}"
|
||||
++ optional (
|
||||
cfg.defaultCacheTtlSsh != null
|
||||
) "default-cache-ttl-ssh ${toString cfg.defaultCacheTtlSsh}"
|
||||
++ optional (cfg.maxCacheTtl != null) "max-cache-ttl ${toString cfg.maxCacheTtl}"
|
||||
++ optional (cfg.maxCacheTtlSsh != null) "max-cache-ttl-ssh ${toString cfg.maxCacheTtlSsh}"
|
||||
++ optional (
|
||||
cfg.pinentry.package != null
|
||||
) "pinentry-program ${lib.getExe' cfg.pinentry.package cfg.pinentry.program}"
|
||||
++ [ cfg.extraConfig ]
|
||||
);
|
||||
|
||||
home.sessionVariablesExtra = optionalString cfg.enableSshSupport ''
|
||||
unset SSH_AGENT_PID
|
||||
if [ -z "$SSH_CONNECTION" -o -z "$SSH_AUTH_SOCK" ] && [ "''${gnupg_SSH_AUTH_SOCK_by:-0}" -ne $$ ]; then
|
||||
export SSH_AUTH_SOCK="$(${gpgPkg}/bin/gpgconf --list-dirs agent-ssh-socket)"
|
||||
fi
|
||||
'';
|
||||
home.sessionVariablesExtra = optionalString cfg.enableSshSupport ''
|
||||
unset SSH_AGENT_PID
|
||||
if [ -z "$SSH_CONNECTION" -o -z "$SSH_AUTH_SOCK" ] && [ "''${gnupg_SSH_AUTH_SOCK_by:-0}" -ne $$ ]; then
|
||||
export SSH_AUTH_SOCK="$(${gpgPkg}/bin/gpgconf --list-dirs agent-ssh-socket)"
|
||||
fi
|
||||
'';
|
||||
|
||||
programs = {
|
||||
bash.initExtra = mkIf cfg.enableBashIntegration gpgBashInitStr;
|
||||
zsh.initContent = mkIf cfg.enableZshIntegration gpgZshInitStr;
|
||||
fish.interactiveShellInit = mkIf cfg.enableFishIntegration gpgFishInitStr;
|
||||
nushell.extraConfig = mkIf cfg.enableNushellIntegration gpgNushellInitStr;
|
||||
programs = {
|
||||
bash.initExtra = mkIf cfg.enableBashIntegration gpgBashInitStr;
|
||||
zsh.initContent = mkIf cfg.enableZshIntegration gpgZshInitStr;
|
||||
fish.interactiveShellInit = mkIf cfg.enableFishIntegration gpgFishInitStr;
|
||||
nushell.extraConfig = mkIf cfg.enableNushellIntegration gpgNushellInitStr;
|
||||
};
|
||||
|
||||
# Trailing newlines are important
|
||||
home.file."${homedir}/sshcontrol" = mkIf (cfg.sshKeys != null) {
|
||||
text = lib.concatMapStrings (s: ''
|
||||
${s}
|
||||
'') cfg.sshKeys;
|
||||
};
|
||||
|
||||
systemd.user = {
|
||||
services.gpg-agent = {
|
||||
Unit = {
|
||||
Description = "GnuPG cryptographic agent and passphrase cache";
|
||||
Documentation = "man:gpg-agent(1)";
|
||||
Requires = "gpg-agent.socket";
|
||||
After = "gpg-agent.socket";
|
||||
# This is a socket-activated service:
|
||||
RefuseManualStart = true;
|
||||
};
|
||||
}
|
||||
|
||||
(mkIf (cfg.sshKeys != null) {
|
||||
# Trailing newlines are important
|
||||
home.file."${homedir}/sshcontrol".text = lib.concatMapStrings (s: ''
|
||||
${s}
|
||||
'') cfg.sshKeys;
|
||||
})
|
||||
Service = {
|
||||
ExecStart = "${gpgPkg}/bin/gpg-agent --supervised" + optionalString cfg.verbose " --verbose";
|
||||
ExecReload = "${gpgPkg}/bin/gpgconf --reload gpg-agent";
|
||||
Environment = [ "GNUPGHOME=${homedir}" ];
|
||||
};
|
||||
};
|
||||
|
||||
(lib.mkMerge [
|
||||
(mkIf pkgs.stdenv.isLinux {
|
||||
systemd.user = {
|
||||
services.gpg-agent = {
|
||||
Unit = {
|
||||
Description = "GnuPG cryptographic agent and passphrase cache";
|
||||
Documentation = "man:gpg-agent(1)";
|
||||
Requires = "gpg-agent.socket";
|
||||
After = "gpg-agent.socket";
|
||||
# This is a socket-activated service:
|
||||
RefuseManualStart = true;
|
||||
};
|
||||
sockets = {
|
||||
gpg-agent = mkSocket {
|
||||
desc = "GnuPG cryptographic agent and passphrase cache";
|
||||
docs = "man:gpg-agent(1)";
|
||||
stream = "S.gpg-agent";
|
||||
fdName = "std";
|
||||
};
|
||||
|
||||
Service = {
|
||||
ExecStart = "${gpgPkg}/bin/gpg-agent --supervised" + optionalString cfg.verbose " --verbose";
|
||||
ExecReload = "${gpgPkg}/bin/gpgconf --reload gpg-agent";
|
||||
Environment = [ "GNUPGHOME=${homedir}" ];
|
||||
};
|
||||
};
|
||||
gpg-agent-ssh = mkIf cfg.enableSshSupport (mkSocket {
|
||||
desc = "GnuPG cryptographic agent (ssh-agent emulation)";
|
||||
docs = "man:gpg-agent(1) man:ssh-add(1) man:ssh-agent(1) man:ssh(1)";
|
||||
stream = "S.gpg-agent.ssh";
|
||||
fdName = "ssh";
|
||||
});
|
||||
|
||||
sockets = {
|
||||
gpg-agent = mkSocket {
|
||||
desc = "GnuPG cryptographic agent and passphrase cache";
|
||||
docs = "man:gpg-agent(1)";
|
||||
stream = "S.gpg-agent";
|
||||
fdName = "std";
|
||||
};
|
||||
gpg-agent-extra = mkIf cfg.enableExtraSocket (mkSocket {
|
||||
desc = "GnuPG cryptographic agent and passphrase cache (restricted)";
|
||||
docs = "man:gpg-agent(1) man:ssh(1)";
|
||||
stream = "S.gpg-agent.extra";
|
||||
fdName = "extra";
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
gpg-agent-ssh = mkIf cfg.enableSshSupport (mkSocket {
|
||||
desc = "GnuPG cryptographic agent (ssh-agent emulation)";
|
||||
docs = "man:gpg-agent(1) man:ssh-add(1) man:ssh-agent(1) man:ssh(1)";
|
||||
stream = "S.gpg-agent.ssh";
|
||||
fdName = "ssh";
|
||||
});
|
||||
|
||||
gpg-agent-extra = mkIf cfg.enableExtraSocket (mkSocket {
|
||||
desc = "GnuPG cryptographic agent and passphrase cache (restricted)";
|
||||
docs = "man:gpg-agent(1) man:ssh(1)";
|
||||
stream = "S.gpg-agent.extra";
|
||||
fdName = "extra";
|
||||
});
|
||||
};
|
||||
};
|
||||
})
|
||||
|
||||
(mkIf pkgs.stdenv.isDarwin {
|
||||
launchd.agents.gpg-agent = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
"${gpgPkg}/bin/gpg-agent"
|
||||
"--supervised"
|
||||
]
|
||||
++ optional cfg.verbose "--verbose";
|
||||
EnvironmentVariables = {
|
||||
GNUPGHOME = homedir;
|
||||
};
|
||||
KeepAlive = {
|
||||
Crashed = true;
|
||||
SuccessfulExit = false;
|
||||
};
|
||||
ProcessType = "Background";
|
||||
RunAtLoad = cfg.enableSshSupport;
|
||||
Sockets = {
|
||||
Agent = mkAgentSock "S.gpg-agent";
|
||||
Ssh = mkIf cfg.enableSshSupport (mkAgentSock "S.gpg-agent.ssh");
|
||||
Extra = mkIf cfg.enableExtraSocket (mkAgentSock "S.gpg-agent.extra");
|
||||
};
|
||||
};
|
||||
};
|
||||
})
|
||||
])
|
||||
]
|
||||
);
|
||||
launchd.agents.gpg-agent = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
"${gpgPkg}/bin/gpg-agent"
|
||||
"--supervised"
|
||||
]
|
||||
++ optional cfg.verbose "--verbose";
|
||||
EnvironmentVariables = {
|
||||
GNUPGHOME = homedir;
|
||||
};
|
||||
KeepAlive = {
|
||||
Crashed = true;
|
||||
SuccessfulExit = false;
|
||||
};
|
||||
ProcessType = "Background";
|
||||
RunAtLoad = cfg.enableSshSupport;
|
||||
Sockets = {
|
||||
Agent = mkAgentSock "S.gpg-agent";
|
||||
Ssh = mkIf cfg.enableSshSupport (mkAgentSock "S.gpg-agent.ssh");
|
||||
Extra = mkIf cfg.enableExtraSocket (mkAgentSock "S.gpg-agent.extra");
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -81,46 +81,38 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable (
|
||||
lib.mkMerge [
|
||||
(lib.mkIf pkgs.stdenv.isLinux {
|
||||
systemd.user = {
|
||||
timers.home-manager-auto-expire = {
|
||||
Unit.Description = "Home Manager expire generations timer";
|
||||
config = lib.mkIf cfg.enable {
|
||||
|
||||
Install.WantedBy = [ "timers.target" ];
|
||||
|
||||
Timer = {
|
||||
OnCalendar = cfg.frequency;
|
||||
Unit = "home-manager-auto-expire.service";
|
||||
Persistent = true;
|
||||
};
|
||||
};
|
||||
|
||||
services.home-manager-auto-expire = {
|
||||
Unit.Description = "Home Manager expire generations";
|
||||
|
||||
Service.ExecStart = toString script;
|
||||
};
|
||||
systemd.user = {
|
||||
timers.home-manager-auto-expire = {
|
||||
Unit.Description = "Home Manager expire generations timer";
|
||||
Install.WantedBy = [ "timers.target" ];
|
||||
Timer = {
|
||||
OnCalendar = cfg.frequency;
|
||||
Unit = "home-manager-auto-expire.service";
|
||||
Persistent = true;
|
||||
};
|
||||
})
|
||||
};
|
||||
services.home-manager-auto-expire = {
|
||||
Unit.Description = "Home Manager expire generations";
|
||||
Service.ExecStart = toString script;
|
||||
};
|
||||
};
|
||||
|
||||
(lib.mkIf pkgs.stdenv.isDarwin {
|
||||
assertions = [
|
||||
(lib.hm.darwin.assertInterval "services.home-manager.autoExpire.frequency" cfg.frequency pkgs)
|
||||
];
|
||||
assertions = [
|
||||
(lib.hm.darwin.assertInterval "services.home-manager.autoExpire.frequency" cfg.frequency pkgs)
|
||||
];
|
||||
|
||||
launchd.agents.home-manager-auto-expire = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [ (toString script) ];
|
||||
ProcessType = "Background";
|
||||
StartCalendarInterval = lib.hm.darwin.mkCalendarInterval cfg.frequency;
|
||||
StandardOutPath = "${config.home.homeDirectory}/Library/Logs/home-manager-auto-expire/launchd-stdout.log";
|
||||
StandardErrorPath = "${config.home.homeDirectory}/Library/Logs/home-manager-auto-expire/launchd-stderr.log";
|
||||
};
|
||||
};
|
||||
})
|
||||
]
|
||||
);
|
||||
launchd.agents.home-manager-auto-expire = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [ (toString script) ];
|
||||
ProcessType = "Background";
|
||||
StartCalendarInterval = lib.hm.darwin.mkCalendarInterval cfg.frequency;
|
||||
StandardOutPath = "${config.home.homeDirectory}/Library/Logs/home-manager-auto-expire/launchd-stdout.log";
|
||||
StandardErrorPath = "${config.home.homeDirectory}/Library/Logs/home-manager-auto-expire/launchd-stderr.log";
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -45,16 +45,18 @@ in
|
||||
'';
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
ipc = "on";
|
||||
splash = false;
|
||||
splash_offset = 2.0;
|
||||
|
||||
preload =
|
||||
[ "/share/wallpapers/buttons.png" "/share/wallpapers/cat_pacman.png" ];
|
||||
|
||||
wallpaper = [
|
||||
"DP-3,/share/wallpapers/buttons.png"
|
||||
"DP-1,/share/wallpapers/cat_pacman.png"
|
||||
{
|
||||
monitor = "DP-3";
|
||||
path = "/share/wallpapers/buttons.png";
|
||||
fit_mode = "tile";
|
||||
}
|
||||
{
|
||||
monitor = "DP-1";
|
||||
path = "/share/wallpapers/cat_pacman.png";
|
||||
}
|
||||
];
|
||||
}
|
||||
'';
|
||||
|
||||
@@ -29,7 +29,7 @@ in
|
||||
default = { };
|
||||
description = ''
|
||||
Configuration settings for hyprshell. All the avaiblable
|
||||
options can be found here: <https://github.com/H3rmt/hyprshell/blob/hyprshell-release/CONFIGURE.md#config-options>
|
||||
options can be found here: <https://github.com/H3rmt/hyprshell/blob/hyprshell-release/docs/CONFIGURE.md#config-options>
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -38,7 +38,7 @@ in
|
||||
default = "";
|
||||
description = ''
|
||||
CSS file for customizing hyprshell. All the available
|
||||
options can be found here: <https://github.com/H3rmt/hyprshell/blob/hyprshell-release/CONFIGURE.md#css>
|
||||
options can be found here: <https://github.com/H3rmt/hyprshell/blob/hyprshell-release/docs/CONFIGURE.md#css>
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ let
|
||||
inherit (lib) mkOption types;
|
||||
|
||||
cfg = config.services.linux-wallpaperengine;
|
||||
|
||||
in
|
||||
{
|
||||
meta.maintainers = [ lib.hm.maintainers.ckgxrg ];
|
||||
@@ -105,10 +104,10 @@ in
|
||||
config = lib.mkIf cfg.enable {
|
||||
assertions = [
|
||||
(lib.hm.assertions.assertPlatform "services.linux-wallpaperengine" pkgs lib.platforms.linux)
|
||||
({
|
||||
{
|
||||
assertion = cfg.wallpapers != null;
|
||||
message = "linux-wallpaperengine: You must set at least one wallpaper";
|
||||
})
|
||||
}
|
||||
];
|
||||
|
||||
home.packages = [ cfg.package ];
|
||||
@@ -121,7 +120,7 @@ in
|
||||
lib.cli.toGNUCommandLine { } {
|
||||
screen-root = each.monitor;
|
||||
inherit (each) scaling fps;
|
||||
silent = each.audio.silent;
|
||||
inherit (each.audio) silent;
|
||||
noautomute = !each.audio.automute;
|
||||
no-audio-processing = !each.audio.processing;
|
||||
}
|
||||
@@ -138,11 +137,12 @@ in
|
||||
PartOf = [ "graphical-session.target" ];
|
||||
};
|
||||
Service = {
|
||||
ExecStart =
|
||||
lib.getExe cfg.package
|
||||
+ (lib.optionalString (cfg.assetsPath != null) " --assets-dir ${cfg.assetsPath} ")
|
||||
+ (lib.optionalString (cfg.clamping != null) "--clamping ${cfg.clamping} ")
|
||||
+ (lib.strings.concatStringsSep " " args);
|
||||
ExecStart = lib.concatStringsSep " " (
|
||||
[ (lib.getExe cfg.package) ]
|
||||
++ lib.optional (cfg.assetsPath != null) "--assets-dir ${cfg.assetsPath}"
|
||||
++ lib.optional (cfg.clamping != null) "--clamping ${cfg.clamping}"
|
||||
++ args
|
||||
);
|
||||
Restart = "on-failure";
|
||||
};
|
||||
Install = {
|
||||
|
||||
@@ -75,7 +75,7 @@ let
|
||||
|
||||
in
|
||||
{
|
||||
meta.maintainers = [ lib.maintainers.foo-dogsquared ];
|
||||
meta.maintainers = [ ];
|
||||
|
||||
options.services.mopidy = {
|
||||
enable = lib.mkEnableOption "Mopidy music player daemon";
|
||||
|
||||
@@ -22,6 +22,15 @@ in
|
||||
|
||||
package = lib.mkPackageOption pkgs "mpd" { };
|
||||
|
||||
enableSessionVariables = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to set {env}`MPD_HOST` {env}`MPD_PORT` environment variables
|
||||
according to {option}`services.mpd.network`.
|
||||
'';
|
||||
};
|
||||
|
||||
musicDirectory = mkOption {
|
||||
type = with types; either path str;
|
||||
defaultText = lib.literalExpression ''
|
||||
@@ -155,7 +164,13 @@ in
|
||||
);
|
||||
in
|
||||
mkIf cfg.enable {
|
||||
home.packages = [ cfg.package ];
|
||||
home = {
|
||||
packages = [ cfg.package ];
|
||||
sessionVariables = mkIf cfg.enableSessionVariables {
|
||||
MPD_HOST = mkIf (cfg.network.listenAddress != "any") cfg.network.listenAddress;
|
||||
MPD_PORT = builtins.toString cfg.network.port;
|
||||
};
|
||||
};
|
||||
|
||||
services.mpd = lib.mkMerge [
|
||||
(mkIf (lib.versionAtLeast config.home.stateVersion "22.11" && config.xdg.userDirs.enable) {
|
||||
@@ -167,7 +182,7 @@ in
|
||||
})
|
||||
];
|
||||
|
||||
systemd.user = lib.mkIf pkgs.stdenv.hostPlatform.isLinux {
|
||||
systemd.user = {
|
||||
services.mpd = {
|
||||
Unit = lib.mkMerge [
|
||||
{
|
||||
@@ -221,7 +236,7 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
launchd.agents.mpd = lib.mkIf pkgs.stdenv.hostPlatform.isDarwin {
|
||||
launchd.agents.mpd = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
|
||||
@@ -83,56 +83,51 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.automatic (
|
||||
lib.mkMerge [
|
||||
(lib.mkIf pkgs.stdenv.isLinux {
|
||||
systemd.user.services.nix-gc = {
|
||||
Unit = {
|
||||
Description = "Nix Garbage Collector";
|
||||
};
|
||||
Service = {
|
||||
Type = "oneshot";
|
||||
ExecStart = pkgs.writeShellScript "nix-gc" "exec ${nixPackage}/bin/nix-collect-garbage ${
|
||||
lib.optionalString (cfg.options != null) cfg.options
|
||||
}";
|
||||
};
|
||||
};
|
||||
systemd.user.timers.nix-gc = {
|
||||
Unit = {
|
||||
Description = "Nix Garbage Collector";
|
||||
};
|
||||
Timer = {
|
||||
OnCalendar = cfg.dates;
|
||||
RandomizedDelaySec = cfg.randomizedDelaySec;
|
||||
Persistent = cfg.persistent;
|
||||
Unit = "nix-gc.service";
|
||||
};
|
||||
Install = {
|
||||
WantedBy = [ "timers.target" ];
|
||||
};
|
||||
};
|
||||
})
|
||||
config = lib.mkIf cfg.automatic {
|
||||
systemd.user.services.nix-gc = {
|
||||
Unit = {
|
||||
Description = "Nix Garbage Collector";
|
||||
};
|
||||
Service = {
|
||||
Type = "oneshot";
|
||||
ExecStart = pkgs.writeShellScript "nix-gc" "exec ${nixPackage}/bin/nix-collect-garbage ${
|
||||
lib.optionalString (cfg.options != null) cfg.options
|
||||
}";
|
||||
};
|
||||
};
|
||||
|
||||
(lib.mkIf pkgs.stdenv.isDarwin {
|
||||
assertions = [
|
||||
{
|
||||
assertion = (lib.length cfg.dates) == 1;
|
||||
message = "On Darwin, `nix.gc.dates` must contain a single element.";
|
||||
}
|
||||
(lib.hm.darwin.assertInterval "nix.gc.dates.*" (lib.elemAt cfg.dates 0) pkgs)
|
||||
];
|
||||
systemd.user.timers.nix-gc = {
|
||||
Unit = {
|
||||
Description = "Nix Garbage Collector";
|
||||
};
|
||||
Timer = {
|
||||
OnCalendar = cfg.dates;
|
||||
RandomizedDelaySec = cfg.randomizedDelaySec;
|
||||
Persistent = cfg.persistent;
|
||||
Unit = "nix-gc.service";
|
||||
};
|
||||
Install = {
|
||||
WantedBy = [ "timers.target" ];
|
||||
};
|
||||
};
|
||||
|
||||
launchd.agents.nix-gc = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
"${nixPackage}/bin/nix-collect-garbage"
|
||||
]
|
||||
++ lib.optional (cfg.options != null) cfg.options;
|
||||
StartCalendarInterval = lib.hm.darwin.mkCalendarInterval (lib.elemAt cfg.dates 0);
|
||||
};
|
||||
};
|
||||
})
|
||||
]
|
||||
);
|
||||
assertions = [
|
||||
{
|
||||
assertion = pkgs.stdenv.isDarwin -> (lib.length cfg.dates == 1);
|
||||
message = "On Darwin, `nix.gc.dates` must contain a single element.";
|
||||
}
|
||||
(lib.hm.darwin.assertInterval "nix.gc.dates.*" (lib.elemAt cfg.dates 0) pkgs)
|
||||
];
|
||||
|
||||
launchd.agents.nix-gc = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
"${nixPackage}/bin/nix-collect-garbage"
|
||||
]
|
||||
++ lib.optional (cfg.options != null) cfg.options;
|
||||
StartCalendarInterval = lib.hm.darwin.mkCalendarInterval (lib.elemAt cfg.dates 0);
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ in
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
systemd.user.services.ollama = mkIf pkgs.stdenv.isLinux {
|
||||
systemd.user.services.ollama = {
|
||||
Unit = {
|
||||
Description = "Server for local large language models";
|
||||
After = [ "network.target" ];
|
||||
@@ -105,7 +105,7 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
launchd.agents.ollama = mkIf pkgs.stdenv.isDarwin {
|
||||
launchd.agents.ollama = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
|
||||
@@ -11,7 +11,7 @@ let
|
||||
pueuedBin = "${cfg.package}/bin/pueued";
|
||||
in
|
||||
{
|
||||
meta.maintainers = [ lib.maintainers.AndersonTorres ];
|
||||
meta.maintainers = [ ];
|
||||
|
||||
options.services.pueue = {
|
||||
enable = lib.mkEnableOption "Pueue, CLI process scheduler and manager";
|
||||
@@ -35,51 +35,49 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable (
|
||||
lib.mkMerge [
|
||||
{
|
||||
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||
}
|
||||
(lib.mkIf pkgs.stdenv.isLinux {
|
||||
xdg.configFile."pueue/pueue.yml".source = configFile;
|
||||
systemd.user = lib.mkIf (cfg.package != null) {
|
||||
services.pueued = {
|
||||
Unit = {
|
||||
Description = "Pueue Daemon - CLI process scheduler and manager";
|
||||
};
|
||||
config = lib.mkIf cfg.enable {
|
||||
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||
|
||||
Service = {
|
||||
Restart = "on-failure";
|
||||
ExecStart = "${pueuedBin} -v -c ${configFile}";
|
||||
};
|
||||
xdg.configFile."pueue/pueue.yml" = lib.mkIf pkgs.stdenv.isLinux { source = configFile; };
|
||||
|
||||
Install.WantedBy = [ "default.target" ];
|
||||
};
|
||||
systemd.user = lib.mkIf (cfg.package != null) {
|
||||
services.pueued = {
|
||||
Unit = {
|
||||
Description = "Pueue Daemon - CLI process scheduler and manager";
|
||||
};
|
||||
})
|
||||
(lib.mkIf pkgs.stdenv.isDarwin {
|
||||
# This is the default configuration file location for pueue on
|
||||
# darwin (https://github.com/Nukesor/pueue/wiki/Configuration)
|
||||
home.file."Library/Application Support/pueue/pueue.yml".source = configFile;
|
||||
launchd.agents.pueued = lib.mkIf (cfg.package != null) {
|
||||
enable = true;
|
||||
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
pueuedBin
|
||||
"-v"
|
||||
"-c"
|
||||
"${configFile}"
|
||||
];
|
||||
KeepAlive = {
|
||||
Crashed = true;
|
||||
SuccessfulExit = false;
|
||||
};
|
||||
ProcessType = "Background";
|
||||
RunAtLoad = true;
|
||||
};
|
||||
Service = {
|
||||
Restart = "on-failure";
|
||||
ExecStart = "${pueuedBin} -v -c ${configFile}";
|
||||
};
|
||||
})
|
||||
]
|
||||
);
|
||||
|
||||
Install.WantedBy = [ "default.target" ];
|
||||
};
|
||||
};
|
||||
|
||||
# This is the default configuration file location for pueue on
|
||||
# darwin (https://github.com/Nukesor/pueue/wiki/Configuration)
|
||||
home.file."Library/Application Support/pueue/pueue.yml" = lib.mkIf pkgs.stdenv.isDarwin {
|
||||
source = configFile;
|
||||
};
|
||||
|
||||
launchd.agents.pueued = lib.mkIf (cfg.package != null) {
|
||||
enable = true;
|
||||
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
pueuedBin
|
||||
"-v"
|
||||
"-c"
|
||||
"${configFile}"
|
||||
];
|
||||
KeepAlive = {
|
||||
Crashed = true;
|
||||
SuccessfulExit = false;
|
||||
};
|
||||
ProcessType = "Background";
|
||||
RunAtLoad = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ let
|
||||
settingsFormat = recollConfFormat { };
|
||||
in
|
||||
{
|
||||
meta.maintainers = [ lib.maintainers.foo-dogsquared ];
|
||||
meta.maintainers = [ ];
|
||||
|
||||
options.services.recoll = {
|
||||
enable = lib.mkEnableOption "Recoll file index service";
|
||||
|
||||
@@ -62,15 +62,13 @@ let
|
||||
))
|
||||
];
|
||||
|
||||
inherit (pkgs.stdenv.hostPlatform) isLinux;
|
||||
|
||||
# Until we have launchd support (#7924), mark the options
|
||||
# not used in the helper script as "linux exclusive"
|
||||
linuxExclusive =
|
||||
option:
|
||||
option
|
||||
// {
|
||||
readOnly = pkgs.stdenv.hostPlatform.isDarwin;
|
||||
readOnly = !pkgs.stdenv.hostPlatform.isLinux;
|
||||
|
||||
description = option.description + ''
|
||||
|
||||
@@ -393,219 +391,209 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable (
|
||||
lib.mkMerge [
|
||||
{
|
||||
assertions = lib.mapAttrsToList (n: v: {
|
||||
assertion = lib.xor (v.repository == null) (v.repositoryFile == null);
|
||||
message = "services.restic.backups.${n}: exactly one of repository or repositoryFile should be set";
|
||||
}) cfg.backups;
|
||||
}
|
||||
config = lib.mkIf cfg.enable {
|
||||
assertions = lib.mapAttrsToList (n: v: {
|
||||
assertion = lib.xor (v.repository == null) (v.repositoryFile == null);
|
||||
message = "services.restic.backups.${n}: exactly one of repository or repositoryFile should be set";
|
||||
}) cfg.backups;
|
||||
|
||||
(lib.mkIf isLinux {
|
||||
systemd.user.services = lib.mapAttrs' (
|
||||
name: backup:
|
||||
let
|
||||
doBackup = backup.dynamicFilesFrom != null || backup.paths != [ ];
|
||||
doPrune = backup.pruneOpts != [ ];
|
||||
doCheck = backup.runCheck;
|
||||
serviceName = "restic-backups-${name}";
|
||||
systemd.user.services = lib.mapAttrs' (
|
||||
name: backup:
|
||||
let
|
||||
doBackup = backup.dynamicFilesFrom != null || backup.paths != [ ];
|
||||
doPrune = backup.pruneOpts != [ ];
|
||||
doCheck = backup.runCheck;
|
||||
serviceName = "restic-backups-${name}";
|
||||
|
||||
extraOptions = lib.concatMap (arg: [
|
||||
"-o"
|
||||
arg
|
||||
]) backup.extraOptions;
|
||||
extraOptions = lib.concatMap (arg: [
|
||||
"-o"
|
||||
arg
|
||||
]) backup.extraOptions;
|
||||
|
||||
excludeFile = pkgs.writeText "exclude-patterns" (lib.concatLines backup.exclude);
|
||||
excludeFileFlag = "--exclude-file=${excludeFile}";
|
||||
excludeFile = pkgs.writeText "exclude-patterns" (lib.concatLines backup.exclude);
|
||||
excludeFileFlag = "--exclude-file=${excludeFile}";
|
||||
|
||||
filesFromTmpFile = "/run/user/$UID/${serviceName}/includes";
|
||||
filesFromFlag = "--files-from=${filesFromTmpFile}";
|
||||
filesFromTmpFile = "/run/user/$UID/${serviceName}/includes";
|
||||
filesFromFlag = "--files-from=${filesFromTmpFile}";
|
||||
|
||||
inhibitCmd = lib.optionals backup.inhibitsSleep [
|
||||
"${pkgs.systemd}/bin/systemd-inhibit"
|
||||
"--mode='block'"
|
||||
"--who='restic'"
|
||||
"--what='idle'"
|
||||
"--why=${lib.escapeShellArg "Scheduled backup ${name}"}"
|
||||
];
|
||||
inhibitCmd = lib.optionals backup.inhibitsSleep [
|
||||
"${pkgs.systemd}/bin/systemd-inhibit"
|
||||
"--mode='block'"
|
||||
"--who='restic'"
|
||||
"--what='idle'"
|
||||
"--why=${lib.escapeShellArg "Scheduled backup ${name}"}"
|
||||
];
|
||||
|
||||
mkResticCmd' =
|
||||
pre: args:
|
||||
lib.concatStringsSep " " (
|
||||
pre ++ lib.singleton (lib.getExe backup.package) ++ extraOptions ++ lib.flatten args
|
||||
);
|
||||
mkResticCmd = mkResticCmd' [ ];
|
||||
mkResticCmd' =
|
||||
pre: args:
|
||||
lib.concatStringsSep " " (
|
||||
pre ++ lib.singleton (lib.getExe backup.package) ++ extraOptions ++ lib.flatten args
|
||||
);
|
||||
mkResticCmd = mkResticCmd' [ ];
|
||||
|
||||
backupCmd =
|
||||
"${lib.getExe pkgs.bash} -c "
|
||||
+ lib.escapeShellArg (
|
||||
mkResticCmd' inhibitCmd [
|
||||
"backup"
|
||||
backup.extraBackupArgs
|
||||
excludeFileFlag
|
||||
filesFromFlag
|
||||
]
|
||||
);
|
||||
backupCmd =
|
||||
"${lib.getExe pkgs.bash} -c "
|
||||
+ lib.escapeShellArg (
|
||||
mkResticCmd' inhibitCmd [
|
||||
"backup"
|
||||
backup.extraBackupArgs
|
||||
excludeFileFlag
|
||||
filesFromFlag
|
||||
]
|
||||
);
|
||||
|
||||
forgetCmd = mkResticCmd [
|
||||
"forget"
|
||||
"--prune"
|
||||
backup.pruneOpts
|
||||
];
|
||||
checkCmd = mkResticCmd [
|
||||
"check"
|
||||
backup.checkOpts
|
||||
];
|
||||
unlockCmd = mkResticCmd "unlock";
|
||||
in
|
||||
lib.nameValuePair serviceName {
|
||||
Unit = {
|
||||
Description = "Restic backup service";
|
||||
Wants = [ "network-online.target" ];
|
||||
After = [ "network-online.target" ];
|
||||
};
|
||||
forgetCmd = mkResticCmd [
|
||||
"forget"
|
||||
"--prune"
|
||||
backup.pruneOpts
|
||||
];
|
||||
checkCmd = mkResticCmd [
|
||||
"check"
|
||||
backup.checkOpts
|
||||
];
|
||||
unlockCmd = mkResticCmd "unlock";
|
||||
in
|
||||
lib.nameValuePair serviceName {
|
||||
Unit = {
|
||||
Description = "Restic backup service";
|
||||
Wants = [ "network-online.target" ];
|
||||
After = [ "network-online.target" ];
|
||||
};
|
||||
|
||||
Service = {
|
||||
Type = "oneshot";
|
||||
Service = {
|
||||
Type = "oneshot";
|
||||
|
||||
X-RestartIfChanged = true;
|
||||
RuntimeDirectory = serviceName;
|
||||
CacheDirectory = serviceName;
|
||||
CacheDirectoryMode = "0700";
|
||||
PrivateTmp = true;
|
||||
X-RestartIfChanged = true;
|
||||
RuntimeDirectory = serviceName;
|
||||
CacheDirectory = serviceName;
|
||||
CacheDirectoryMode = "0700";
|
||||
PrivateTmp = true;
|
||||
|
||||
Environment = mkEnvironment backup ++ [ "RESTIC_CACHE_DIR=%C/${serviceName}" ];
|
||||
Environment = mkEnvironment backup ++ [ "RESTIC_CACHE_DIR=%C/${serviceName}" ];
|
||||
|
||||
ExecStart =
|
||||
lib.optional doBackup backupCmd
|
||||
++ lib.optionals doPrune [
|
||||
unlockCmd
|
||||
forgetCmd
|
||||
]
|
||||
++ lib.optional doCheck checkCmd;
|
||||
ExecStart =
|
||||
lib.optional doBackup backupCmd
|
||||
++ lib.optionals doPrune [
|
||||
unlockCmd
|
||||
forgetCmd
|
||||
]
|
||||
++ lib.optional doCheck checkCmd;
|
||||
|
||||
ExecStartPre = lib.getExe (
|
||||
pkgs.writeShellApplication {
|
||||
name = "${serviceName}-exec-start-pre";
|
||||
inherit runtimeInputs;
|
||||
text = ''
|
||||
set -x
|
||||
ExecStartPre = lib.getExe (
|
||||
pkgs.writeShellApplication {
|
||||
name = "${serviceName}-exec-start-pre";
|
||||
inherit runtimeInputs;
|
||||
text = ''
|
||||
set -x
|
||||
|
||||
${lib.optionalString (backup.backupPrepareCommand != null) ''
|
||||
${pkgs.writeShellScript "backupPrepareCommand" backup.backupPrepareCommand}
|
||||
''}
|
||||
${lib.optionalString (backup.backupPrepareCommand != null) ''
|
||||
${pkgs.writeShellScript "backupPrepareCommand" backup.backupPrepareCommand}
|
||||
''}
|
||||
|
||||
${lib.optionalString (backup.initialize) ''
|
||||
${
|
||||
mkResticCmd [
|
||||
"cat"
|
||||
"config"
|
||||
]
|
||||
} 2>/dev/null || ${mkResticCmd "init"}
|
||||
''}
|
||||
${lib.optionalString (backup.initialize) ''
|
||||
${
|
||||
mkResticCmd [
|
||||
"cat"
|
||||
"config"
|
||||
]
|
||||
} 2>/dev/null || ${mkResticCmd "init"}
|
||||
''}
|
||||
|
||||
${lib.optionalString (backup.paths != null && backup.paths != [ ]) ''
|
||||
cat ${pkgs.writeText "staticPaths" (lib.concatLines backup.paths)} >> ${filesFromTmpFile}
|
||||
''}
|
||||
${lib.optionalString (backup.paths != null && backup.paths != [ ]) ''
|
||||
cat ${pkgs.writeText "staticPaths" (lib.concatLines backup.paths)} >> ${filesFromTmpFile}
|
||||
''}
|
||||
|
||||
${lib.optionalString (backup.dynamicFilesFrom != null) ''
|
||||
${pkgs.writeShellScript "dynamicFilesFromScript" backup.dynamicFilesFrom} >> ${filesFromTmpFile}
|
||||
''}
|
||||
'';
|
||||
}
|
||||
);
|
||||
|
||||
ExecStopPost = lib.getExe (
|
||||
pkgs.writeShellApplication {
|
||||
name = "${serviceName}-exec-stop-post";
|
||||
inherit runtimeInputs;
|
||||
text = ''
|
||||
set -x
|
||||
|
||||
${lib.optionalString (backup.backupCleanupCommand != null) ''
|
||||
${pkgs.writeShellScript "backupCleanupCommand" backup.backupCleanupCommand}
|
||||
''}
|
||||
'';
|
||||
}
|
||||
);
|
||||
${lib.optionalString (backup.dynamicFilesFrom != null) ''
|
||||
${pkgs.writeShellScript "dynamicFilesFromScript" backup.dynamicFilesFrom} >> ${filesFromTmpFile}
|
||||
''}
|
||||
'';
|
||||
}
|
||||
// lib.optionalAttrs (backup.environmentFile != null) {
|
||||
EnvironmentFile = backup.environmentFile;
|
||||
};
|
||||
}
|
||||
) cfg.backups;
|
||||
})
|
||||
);
|
||||
|
||||
(lib.mkIf isLinux {
|
||||
systemd.user.timers = lib.mapAttrs' (
|
||||
name: backup:
|
||||
lib.nameValuePair "restic-backups-${name}" {
|
||||
Unit.Description = "Restic backup service";
|
||||
Install.WantedBy = [ "timers.target" ];
|
||||
ExecStopPost = lib.getExe (
|
||||
pkgs.writeShellApplication {
|
||||
name = "${serviceName}-exec-stop-post";
|
||||
inherit runtimeInputs;
|
||||
text = ''
|
||||
set -x
|
||||
|
||||
Timer = backup.timerConfig;
|
||||
}
|
||||
) (lib.filterAttrs (_: v: v.timerConfig != null) cfg.backups);
|
||||
})
|
||||
|
||||
{
|
||||
home.packages = lib.mapAttrsToList (
|
||||
name: backup:
|
||||
let
|
||||
serviceName = "restic-backups-${name}";
|
||||
environment = mkEnvironment backup;
|
||||
notPathVar = x: !(lib.hasPrefix "PATH" x);
|
||||
extraOptions = lib.concatMap (arg: [
|
||||
"-o"
|
||||
arg
|
||||
]) backup.extraOptions;
|
||||
restic = lib.concatStringsSep " " (
|
||||
lib.flatten [
|
||||
(lib.getExe backup.package)
|
||||
extraOptions
|
||||
]
|
||||
);
|
||||
in
|
||||
pkgs.writeShellApplication {
|
||||
name = "restic-${name}";
|
||||
excludeShellChecks = [
|
||||
# https://github.com/koalaman/shellcheck/issues/1986
|
||||
"SC2034"
|
||||
# Allow sourcing environmentFile
|
||||
"SC1091"
|
||||
];
|
||||
bashOptions = [
|
||||
"errexit"
|
||||
"nounset"
|
||||
"allexport"
|
||||
];
|
||||
text = ''
|
||||
${lib.optionalString (backup.environmentFile != null) ''
|
||||
source ${backup.environmentFile}
|
||||
''}
|
||||
|
||||
# Set same environment variables as the systemd service
|
||||
${lib.pipe environment [
|
||||
(lib.filter notPathVar)
|
||||
lib.concatLines
|
||||
]}
|
||||
|
||||
RESTIC_CACHE_DIR=${config.xdg.cacheHome}/${serviceName}
|
||||
|
||||
PATH=${
|
||||
lib.pipe environment [
|
||||
(lib.filter (lib.hasPrefix "PATH="))
|
||||
lib.head
|
||||
(lib.removePrefix "PATH=")
|
||||
]
|
||||
}:$PATH
|
||||
|
||||
exec ${restic} "$@"
|
||||
'';
|
||||
}
|
||||
) (lib.filterAttrs (_: v: v.createWrapper) cfg.backups);
|
||||
${lib.optionalString (backup.backupCleanupCommand != null) ''
|
||||
${pkgs.writeShellScript "backupCleanupCommand" backup.backupCleanupCommand}
|
||||
''}
|
||||
'';
|
||||
}
|
||||
);
|
||||
}
|
||||
// lib.optionalAttrs (backup.environmentFile != null) {
|
||||
EnvironmentFile = backup.environmentFile;
|
||||
};
|
||||
}
|
||||
]
|
||||
);
|
||||
) cfg.backups;
|
||||
|
||||
systemd.user.timers = lib.mapAttrs' (
|
||||
name: backup:
|
||||
lib.nameValuePair "restic-backups-${name}" {
|
||||
Unit.Description = "Restic backup service";
|
||||
Install.WantedBy = [ "timers.target" ];
|
||||
|
||||
Timer = backup.timerConfig;
|
||||
}
|
||||
) (lib.filterAttrs (_: v: v.timerConfig != null) cfg.backups);
|
||||
|
||||
home.packages = lib.mapAttrsToList (
|
||||
name: backup:
|
||||
let
|
||||
serviceName = "restic-backups-${name}";
|
||||
environment = mkEnvironment backup;
|
||||
notPathVar = x: !(lib.hasPrefix "PATH" x);
|
||||
extraOptions = lib.concatMap (arg: [
|
||||
"-o"
|
||||
arg
|
||||
]) backup.extraOptions;
|
||||
restic = lib.concatStringsSep " " (
|
||||
lib.flatten [
|
||||
(lib.getExe backup.package)
|
||||
extraOptions
|
||||
]
|
||||
);
|
||||
in
|
||||
pkgs.writeShellApplication {
|
||||
name = "restic-${name}";
|
||||
excludeShellChecks = [
|
||||
# https://github.com/koalaman/shellcheck/issues/1986
|
||||
"SC2034"
|
||||
# Allow sourcing environmentFile
|
||||
"SC1091"
|
||||
];
|
||||
bashOptions = [
|
||||
"errexit"
|
||||
"nounset"
|
||||
"allexport"
|
||||
];
|
||||
text = ''
|
||||
${lib.optionalString (backup.environmentFile != null) ''
|
||||
source ${backup.environmentFile}
|
||||
''}
|
||||
|
||||
# Set same environment variables as the systemd service
|
||||
${lib.pipe environment [
|
||||
(lib.filter notPathVar)
|
||||
lib.concatLines
|
||||
]}
|
||||
|
||||
RESTIC_CACHE_DIR=${config.xdg.cacheHome}/${serviceName}
|
||||
|
||||
PATH=${
|
||||
lib.pipe environment [
|
||||
(lib.filter (lib.hasPrefix "PATH="))
|
||||
lib.head
|
||||
(lib.removePrefix "PATH=")
|
||||
]
|
||||
}:$PATH
|
||||
|
||||
exec ${restic} "$@"
|
||||
'';
|
||||
}
|
||||
) (lib.filterAttrs (_: v: v.createWrapper) cfg.backups);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -46,91 +46,85 @@ in
|
||||
enableNushellIntegration = lib.hm.shell.mkNushellIntegrationOption { inherit config; };
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable (
|
||||
lib.mkMerge [
|
||||
{
|
||||
programs =
|
||||
config = lib.mkIf cfg.enable {
|
||||
|
||||
programs =
|
||||
let
|
||||
socketPath =
|
||||
if pkgs.stdenv.isDarwin then
|
||||
"$(${lib.getExe pkgs.getconf} DARWIN_USER_TEMP_DIR)/${cfg.socket}"
|
||||
else
|
||||
"$XDG_RUNTIME_DIR/${cfg.socket}";
|
||||
|
||||
# Preserve $SSH_AUTH_SOCK only if it stems from a forwarded agent which
|
||||
# is the case if both $SSH_AUTH_SOCK and $SSH_CONNECTION are set.
|
||||
bashIntegration = ''
|
||||
if [ -z "$SSH_AUTH_SOCK" -o -z "$SSH_CONNECTION" ]; then
|
||||
export SSH_AUTH_SOCK=${socketPath}
|
||||
fi
|
||||
'';
|
||||
fishIntegration = ''
|
||||
if test -z "$SSH_AUTH_SOCK"; or test -z "$SSH_CONNECTION"
|
||||
set -x SSH_AUTH_SOCK ${socketPath}
|
||||
end
|
||||
'';
|
||||
nushellIntegration =
|
||||
let
|
||||
unsetOrEmpty = var: ''("${var}" not-in $env) or ($env.${var} | is-empty)'';
|
||||
socketPath =
|
||||
if pkgs.stdenv.isDarwin then
|
||||
"$(${lib.getExe pkgs.getconf} DARWIN_USER_TEMP_DIR)/${cfg.socket}"
|
||||
''$"(${lib.getExe pkgs.getconf} DARWIN_USER_TEMP_DIR)/${cfg.socket}"''
|
||||
else
|
||||
"$XDG_RUNTIME_DIR/${cfg.socket}";
|
||||
|
||||
bashIntegration = ''
|
||||
if [ -z "$SSH_AUTH_SOCK" ]; then
|
||||
export SSH_AUTH_SOCK=${socketPath}
|
||||
fi
|
||||
'';
|
||||
|
||||
fishIntegration = ''
|
||||
if test -z "$SSH_AUTH_SOCK"
|
||||
set -x SSH_AUTH_SOCK ${socketPath}
|
||||
end
|
||||
'';
|
||||
|
||||
nushellIntegration =
|
||||
if pkgs.stdenv.isDarwin then
|
||||
''
|
||||
if "SSH_AUTH_SOCK" not-in $env {
|
||||
$env.SSH_AUTH_SOCK = $"(${lib.getExe pkgs.getconf} DARWIN_USER_TEMP_DIR)/${cfg.socket}"
|
||||
}
|
||||
''
|
||||
else
|
||||
''
|
||||
if "SSH_AUTH_SOCK" not-in $env {
|
||||
$env.SSH_AUTH_SOCK = $"($env.XDG_RUNTIME_DIR)/${cfg.socket}"
|
||||
}
|
||||
'';
|
||||
''$"($env.XDG_RUNTIME_DIR)/${cfg.socket}"'';
|
||||
in
|
||||
{
|
||||
bash.initExtra = lib.mkIf cfg.enableBashIntegration bashIntegration;
|
||||
''
|
||||
if ${unsetOrEmpty "SSH_AUTH_SOCK"} or ${unsetOrEmpty "SSH_CONNECTION"} {
|
||||
$env.SSH_AUTH_SOCK = ${socketPath}
|
||||
}
|
||||
'';
|
||||
in
|
||||
{
|
||||
# $SSH_AUTH_SOCK has to be set early since other tools rely on it
|
||||
bash.profileExtra = lib.mkIf cfg.enableBashIntegration (lib.mkOrder 900 bashIntegration);
|
||||
fish.shellInit = lib.mkIf cfg.enableFishIntegration (lib.mkOrder 900 fishIntegration);
|
||||
nushell.extraConfig = lib.mkIf cfg.enableNushellIntegration (lib.mkOrder 900 nushellIntegration);
|
||||
zsh.envExtra = lib.mkIf cfg.enableZshIntegration (lib.mkOrder 900 bashIntegration);
|
||||
};
|
||||
|
||||
zsh.initContent = lib.mkIf cfg.enableZshIntegration bashIntegration;
|
||||
systemd.user.services.ssh-agent = {
|
||||
Install.WantedBy = [ "default.target" ];
|
||||
Unit = {
|
||||
Description = "SSH authentication agent";
|
||||
Documentation = "man:ssh-agent(1)";
|
||||
};
|
||||
Service.ExecStart = "${lib.getExe' cfg.package "ssh-agent"} -D -a %t/${cfg.socket}${
|
||||
lib.optionalString (
|
||||
cfg.defaultMaximumIdentityLifetime != null
|
||||
) " -t ${toString cfg.defaultMaximumIdentityLifetime}"
|
||||
}";
|
||||
};
|
||||
|
||||
fish.interactiveShellInit = lib.mkIf cfg.enableFishIntegration fishIntegration;
|
||||
|
||||
nushell.extraConfig = lib.mkIf cfg.enableNushellIntegration nushellIntegration;
|
||||
};
|
||||
}
|
||||
|
||||
(lib.mkIf pkgs.stdenv.isLinux {
|
||||
systemd.user.services.ssh-agent = {
|
||||
Install.WantedBy = [ "default.target" ];
|
||||
Unit = {
|
||||
Description = "SSH authentication agent";
|
||||
Documentation = "man:ssh-agent(1)";
|
||||
};
|
||||
Service.ExecStart = "${lib.getExe' cfg.package "ssh-agent"} -D -a %t/${cfg.socket}${
|
||||
launchd.agents.ssh-agent = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
(lib.getExe pkgs.bash)
|
||||
"-c"
|
||||
''${lib.getExe' cfg.package "ssh-agent"} -D -a "$(${lib.getExe pkgs.getconf} DARWIN_USER_TEMP_DIR)/${cfg.socket}"${
|
||||
lib.optionalString (
|
||||
cfg.defaultMaximumIdentityLifetime != null
|
||||
) " -t ${toString cfg.defaultMaximumIdentityLifetime}"
|
||||
}";
|
||||
}''
|
||||
];
|
||||
KeepAlive = {
|
||||
Crashed = true;
|
||||
SuccessfulExit = false;
|
||||
};
|
||||
})
|
||||
ProcessType = "Background";
|
||||
RunAtLoad = true;
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
(lib.mkIf pkgs.stdenv.isDarwin {
|
||||
launchd.agents.ssh-agent = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
(lib.getExe pkgs.bash)
|
||||
"-c"
|
||||
''${lib.getExe' cfg.package "ssh-agent"} -D -a "$(${lib.getExe pkgs.getconf} DARWIN_USER_TEMP_DIR)/${cfg.socket}"${
|
||||
lib.optionalString (
|
||||
cfg.defaultMaximumIdentityLifetime != null
|
||||
) " -t ${toString cfg.defaultMaximumIdentityLifetime}"
|
||||
}''
|
||||
];
|
||||
KeepAlive = {
|
||||
Crashed = true;
|
||||
SuccessfulExit = false;
|
||||
};
|
||||
ProcessType = "Background";
|
||||
RunAtLoad = true;
|
||||
};
|
||||
};
|
||||
})
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ let
|
||||
|
||||
in
|
||||
{
|
||||
meta.maintainers = [ lib.maintainers.AndersonTorres ];
|
||||
meta.maintainers = [ ];
|
||||
|
||||
options = {
|
||||
xsession.windowManager.fluxbox = {
|
||||
|
||||
@@ -48,6 +48,11 @@ in
|
||||
[ "wayland" "windowManager" "hyprland" "systemdIntegration" ] # \
|
||||
[ "wayland" "windowManager" "hyprland" "systemd" "enable" ]
|
||||
)
|
||||
|
||||
(lib.mkRenamedOptionModule # \
|
||||
[ "wayland" "windowManager" "hyprland" "xwayland" "enable" ] # \
|
||||
[ "wayland" "windowManager" "hyprland" "settings" "xwayland" "enable" ]
|
||||
)
|
||||
];
|
||||
|
||||
options.wayland.windowManager.hyprland = {
|
||||
@@ -79,11 +84,7 @@ in
|
||||
finalPackage = lib.mkOption {
|
||||
type = with lib.types; nullOr package;
|
||||
readOnly = true;
|
||||
default =
|
||||
if cfg.package != null then
|
||||
cfg.package.override { enableXWayland = cfg.xwayland.enable; }
|
||||
else
|
||||
null;
|
||||
default = if cfg.package != null then cfg.package else null;
|
||||
defaultText = lib.literalMD "`wayland.windowManager.hyprland.package` with applied configuration";
|
||||
description = ''
|
||||
The Hyprland package after applying configuration.
|
||||
@@ -162,10 +163,6 @@ in
|
||||
{manpage}`systemd-xdg-autostart-generator(8)`'';
|
||||
};
|
||||
|
||||
xwayland.enable = lib.mkEnableOption "XWayland" // {
|
||||
default = true;
|
||||
};
|
||||
|
||||
settings = lib.mkOption {
|
||||
type =
|
||||
with lib.types;
|
||||
@@ -357,7 +354,10 @@ in
|
||||
submapWarnings ++ lib.optional inconsistent warning;
|
||||
|
||||
home.packages = lib.mkIf (cfg.package != null) (
|
||||
[ cfg.finalPackage ] ++ lib.optional cfg.xwayland.enable pkgs.xwayland
|
||||
[ cfg.finalPackage ]
|
||||
++ lib.optional (
|
||||
(lib.hasAttrByPath [ "settings" "xwayland" "enable" ] cfg) && cfg.settings.xwayland.enable
|
||||
) pkgs.xwayland
|
||||
);
|
||||
|
||||
xdg.configFile."hypr/hyprland.conf" =
|
||||
|
||||
@@ -19,79 +19,71 @@ in
|
||||
package = lib.mkPackageOption pkgs "yubikey-agent" { };
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable (
|
||||
lib.mkMerge [
|
||||
{ home.packages = [ cfg.package ]; }
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ cfg.package ];
|
||||
|
||||
(mkIf pkgs.stdenv.isLinux {
|
||||
systemd.user.services.yubikey-agent = {
|
||||
Unit = {
|
||||
Description = "Seamless ssh-agent for YubiKeys";
|
||||
Documentation = "https://github.com/FiloSottile/yubikey-agent";
|
||||
Requires = "yubikey-agent.socket";
|
||||
After = "yubikey-agent.socket";
|
||||
RefuseManualStart = true;
|
||||
};
|
||||
home.sessionVariables.SSH_AUTH_SOCK =
|
||||
if pkgs.stdenv.isDarwin then
|
||||
"/tmp/yubikey-agent.sock"
|
||||
else
|
||||
"\${XDG_RUNTIME_DIR:-/run/user/$UID}/yubikey-agent/yubikey-agent.sock";
|
||||
|
||||
Service = {
|
||||
ExecStart = "${cfg.package}/bin/yubikey-agent -l %t/yubikey-agent/yubikey-agent.sock";
|
||||
Type = "simple";
|
||||
# /run/user/$UID for the socket
|
||||
ReadWritePaths = [ "%t" ];
|
||||
systemd.user.services.yubikey-agent = {
|
||||
Unit = {
|
||||
Description = "Seamless ssh-agent for YubiKeys";
|
||||
Documentation = "https://github.com/FiloSottile/yubikey-agent";
|
||||
Requires = "yubikey-agent.socket";
|
||||
After = "yubikey-agent.socket";
|
||||
RefuseManualStart = true;
|
||||
};
|
||||
|
||||
Service = {
|
||||
ExecStart = "${cfg.package}/bin/yubikey-agent -l %t/yubikey-agent/yubikey-agent.sock";
|
||||
Type = "simple";
|
||||
# /run/user/$UID for the socket
|
||||
ReadWritePaths = [ "%t" ];
|
||||
};
|
||||
};
|
||||
|
||||
systemd.user.sockets.yubikey-agent = {
|
||||
Unit = {
|
||||
Description = "Unix domain socket for Yubikey SSH agent";
|
||||
Documentation = "https://github.com/FiloSottile/yubikey-agent";
|
||||
};
|
||||
|
||||
Socket = {
|
||||
ListenStream = "%t/yubikey-agent/yubikey-agent.sock";
|
||||
RuntimeDirectory = "yubikey-agent";
|
||||
SocketMode = "0600";
|
||||
DirectoryMode = "0700";
|
||||
};
|
||||
|
||||
Install = {
|
||||
WantedBy = [ "sockets.target" ];
|
||||
};
|
||||
};
|
||||
|
||||
launchd.agents.yubikey-agent = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
"${cfg.package}/bin/yubikey-agent"
|
||||
"-l"
|
||||
"/tmp/yubikey-agent.sock"
|
||||
];
|
||||
|
||||
KeepAlive = {
|
||||
Crashed = true;
|
||||
SuccessfulExit = false;
|
||||
};
|
||||
ProcessType = "Background";
|
||||
Sockets = {
|
||||
Listener = {
|
||||
SockPathName = "/tmp/yubikey-agent.sock";
|
||||
SockPathMode = 384; # 0600 in decimal
|
||||
};
|
||||
};
|
||||
|
||||
systemd.user.sockets.yubikey-agent = {
|
||||
Unit = {
|
||||
Description = "Unix domain socket for Yubikey SSH agent";
|
||||
Documentation = "https://github.com/FiloSottile/yubikey-agent";
|
||||
};
|
||||
|
||||
Socket = {
|
||||
ListenStream = "%t/yubikey-agent/yubikey-agent.sock";
|
||||
RuntimeDirectory = "yubikey-agent";
|
||||
SocketMode = "0600";
|
||||
DirectoryMode = "0700";
|
||||
};
|
||||
|
||||
Install = {
|
||||
WantedBy = [ "sockets.target" ];
|
||||
};
|
||||
};
|
||||
|
||||
home.sessionVariables = {
|
||||
SSH_AUTH_SOCK = "\${XDG_RUNTIME_DIR:-/run/user/$UID}/yubikey-agent/yubikey-agent.sock";
|
||||
};
|
||||
})
|
||||
|
||||
(mkIf pkgs.stdenv.isDarwin {
|
||||
launchd.agents.yubikey-agent = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
"${cfg.package}/bin/yubikey-agent"
|
||||
"-l"
|
||||
"/tmp/yubikey-agent.sock"
|
||||
];
|
||||
|
||||
KeepAlive = {
|
||||
Crashed = true;
|
||||
SuccessfulExit = false;
|
||||
};
|
||||
ProcessType = "Background";
|
||||
Sockets = {
|
||||
Listener = {
|
||||
SockPathName = "/tmp/yubikey-agent.sock";
|
||||
SockPathMode = 384; # 0600 in decimal
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
home.sessionVariables = {
|
||||
SSH_AUTH_SOCK = "/tmp/yubikey-agent.sock";
|
||||
};
|
||||
})
|
||||
]
|
||||
);
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -430,10 +430,7 @@ in
|
||||
# Do not install any user services if username is root.
|
||||
config = mkIf (cfg.enable && config.home.username != "root") {
|
||||
assertions = [
|
||||
{
|
||||
assertion = pkgs.stdenv.isLinux;
|
||||
message = "This module is only available on Linux.";
|
||||
}
|
||||
(lib.hm.assertions.assertPlatform "systemd" pkgs lib.platforms.linux)
|
||||
];
|
||||
|
||||
xdg.configFile = mkMerge [
|
||||
|
||||
@@ -274,6 +274,26 @@ in
|
||||
sed "s|${pkg.out}|$out|g" "$src" > "$dsk"
|
||||
done
|
||||
|
||||
# Patch systemd user services
|
||||
for svc in "$out/share/systemd/user"/*.service ; do
|
||||
if ! grep -q "${pkg.out}" "$svc"; then
|
||||
continue
|
||||
fi
|
||||
src="$(readlink "$svc")"
|
||||
rm "$svc"
|
||||
sed "s|${pkg.out}|$out|g" "$src" > "$svc"
|
||||
done
|
||||
|
||||
# Patch DBus services
|
||||
for svc in "$out/share/dbus-1/services"/*.service ; do
|
||||
if ! grep -q "${pkg.out}" "$svc"; then
|
||||
continue
|
||||
fi
|
||||
src="$(readlink "$svc")"
|
||||
rm "$svc"
|
||||
sed "s|${pkg.out}|$out|g" "$src" > "$svc"
|
||||
done
|
||||
|
||||
shopt -u nullglob # Revert nullglob back to its normal default state
|
||||
'';
|
||||
}))
|
||||
|
||||
@@ -130,6 +130,13 @@ let
|
||||
stateVersion = lib.mkDefault "18.09";
|
||||
};
|
||||
|
||||
# NOTE: Added 2025-12-27
|
||||
# Avoid option change deprecation warning
|
||||
# Remove after deprecation period
|
||||
programs.zsh.dotDir = lib.mkIf (config.home.stateVersion == "18.09") (
|
||||
lib.mkDefault "/home/hm-user"
|
||||
);
|
||||
|
||||
# Avoid including documentation since this will cause
|
||||
# unnecessary rebuilds of the tests.
|
||||
manual.manpages.enable = lib.mkDefault false;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
generators-hyprconf = ./tohyprconf.nix;
|
||||
generators-tokdl = ./tokdl.nix;
|
||||
generators-toscfg-empty = ./toscfg-empty.nix;
|
||||
generators-toscfg-example = ./toscfg-example.nix;
|
||||
|
||||
93
tests/lib/generators/tohyprconf-result.txt
Normal file
93
tests/lib/generators/tohyprconf-result.txt
Normal file
@@ -0,0 +1,93 @@
|
||||
$important=123
|
||||
attrs-section {
|
||||
bool=true
|
||||
float=0.800000
|
||||
int=5
|
||||
null=null
|
||||
string=abc
|
||||
}
|
||||
|
||||
combined-attrs-nested-section {
|
||||
a {
|
||||
a=123
|
||||
}
|
||||
|
||||
a {
|
||||
b=123
|
||||
}
|
||||
|
||||
a {
|
||||
c=123
|
||||
}
|
||||
|
||||
b {
|
||||
a=123
|
||||
}
|
||||
|
||||
b {
|
||||
b=123
|
||||
}
|
||||
|
||||
b {
|
||||
c=123
|
||||
}
|
||||
}
|
||||
|
||||
combined-list-nested-section {
|
||||
b {
|
||||
c {
|
||||
abc=123
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
combined-list-nested-section {
|
||||
bar {
|
||||
baz {
|
||||
aaa=111
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list-section=foo
|
||||
list-section=bar
|
||||
list-section=baz
|
||||
|
||||
list-with-strings-and-attrs=abc
|
||||
list-with-strings-and-attrs {
|
||||
a=123
|
||||
}
|
||||
list-with-strings-and-attrs=foo
|
||||
list-with-strings-and-attrs {
|
||||
b=321
|
||||
}
|
||||
|
||||
nested-attrs-section {
|
||||
a {
|
||||
b {
|
||||
c {
|
||||
abc=123
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foo {
|
||||
bar {
|
||||
baz {
|
||||
aaa=111
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nested-list-section {
|
||||
a=123
|
||||
}
|
||||
|
||||
nested-list-section {
|
||||
b=123
|
||||
}
|
||||
|
||||
nested-list-section {
|
||||
c=123
|
||||
}
|
||||
70
tests/lib/generators/tohyprconf.nix
Normal file
70
tests/lib/generators/tohyprconf.nix
Normal file
@@ -0,0 +1,70 @@
|
||||
{ lib, ... }:
|
||||
|
||||
{
|
||||
home.file."tohyprconf-result.txt".text = lib.hm.generators.toHyprconf {
|
||||
attrs = rec {
|
||||
"$important" = 123;
|
||||
|
||||
list-section = [
|
||||
"foo"
|
||||
"bar"
|
||||
"baz"
|
||||
];
|
||||
|
||||
attrs-section = {
|
||||
string = "abc";
|
||||
int = 5;
|
||||
float = 0.8;
|
||||
bool = true;
|
||||
null = null;
|
||||
};
|
||||
|
||||
nested-attrs-section = {
|
||||
a = {
|
||||
b = {
|
||||
c = {
|
||||
abc = 123;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
foo = {
|
||||
bar = {
|
||||
baz = {
|
||||
aaa = 111;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
nested-list-section = [
|
||||
{ a = 123; }
|
||||
{ b = 123; }
|
||||
{ c = 123; }
|
||||
];
|
||||
|
||||
combined-list-nested-section = [
|
||||
nested-attrs-section.a
|
||||
nested-attrs-section.foo
|
||||
];
|
||||
|
||||
combined-attrs-nested-section = {
|
||||
a = nested-list-section;
|
||||
b = nested-list-section;
|
||||
};
|
||||
|
||||
list-with-strings-and-attrs = [
|
||||
"abc"
|
||||
{ a = 123; }
|
||||
"foo"
|
||||
{ b = 321; }
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
assertFileContent \
|
||||
home-files/tohyprconf-result.txt \
|
||||
${./tohyprconf-result.txt}
|
||||
'';
|
||||
}
|
||||
@@ -2,4 +2,5 @@
|
||||
|
||||
lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux {
|
||||
anyrun = ./basic-config.nix;
|
||||
anyrun-empty-css = ./empty-css.nix;
|
||||
}
|
||||
|
||||
10
tests/modules/programs/anyrun/empty-css.nix
Normal file
10
tests/modules/programs/anyrun/empty-css.nix
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
programs.anyrun = {
|
||||
enable = true;
|
||||
config.plugins = [ ];
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
assertPathNotExists home-files/.config/anyrun/style.css
|
||||
'';
|
||||
}
|
||||
@@ -5,6 +5,8 @@
|
||||
claude-code-assertion = ./assertion.nix;
|
||||
claude-code-memory-management = ./memory-management.nix;
|
||||
claude-code-memory-from-source = ./memory-from-source.nix;
|
||||
claude-code-rules-dir = ./rules-dir.nix;
|
||||
claude-code-rules-path = ./rules-path.nix;
|
||||
claude-code-agents-dir = ./agents-dir.nix;
|
||||
claude-code-commands-dir = ./commands-dir.nix;
|
||||
claude-code-hooks-dir = ./hooks-dir.nix;
|
||||
|
||||
14
tests/modules/programs/claude-code/rules-dir.nix
Normal file
14
tests/modules/programs/claude-code/rules-dir.nix
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
programs.claude-code = {
|
||||
enable = true;
|
||||
rulesDir = ./rules;
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
assertFileExists home-files/.claude/rules/test-rule.md
|
||||
assertLinkExists home-files/.claude/rules/test-rule.md
|
||||
assertFileContent \
|
||||
home-files/.claude/rules/test-rule.md \
|
||||
${./rules/test-rule.md}
|
||||
'';
|
||||
}
|
||||
20
tests/modules/programs/claude-code/rules-path.nix
Normal file
20
tests/modules/programs/claude-code/rules-path.nix
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
programs.claude-code = {
|
||||
enable = true;
|
||||
rules = {
|
||||
test-rule = ./test-rule.md;
|
||||
inline-rule = ''
|
||||
# Inline Rule
|
||||
|
||||
This is an inline rule for testing.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
assertFileExists home-files/.claude/rules/test-rule.md
|
||||
assertFileContent home-files/.claude/rules/test-rule.md \
|
||||
${./test-rule.md}
|
||||
assertFileExists home-files/.claude/rules/inline-rule.md
|
||||
'';
|
||||
}
|
||||
9
tests/modules/programs/claude-code/rules/test-rule.md
Normal file
9
tests/modules/programs/claude-code/rules/test-rule.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Test Rule from Directory
|
||||
|
||||
This is a test rule loaded from a directory.
|
||||
Used to verify rulesDir support functionality.
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Write clean code
|
||||
- Test thoroughly
|
||||
9
tests/modules/programs/claude-code/test-rule.md
Normal file
9
tests/modules/programs/claude-code/test-rule.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Test Rule
|
||||
|
||||
This is a test rule loaded from a file path.
|
||||
Used to verify path support functionality for rules.
|
||||
|
||||
## Guidelines
|
||||
|
||||
- Follow test conventions
|
||||
- Maintain code quality
|
||||
@@ -41,5 +41,9 @@
|
||||
assertFileExists home-files/.gemini/CONTEXT.md
|
||||
assertFileContent home-files/.gemini/CONTEXT.md \
|
||||
${./context-additional.md}
|
||||
|
||||
assertFileExists home-path/etc/profile.d/hm-session-vars.sh
|
||||
assertFileNotRegex home-path/etc/profile.d/hm-session-vars.sh \
|
||||
"GEMINI_MODEL"
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
programs.gemini-cli = {
|
||||
enable = true;
|
||||
defaultModel = "gemini-2.5-flash";
|
||||
settings = {
|
||||
theme = "Default";
|
||||
vimMode = true;
|
||||
@@ -28,5 +29,9 @@
|
||||
${./changelog.toml}
|
||||
assertFileContent home-files/.gemini/commands/git/fix.toml \
|
||||
${./fix.toml}
|
||||
|
||||
assertFileExists home-path/etc/profile.d/hm-session-vars.sh
|
||||
assertFileContains home-path/etc/profile.d/hm-session-vars.sh \
|
||||
'export GEMINI_MODEL="gemini-2.5-flash"'
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
{ lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
ghostty-example-settings = ./example-settings.nix;
|
||||
ghostty-empty-settings = ./empty-settings.nix;
|
||||
ghostty-example-settings = ./example-settings.nix;
|
||||
ghostty-example-theme = ./example-theme.nix;
|
||||
}
|
||||
// lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux {
|
||||
ghostty-systemd-service = ./systemd-service.nix;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
servicePath=home-files/.config/systemd/user/app-com.mitchellh.ghostty.service
|
||||
assertPathNotExists $servicePath
|
||||
|
||||
assertFileContent \
|
||||
home-files/.config/ghostty/config \
|
||||
${./example-config-expected}
|
||||
|
||||
28
tests/modules/programs/ghostty/systemd-service.nix
Normal file
28
tests/modules/programs/ghostty/systemd-service.nix
Normal file
@@ -0,0 +1,28 @@
|
||||
{ config, ... }:
|
||||
{
|
||||
programs.ghostty = {
|
||||
enable = true;
|
||||
package = config.lib.test.mkStubPackage { outPath = null; };
|
||||
systemd.enable = true;
|
||||
settings = {
|
||||
theme = "catppuccin-mocha";
|
||||
font-size = 10;
|
||||
};
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
servicePath=home-files/.config/systemd/user/app-com.mitchellh.ghostty.service
|
||||
serviceOverridesPath=$servicePath.d/overrides.conf
|
||||
|
||||
assertFileExists $serviceOverridesPath
|
||||
assertFileContent $serviceOverridesPath \
|
||||
${builtins.toFile "ghostty-service-overrides" ''
|
||||
[Unit]
|
||||
X-SwitchMethod=keep-old
|
||||
''}
|
||||
|
||||
assertFileContent \
|
||||
home-files/.config/ghostty/config \
|
||||
${./example-config-expected}
|
||||
'';
|
||||
}
|
||||
@@ -3,4 +3,5 @@
|
||||
gpg-mutable-keyfiles = ./mutable-keyfiles.nix;
|
||||
gpg-multiple-keys-trust = ./multiple-keys-trust.nix;
|
||||
gpg-override-defaults = ./override-defaults.nix;
|
||||
gpg-other-settings = ./other-settings.nix;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
{
|
||||
source = realPkgs.fetchurl {
|
||||
url = "https://keys.openpgp.org/pks/lookup?op=get&options=mr&search=0x44CF42371ADF842E12F116EAA9D3F98FCCF5460B";
|
||||
hash = "sha256-bSluCZh6ijwppigk8iF2BwWKZgq1WDbIjyYQRK772dM=";
|
||||
hash = "sha256-csrFDI6QSPfNN+adOPEAupAtspYNBCybFZExvVS+vRY=";
|
||||
};
|
||||
trust = 1; # "unknown"
|
||||
}
|
||||
|
||||
2
tests/modules/programs/gpg/other-dirmngr.conf
Normal file
2
tests/modules/programs/gpg/other-dirmngr.conf
Normal file
@@ -0,0 +1,2 @@
|
||||
keyserver ldaps://ldap.example.com
|
||||
use-tor
|
||||
3
tests/modules/programs/gpg/other-gpgsm.conf
Normal file
3
tests/modules/programs/gpg/other-gpgsm.conf
Normal file
@@ -0,0 +1,3 @@
|
||||
cipher-algo AES256
|
||||
validation-model steed
|
||||
with-md5-fingerprint
|
||||
3
tests/modules/programs/gpg/other-scdaemon.conf
Normal file
3
tests/modules/programs/gpg/other-scdaemon.conf
Normal file
@@ -0,0 +1,3 @@
|
||||
application-priority openpgp p15 sc-hsm nks geldkarte dinsig
|
||||
disable-ccid
|
||||
reader-port 32769
|
||||
32
tests/modules/programs/gpg/other-settings.nix
Normal file
32
tests/modules/programs/gpg/other-settings.nix
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
programs.gpg = {
|
||||
enable = true;
|
||||
|
||||
scdaemonSettings = {
|
||||
disable-ccid = true;
|
||||
reader-port = "32769";
|
||||
application-priority = "openpgp p15 sc-hsm nks geldkarte dinsig";
|
||||
};
|
||||
|
||||
dirmngrSettings = {
|
||||
use-tor = true;
|
||||
keyserver = "ldaps://ldap.example.com";
|
||||
};
|
||||
|
||||
gpgsmSettings = {
|
||||
cipher-algo = "AES256";
|
||||
with-md5-fingerprint = true;
|
||||
validation-model = "steed";
|
||||
};
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
assertFileExists home-files/.gnupg/scdaemon.conf
|
||||
assertFileExists home-files/.gnupg/dirmngr.conf
|
||||
assertFileExists home-files/.gnupg/gpgsm.conf
|
||||
|
||||
assertFileContent home-files/.gnupg/scdaemon.conf ${./other-scdaemon.conf}
|
||||
assertFileContent home-files/.gnupg/dirmngr.conf ${./other-dirmngr.conf}
|
||||
assertFileContent home-files/.gnupg/gpgsm.conf ${./other-gpgsm.conf}
|
||||
'';
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
cert-digest-algo SHA512
|
||||
charset utf-8
|
||||
default-preference-list SHA512 SHA384 SHA256 AES256 AES192 AES ZLIB BZIP2 ZIP Uncompressed
|
||||
fixed-list-mode
|
||||
display-charset utf-8
|
||||
keyid-format 0xlong
|
||||
list-options show-uid-validity
|
||||
|
||||
@@ -16,6 +15,5 @@ s2k-digest-algo SHA512
|
||||
throw-keyids
|
||||
trusted-key 0xXXXXXXXXXXXXX
|
||||
trusted-key 0xYYYYYYYYYYYYY
|
||||
use-agent
|
||||
verify-options show-uid-validity
|
||||
with-fingerprint
|
||||
|
||||
@@ -5,6 +5,9 @@ identity = "hm@example.com"
|
||||
root_mailbox = "/home/hm-user/Mail/hm@example.com"
|
||||
subscribed_mailboxes = ["Inbox", "Sent", "Trash", "Drafts"]
|
||||
|
||||
[accounts."hm@example.com".listing]
|
||||
index_style = "compact"
|
||||
|
||||
[accounts."hm@example.com".mailboxes]
|
||||
|
||||
[accounts."hm@example.com".send_mail]
|
||||
|
||||
@@ -16,7 +16,12 @@
|
||||
};
|
||||
accounts.email.accounts = {
|
||||
"hm@example.com" = {
|
||||
meli.enable = true;
|
||||
meli = {
|
||||
enable = true;
|
||||
settings = {
|
||||
listing.index_style = "compact";
|
||||
};
|
||||
};
|
||||
smtp.port = 1848;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
neovim-plugin-config = ./plugin-config.nix;
|
||||
neovim-coc-config = ./coc-config.nix;
|
||||
neovim-runtime = ./runtime.nix;
|
||||
neovim-wrapper-args = ./wrapper-args.nix;
|
||||
|
||||
# waiting for a nixpkgs patch
|
||||
neovim-no-init = ./no-init.nix;
|
||||
|
||||
@@ -34,15 +34,25 @@ lib.mkIf config.test.enableBig {
|
||||
|
||||
_module.args.pkgs = lib.mkForce realPkgs;
|
||||
|
||||
nmt.script = ''
|
||||
vimout=$(mktemp)
|
||||
echo "redir >> /dev/stdout | echo g:hmExtraConfig | echo g:hmPlugins | redir END" \
|
||||
| ${pkgs.neovim}/bin/nvim -es -u "$TESTED/home-files/.config/nvim/init.lua" \
|
||||
> "$vimout" || true
|
||||
assertFileContains "$vimout" "HM_EXTRA_CONFIG"
|
||||
assertFileContains "$vimout" "HM_PLUGINS_CONFIG"
|
||||
nmt.script =
|
||||
let
|
||||
# Force evaluation of generatedConfigs.
|
||||
luaConfig = config.programs.neovim.generatedConfigs.lua;
|
||||
vimlConfig = config.programs.neovim.generatedConfigs.viml;
|
||||
in
|
||||
''
|
||||
vimout=$(mktemp)
|
||||
echo "redir >> /dev/stdout | echo g:hmExtraConfig | echo g:hmPlugins | redir END" \
|
||||
| ${pkgs.neovim}/bin/nvim -es -u "$TESTED/home-files/.config/nvim/init.lua" \
|
||||
> "$vimout" || true
|
||||
assertFileContains "$vimout" "HM_EXTRA_CONFIG"
|
||||
assertFileContains "$vimout" "HM_PLUGINS_CONFIG"
|
||||
|
||||
initLua="$TESTED/home-files/.config/nvim/init.lua"
|
||||
assertFileContent $(normalizeStorePaths "$initLua") ${./plugin-config.expected}
|
||||
'';
|
||||
initLua="$TESTED/home-files/.config/nvim/init.lua"
|
||||
assertFileContent $(normalizeStorePaths "$initLua") ${./plugin-config.expected}
|
||||
|
||||
# Verify generatedConfigs evaluated properly (issue #8371)
|
||||
echo "Lua config length: ${toString (builtins.stringLength luaConfig)}"
|
||||
echo "Viml config length: ${toString (builtins.stringLength vimlConfig)}"
|
||||
'';
|
||||
}
|
||||
|
||||
83
tests/modules/programs/neovim/wrapper-args.nix
Normal file
83
tests/modules/programs/neovim/wrapper-args.nix
Normal file
@@ -0,0 +1,83 @@
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
inherit (pkgs.stdenv.hostPlatform) isLinux;
|
||||
|
||||
dummyDep = pkgs.runCommand "dummy-dep" { } ''
|
||||
mkdir -p $out/bin
|
||||
echo "echo dummy" > $out/bin/dummy-dep-bin
|
||||
chmod +x $out/bin/dummy-dep-bin
|
||||
'';
|
||||
|
||||
dummyPlugin = pkgs.vimUtils.buildVimPlugin {
|
||||
pname = "dummy-plugin";
|
||||
version = "1.0";
|
||||
src = pkgs.writeTextDir "plugin/dummy.vim" "\" dummy";
|
||||
runtimeDeps = [ dummyDep ];
|
||||
};
|
||||
in
|
||||
{
|
||||
imports = [ ./stubs.nix ];
|
||||
tests.stubs.wl-clipboard = { };
|
||||
|
||||
programs.neovim = {
|
||||
enable = true;
|
||||
extraName = "-my-suffix";
|
||||
withPerl = true;
|
||||
withPython3 = true;
|
||||
withRuby = true;
|
||||
withNodeJs = true;
|
||||
autowrapRuntimeDeps = true;
|
||||
waylandSupport = isLinux;
|
||||
plugins = [ dummyPlugin ];
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
nvimBin="home-path/bin/nvim"
|
||||
|
||||
assertBinaryContains() {
|
||||
local file="$TESTED/$1"
|
||||
if [[ $1 == /* ]]; then file="$1"; fi
|
||||
|
||||
if ! grep -a -qF -- "$2" "$file"; then
|
||||
fail "Expected binary file '$1' to contain '$2' but it did not."
|
||||
fi
|
||||
}
|
||||
|
||||
# Ensure the main binary exists
|
||||
assertFileExists "$nvimBin"
|
||||
|
||||
# 1. extraName: Check if the suffix is in the rplugin manifest path within the wrapper
|
||||
assertBinaryContains "$nvimBin" "-my-suffix/rplugin.vim"
|
||||
|
||||
# 2. withPerl: Check if nvim-perl binary exists and host prog is set
|
||||
assertFileExists "home-path/bin/nvim-perl"
|
||||
assertBinaryContains "$nvimBin" "perl_host_prog="
|
||||
|
||||
# 3. withPython3: Check if nvim-python3 binary exists and host prog is set
|
||||
assertFileExists "home-path/bin/nvim-python3"
|
||||
assertBinaryContains "$nvimBin" "python3_host_prog="
|
||||
|
||||
# 4. withRuby: Check if nvim-ruby binary exists, GEM_HOME and host prog are set
|
||||
assertFileExists "home-path/bin/nvim-ruby"
|
||||
assertBinaryContains "$nvimBin" "GEM_HOME="
|
||||
assertBinaryContains "$nvimBin" "ruby_host_prog="
|
||||
|
||||
# 5. withNodeJs: Check if nvim-node binary exists and host prog is set
|
||||
assertFileExists "home-path/bin/nvim-node"
|
||||
assertBinaryContains "$nvimBin" "node_host_prog="
|
||||
|
||||
# 6. waylandSupport: Check for wl-clipboard path in wrapper's PATH modification
|
||||
# We check for the store path of wl-clipboard in the current pkgs
|
||||
${lib.optionalString isLinux ''
|
||||
assertBinaryContains "$nvimBin" "wl-clipboard-"
|
||||
''}
|
||||
|
||||
# 7. autowrapRuntimeDeps: Check for dummyDep path in wrapper's PATH modification
|
||||
assertBinaryContains "$nvimBin" "${dummyDep}/bin"
|
||||
'';
|
||||
}
|
||||
@@ -9,6 +9,10 @@
|
||||
opencode-agents-path = ./agents-path.nix;
|
||||
opencode-commands-path = ./commands-path.nix;
|
||||
opencode-mixed-content = ./mixed-content.nix;
|
||||
opencode-skills-inline = ./skills-inline.nix;
|
||||
opencode-skills-path = ./skills-path.nix;
|
||||
opencode-skills-directory = ./skills-directory.nix;
|
||||
opencode-skills-bulk-directory = ./skills-bulk-directory.nix;
|
||||
opencode-themes-inline = ./themes-inline.nix;
|
||||
opencode-themes-path = ./themes-path.nix;
|
||||
opencode-mcp-integration = ./mcp-integration.nix;
|
||||
|
||||
10
tests/modules/programs/opencode/git-release-SKILL.md
Normal file
10
tests/modules/programs/opencode/git-release-SKILL.md
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
name: git-release
|
||||
description: Create consistent releases and changelogs
|
||||
---
|
||||
|
||||
## What I do
|
||||
|
||||
- Draft release notes from merged PRs
|
||||
- Propose a version bump
|
||||
- Provide a copy-pasteable `gh release create` command
|
||||
9
tests/modules/programs/opencode/pdf-processing-SKILL.md
Normal file
9
tests/modules/programs/opencode/pdf-processing-SKILL.md
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
name: pdf-processing
|
||||
description: Extract text and tables from PDF files
|
||||
---
|
||||
|
||||
## What I do
|
||||
|
||||
- Extract text from PDFs
|
||||
- Identify tables and structured data
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
name: data-analysis
|
||||
description: Help analyze datasets and results
|
||||
---
|
||||
|
||||
## What I do
|
||||
|
||||
- Summarize datasets
|
||||
- Suggest charts and metrics
|
||||
@@ -0,0 +1 @@
|
||||
extra fixture file
|
||||
15
tests/modules/programs/opencode/skills-bulk-directory.nix
Normal file
15
tests/modules/programs/opencode/skills-bulk-directory.nix
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
programs.opencode = {
|
||||
enable = true;
|
||||
skills = ./skills-bulk;
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
assertFileExists home-files/.config/opencode/skill/git-release/SKILL.md
|
||||
assertFileExists home-files/.config/opencode/skill/pdf-processing/SKILL.md
|
||||
assertFileContent home-files/.config/opencode/skill/git-release/SKILL.md \
|
||||
${./skills-bulk/git-release/SKILL.md}
|
||||
assertFileContent home-files/.config/opencode/skill/pdf-processing/SKILL.md \
|
||||
${./skills-bulk/pdf-processing/SKILL.md}
|
||||
'';
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
name: git-release
|
||||
description: Create consistent releases and changelogs
|
||||
---
|
||||
|
||||
This is the bulk skillsDir fixture for git-release.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
name: pdf-processing
|
||||
description: Extract text and tables from PDF files
|
||||
---
|
||||
|
||||
This is the bulk skillsDir fixture for pdf-processing.
|
||||
15
tests/modules/programs/opencode/skills-directory.nix
Normal file
15
tests/modules/programs/opencode/skills-directory.nix
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
programs.opencode = {
|
||||
enable = true;
|
||||
skills = {
|
||||
data-analysis = ./skill-dir/data-analysis;
|
||||
};
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
assertFileExists home-files/.config/opencode/skill/data-analysis/SKILL.md
|
||||
assertFileExists home-files/.config/opencode/skill/data-analysis/notes.txt
|
||||
assertFileContent home-files/.config/opencode/skill/data-analysis/SKILL.md \
|
||||
${./skill-dir/data-analysis/SKILL.md}
|
||||
'';
|
||||
}
|
||||
25
tests/modules/programs/opencode/skills-inline.nix
Normal file
25
tests/modules/programs/opencode/skills-inline.nix
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
programs.opencode = {
|
||||
enable = true;
|
||||
skills = {
|
||||
git-release = ''
|
||||
---
|
||||
name: git-release
|
||||
description: Create consistent releases and changelogs
|
||||
---
|
||||
|
||||
## What I do
|
||||
|
||||
- Draft release notes from merged PRs
|
||||
- Propose a version bump
|
||||
- Provide a copy-pasteable `gh release create` command
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
assertFileExists home-files/.config/opencode/skill/git-release/SKILL.md
|
||||
assertFileContent home-files/.config/opencode/skill/git-release/SKILL.md \
|
||||
${./git-release-SKILL.md}
|
||||
'';
|
||||
}
|
||||
14
tests/modules/programs/opencode/skills-path.nix
Normal file
14
tests/modules/programs/opencode/skills-path.nix
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
programs.opencode = {
|
||||
enable = true;
|
||||
skills = {
|
||||
pdf-processing = ./pdf-processing-SKILL.md;
|
||||
};
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
assertFileExists home-files/.config/opencode/skill/pdf-processing/SKILL.md
|
||||
assertFileContent home-files/.config/opencode/skill/pdf-processing/SKILL.md \
|
||||
${./pdf-processing-SKILL.md}
|
||||
'';
|
||||
}
|
||||
@@ -1,9 +1,19 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
config = {
|
||||
programs.radicle.enable = true;
|
||||
|
||||
test.stubs.radicle-node = {
|
||||
buildScript = ''
|
||||
mkdir -p "$out/bin"
|
||||
cat > "$out/bin/rad" << 'EOF'
|
||||
#!/bin/sh
|
||||
# Stub rad command that does nothing
|
||||
exit 0
|
||||
EOF
|
||||
chmod +x "$out/bin/rad"
|
||||
'';
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
assertFileContent \
|
||||
home-files/.radicle/config.json \
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user