From a4bed25a864cd226569f655f8b1c17c0ccb28079 Mon Sep 17 00:00:00 2001 From: adisbladis Date: Mon, 13 Jun 2022 17:56:48 +0800 Subject: [PATCH] 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. --- builder/default.nix | 129 +++++++++++++++++++++++++++++++++----------- builder/install.go | 57 ++++++++++++++++++++ go.mod | 2 +- go.sum | 2 - gomod2nix.toml | 4 +- overlay.nix | 2 +- 6 files changed, 158 insertions(+), 38 deletions(-) create mode 100644 builder/install.go diff --git a/builder/default.nix b/builder/default.nix index 77a419d..3f2caa5 100644 --- a/builder/default.nix +++ b/builder/default.nix @@ -33,6 +33,96 @@ let 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 = { modules , go ? pkgs.go @@ -64,39 +154,12 @@ let in 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; + vendorEnv = mkVendorEnv { + inherit go modulesStruct localReplaceCommands; + }; + package = stdenv.mkDerivation (attrs // { nativeBuildInputs = [ removeReferencesTo go ] ++ nativeBuildInputs; @@ -230,4 +293,6 @@ let package; in -buildGoApplication +{ + inherit buildGoApplication mkGoEnv; +} diff --git a/builder/install.go b/builder/install.go new file mode 100644 index 0000000..4f770b0 --- /dev/null +++ b/builder/install.go @@ -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) + } + } +} diff --git a/go.mod b/go.mod index 12c959a..b2db4d3 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( 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 golang.org/x/mod v0.5.1 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect diff --git a/go.sum b/go.sum index 455542d..aeb765e 100644 --- a/go.sum +++ b/go.sum @@ -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/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-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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= diff --git a/gomod2nix.toml b/gomod2nix.toml index 968d573..c8322ea 100644 --- a/gomod2nix.toml +++ b/gomod2nix.toml @@ -29,8 +29,8 @@ schema = 1 version = "v0.1.0" hash = "sha256-QT65kTrNypS5GPWGvgnCpGLPlVbQAL4IYvuqAKhepb4=" [mod."github.com/nix-community/go-nix"] - version = "v0.0.0-20220531154832-fb763dcb3ffc" - hash = "sha256-vCoRCe1DcyNXfz6gun9wGBu/o+j6WGcS8mbFmXZfyps=" + version = "v0.0.0-20220528121639-b940fb0a12d8" + hash = "sha256-r6fq1mu0gRFqdI6msuAZp3ZoncAw5L16oBFPUA9vPYk=" [mod."github.com/pkg/errors"] version = "v0.9.1" hash = "sha256-mNfQtcrQmu3sNg/7IwiieKWOgFQOVVe2yXgKBpe/wZw=" diff --git a/overlay.nix b/overlay.nix index 617ce4f..d878444 100644 --- a/overlay.nix +++ b/overlay.nix @@ -1,4 +1,4 @@ final: prev: { - buildGoApplication = final.callPackage ./builder { }; + inherit (final.callPackage ./builder { }) buildGoApplication mkGoEnv; gomod2nix = final.callPackage ./default.nix { }; }