Using Haskell GitHash TH splices (build-time git availability)

I have a nixpkgs.nix file in my Haskell project but have imported GitHash into a couple of modules to obtain and report on the git status of the application. This defines some TH splices that require git to be available at build time. At the moment, although git is installed on my system, I’m guessing that it isn’t available in the build sandbox - at least I get build errors suggesting this.

How do I add git into the build environment? I’ve tried a few things, but I’m still very new to nix and most of what I do is rather recipe-based at the moment :frowning:

The content of my nixpkgs.nix file is below. I need this to work with nix-build, so not just in a nix shell.


let
  # Fetch the external Git repository for the boa package
  boaPackage = builtins.fetchGit {
    url = "git@bitbucket.org:levans/boa.git";
    rev = "345ee367141c4771cd5bc43e5bea414a630a9152";
  };

  project-overlay = final: prev: {
      # Update to use ghc965
      ppilot-haskell-packages = prev.haskell.packages.ghc965.override {
        overrides = haskellPackagesNew: haskellPackagesOld: {
          mkDerivation = args: haskellPackagesOld.mkDerivation (args // {
            doCheck = false;
            doHaddock = false;
            enableSeparateDataOutput = false;

            # Ensure git is available during the build process
            nativeBuildInputs = (args.nativeBuildInputs or []) ++ [ final.git ];

            postInstall = 
              let ghcName = "${haskellPackagesNew.ppilot.passthru.compiler.targetPrefix}${haskellPackagesNew.ppilot.passthru.compiler.haskellCompilerName}";
                  sysPlusGhc = "${haskellPackagesNew.ppilot.system}-${ghcName}";
                  ppilotName = haskellPackagesNew.ppilot.name;
                  fullDataPath = "share/${sysPlusGhc}/${ppilotName}";
              in
                ''
                  ln -sf "$out/${fullDataPath}/config" $out/config
                  ln -sf "$out/${fullDataPath}/static" $out/static
                  ln -sf "$out/${fullDataPath}/client" $out/client
                  ln -sf "$out/${fullDataPath}/clientpp" $out/clientpp
                  ln -sf "$out/${fullDataPath}/adminclient" $out/adminclient
                  ln -sf "$out/${fullDataPath}/tagcatalog" $out/tagcatalog
                '';
          });

          # Local project dependencies here
          ppilot = final.haskell.lib.dontCheck (haskellPackagesNew.callCabal2nix "ppilot" ./. { });
          boa = final.haskell.lib.dontCheck (haskellPackagesNew.callCabal2nix "boa" boaPackage { });
        };
      };

    #ppilot = final.haskell.lib.justStaticExecutables final.ppilot-haskell-packages.ppilot;
    ppilot = final.haskell.lib.justStaticExecutables (final.ppilot-haskell-packages.ppilot.overrideAttrs (oldAttrs: {
      nativeBuildInputs = (oldAttrs.nativeBuildInputs or []) ++ [ final.git ];
    }));


    ppilot-dev-shell = final.ppilot-haskell-packages.shellFor {
      withHoogle = false;
      packages = hpkgs: [ hpkgs.ppilot hpkgs.gantt ];  # Add all necessary packages here
      buildInputs = [ ];
      nativeBuildInputs = [
        final.cabal-install
        final.ghcid
        final.git
        final.haskell.packages.ghc965.haskell-language-server
        final.haskell.packages.ghc965.fourmolu
      ];
    };
  };

  nixpkgs-src = builtins.fetchTarball {
    # Updated nixpkgs-unstable version
    name = "nixpkgs-for-ppilot";                                  
    url = "https://github.com/NixOS/nixpkgs/archive/cb8e8bbe7579a5283f6fae1dd40a5a7386db2f2f.tar.gz";
    sha256 = "0120nbmjp4l2scsrn7vxlv7jark0x41a71a7x4lk4mx8x1axwcyy";
  };
in
  import nixpkgs-src { overlays = [ project-overlay ]; }

(You should stick a ``` fence before and after your code in your post, to make it readable.)

1 Like

Should have thought about that - thanks for the poke.

1 Like

It’s hard for me to give conclusive advice not being able to test a build of ppilot, but just by eyeballing, I think there are more epicycles here than necessary.

  • The Nixpkgs overlay is just extra complexity; I don’t see a reason here why you would need it.
pinned-nixpkgs-src = builtins.fetchTarball { ... };
pkgs = import pinned-nixpkgs-src { };
  • Neither boa nor ppilot are in the Nixpkgs haskellPackages set, so there shouldn’t be a need to override it. Just call haskell.packages.ghc965.callCabal2Nix directly on your inputs:
boa = pkgs.haskell.packages.ghc965.callCabal2nix "boa" boa-src { };
ppilot = pkgs.haskell.packages.ghc965.callCabal2nix "ppilot" ppilot-src { inherit boa; };
  • In either or both derivation, you can call overrideAttrs on the result to add native build inputs, postInstall scripts, etc.
ppilot = (...the above stuff...).overrideAttrs (oldAttrs: {
  nativeBuildInputs = oldAttrs.nativeBuildInputs or [ ] ++ [
    pkgs.git
  ];
  postInstall = oldAttrs.postInstall or "" + ''
    ...
  '';
});

I don’t know if that’ll get you as far as you need to go, but those are the first changes I’d try if I could test this locally.