cachix / devenv

Fast, Declarative, Reproducible, and Composable Developer Environments
https://devenv.sh
Apache License 2.0
4.48k stars 339 forks source link

Cannot run task after `poetry install` #1557

Open anoadragon453 opened 3 weeks ago

anoadragon453 commented 3 weeks ago

Describe the bug I'm attempting to run a small script after poetry install completes in my repo. poetry install downloads some binaries that are dynamically linked against ld, and thus do not work on NixOS. I'm trying to automatically run patchelf after poetry install completes in order to patch ruff, thus allowing NixOS developers to not have to worry about doing it themselves or manually running a command after each poetry install.

Here is my devenv module:

{
  # Configure packages to install.
  # Search for package names at https://search.nixos.org/packages?channel=unstable
  packages = with pkgs; [
    openssl

    patchelf
    autoPatchelfHook
  ];

  # Install Python and manage a virtualenv with Poetry.
  languages.python.enable = true;
  languages.python.poetry.enable = true;
  # Automatically activate the poetry virtualenv upon entering the shell.
  languages.python.poetry.activate.enable = true;
  languages.python.poetry.install.installRootPackage = true;
  languages.python.poetry.install.enable = true;

  tasks = {
    "sygnal:patchpythonbinaries" = {
      description = "Patch binaries dynamically linked to ld, which will not work on NixOS";
      exec = ''
        patchelf --remove-rpath .venv/bin/ruff
        autoPatchelf .venv/bin/ruff
      '';
      after = [ "devenv:enterShell" ];
    };
  };
}

I first tried to put the above patchelf; autoPatchelf invocation in enterShell, but that failed as poetry install runs after whatever a devenv module defines in enterShell. Meaning patchelf would be called, and then ruff would be downloaded by poetry install.

Interestingly, poetry install is defined as a task that apparently runs after enterShell:

https://github.com/cachix/devenv/blob/fa53082e82e90bd378cf850ca3d2b6892eebc77e/src/modules/languages/python.nix#L457-L486

I attempted all sorts of combinations of trying to get my task to run after both "devenv:enterShell" and "devenv:python:poetry", but to no avail. If I do:

      before = [ "devenv:enterShell" ];

then my task runs, but does so before the poetry install, so fails as ruff does not exist:

direnv: loading ~/code/sygnal/.envrc
direnv: using flake path:///home/work/code/nix-flakes/project-flakes/sygnal --impure
[0/1 built, 0.0 MiB DL] querying devenv-shell-env on https://devenv.cachix.orgdirenv: ([/nix/store/3mydh7746lji25ry2aygsy5i4s0i23x2-direnv-2.35.0/bin/direnv export zsh]) is taking a while to execute. Use CTRL-C to give up.
direnv: nix-direnv: Renewed cache
Running tasks     devenv:enterShell
Failed            sygnal:patchpythonbinaries 3ms
Succeeded         devenv:python:poetry       2582ms
Dependency failed devenv:enterShell          
1 Succeeded, 1 Failed, 1 Dependency Failed   2.59s

--- sygnal:patchpythonbinaries failed with error: Task exited with status: exit status: 1
--- sygnal:patchpythonbinaries stdout:
--- sygnal:patchpythonbinaries stderr:
0002.59: patchelf: getting info about '.venv/bin/ruff': No such file or directory

however, if I do the logical thing and:

      after = [ "devenv:enterShell" ];

my task doesn't run at all:

direnv: loading ~/code/sygnal/.envrc
direnv: using flake path:///home/work/code/nix-flakes/project-flakes/sygnal --impure
direnv: ([/nix/store/3mydh7746lji25ry2aygsy5i4s0i23x2-direnv-2.35.0/bin/direnv export zsh]) is taking a while to execute. Use CTRL-C to give up.
direnv: nix-direnv: Renewed cache
Running tasks     devenv:enterShell
Succeeded         devenv:python:poetry       2675ms
Succeeded         devenv:enterShell          7ms
2 Succeeded                                  2.68s

So I'm at a loss. This is using a flake, not devenv.nix/yaml/lock.

To reproduce

My devenv module can be found here, along with all other relevant files: https://github.com/element-hq/nix-flakes/blob/anoa/devenv_repro/project-flakes/sygnal/module.nix

Version

Using flakes, devenv v1.3.1.

sandydoo commented 3 weeks ago

I'm not familiar with the tasks implementation, but something tells me we have an issue in the graph traversal somewhere, ie. we're not picking up indirect dependencies of enterShell + the ordering appears reversed.

sandydoo commented 3 weeks ago

I think I've found the issue. We'll discuss it next week and have a fix out promptly.

dmarcoux commented 2 weeks ago

After a search on GitHub, I have found a way to make this work. Credits go to this commit. It's a matter of defining both before and after for the task. Personally, I don't use Poetry, but only rely on venv with a requirements.txt file. This is how I've patched ruff:

devenv.nix

  (...)

  languages.python = {
    enable = true;
    version = "3.12.7";
    venv = {
      enable = true;
      requirements = ./requirements.txt;
    };
  };

  tasks = {
    # Patch ruff to make it runnable
    "venv:patchelf" = {
      exec = "${lib.getExe pkgs.patchelf} --set-interpreter ${pkgs.stdenv.cc.bintools.dynamicLinker} $VIRTUAL_ENV/bin/ruff";
      after = [ "devenv:python:virtualenv" ]; # Runs after this
      before = [ "devenv:enterShell" ]; # Runs before this
    };
  };