diff --git a/docs/index.md b/docs/index.md index aeec6be..9efb17b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -13,6 +13,8 @@ devshell.mkShell { # use the modules lefthook.enable = true; + + task.",".tasks = { ... }; } ``` diff --git a/lib/modules/process_compose.nix b/lib/modules/process_compose.nix index 32728d4..1b2a74e 100644 --- a/lib/modules/process_compose.nix +++ b/lib/modules/process_compose.nix @@ -4,44 +4,79 @@ config, ... }: let - inherit (lib) mkEnableOption mkOption mkIf types; - cfg = config.process-compose; - - configFile = (pkgs.formats.yaml {}).generate "process-compose.yaml" cfg.config; - pcAlias = pkgs.writeTextFile { - name = "pc-alias"; - destination = "/bin/${cfg.alias}"; - executable = true; - text = - # sh - '' - ${pkgs.process-compose}/bin/process-compose --config "${configFile}" ''${@:1} - ''; - }; + inherit (lib) mkOption types; in { - options.process-compose = { - enable = - mkEnableOption "Process-Compose" - // { - default = cfg.config != {}; + options.process-compose = mkOption { + type = types.attrsOf (types.submodule ({ + config, + name, + ... + }: { + options = { + alias = mkOption { + type = types.str; + default = + if name == "default" + then "pc" + else name; + description = '' + Alias for `process-compose`. + Defaults to `"pc"` if `${name}` is `"default"` + ''; + }; + lazy = mkOption { + type = types.bool; + default = true; + description = '' + Whether the process compose config should be built on-demand/lazily. + It will probably not land in the gcroot and thus might get cleaned up with every gc. + On the other hand, this way loading the devshell is faster. Decide for yourself :) + ''; + }; + config = mkOption { + type = types.attrs; + default = {}; + description = '' + Configure process-compose here. + ''; + }; + + configFile = mkOption { + internal = true; + type = types.package; + }; + pcAlias = mkOption { + internal = true; + type = types.package; + }; }; - alias = mkOption { - type = types.str; - default = "pc"; - description = '' - Alias for `process-compose`. - ''; - }; - config = mkOption { - type = types.attrs; - default = {}; - description = '' - Configure process-compose here. - ''; - }; + config = rec { + configFile = (pkgs.formats.yaml {}).generate "process-compose.yaml" config.config; + pcAlias = pkgs.writeTextFile { + name = "pc-alias"; + destination = "/bin/${config.alias}"; + executable = true; + text = let + configScript = + if config.lazy + then + # sh + "$(nix build '${builtins.unsafeDiscardOutputDependency configFile.drvPath}^*' --no-link --print-out-paths)" + else configFile; + in + # sh + '' + CONFIG_FILE="${configScript}" + ${pkgs.process-compose}/bin/process-compose --config "$CONFIG_FILE" ''${@:1} + ''; + }; + }; + })); + default = {}; + description = '' + Define your process-compose instances here. + ''; }; - config = mkIf cfg.enable { - packages = [pcAlias]; - }; + config.packages = map (val: val.pcAlias) (builtins.attrValues config.process-compose); } diff --git a/lib/modules/process_compose_test.nix b/lib/modules/process_compose_test.nix index 86c8935..c5991b3 100644 --- a/lib/modules/process_compose_test.nix +++ b/lib/modules/process_compose_test.nix @@ -14,7 +14,7 @@ in { script = let shell = devshell.mkShell { imports = [module]; - process-compose.enable = true; + process-compose."default" = {}; }; in # sh @@ -23,6 +23,21 @@ in { assert "-f ${shell}/bin/pc" "/bin/pc should exist" ''; } + { + name = "alias"; + type = "script"; + script = let + shell = devshell.mkShell { + imports = [module]; + process-compose."pctest" = {}; + }; + in + # sh + '' + ${ntlib.helpers.scriptHelpers} + assert "-f ${shell}/bin/pctest" "/bin/pctest should exist" + ''; + } ]; }; } diff --git a/lib/modules/taskfile.nix b/lib/modules/taskfile.nix index 02d20ae..a110f5c 100644 --- a/lib/modules/taskfile.nix +++ b/lib/modules/taskfile.nix @@ -4,99 +4,118 @@ config, ... }: let - inherit (lib) mapAttrs mkEnableOption mkOption mkIf types; - cfg = config.task; - - patchedTasks = mapAttrs (_name: value: let - taskDir = value.dir or ""; - absolutePathOrTemplate = (builtins.substring 0 1 taskDir) == "/" || (builtins.substring 0 1 taskDir) == "{"; - in - value - // { - dir = - if absolutePathOrTemplate - then taskDir - else ''{{env "TASK_ROOT_DIR" | default .USER_WORKING_DIR}}/${taskDir}''; - }) - cfg.tasks; + inherit (lib) mapAttrs mkOption types; generator = name: value: pkgs.writeTextFile { inherit name; text = builtins.toJSON value; }; - # NOTE: this requires python just to convert json to yaml, since json is valid yaml we just ignore that - # generator = (pkgs.formats.yaml {}).generate; - taskfile = generator "taskfile" { - version = 3; - inherit (cfg) interval; - tasks = patchedTasks; - }; - # when using a , as alias for example the store path looks weird. - # This way it can be identified as being the task alias - taskAlias = pkgs.writeTextFile { - name = "task-alias"; - destination = "/bin/${cfg.alias}"; - executable = true; - text = let - taskfileScript = - if cfg.lazy - then - # sh - "$(nix build '${builtins.unsafeDiscardOutputDependency taskfile.drvPath}^*' --no-link --print-out-paths)" - else taskfile; - in - # sh - '' - TASKFILE="${taskfileScript}" - STATE_DIR="''${REN_STATE:-''${DEVENV_STATE:-''${PRJ_CACHE_HOME}}}" - ROOT_DIR="''${REN_ROOT:-''${DEVENV_ROOT:-''${PRJ_ROOT}}}" - - TASK_TEMP_DIR="''${STATE_DIR}/.task" \ - TASK_ROOT_DIR="$ROOT_DIR" \ - ${pkgs.go-task}/bin/task --taskfile "$TASKFILE" ''${@:1} - ''; - }; in { - options.task = { - enable = - mkEnableOption "Task" - // { - default = cfg.tasks != {}; + options.task = mkOption { + type = types.attrsOf (types.submodule ({ + config, + name, + ... + }: { + options = { + lazy = mkOption { + type = types.bool; + default = true; + description = '' + Whether the taskfile should be built on-demand/lazily. + It will probably not land in the gcroot and thus might get cleaned up with every gc. + On the other hand, this way loading the devshell is faster. Decide for yourself :) + ''; + }; + alias = mkOption { + type = types.str; + default = + if name == "default" + then "task" + else name; + description = '' + Alias for `task`, eg. set to `,` to be able to run `, --list-all`. + Defaults to `"task"` if `${name}` is `"default"` + ''; + }; + interval = mkOption { + type = types.str; + default = "5000ms"; + description = '' + Interval for `task` to check for filesystem changes/watcher updates. + ''; + }; + tasks = mkOption { + type = types.attrs; + default = {}; + description = '' + Configure all your tasks here. + ''; + }; + + taskfile = mkOption { + internal = true; + type = types.package; + }; + taskAlias = mkOption { + internal = true; + type = types.package; + }; }; - lazy = mkOption { - type = types.bool; - default = true; - description = '' - Whether the taskfile should be built on-demand/lazily. - It will probably not land in the gcroot and thus might get cleaned up with every gc. - On the other hand, this way loading the devshell is faster. Decide for yourself :) - ''; - }; - alias = mkOption { - type = types.str; - default = "task"; - description = '' - Alias for `task`, eg. set to `,` to be able to run `, --list-all`. - ''; - }; - interval = mkOption { - type = types.str; - default = "5000ms"; - description = '' - Interval for `task` to check for filesystem changes/watcher updates. - ''; - }; - tasks = mkOption { - type = types.attrs; - default = {}; - description = '' - Configure all your tasks here. - ''; - }; + config = let + patchedTasks = mapAttrs (_name: value: let + taskDir = value.dir or ""; + absolutePathOrTemplate = (builtins.substring 0 1 taskDir) == "/" || (builtins.substring 0 1 taskDir) == "{"; + in + value + // { + dir = + if absolutePathOrTemplate + then taskDir + else ''{{env "TASK_ROOT_DIR" | default .USER_WORKING_DIR}}/${taskDir}''; + }) + config.tasks; + in rec { + # NOTE: this requires python just to convert json to yaml, since json is valid yaml we just ignore that + # generator = (pkgs.formats.yaml {}).generate; + taskfile = generator "taskfile" { + version = 3; + inherit (config) interval; + tasks = patchedTasks; + }; + # when using a , as alias for example the store path looks weird. + # This way it can be identified as being the task alias + taskAlias = pkgs.writeTextFile { + name = "task-alias"; + destination = "/bin/${config.alias}"; + executable = true; + text = let + taskfileScript = + if config.lazy + then + # sh + "$(nix build '${builtins.unsafeDiscardOutputDependency taskfile.drvPath}^*' --no-link --print-out-paths)" + else taskfile; + in + # sh + '' + TASKFILE="${taskfileScript}" + STATE_DIR="''${REN_STATE:-''${DEVENV_STATE:-''${PRJ_CACHE_HOME}}}" + ROOT_DIR="''${REN_ROOT:-''${DEVENV_ROOT:-''${PRJ_ROOT}}}" + + TASK_TEMP_DIR="''${STATE_DIR}/.task" \ + TASK_ROOT_DIR="$ROOT_DIR" \ + ${pkgs.go-task}/bin/task --taskfile "$TASKFILE" ''${@:1} + ''; + }; + }; + })); + default = {}; + description = '' + Define your Taskfile instances here. + ''; }; - config = mkIf cfg.enable { - packages = [taskAlias]; - }; + config.packages = map (val: val.taskAlias) (builtins.attrValues config.task); } diff --git a/lib/modules/taskfile_test.nix b/lib/modules/taskfile_test.nix index 5b44007..8e68ccc 100644 --- a/lib/modules/taskfile_test.nix +++ b/lib/modules/taskfile_test.nix @@ -14,7 +14,7 @@ in { script = let shell = devshell.mkShell { imports = [module]; - task.enable = true; + task."default" = {}; }; in # sh @@ -29,10 +29,7 @@ in { script = let shell = devshell.mkShell { imports = [module]; - task = { - enable = true; - alias = ","; - }; + task."," = {}; }; in # sh diff --git a/nix/repo/devShells.nix b/nix/repo/devShells.nix index df160d0..aca5e73 100644 --- a/nix/repo/devShells.nix +++ b/nix/repo/devShells.nix @@ -25,12 +25,9 @@ in { treefmtWrapper ]; - task = { - alias = ","; - tasks = { - "hello" = { - cmd = "echo world!"; - }; + task.",".tasks = { + "hello" = { + cmd = "echo world!"; }; }; @@ -54,7 +51,7 @@ in { }; }; - process-compose.config.processes = { + process-compose."default".config.processes = { hello.command = "echo 'Hello World'"; pc = { command = "echo 'From Process Compose'";