mirror of
https://github.com/nix-community/home-manager.git
synced 2026-01-11 17:39:37 +08:00
tree-wide: remove redundant platform checks
In the code base, there are lots of configurations locally guarded by `stdenv.hostPlatform.is(Darwin|Linux)` despite the targeted options already being guarded. Examples for these targeted options are: - `systemd.user.*`: globally guarded by `systemd.user.enable`. - `launchd.*`: globally guarded by `launchd.enable`. - `lib.hm.darwin.assertInterval`: only effective on Darwin. These local guards are an antipattern since they weaken the global guards. Furthermore, they hamper readability. This series of commits remove instances of these local guards.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
};
|
||||
})
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ in
|
||||
})
|
||||
];
|
||||
|
||||
systemd.user = lib.mkIf pkgs.stdenv.hostPlatform.isLinux {
|
||||
systemd.user = {
|
||||
services.mpd = {
|
||||
Unit = lib.mkMerge [
|
||||
{
|
||||
@@ -236,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 = [
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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}";
|
||||
|
||||
# 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}"''
|
||||
else
|
||||
''$"($env.XDG_RUNTIME_DIR)/${cfg.socket}"'';
|
||||
in
|
||||
''
|
||||
if ${unsetOrEmpty "SSH_AUTH_SOCK"} or ${unsetOrEmpty "SSH_CONNECTION"} {
|
||||
$env.SSH_AUTH_SOCK = ${socketPath}
|
||||
}
|
||||
'';
|
||||
''$"($env.XDG_RUNTIME_DIR)/${cfg.socket}"'';
|
||||
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);
|
||||
};
|
||||
}
|
||||
''
|
||||
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);
|
||||
};
|
||||
|
||||
(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}${
|
||||
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}"
|
||||
}";
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
};
|
||||
})
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
})
|
||||
]
|
||||
);
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user