{ config, lib, pkgs, utils, ... }: let cfg = config.services.docker-compose; settingsFormat = pkgs.formats.yaml { }; jobModule = { name, lib, config, ... }: { options = { extraArgs = lib.mkOption { type = with lib.types; listOf str; default = [ ]; description = '' Job-specific set of arguments to be added to {command}`docker compose`. ''; }; files = lib.mkOption { type = with lib.types; listOf path; description = '' List of files to be used when setting up the docker-compose service. ''; default = []; example = lib.literalExpression '' [ /path/to/docker-compose.yml ] ''; }; settings = lib.mkOption { type = settingsFormat.type; description = '' Configuration to be used for the docker-compose process. ''; default = { }; example = { }; }; }; config = { extraArgs = cfg.extraArgs ++ lib.concatMap (f: [ "--file" f ]) config.files; files = lib.optionals (config.settings != { }) [ (settingsFormat.generate "docker-compose-generated-${name}" config.settings) ]; }; }; mkDockerComposeService = name: value: lib.nameValuePair "docker-compose-${utils.escapeSystemdPath name}" { path = [ config.virtualisation.docker.package ]; script = "docker compose --project-name ${name} up"; postStop = "docker compose --project-name ${name} down"; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; }; }; in { options.services.docker-compose = { enable = lib.mkEnableOption "integration with docker-compose"; extraArgs = lib.mkOption { type = with lib.types; listOf str; default = []; }; jobs = lib.mkOption { type = with lib.types; attrsOf (submodule jobModule); default = { }; description = '' A jobset of Docker compose services to be integrated with the system. ''; }; }; config = lib.mkIf cfg.enable { assertions = lib.singleton { assertion = cfg.enable && config.virtualisation.docker.enable; message = "Docker server is not enabled."; }; systemd.services = lib.mapAttrs' mkDockerComposeService cfg.jobs; }; }