Add mkGoEnv function

This creates an `mkGoEnv` function which takes care of adding the
correct Go package to your development environment and installs
development dependencies from tools.go in a Nix derivation.

The "normal" workflow around Go with tools.go just sticks development
dependencies in $GOBIN which isn't ideal since you have no separation
between projects.
This commit is contained in:
adisbladis 2022-06-13 17:56:48 +08:00
parent d7830bd5b2
commit a4bed25a86
6 changed files with 158 additions and 38 deletions

View file

@ -33,6 +33,96 @@ let
impureEnvVars = lib.fetchers.proxyImpureEnvVars ++ [ "GOPROXY" ]; impureEnvVars = lib.fetchers.proxyImpureEnvVars ++ [ "GOPROXY" ];
}; };
mkVendorEnv = { go, modulesStruct, localReplaceCommands ? [ ] }: runCommand "vendor-env"
{
nativeBuildInputs = [ go ];
json = builtins.toJSON modulesStruct;
sources = builtins.toJSON (
lib.mapAttrs
(goPackagePath: meta: fetchGoModule {
goPackagePath = meta.replaced or goPackagePath;
inherit (meta) version hash;
inherit go;
})
modulesStruct.mod
);
passAsFile = [ "json" "sources" ];
}
(
''
mkdir vendor
export GOCACHE=$TMPDIR/go-cache
export GOPATH="$TMPDIR/go"
go run ${./symlink.go}
${lib.concatStringsSep "\n" localReplaceCommands}
mv vendor $out
''
);
mkGoEnv =
{ pwd
}@attrs:
let
goMod = parseGoMod (builtins.readFile "${builtins.toString pwd}/go.mod");
modulesStruct = builtins.fromTOML (builtins.readFile "${builtins.toString pwd}/gomod2nix.toml");
go = attrs.go or (
let
goVersion = goMod.go;
goAttr = "go_" + (lib.replaceStrings [ "." ] [ "_" ] goVersion);
in
(
if builtins.hasAttr goAttr pkgs then pkgs.${goAttr}
else builtins.trace "go.mod specified Go version ${goVersion} but doesn't exist. Falling back to ${pkgs.go.version}." pkgs.go
)
);
vendorEnv = mkVendorEnv {
inherit go modulesStruct;
};
in
stdenv.mkDerivation {
name = "${builtins.baseNameOf goMod.module}-env";
dontUnpack = true;
dontConfigure = true;
dontInstall = true;
propagatedNativeBuildInputs = [ go ];
GO_NO_VENDOR_CHECKS = "1";
GO111MODULE = "on";
GOFLAGS = "-mod=vendor";
preferLocalBuild = true;
buildPhase = ''
mkdir $out
export GOCACHE=$TMPDIR/go-cache
export GOPATH="$out"
export GOSUMDB=off
export GOPROXY=off
'' + lib.optionalString (lib.pathExists (pwd + "/tools./.go")) ''
mkdir source
cp ${pwd + "/go.mod"} source/go.mod
cp ${pwd + "/go.sum"} source/go.sum
cp ${pwd + "/tools.go"} source/tools.go
cd source
ln -s ${vendorEnv} vendor
go run ${./install.go}
'';
};
buildGoApplication = buildGoApplication =
{ modules { modules
, go ? pkgs.go , go ? pkgs.go
@ -64,39 +154,12 @@ let
in in
if pwd != null then commands else [ ]; if pwd != null then commands else [ ];
vendorEnv = runCommand "vendor-env"
{
nativeBuildInputs = [ go ];
json = builtins.toJSON modulesStruct;
sources = builtins.toJSON (
lib.mapAttrs
(goPackagePath: meta: fetchGoModule {
goPackagePath = meta.replaced or goPackagePath;
inherit (meta) version hash;
inherit go;
})
modulesStruct.mod
);
passAsFile = [ "json" "sources" ];
}
(
''
mkdir vendor
export GOCACHE=$TMPDIR/go-cache
export GOPATH="$TMPDIR/go"
go run ${./symlink.go}
${lib.concatStringsSep "\n" localReplaceCommands}
mv vendor $out
''
);
removeReferences = [ ] ++ lib.optional (!allowGoReference) go; removeReferences = [ ] ++ lib.optional (!allowGoReference) go;
vendorEnv = mkVendorEnv {
inherit go modulesStruct localReplaceCommands;
};
package = stdenv.mkDerivation (attrs // { package = stdenv.mkDerivation (attrs // {
nativeBuildInputs = [ removeReferencesTo go ] ++ nativeBuildInputs; nativeBuildInputs = [ removeReferencesTo go ] ++ nativeBuildInputs;
@ -230,4 +293,6 @@ let
package; package;
in in
buildGoApplication {
inherit buildGoApplication mkGoEnv;
}

57
builder/install.go Normal file
View file

@ -0,0 +1,57 @@
package main
import (
"fmt"
"go/parser"
"go/token"
"io"
"os"
"os/exec"
"strconv"
)
const filename = "tools.go"
func main() {
fset := token.NewFileSet()
var src []byte
{
f, err := os.Open(filename)
if err != nil {
panic(err)
}
src, err = io.ReadAll(f)
if err != nil {
panic(err)
}
}
f, err := parser.ParseFile(fset, filename, src, parser.ImportsOnly)
if err != nil {
fmt.Println(err)
return
}
for _, s := range f.Imports {
path, err := strconv.Unquote(s.Path.Value)
if err != nil {
panic(err)
}
cmd := exec.Command("go", "install", path)
fmt.Printf("Executing '%s'\n", cmd)
err = cmd.Start()
if err != nil {
panic(err)
}
err = cmd.Wait()
if err != nil {
panic(err)
}
}
}

2
go.mod
View file

@ -4,7 +4,7 @@ go 1.14
require ( require (
github.com/BurntSushi/toml v1.1.0 github.com/BurntSushi/toml v1.1.0
github.com/nix-community/go-nix v0.0.0-20220531154832-fb763dcb3ffc github.com/nix-community/go-nix v0.0.0-20220528121639-b940fb0a12d8
github.com/sirupsen/logrus v1.8.1 github.com/sirupsen/logrus v1.8.1
golang.org/x/mod v0.5.1 golang.org/x/mod v0.5.1
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect

2
go.sum
View file

@ -15,8 +15,6 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/nix-community/go-nix v0.0.0-20220528121639-b940fb0a12d8 h1:IYr+3pldQtTwS55Xm2+3Ry81MpSKNVpMyYMNr7yQpts= github.com/nix-community/go-nix v0.0.0-20220528121639-b940fb0a12d8 h1:IYr+3pldQtTwS55Xm2+3Ry81MpSKNVpMyYMNr7yQpts=
github.com/nix-community/go-nix v0.0.0-20220528121639-b940fb0a12d8/go.mod h1:r5pCQAjHNSDWTsy6+UbacPN8EzMVJiCAXDWbRN2qfwU= github.com/nix-community/go-nix v0.0.0-20220528121639-b940fb0a12d8/go.mod h1:r5pCQAjHNSDWTsy6+UbacPN8EzMVJiCAXDWbRN2qfwU=
github.com/nix-community/go-nix v0.0.0-20220531154832-fb763dcb3ffc h1:/uRl4vxjqF0N8m8ha+TouWZxsMRCA98Fft24WNIb0L8=
github.com/nix-community/go-nix v0.0.0-20220531154832-fb763dcb3ffc/go.mod h1:r5pCQAjHNSDWTsy6+UbacPN8EzMVJiCAXDWbRN2qfwU=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=

View file

@ -29,8 +29,8 @@ schema = 1
version = "v0.1.0" version = "v0.1.0"
hash = "sha256-QT65kTrNypS5GPWGvgnCpGLPlVbQAL4IYvuqAKhepb4=" hash = "sha256-QT65kTrNypS5GPWGvgnCpGLPlVbQAL4IYvuqAKhepb4="
[mod."github.com/nix-community/go-nix"] [mod."github.com/nix-community/go-nix"]
version = "v0.0.0-20220531154832-fb763dcb3ffc" version = "v0.0.0-20220528121639-b940fb0a12d8"
hash = "sha256-vCoRCe1DcyNXfz6gun9wGBu/o+j6WGcS8mbFmXZfyps=" hash = "sha256-r6fq1mu0gRFqdI6msuAZp3ZoncAw5L16oBFPUA9vPYk="
[mod."github.com/pkg/errors"] [mod."github.com/pkg/errors"]
version = "v0.9.1" version = "v0.9.1"
hash = "sha256-mNfQtcrQmu3sNg/7IwiieKWOgFQOVVe2yXgKBpe/wZw=" hash = "sha256-mNfQtcrQmu3sNg/7IwiieKWOgFQOVVe2yXgKBpe/wZw="

View file

@ -1,4 +1,4 @@
final: prev: { final: prev: {
buildGoApplication = final.callPackage ./builder { }; inherit (final.callPackage ./builder { }) buildGoApplication mkGoEnv;
gomod2nix = final.callPackage ./default.nix { }; gomod2nix = final.callPackage ./default.nix { };
} }