A nix shell with a nix package in a git repo

I have a trivial “hello world” project in a git repo with the following default.nix.

with (import <nixpkgs> {});
stdenv.mkDerivation rec {
  pname = "hello-nix";
  version = "1.0.0";
  src = ./.;

  installPhase =
    ''
      mkdir -p $out/bin
      cp $src/hello-nix $out/bin/hello-nix
      chmod +x $out/bin/hello-nix
    '';
}

So now I’m trying to write a shell.nix that will give me an environment where my hello-nix script is available. I expected this to work:

with (import <nixpkgs> {});
let
  hello = callPackage (builtins.fetchGit {
                                           url = "https://codeberg.org/mhwombat/hello-nix";
                                           rev = "aa2c87f8b89578b069b09fdb2be30a0c9d8a77d8";
                                         }) {};
in
mkShell {
  buildInputs = [ hello ];
}

However, I get the following error. How can I fix this?

$ nix-shell shell-with-git-nix-pkg.nix
error: 'functionArgs' requires a function

       at /nix/store/fy9zn4myvzbx1740vxk3309i6fxb76dg-nixos/nixos/lib/trivial.nix:443:10:

          442|     then f.__functionArgs or (lib.functionArgs (f.__functor f))
          443|     else builtins.functionArgs f;
             |          ^
          444|
(use '--show-trace' to show detailed location information)

That default.nix isn’t formatted correctly for callPackage, for the way you’ve written it, you’d just use import and not pass the {} argument.

Ah, thank you! As a general practice, would it be better to modify the default.nix in my repo so I can use callPackage (and if so, how)?

I’m working on a set of basic Nix “recipes” to include in my Nix for Numbskulls repo, so I want to follow tbest practice.

For the benefit of future readers, here is the change suggested by @tejing, which works:

with (import <nixpkgs> {});
let
  hello = import (builtins.fetchGit {
                                           url = "https://codeberg.org/mhwombat/hello-nix";
                                           rev = "aa2c87f8b89578b069b09fdb2be30a0c9d8a77d8";
                                         });
in
mkShell {
  buildInputs = [ hello ];
}

The typical thing to do, if you want to expose something callPackageable, would be 2 have to files:

  • A foo.nix (whatever your package name is, for example), which is structured to be callPackaged.
  • A default.nix which looks something like this:
{ pkgs ? import <nixpkgs> {} }:
pkgs.callPackage ./foo.nix {}

This way, the importer can choose whether to:

  • import (fetchGit {...}) {}
  • import (fetchGit {...}) { inherit pkgs; }
  • callPackage "${fetchGit {...}}/foo.nix" {}

It’s also possible to make a single file suitable for both nix-build/import and callPackage like this:

{
  pkgs ? import <nixpkgs> {},
  stdenv ? pkgs.stdenv,
  foo ? pkgs.foo,
  bar ? pkgs.bar
}:
stdenv.mkDerivation {

(and then don’t use pkgs in the rest of the file)

This form would be usable in any of these ways:

  • import (fetchGit {...}) {}
  • import (fetchGit {...}) { inherit pkgs; }
  • callPackage (fetchGit {...}) {}
1 Like