Wrapping ruby applications into custom PATH

I am trying to package lolcommits.
After invoking bundix --magic like described in the nixpkgs manual and writing a small default.nix based on bundler-env, the package built successfully but it turned out that lolcommits has some runtime dependencies.

As adding these runtime dependencies to buildInputs alone isn’t sufficient, I tried to create a wrapper to adjust PATH accordingly:

{ stdenv, lib, bundlerEnv, ruby, mplayer, imagemagick, makeWrapper }:

let
  name = "lolcommits";
  gems = bundlerEnv rec {
    inherit name;
    #version = (import gemset).lolcommits.version;
    inherit ruby;
    gemdir = ./.;
  };
in stdenv.mkDerivation {
  inherit name;
  src = ./.;
  nativeBuildInputs = [ makeWrapper ];
  buildInputs = [ gems ruby mplayer imagemagick ];

  # create wrapper so all dependencies are in path
  installPhase = ''
    mkdir -p $out
    cp -r $src $out
    wrapProgram "$out/bin/lolcommits" --prefix PATH : ${lib.makeBinPath [ mplayer imagemagick ]}
  '';
}

But as bundlerEnv already creates a wrapper on its own, wrapProgram fails with a Cannot wrap ‘/nix/store/h4i9ra7997blr2gg0a6rig5gq3zlw3cd-lolcommits/bin/lolcommits’ because it is not an executable file.

So what is the best way to adjust the PATH of a ruby application? After a quick glance at the source of bundler-env and bundler-app I haven’t found any designated way to do so.

/cc @manveru

Sorry this took me a while to get to it; I forgot to help you out.

I ended up creating the derivation here: GitHub - fzakaria/lolcommits-nixpkgs: A nixpkgs derivation for lolcommits for you.

I just followed the Ruby guide https://github.com/NixOS/nixpkgs/blob/703f052de185c3dd1218165e62b105a68e05e15f/doc/languages-frameworks/ruby.section.md

nix run -f https://github.com/fzakaria/lolcommits/archive/master.tar.gz --command lolcommits

Do what exactly?
Try: lolcommits --enable (when in a git repository)
Or:  lolcommits --help

It’s also wrapping the dependencies you listed.

❯ cat ./result/bin/lolcommits
#! /nix/store/j8vysakw78bpgngba32hfwwikqda9yx2-bash-4.4-p23/bin/bash -e
export PATH='/nix/store/1dysm4zfzss74rw6vvhqbs623rxgygx4-mplayer-1.4/bin:/nix/store/z1fh9yz3mikpmdmxpnbs2i249477q5yf-imagemagick-6.9.11-14/bin'${PATH:+':'}$PATH
exec -a "$0" "/nix/store/xjvpw6p1yqsid0fags6bya607hzd6ff8-lolcommits-0.16.2/bin/.lolcommits-wrapped"  "$@"

Thanks for your proposal.
Interesting that wrapProgram works for bundlerApp, but not for bundlerEnv.
Unfortunately your approach isn’t fully correct, as makeWrapper, being run during build and not during runtime, belongs into nativeBuildInputs instead of buildInputs. But bundlerAp doesn’t take nativeBuildInputs as an argument while my approach with a bundlerEnv does. But that then seems to have problems with wrapProgram.

Additionally, mplayer doesn’t support my webcam as it lacks the v4l driver. But that is a totally different can of worms.

Update: I got my webcam working under MPlayer. But the uncleanliness of the lolcommits expression remains.

The uncleanliness of nativeBuildInputs for makeWrapper ? That’s not even necessary since makeWrapper is just bash anyways.

There’s no difference between host and target

Practically speaking you are correct indeed, but strictly you aren’t. I don’t know whether there is another distinction between nativeBuildInputs needed at build time and the buildInputs at runtime, maybe there are some optimisations based on that distinction?

I might be overly cautious though.

Is it okay if I put your expression into a NUR repo and maybe later into nixpkgs?

nixpkgs manual on buildInputs:

Even in the dynamic case, the library may also be needed at build-time to appease the linker.

So while I’d put makeWrapper into nativeBuildInputs if that was available, it seems to be acceptable to have it in buildInputs instead.

Do what you want :slight_smile: sure.
If you upstream it to nixpkgs I’ll review.

The only distinction to make something a runtime dependency is it’s greppable in the /nix/store entry.

Nix takes all buildInputs and then filters the ones that can be found in UTF8 in a file in the $out path.