about summary refs log tree commit diff
path: root/buildGo.nix
diff options
context:
space:
mode:
authorVincent Ambo <tazjin@google.com>2019-11-24T20·17+0000
committerVincent Ambo <tazjin@google.com>2019-11-24T20·17+0000
commitd441e035aabac877948f754289b3ab028408550b (patch)
treeb634459ce505c92a6e24efb08254a00535f9e05c /buildGo.nix
parent24225580e8dd6dbbb930e01d0b4947f2feaa70c7 (diff)
feat: Add support for Protobuf-generated libraries
Adds a 'buildGo.proto' function which takes a single .proto file as
its source and generates a corresponding Go library which can then be
imported.

'proto' takes these arguments (Yants-style type definition):

struct "protoArgs" {
  # required:
  name = string;
  proto = path;

  # optional:
  extraDeps = list goLib; # defaults to [ ]
  protocFlags = option string;
}

Note that proto libraries will automatically have dependencies for the
required protobuf Go libraries added to them.

gRPC is not (yet) supported.
Diffstat (limited to 'buildGo.nix')
-rw-r--r--buildGo.nix78
1 files changed, 75 insertions, 3 deletions
diff --git a/buildGo.nix b/buildGo.nix
index 090627c591..029271f2f7 100644
--- a/buildGo.nix
+++ b/buildGo.nix
@@ -15,9 +15,11 @@ let
     filter
     map
     match
-    readDir;
+    readDir
+    replaceStrings
+    toPath;
 
-  inherit (pkgs) lib go runCommand;
+  inherit (pkgs) lib go runCommand fetchFromGitHub protobuf;
 
   # Helpers for low-level Go compiler invocations
   spaceOut = lib.concatStringsSep " ";
@@ -64,7 +66,77 @@ let
     ${srcList path (map (s: "${s}") srcs)}
     ${go}/bin/go tool compile -o $out/${path}.a -trimpath=$PWD -trimpath=${go} -p ${path} ${includeSources uniqueDeps} ${spaceOut srcs}
   '') // { goDeps = uniqueDeps; };
+
+  # Build a Go library out of the specified protobuf definition.
+  proto = { name, proto, path ? name, protocFlags ? "", extraDeps ? [] }: package {
+    inherit name path;
+    deps = [ goProto ] ++ extraDeps;
+    srcs = lib.singleton (runCommand "goproto-${name}.pb.go" {} ''
+      cp ${proto} ${baseNameOf proto}
+      ${protobuf}/bin/protoc --plugin=${protocGo}/bin/protoc-gen-go \
+        --go_out=${protocFlags}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";
+  };
+
+  protoPart = path: deps: package {
+    inherit deps;
+    name = replaceStrings ["/"] ["_"] path;
+    path = "github.com/golang/protobuf/${path}";
+    srcs = goFilesIn (toPath "${proto-go-src}/${path}");
+  };
+
+  goProto =
+    let
+      protobuf = package {
+        name = "protobuf";
+        path = "github.com/golang/protobuf/proto";
+        # TODO(tazjin): How does this build toggle work?
+        srcs = filter
+          (f: (match "(.*)/pointer_reflect.go" f) == null)
+          (goFilesIn (toPath "${proto-go-src}/proto"));
+      };
+      type = name: protoPart "ptypes/${name}" [ protobuf ];
+      descriptor = protoPart "descriptor" [ protobuf ];
+      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 ]); };
+
+  protocDescriptor = (protoPart "protoc-gen-go/descriptor" [ goProto ]);
+  protocGo =
+    let
+      generator = protoPart "protoc-gen-go/generator" [
+        (protoPart "protoc-gen-go/generator/internal/remap" [])
+        (protoPart "protoc-gen-go/plugin" [ protocDescriptor ])
+      ];
+      grpc = protoPart "protoc-gen-go/grpc" [ generator ];
+    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;
+  inherit program package proto;
 }