How to create modSha256 for buildGoModule

Hi,

I’m new to nix and wondering how to properly use the buildGoModule function, specifically how does one generate the modSha256.

Thanks.

Nix will generate the hash for you, and you have to trust it on first use. There is no way you can figure this out otherwise.

You give it a fake hash (like 0000000000000000000000000000000000000000000000000000) for the first run, and use the value it gives you on a mismatch. This will look something like this:

hash mismatch in fixed-output derivation '/nix/store/q4cfnancqqvkc3v18r48zfq0vig6v6y9-pgmetrics-1.6.2-go-modules':
  wanted: sha256:0000000000000000000000000000000000000000000000000000
  got:    sha256:0llbx2sgcx95ym2q4l3334rdj3nkgr9z5jyp8406cp3k1ixi7gdb

Then you simply replace the modSha256 with the actual hash.

If you update your Go dependencies again, you’ll encounter a new mismatch, in which case you can update the hash again.

Incidentally you can use lib.fakeSha256 (or stdenv.lib.fakeSha256) if you don’t want to type out all of those zeroes.

2 Likes

Maybe we can ask msteen to add support for buildGoModule too: https://github.com/msteen/nix-prefetch

Thanks for the help guys. Unfortunately I’m also new to go modules, and I imagine this is a go module related problem. Getting

source root is source
patching sources
configuring
building
warning: pattern "all" matched no module dependencies
installing
cp: cannot stat '/private/var/folders/v1/g_sph9b951qcn0k1sq0d40gdc5xb6t/T/nix-build-docopts-v0.6.1+fix-go-modules.drv-0/go/pkg/mod/cache/download': No such file or directory
builder for '/nix/store/vdz3abswdhrjdvvmb6bdfalcsh9554z5-docopts-v0.6.1+fix-go-modules.drv' failed with exit code 1

with this derivation

with import <nixpkgs> { };

buildGoModule rec {
  name = "docopt.go-${version}";
  version = "0.6.2";

  src = fetchFromGitHub {
    owner = "docopt";
    repo = "docopt.go";
    sha256 = "0wwz48jl9fvl1iknvn9dqr4gfy1qs03gxaikrxxp9gry6773v3sj";
    rev = "${version}";
  };

  modSha256 = stdenv.lib.fakeSha256;
}

Well, that repo doesn’t have any Go modules. Good news is that it doesn’t have any dependencies at all outside of the Go stdlib.
So… in theory you can build it with this derivation:

with import <nixpkgs> { };

buildGoPackage rec {
  name = "docopt.go-${version}";
  version = "0.6.2";

  src = fetchFromGitHub {
    owner = "docopt";
    repo = "docopt.go";
    sha256 = "0wwz48jl9fvl1iknvn9dqr4gfy1qs03gxaikrxxp9gry6773v3sj";
    rev = "${version}";
  };

  goPackagePath = "github.com/docopt/docopt-go";
}

The bad news is, that this is really only a library that you can use for building applications, it doesn’t have any executables itself. So the derivation won’t help you much.

It would help to know what you actually want to do :slight_smile:

The ultimate end goal is to setup up a nix derivation for a local bash script that uses doctops: https://github.com/docopt/docopts, which is the shell for docopt and has those executables.

I ended up using the python version of docopts and have a derivation like this, but the nix-build output cannot find docopts, even though it’s availabe in the nix-shell.

with import <nixpkgs> { };

let
  docopts = stdenv.mkDerivation {
     name = "docopts";

     src = fetchFromGitHub {
      owner = "doordash";
      repo = "docopts";
      rev = "4c8b652998a5ffda5068197f002b5ab5735761d6";
      sha256 = "0h7ywn2bcyckh9pvgaiwp3n5jnfszsj9mrxpri7w647wjihh4i12";
    };

    installPhase = ''
      mkdir -p $out/bin

      cp docopts $out/bin/
      chmod +x $out/bin/docopts
    '';
  };
in
stdenv.mkDerivation rec {
  name = "data-deployer";

  propagatedBuildInputs = [
    docopts
    pkgs.python37
    pkgs.python37Packages.docopt
    pkgs.yq
  ];

  src = ./.;

  installPhase = ''
    mkdir -p $out/bin
    cp -r ${src}/src/* $out/bin
    chmod +x $out/bin/data-deployer
  '';
}
``

So here’s what I did. First the default.nix:

with import <nixpkgs> {};

buildGoPackage {
  name = "docopts";
  src = fetchFromGitHub {
    owner = "docopt";
    repo = "docopts";
    rev = "dab1ec98c9b2c9f36abcde5b9780d041dfc11b0f";
    sha256 = "06dyhcbh5s70i9fzwayr16c2fpyv7iw0qigjxz48pm3xrpkb4c5l";
  };
  goPackagePath = [ "github.com/docopt/docopts" ];
  goDeps = ./deps.nix;
}

I made the ´deps.nix´ by cloning the docopts repo, then running go mod init; go build; vgo2nix.

It looks like this:

# file generated from go.mod using vgo2nix (https://github.com/adisbladis/vgo2nix)
[
  {
    goPackagePath = "github.com/docopt/docopt-go";
    fetch = {
      type = "git";
      url = "https://github.com/docopt/docopt-go";
      rev = "ee0de3bc6815";
      sha256 = "0hlra7rmi5pmd7d93rv56ahiy4qkgmq8a6mz0jpadvbi5qh8lq6j";
    };
  }
]

Once you run nix-build, you’ll get a ./result-bin/bin/docopts.
Hope that helps.

1 Like

Thanks a lot! I’ve got some questions here about the choices made. I would’ve assumed that ./deps.nix would be replaceable by the contents of ./deps.nix, but I get a cannot coerce a list to a string. So goDeps expects a path, which it thinks is a string, but goDeps = ./deps.nix; doesn’t look like a string. Is there some sugar I’m missing here?

That’s an artifact of how import works. Which is how the goDeps is loaded, it doesn’t check whether it’s a list first, it just tries to import it. And paths are basically strings, see https://nixos.org/nix/manual/#ch-expression-language for a bit more info.