nix-community / nix-direnv

A fast, persistent use_nix/use_flake implementation for direnv [maintainer=@Mic92 / @bbenne10]
MIT License
1.78k stars 101 forks source link

Question: Dependencies beyond packages (systemd-pm2, udev, kernel modules). #501

Closed adminy closed 3 months ago

adminy commented 3 months ago

I like this idea and sounds like an awesome project I'd like to be using everywhere now. But there is all these questions at the back of my mind, like what if a demon needs to be running in systemd like pm2? or certain kernel modules not to be loaded? what about udev packages?

  boot.blacklistedKernelModules = [ "dvb_usb_rtl28xxu" "e4000" "rtl2832" ];
  services.udev.packages = with pkgs; [ hackrf rtl-sdr-blog ];
  systemd.services.pm2 = {
    enable = true;
    description = "PM2 process manager";
    wantedBy = [ "multi-user.target" ];
    after = [ "network.target" ];

    serviceConfig = {
      Type="forking";
      User="root";
      LimitNOFILE="infinity";
      LimitNPROC="infinity";
      LimitCORE="infinity";
      Environment="PM2_HOME=/root/.pm2";
      PIDFile="/root/.pm2/pm2.pid";
      Restart="on-failure";
      ExecStart = "${pkgs.nodePackages_latest.pm2}/bin/pm2 resurrect";
      ExecReload = "${pkgs.nodePackages_latest.pm2}/bin/pm2 reload all";
      ExecStop = "${pkgs.nodePackages_latest.pm2}/bin/pm2 kill";
    };
  };

Should this live inside projects flake or is better if this was installed at the system level? Is there a way to put these inside the flake? If so how?

bbenne10 commented 3 months ago

Unless there is some advancement in the nix space of which I am unaware, those sorts of system configuration bits simply cannot live in a mkShell call. mkShell wraps mkDerivation, which produces a single "package" rather than a system-definition (which is where these other options live).

However, you could provide a NixOS VM built with system specific options and then add it to the PATH as shown here: https://wiki.nixos.org/wiki/Adding_VMs_to_PATH (this boils down tp "add the package to inputs in your flake's devShell call")

bew commented 3 months ago

For services, it could work if you use process-compose which is the default if you use devenv for your dev environment.

For specific udev rules & kernel modules.. you best bet is a VM yes I think or apply those on your system. Your flake could expose a nixos module that you then use in your system config, but it won't be possible AFAIK directly from the project directory itself and you'd have to install the module separately.

bbenne10 commented 3 months ago

Services spun up this way are not EXACTLY the same as those NixOS services, which is why I did not recommend it. There is simply no way that I am aware of to get the EXACT NixOS service running as part of a flake devShell without some kind of virtualization going on.

However, if you just want the process running and dont need specifics around the service definition: yah! Process-compose is perfect.

Mic92 commented 3 months ago

If you need those nixos configuration in your system, you can expose it as a module in your repository. In flakes you put them in nixosModules (see https://wiki.nixos.org/wiki/Flakes#Output_schema). However than activating this is a manual process. Otherwise there is also this: https://github.com/Mic92/nixos-shell which gives you adhoc virtual machines with little configuration.

Mic92 commented 3 months ago

It feels like this has been sufficiently answered now.

adminy commented 3 months ago

thank you for all the lovely answers. I've put things in os level configuration.nix for now. But I'll be trying out each of the suggestions, see which one's best for the job.

adminy commented 3 months ago

I noticed something strange. If the package is in systemPackages. It will show up under /run/current-system/sw/lib, e.g. libgpiod.so.3 file. If its defined as a direnv package it won't show up under /run/current-system/sw/lib. is this normal behaviour?

bbenne10 commented 3 months ago

Is that not the same path?

bbenne10 commented 3 months ago

Oh. I misread. Ill have to check on thatbefore I say more

adminy commented 3 months ago

Yep, should it not show up as a library in the environment?

bbenne10 commented 3 months ago

How is your environment defined? How is it added to systemPackages meaningfully in a nix-direnv facing way? How do you expect it to be exposed?

adminy commented 3 months ago
{
  description = "Flake for this environment folder";
  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
  inputs.flake-utils.url = "github:numtide/flake-utils";
  outputs = { nixpkgs, flake-utils, ... }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = nixpkgs.legacyPackages.${system};
      in {
        devShells.default = pkgs.mkShell {
          packages = with pkgs; [
            bashInteractive
            libgpiod # should create an entry in /run/current-system/sw/lib but doesn't.
            libgpiod python3Packages.libgpiod
          ];
        };
      });
}

Hoever if I define it in my configuration.nix file:

{ pkgs, ... }:
{
   environment.systemPackages = [ pkgs.libgpiod ]; # adds entry to /run/current-system/sw/lib guaranteed
}

However I'd prefer not to polute my configuration.nix with project specific packages.

One hacky thing comes to mind, is to define a mkShell hook:

shellHook = "export LD_LIBRARY_PATH = "${pkgs.libgpiod}/lib";

bbenne10 commented 3 months ago

No. /run/current-system is reserved for...well, the current NixOS system. DevShells don't activate the running system as such and so dont get linked there. I have found mkShell to be inconsistent (at best) when using libraries. It reliably adds stuff to PATH. Building a derivation using the library typically resolves this for me, but that is a poor solution in some cases. I may find time tomorrow to go look at the mkShell implementation, but I am under the weather at the moment and frankly lacking motivation.

bbenne10 commented 3 months ago

I just realized that if you add pkg-config to the inputs, hooks will set PKG_CONFIG_PATH. I know that doesn't help in a "raw" LD_LIBRARY_PATH scenario, but maybe it is enough?

adminy commented 3 months ago

I hope you will feel better soon!

Not sure if it cover my libgpiod use case, but that's interesting that having it in the inputs exposes the variables for the shell. Maybe that's all that's needed indeed. I was using python so I just imported it from the python3Packages and that depends on the top-level libgpiod, for now at least, I'm happy with the solution I have. I think inputs pattern makes most sense.