colima: add homeDir & respect XDG

This commit is contained in:
Utkarsh Gupta
2026-02-26 21:34:24 -06:00
committed by Austin Horstman
parent 6f35059f9a
commit 91920e955f
11 changed files with 375 additions and 92 deletions
+151 -88
View File
@@ -16,6 +16,23 @@ in
options.services.colima = {
enable = lib.mkEnableOption "Colima, a container runtime";
colimaHomeDir = lib.mkOption {
type = lib.types.str;
apply = p: lib.removePrefix "${config.home.homeDirectory}/" p;
default = ".colima";
example = lib.literalExpression "\${config.xdg.configHome}/colima";
description = "Directory to store colima configuration. This also sets $COLIMA_HOME.";
};
limaHomeDir = lib.mkOption {
type = lib.types.nullOr lib.types.str;
apply = p: if p != null then lib.removePrefix "${config.home.homeDirectory}/" p else p;
default = null;
defaultText = "Colima uses $COLIMA_HOME/_lima by default.";
example = lib.literalExpression "\${config.xdg.dataHome}/lima";
description = "Directory to store lima files. This also sets $LIMA_HOME.";
};
package = lib.mkPackageOption pkgs "colima" { };
dockerPackage = lib.mkPackageOption pkgs "docker" {
extraDescription = "Used by colima to activate profiles. Not needed if no profile is set to isActive.";
@@ -99,10 +116,20 @@ in
'';
};
setDockerHost = lib.mkOption {
type = lib.types.bool;
default = false;
example = true;
description = ''
Set this context as $DOCKER_HOST.
Exactly one or zero profiles should have this option set.
'';
};
logFile = lib.mkOption {
type = lib.types.path;
default = "${config.home.homeDirectory}/.local/state/colima-${name}.log";
defaultText = lib.literalExpression "\${config.home.homeDirectory}/.local/state/colima-\${name}.log";
default = "${config.xdg.stateHome}/colima/${name}.log";
defaultText = lib.literalExpression "\${config.xdg.stateHome}/colima/\${name}.log";
description = "Combined stdout and stderr log file for the Colima service.";
};
@@ -163,85 +190,73 @@ in
};
};
config = lib.mkIf cfg.enable {
assertions = [
{
assertion = (lib.count (p: p.isActive) (lib.attrValues cfg.profiles)) <= 1;
message = "Only one Colima profile can be active at a time.";
}
];
config =
let
colimaHome = "${config.home.homeDirectory}/${cfg.colimaHomeDir}";
limaHome =
if cfg.limaHomeDir != null then "${config.home.homeDirectory}/${cfg.limaHomeDir}" else null;
dockerConfig =
if config.programs.docker-cli.enable then config.home.sessionVariables.DOCKER_CONFIG else null;
activeProfile = lib.findFirst (p: p.isActive) null (lib.attrValues cfg.profiles);
currentContext =
if activeProfile != null then
(if activeProfile.name == "default" then "colima" else "colima-${activeProfile.name}")
else
null;
dockerHostProfile = lib.findFirst (p: p.setDockerHost) null (lib.attrValues cfg.profiles);
in
lib.mkIf cfg.enable {
assertions = [
{
assertion = (lib.count (p: p.isActive) (lib.attrValues cfg.profiles)) <= 1;
message = "Only one Colima profile can be active at a time.";
}
];
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
home = {
packages = lib.mkIf (cfg.package != null) [ cfg.package ];
home.file = lib.mkMerge (
lib.mapAttrsToList (profileName: profile: {
".colima/${profileName}/colima.yaml" = {
source = yamlFormat.generate "colima.yaml" profile.settings;
file = lib.mkMerge (
lib.mapAttrsToList (profileName: profile: {
"${cfg.colimaHomeDir}/${profileName}/colima.yaml" = {
source = yamlFormat.generate "colima.yaml" profile.settings;
};
}) (lib.filterAttrs (name: profile: profile.settings != { }) cfg.profiles)
);
sessionVariables = {
COLIMA_HOME = colimaHome;
}
// lib.optionalAttrs (limaHome != null) {
LIMA_HOME = limaHome;
}
// lib.optionalAttrs (dockerHostProfile != null) {
DOCKER_HOST = "unix://${colimaHome}/${dockerHostProfile.name}/docker.sock";
};
}) (lib.filterAttrs (name: profile: profile.settings != { }) cfg.profiles)
);
};
programs.docker-cli.settings.currentContext =
let
activeProfile = lib.findFirst (p: p.isActive) null (lib.attrValues cfg.profiles);
in
lib.mkIf (activeProfile != null) (
if activeProfile.name != "default" then "colima-${activeProfile.name}" else "colima"
);
programs.docker-cli.settings.currentContext = lib.mkIf (currentContext != null) currentContext;
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 = {
SuccessfulExit = 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.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 [
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 = {
SuccessfulExit = true;
};
RunAtLoad = true;
EnvironmentVariables = {
COLIMA_HOME = colimaHome;
PATH = lib.makeBinPath [
cfg.package
cfg.perlPackage
cfg.dockerPackage
@@ -249,16 +264,64 @@ in
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);
};
pkgs.darwin.DarwinTools
];
}
// lib.optionalAttrs (limaHome != null) {
LIMA_HOME = limaHome;
}
// lib.optionalAttrs (dockerConfig != null) {
DOCKER_CONFIG = dockerConfig;
}
// lib.optionalAttrs config.xdg.enable {
XDG_CACHE_HOME = config.xdg.cacheHome;
};
StandardOutPath = profile.logFile;
StandardErrorPath = profile.logFile;
};
}
) (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 = [
"COLIMA_HOME=${colimaHome}"
"PATH=${
lib.makeBinPath [
cfg.package
cfg.perlPackage
cfg.dockerPackage
cfg.sshPackage
cfg.coreutilsPackage
cfg.curlPackage
cfg.bashPackage
]
}"
]
++ lib.optional (limaHome != null) "LIMA_HOME=${limaHome}"
++ lib.optional (dockerConfig != null) "DOCKER_CONFIG=${dockerConfig}";
StandardOutput = "append:${profile.logFile}";
StandardError = "append:${profile.logFile}";
};
Install = {
WantedBy = [ "default.target" ];
};
}
) (lib.filterAttrs (_: p: p.isService) cfg.profiles);
};
}
@@ -0,0 +1,3 @@
{
"currentContext": "colima"
}
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>EnvironmentVariables</key>
<dict>
<key>COLIMA_HOME</key>
<string>/home/hm-user/.config/colima</string>
<key>DOCKER_CONFIG</key>
<string>/home/hm-user/.config/docker</string>
<key>LIMA_HOME</key>
<string>/home/hm-user/.local/share/lima</string>
<key>PATH</key>
<string>@colima@/bin:@perl@/bin:@docker@/bin:@openssh@/bin:@coreutils@/bin:@curl@/bin:@bashNonInteractive@/bin:@DarwinTools@/bin</string>
<key>XDG_CACHE_HOME</key>
<string>/home/hm-user/.cache</string>
</dict>
<key>KeepAlive</key>
<dict>
<key>SuccessfulExit</key>
<true/>
</dict>
<key>Label</key>
<string>org.nix-community.home.colima-default</string>
<key>ProgramArguments</key>
<array>
<string>/bin/sh</string>
<string>-c</string>
<string>/bin/wait4path /nix/store &amp;&amp; exec @colima@/bin/colima start default -f &apos;--activate=true&apos; &apos;--save-config=false&apos;</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StandardErrorPath</key>
<string>/home/hm-user/.local/state/colima/default.log</string>
<key>StandardOutPath</key>
<string>/home/hm-user/.local/state/colima/default.log</string>
</dict>
</plist>
@@ -0,0 +1,79 @@
{
config,
lib,
pkgs,
...
}:
{
nixpkgs.overlays = [
(self: super: {
darwin = super.darwin // {
DarwinTools = config.lib.test.mkStubPackage {
name = "DarwinTools";
outPath = "@DarwinTools@";
};
};
})
];
programs.docker-cli = {
enable = true;
configDir = "${config.xdg.configHome}/docker";
};
services.colima = {
enable = true;
colimaHomeDir = "${config.xdg.configHome}/colima";
limaHomeDir = "${config.xdg.dataHome}/lima";
package = config.lib.test.mkStubPackage {
name = "colima";
outPath = "@colima@";
};
dockerPackage = config.lib.test.mkStubPackage {
name = "docker";
outPath = "@docker@";
};
perlPackage = config.lib.test.mkStubPackage {
name = "perl";
outPath = "@perl@";
};
sshPackage = config.lib.test.mkStubPackage {
name = "openssh";
outPath = "@openssh@";
};
coreutilsPackage = config.lib.test.mkStubPackage {
name = "coreutils";
outPath = "@coreutils@";
};
curlPackage = config.lib.test.mkStubPackage {
name = "curl";
outPath = "@curl@";
};
bashPackage = config.lib.test.mkStubPackage {
name = "bashNonInteractive";
outPath = "@bashNonInteractive@";
};
};
nmt.script =
let
cfgColima = config.services.colima;
cfgDocker = config.programs.docker-cli;
pathColimaHome = "/home/hm-user/${cfgColima.colimaHomeDir}";
pathDockerConfig = "home-files/${cfgDocker.configDir}/config.json";
in
''
assertPathNotExists home-files/.config/colima/default/colima.yaml
serviceFile=LaunchAgents/org.nix-community.home.colima-default.plist
assertFileExists "$serviceFile"
assertFileContent "$serviceFile" ${./colima-docker-cli-expected.plist}
assertFileExists "${pathDockerConfig}"
assertFileContent "${pathDockerConfig}" ${./colima-docker-cli-expected.json}
assertFileContains home-path/etc/profile.d/hm-session-vars.sh \
'export COLIMA_HOME="${pathColimaHome}"'
'';
}
@@ -1,4 +1,5 @@
{
"colima-default-config" = ./colima-default-config.nix;
"colima-custom-settings" = ./colima-custom-settings.nix;
"colima-docker-cli" = ./colima-docker-cli.nix;
}
@@ -4,8 +4,12 @@
<dict>
<key>EnvironmentVariables</key>
<dict>
<key>COLIMA_HOME</key>
<string>/home/hm-user/.colima</string>
<key>PATH</key>
<string>@colima@/bin:@perl@/bin:@docker@/bin:@openssh@/bin:@coreutils@/bin:@curl@/bin:@bashNonInteractive@/bin:@DarwinTools@/bin</string>
<key>XDG_CACHE_HOME</key>
<string>/home/hm-user/.cache</string>
</dict>
<key>KeepAlive</key>
<dict>
@@ -23,8 +27,8 @@
<key>RunAtLoad</key>
<true/>
<key>StandardErrorPath</key>
<string>/home/hm-user/.local/state/colima-default.log</string>
<string>/home/hm-user/.local/state/colima/default.log</string>
<key>StandardOutPath</key>
<string>/home/hm-user/.local/state/colima-default.log</string>
<string>/home/hm-user/.local/state/colima/default.log</string>
</dict>
</plist>
@@ -0,0 +1,3 @@
{
"currentContext": "colima"
}
@@ -0,0 +1,22 @@
[Install]
WantedBy=default.target
[Service]
Environment=COLIMA_HOME=/home/hm-user/.config/colima
Environment=PATH=@colima@/bin:@perl@/bin:@docker@/bin:@openssh@/bin:@coreutils@/bin:@curl@/bin:@bashNonInteractive@/bin
Environment=LIMA_HOME=/home/hm-user/.local/share/lima
Environment=DOCKER_CONFIG=/home/hm-user/.config/docker
ExecStart=@colima@/bin/colima start default \
-f \
--activate=true \
--save-config=false
Restart=always
RestartSec=2
StandardError=append:/home/hm-user/.local/state/colima/default.log
StandardOutput=append:/home/hm-user/.local/state/colima/default.log
[Unit]
After=network-online.target
Description=Colima container runtime (default profile)
Wants=network-online.target
@@ -0,0 +1,68 @@
{
config,
lib,
pkgs,
...
}:
{
programs.docker-cli = {
enable = true;
configDir = "${config.xdg.configHome}/docker";
};
services.colima = {
enable = true;
colimaHomeDir = "${config.xdg.configHome}/colima";
limaHomeDir = "${config.xdg.dataHome}/lima";
package = config.lib.test.mkStubPackage {
name = "colima";
outPath = "@colima@";
};
dockerPackage = config.lib.test.mkStubPackage {
name = "docker";
outPath = "@docker@";
};
perlPackage = config.lib.test.mkStubPackage {
name = "perl";
outPath = "@perl@";
};
sshPackage = config.lib.test.mkStubPackage {
name = "openssh";
outPath = "@openssh@";
};
coreutilsPackage = config.lib.test.mkStubPackage {
name = "coreutils";
outPath = "@coreutils@";
};
curlPackage = config.lib.test.mkStubPackage {
name = "curl";
outPath = "@curl@";
};
bashPackage = config.lib.test.mkStubPackage {
name = "bashNonInteractive";
outPath = "@bashNonInteractive@";
};
};
nmt.script =
let
cfgColima = config.services.colima;
cfgDocker = config.programs.docker-cli;
pathColimaHome = "/home/hm-user/${cfgColima.colimaHomeDir}";
pathDockerConfig = "home-files/${cfgDocker.configDir}/config.json";
in
''
assertPathNotExists home-files/.config/colima/default/colima.yaml
serviceFile=home-files/.config/systemd/user/colima-default.service
assertFileExists "$serviceFile"
assertFileContent "$serviceFile" ${./colima-docker-cli-expected.service}
assertFileExists "${pathDockerConfig}"
assertFileContent "${pathDockerConfig}" ${./colima-docker-cli-expected.json}
assertFileContains home-path/etc/profile.d/hm-session-vars.sh \
'export COLIMA_HOME="${pathColimaHome}"'
'';
}
@@ -1,3 +1,4 @@
{
"colima-default-config" = ./colima-default-config.nix;
"colima-docker-cli" = ./colima-docker-cli.nix;
}
@@ -2,6 +2,7 @@
WantedBy=default.target
[Service]
Environment=COLIMA_HOME=/home/hm-user/.colima
Environment=PATH=@colima@/bin:@perl@/bin:@docker@/bin:@openssh@/bin:@coreutils@/bin:@curl@/bin:@bashNonInteractive@/bin
ExecStart=@colima@/bin/colima start default \
-f \
@@ -10,8 +11,8 @@ ExecStart=@colima@/bin/colima start default \
Restart=always
RestartSec=2
StandardError=append:/home/hm-user/.local/state/colima-default.log
StandardOutput=append:/home/hm-user/.local/state/colima-default.log
StandardError=append:/home/hm-user/.local/state/colima/default.log
StandardOutput=append:/home/hm-user/.local/state/colima/default.log
[Unit]
After=network-online.target