From d0cd6f9d090ccfd247890bf1c5932b598c6a20cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Domen=20Ko=C5=BEar?= Date: Tue, 3 Sep 2024 10:19:05 +0100 Subject: [PATCH] tasks: convert some of the enterShell into tasks --- devenv.nix | 6 -- devenv/init/devenv.nix | 6 ++ devenv/src/devenv.rs | 10 ++- docs/tasks.md | 81 ++++++++++++++++++++----- src/modules/integrations/pre-commit.nix | 11 ++-- src/modules/tasks.nix | 4 +- 6 files changed, 89 insertions(+), 29 deletions(-) diff --git a/devenv.nix b/devenv.nix index a6fd23534..0e1816b00 100644 --- a/devenv.nix +++ b/devenv.nix @@ -210,12 +210,6 @@ EOF ''; }; - - tasks."devenv:sleep3".exec = "sleep 3"; - tasks."devenv:sleep".exec = "sleep 5"; - tasks."devenv:sleep".depends = [ "devenv:sleep3" ]; - tasks."devenv:enterShell".depends = [ "devenv:sleep" ]; - pre-commit.hooks = { nixpkgs-fmt.enable = true; #shellcheck.enable = true; diff --git a/devenv/init/devenv.nix b/devenv/init/devenv.nix index 5a693e8b7..4220a2db5 100644 --- a/devenv/init/devenv.nix +++ b/devenv/init/devenv.nix @@ -26,6 +26,12 @@ git --version ''; + # https://devenv.sh/tasks/ + # tasks = { + # "myproj:setup".exec = "mytool build"; + # "devenv:enterShell".depends = ["myproj:setup"]; + # }; + # https://devenv.sh/tests/ enterTest = '' echo "Running tests" diff --git a/devenv/src/devenv.rs b/devenv/src/devenv.rs index c67138797..09f587387 100644 --- a/devenv/src/devenv.rs +++ b/devenv/src/devenv.rs @@ -251,7 +251,10 @@ impl<'a> Devenv<'a> { self.assemble(false)?; let (_, gc_root) = self.get_dev_environment(false, true).await?; - let mut develop_args = vec![gc_root.to_str().expect("gc root should be utf-8")]; + let mut develop_args = vec![ + "develop", + gc_root.to_str().expect("gc root should be utf-8"), + ]; let default_clean = config::Clean { enabled: false, @@ -665,7 +668,7 @@ impl<'a> Devenv<'a> { let mut cmd = self .nix .prepare_command_with_substituters( - "develop", + "nix", &develop_args .iter() .map(AsRef::as_ref) @@ -700,7 +703,8 @@ impl<'a> Devenv<'a> { } self.logger.info("Stop: $ devenv processes stop"); } else { - cmd.exec(); + let err = cmd.exec(); + bail!(err); } Ok(()) } diff --git a/docs/tasks.md b/docs/tasks.md index 18f26bf92..715bcf59e 100644 --- a/docs/tasks.md +++ b/docs/tasks.md @@ -8,19 +8,32 @@ Tasks allow you to form dependencies between commands, executed in parallel. { tasks."myapp:hello" = { exec = ''echo "Hello, world!"''; - desc = "hello world in bash"; }; } ``` ```shell-session $ devenv tasks run hello -• Building shell ... -• Entering shell ... -Hello, world! +Hello, world $ ``` +## enterShell / enterTest + +If you'd like the tasks to run as part of the `enterShell` or `enterTest`: + +```nix title="devenv.nix" +{ pkgs, lib, config, ... }: + +{ + tasks = { + "bash:hello".exec = "echo 'Hello world from bash!'"; + "devenv:enterShell".depends = [ "bash:hello" ]; + "devenv:enterTest".depends = [ "bash:hello" ]; + }; +} +``` + ## Using your favourite language Tasks can also reference scripts and depend on other tasks, for example when entering the shell: @@ -31,25 +44,65 @@ Tasks can also reference scripts and depend on other tasks, for example when ent { tasks = { "python:hello"" = { - exec = ''print("Hello world from Python!")''; + exec = '' + print("Hello world from Python!") + ''; package = config.languages.python.package; }; - "bash:hello" = { - exec = "echo 'Hello world from bash!'"; - depends = [ "python:hello" ]; - }; - "devenv:enterShell".depends = [ "bash:hello" ]; }; } ``` ```shell-session $ devenv shell -• Building shell ... -• Entering shell ... ... -$ ``` -`status` +## Avoiding running expensive `exec` via `status` check + +If you define a `status` command, it will be executed first and if it returns `0`, `exec` will be skipped. + +```nix title="devenv.nix" +{ pkgs, lib, config, ... }: + +{ + tasks = { + "myapp:migrations" = { + exec = "db-migrate"; + status = "db-needs-migrations"; + }; + }; +} +``` + +## Inputs / Outputs + +Tasks support passing inputs and produce outputs, both as JSON objects: + +- `$DEVENV_TASK_INPUTS`: JSON object serializing `tasks."myapp:mytask".inputs`. +- `$DEVENV_TASK_OUTPUTS`: a writable file with tasks' outputs in JSON. +- `$DEVENV_TASKS_OUTPUTS`: JSON object with dependent tasks as keys and their outputs as values. + +```nix title="devenv.nix" +{ pkgs, lib, config, ... }: + +{ + tasks = { + "myapp:mytask" = { + exec = '' + echo $DEVENV_TASK_INPUTS > $DEVENV_ROOT/inputs.json + echo '{ "output" = 1; }' > $DEVENV_TASK_OUTPUTS + echo $DEVENV_TASKS_OUTPUTS > $DEVENV_ROOT/outputs.json + ''; + inputs = { + value = 1; + }; + }; + }; +} +``` + +## SDK + +See [xxx](xxx) for a proposal how defining tasks in your favorite language would look like. diff --git a/src/modules/integrations/pre-commit.nix b/src/modules/integrations/pre-commit.nix index 5e27432ec..90397841a 100644 --- a/src/modules/integrations/pre-commit.nix +++ b/src/modules/integrations/pre-commit.nix @@ -20,11 +20,14 @@ config = lib.mkIf ((lib.filterAttrs (id: value: value.enable) config.pre-commit.hooks) != { }) { ci = [ config.pre-commit.run ]; - enterTest = '' - pre-commit run -a - ''; # Add the packages for any enabled hooks at the end to avoid overriding the language-defined packages. packages = lib.mkAfter ([ config.pre-commit.package ] ++ (config.pre-commit.enabledPackages or [ ])); - enterShell = config.pre-commit.installationScript; + tasks = { + # TODO: split installation script into status + exec + "devenv:pre-commit:install".exec = config.pre-commit.installationScript; + "devenv:pre-commit:run".exec = "pre-commit run -a"; + "devenv:enterShell".depends = [ "devenv:pre-commit:install" ]; + "devenv:enterTest".depends = [ "devenv:pre-commit:run" ]; + }; }; } diff --git a/src/modules/tasks.nix b/src/modules/tasks.nix index 77432915c..a5a6b1524 100644 --- a/src/modules/tasks.nix +++ b/src/modules/tasks.nix @@ -97,7 +97,7 @@ in description = "Runs when entering the test environment"; }; }; - #enterShell = "devenv tasks run devenv:enterShell"; - #enterTest = "devenv tasks run devenv:enterTest"; + enterShell = "devenv tasks run devenv:enterShell"; + enterTest = "devenv tasks run devenv:enterTest"; }; }