Using the default.nix from NixOS/nixpkgs to launch a shell

I installed a package in NixOS, and I found a bug. Supposedly the fix for the bug is in the latest code in the repo. So I want to grab the latest code, and build it locally, perhaps doing some additional development.

I hoped I could take the default.nix from NixOS/nixpkgs, tweak it to get the latest version of the code from the repo, and use it to launch a nix shell. However, the derivations from NixOS/nixpkgs expect a lot of stuff to passed to them, so using them directly doesn’t work.

$ nix-shell
error: cannot evaluate a function that has an argument without a value ('lib')

       Nix attempted to evaluate a function as a top level expression; in
       this case it must have its arguments supplied either by default
       values, or passed explicitly with '--arg' or '--argstr'. See
       https://nixos.org/manual/nix/stable/#ss-functions.

       at /home/amy/waybar-amy/default.nix:1:3:

            1| { lib
             |   ^
            2| , stdenv

Is there a magic incantation that will let me run nix-shell on this default.nix? Failing that, how do I modify it? (Note: I put lib.fakeSha256 there temporarily; I know I can get the real value when it tries to fetch the source.) I’ve only written a few simple nix derivations; writing this one from scratch is beyond my skills.

$ cat default.nix
{ lib
, stdenv
, fetchFromGitHub
, meson
, pkg-config
, ninja
, wrapGAppsHook
, wayland
, wlroots
, gtkmm3
, libsigcxx
, jsoncpp
, scdoc
, spdlog
, gtk-layer-shell
, howard-hinnant-date
, libxkbcommon
, traySupport     ? true,  libdbusmenu-gtk3
, pulseSupport    ? true,  libpulseaudio
, sndioSupport    ? true,  sndio
, nlSupport       ? true,  libnl
, udevSupport     ? true,  udev
, evdevSupport    ? true,  libevdev
, swaySupport     ? true,  sway
, mpdSupport      ? true,  libmpdclient
, rfkillSupport   ? true
, withMediaPlayer ? false, glib, gobject-introspection, python3, python38Packages, playerctl
}:

stdenv.mkDerivation rec {
  pname = "waybar";
  version = "0.9.8";

  src = fetchFromGitHub {
    owner = "Alexays";
    repo = "Waybar";
    rev = master;
    sha256 = lib.fakeSha256;
  };

  nativeBuildInputs = [
    meson ninja pkg-config scdoc wrapGAppsHook
  ] ++ lib.optional withMediaPlayer gobject-introspection;

  propagatedBuildInputs = lib.optionals withMediaPlayer [
    glib
    playerctl
    python38Packages.pygobject3
  ];
  strictDeps = false;

  buildInputs = with lib;
    [ wayland wlroots gtkmm3 libsigcxx jsoncpp spdlog gtk-layer-shell howard-hinnant-date libxkbcommon ]
    ++ optional  traySupport  libdbusmenu-gtk3
    ++ optional  pulseSupport libpulseaudio
    ++ optional  sndioSupport sndio
    ++ optional  nlSupport    libnl
    ++ optional  udevSupport  udev
    ++ optional  evdevSupport libevdev
    ++ optional  swaySupport  sway
    ++ optional  mpdSupport   libmpdclient;

  mesonFlags = (lib.mapAttrsToList
    (option: enable: "-D${option}=${if enable then "enabled" else "disabled"}")
    {
      dbusmenu-gtk = traySupport;
      pulseaudio = pulseSupport;
      sndio = sndioSupport;
      libnl = nlSupport;
      libudev = udevSupport;
      mpd = mpdSupport;
      rfkill = rfkillSupport;
    }
  ) ++ [
    "-Dsystemd=disabled"
    "-Dgtk-layer-shell=enabled"
    "-Dman-pages=enabled"
  ];

  preFixup = lib.optionalString withMediaPlayer ''
      cp $src/resources/custom_modules/mediaplayer.py $out/bin/waybar-mediaplayer.py

      wrapProgram $out/bin/waybar-mediaplayer.py \
        --prefix PYTHONPATH : "$PYTHONPATH:$out/${python3.sitePackages}"
    '';

  meta = with lib; {
    description = "Highly customizable Wayland bar for Sway and Wlroots based compositors";
    license = licenses.mit;
    maintainers = with maintainers; [ FlorianFranzen minijackson synthetica lovesegfault ];
    platforms = platforms.unix;
    homepage = "https://github.com/alexays/waybar";
  };
}

Sure, you need to inject the dependencies like pkgs/top-level/all-packages.nix does:

nix-shell -E '
let
  pkgs = import <nixpkgs> {};
  waybar = pkgs.callPackage ./pkgs/applications/misc/waybar/default.nix {};
in
pkgs.mkShell {
  buildInputs = [
    waybar
  ];
}
'

or slightly simpler relying on the default shell expression:

nix-shell -p '
let
  pkgs = import <nixpkgs> {};
in
pkgs.callPackage ./pkgs/applications/misc/waybar/default.nix {}
'
3 Likes

That is beautiful in its simplicity! Thank you so much.

I really think this concept needs more documentation, because it exactly what got me stuck in the early days of my nix adventure

if it has documentation , and i missed it, perhaps needs to be in a bigger font :wink: .

3 Likes

The relevant documentation is Arguments and Variables and NixOS - Nix Pills. I guess it would be also nice to have it described in the Nixpkgs manual, since the concept comes from Nixpkgs :woman_shrugging:

I’ve written up a tutorial with this solution and added it to my Nix for Numbskulls repo, with acknowledgement to @jtojnar. Please feel free to adapt it and include it anywhere else you like. I would add it to Nix Pills or the NixOS and Nix manuals myself, but I think it needs a little more context added that I don’t yet feel qualified to write.

1 Like