Ensuring git is present when evaluating fetchGit

Given a file XXX.nix with contents

{ pkgs ? import <nixpkgs> {} }:
with pkgs;
{
  XXX = let
    src = builtins.fetchGit { ... };
  in callPackage "${src}/XXX" { path = "${src}"; };
}

which is intended to be used thus:

# client
(pkgs.callPackage path/to/XXX.nix {}).XXX

The evaluation of builtins.fetchGit seems to fail if Git is not installed in the caller’s environment.

Is there any way that the availability of Git can be assured from within XXX.nix? Failing that, can it be assured by the client code?

I’m trying to use this approach in bootstrapping-scripts, where pretty much the only guarantee is that Nix is installed. I would like to absolve the user of the need to install Git before running the script.

This also always annoys me. I read somewhere that is by design, so nix does not have to ship with its own git.

Your use case allows a workaround where you introduce a wrapper environment which is managed by nix-shell along the lines of this:

install.sh

#! /usr/bin/env nix-shell
#! nix-shell -p git

nix-shell -E '(import ./XXX.nix {}).XXX‘ --run  XXX

The exact invocation is of course subject to your specific situation.

Yes, the wrapping-in-nix shell approach has served me well up to a point. But if I try to use this with XXX=home-manager I then end up wanting to write

home.packages = [
  (pkgs.callPackage ../home-manager.nix {}).home-manager
  other
  packages
]

inside home.nix, so that home-manager installs my specific version of itself, and I haven’t found a solution for this case.

And anyway, it’s XXX.nix that requres git, so I was hoping there would be a way for XXX.nix to provide git once and for all.

The setup I use does exactly this. Essentially my bootstrap script is in a nix-shell as above, and evaluates my home.nix environment, which contains the same home-manager and of course git (not explicitly mentioned in the linked post).

OK, you can’t directly bundle nix with git, you have to ensure it once at bootstrap time. After that, it will be part of your user environment, which is self-perpetuating by that design.

In your setup, why do you wrap home-manager in writeShellScriptBin?

In mine I use (pkgs.callPackage ../home-manager.nix {}).home-manager directly in home.packages and that seems to work fine (as long as I enable git somewhere in home.nix, to ensure availability of git for subsequent home-manager switches). Am I missing something?

Is writeShellScriptBin documented anywhere?

This is just to point it to my configuration file, which is not in the default location.

Now that you ask, I couldn’t even find anything. Google search was more helpful just a few months ago, now it doesn’t even show the source any more. I guess when I came up with this back then, I saw a snippet somewhere and then found the source.