From 78ca29dd23a327f5199ad263ea057d701ddefed6 Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Thu, 21 Nov 2019 10:55:10 +0000 Subject: feat(buildGo): Introduce Bazel-style Nix builders for Go --- overrides/buildGo.nix | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 overrides/buildGo.nix (limited to 'overrides') diff --git a/overrides/buildGo.nix b/overrides/buildGo.nix new file mode 100644 index 0000000000..e6531393db --- /dev/null +++ b/overrides/buildGo.nix @@ -0,0 +1,169 @@ +# buildGo provides Nix functions to build Go packages in the style of Bazel's +# rules_go. +# +# TODO(tazjin): Go through Bazel rules_go options and implement corresponding flags +# TODO(tazjin): Refactor to include /golang/protobuf/descriptor in goProto deps + +{ pkgs, ... }@args: + +let + inherit (builtins) + attrNames + baseNameOf + currentSystem + filter + isString + head + map + match + readDir + toFile + toPath + toString; + + inherit (pkgs) bash lib go runCommand fetchFromGitHub protobuf; + + # Helpers for low-level Go compiler invocations + spaceOut = lib.concatStringsSep " "; + + includeDepSrc = dep: "-I ${dep}"; + includeSources = deps: spaceOut (map includeDepSrc deps); + + includeDepLib = dep: "-L ${dep}"; + includeLibs = deps: spaceOut (map includeDepLib deps); + + srcBasename = src: head (filter isString (match "([a-z0-9]{32}\-)?(.*\.go)" (baseNameOf src))); + srcCopy = path: src: "cp ${src} $out/${path}/${srcBasename src}"; + srcList = path: srcs: lib.concatStringsSep "\n" (map (srcCopy path) srcs); + + isGoFile = f: (match ".*\.go" f) != null; + isGoTest = f: (match ".*_test\.go" f) != null; + goFileFilter = k: v: (v == "regular") && (isGoFile k) && (!isGoTest k); + goFilesIn = dir: + let files = readDir dir; + goFiles = filter (f: goFileFilter f files."${f}") (attrNames files); + in map (f: dir + "/" + f) goFiles; + + allDeps = deps: lib.unique (lib.flatten (deps ++ (map (d: d.goDeps) deps))); + + # High-level build functions + + # Build a Go program out of the specified files and dependencies. + program = { name, srcs, deps ? [] }: + let uniqueDeps = allDeps deps; + in runCommand name {} '' + ${go}/bin/go tool compile -o ${name}.a -trimpath=$PWD ${includeSources uniqueDeps} ${spaceOut srcs} + mkdir -p $out/bin + ${go}/bin/go tool link -o $out/bin/${name} ${includeLibs uniqueDeps} ${name}.a + ''; + + # Build a Go library assembled out of the specified files. + # + # This outputs both the sources and compiled binary, as both are + # needed when downstream packages depend on it. + package = { name, srcs, deps ? [], path ? name }: + let uniqueDeps = allDeps deps; + in (runCommand "golib-${name}" {} '' + mkdir -p $out/${path} + ${srcList path (map (s: "${s}") srcs)} + ${go}/bin/go tool compile -o $out/${path}.a -trimpath=$PWD -p ${path} ${includeSources uniqueDeps} ${spaceOut srcs} + '') // { goDeps = uniqueDeps; }; + + # Build a Go library out of the specified proto/gRPC file. + proto = { name, proto, path ? name }: package { + inherit name path; + deps = [ goProto ]; + srcs = lib.singleton (runCommand "goproto-${name}.pb.go" {} '' + cp ${proto} ${baseNameOf proto} + ${protobuf}/bin/protoc --plugin=${protocGo}/bin/protoc-gen-go \ + --go_out=import_path=${baseNameOf path}:. ${baseNameOf proto} + mv *.pb.go $out + ''); + }; + + # Protobuf & gRPC integration requires these dependencies: + proto-go-src = fetchFromGitHub { + owner = "golang"; + repo = "protobuf"; + rev = "ed6926b37a637426117ccab59282c3839528a700"; + sha256 = "0fynqrim022x9xi2bivkw19npbz4316v4yr7mb677s9s36z4dc4h"; + }; + + goProto = + let + protobuf = package { + name = "protobuf"; + path = "github.com/golang/protobuf/proto"; + srcs = filter + (f: (match "(.*)/pointer_reflect.go" f) == null) + (goFilesIn (toPath "${proto-go-src}/proto")); + }; + type = name: package { + name = "ptypes-${name}"; + path = "github.com/golang/protobuf/ptypes/${name}"; + srcs = goFilesIn (toPath "${proto-go-src}/ptypes/${name}"); + deps = [ protobuf ]; + }; + # descriptor = package { + # name = "descriptor"; + # path = "github.com/golang/protobuf/descriptor"; + # deps = [ protobuf ]; + # srcs = goFilesIn (toPath "${proto-go-src}/descriptor"); + # }; + ptypes = package { + name = "ptypes"; + path = "github.com/golang/protobuf/ptypes"; + srcs = goFilesIn (toPath "${proto-go-src}/ptypes"); + deps = map type [ + "any" + "duration" + "empty" + "struct" + "timestamp" + "wrappers" + ]; + }; + in protobuf // { goDeps = allDeps (protobuf.goDeps ++ [ ptypes ]); }; + + protocGo = + let + descriptor = package { + name = "descriptor"; + path = "github.com/golang/protobuf/protoc-gen-go/descriptor"; + srcs = goFilesIn (toPath "${proto-go-src}/protoc-gen-go/descriptor"); + deps = [ goProto ]; + }; + plugin = package { + name = "plugin"; + path = "github.com/golang/protobuf/protoc-gen-go/plugin"; + srcs = goFilesIn (toPath "${proto-go-src}/protoc-gen-go/plugin"); + deps = [ descriptor ]; + }; + remap = package { + name = "remap"; + path = "github.com/golang/protobuf/protoc-gen-go/generator/internal/remap"; + srcs = goFilesIn (toPath "${proto-go-src}/protoc-gen-go/generator/internal/remap"); + }; + generator = package { + name = "generator"; + path = "github.com/golang/protobuf/protoc-gen-go/generator"; + srcs = goFilesIn (toPath "${proto-go-src}/protoc-gen-go/generator"); + deps = [ descriptor remap plugin ]; + }; + grpc = package { + name = "grpc"; + path = "github.com/golang/protobuf/protoc-gen-go/grpc"; + deps = [ generator ]; + srcs = goFilesIn (toPath "${proto-go-src}/protoc-gen-go/grpc"); + }; + in program { + name = "protoc-gen-go"; + deps = [ goProto grpc generator ]; + srcs = filter + (f: (match "(.*)/doc.go" f) == null) + (goFilesIn (toPath "${proto-go-src}/protoc-gen-go")); + }; +in { + # Only the high-level builder functions are exposed + inherit program package proto; +} -- cgit 1.4.1