From 29595e28e991b29828eec0ad582ea2e9916ca47c Mon Sep 17 00:00:00 2001 From: Michael Kipper Date: Tue, 19 Feb 2019 20:58:46 -0500 Subject: [PATCH 1/4] Fixed a typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e3d99ff..85d0897 100644 --- a/README.md +++ b/README.md @@ -191,7 +191,7 @@ name. For projects that use `gogo_protobuf`, e.g. envoy, this can be very confusing. -To resolve this, use the package `github.com/stripe/skycfg/gogocopmat` +To resolve this, use the package `github.com/stripe/skycfg/gogocompat` in your go code. This will allow skycfg code to load `proto.package("gogo:google.protobuf") and the internal registry it creates will handle the conversion of these types. From 7d09cd78a3850e91913a5c0a2f0b02c22beaca14 Mon Sep 17 00:00:00 2001 From: Michael Kipper Date: Tue, 19 Feb 2019 20:58:57 -0500 Subject: [PATCH 2/4] Added proto.to_any() --- internal/go/skycfg/proto_api.go | 16 ++++++++++++++++ internal/go/skycfg/proto_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/internal/go/skycfg/proto_api.go b/internal/go/skycfg/proto_api.go index 806ddf9..bfb9b9c 100644 --- a/internal/go/skycfg/proto_api.go +++ b/internal/go/skycfg/proto_api.go @@ -25,6 +25,7 @@ import ( "github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" "go.starlark.net/starlark" yaml "gopkg.in/yaml.v2" ) @@ -53,6 +54,7 @@ func NewProtoModule(registry ProtoRegistry) *ProtoModule { "merge": starlark.NewBuiltin("proto.merge", fnProtoMerge), "set_defaults": starlark.NewBuiltin("proto.set_defaults", fnProtoSetDefaults), "to_json": starlark.NewBuiltin("proto.to_json", fnProtoToJson), + "to_any": starlark.NewBuiltin("proto.to_any", fnProtoToAny), "to_text": starlark.NewBuiltin("proto.to_text", fnProtoToText), "to_yaml": starlark.NewBuiltin("proto.to_yaml", fnProtoToYaml), }, @@ -234,6 +236,20 @@ func fnProtoToJson(t *starlark.Thread, fn *starlark.Builtin, args starlark.Tuple return starlark.String(jsonData), nil } +func fnProtoToAny(t *starlark.Thread, fn *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { + var msg *skyProtoMessage + if err := wantSingleProtoMessage("proto.to_any", args, kwargs, &msg); err != nil { + return nil, err + } + + any, err := ptypes.MarshalAny(msg.msg) + if err != nil { + return nil, err + } + + return NewSkyProtoMessage(any), nil +} + // Implementation of the `proto.to_yaml()` built-in function. Returns the // YAML-formatted content of a protobuf message. func fnProtoToYaml(t *starlark.Thread, fn *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { diff --git a/internal/go/skycfg/proto_test.go b/internal/go/skycfg/proto_test.go index 8b7fdd6..f885114 100644 --- a/internal/go/skycfg/proto_test.go +++ b/internal/go/skycfg/proto_test.go @@ -27,6 +27,8 @@ import ( gogo_proto "github.com/gogo/protobuf/proto" "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "github.com/golang/protobuf/ptypes/any" "github.com/kylelemons/godebug/pretty" "go.starlark.net/resolve" "go.starlark.net/starlark" @@ -288,6 +290,29 @@ func TestProtoToJsonFull(t *testing.T) { } } +func TestProtoToAny(t *testing.T) { + val := skyEval(t, `proto.to_any(proto.package("skycfg.test_proto").MessageV3( + f_string = "some string", + ))`) + myAny := val.(*skyProtoMessage).msg.(*any.Any) + + want := "type.googleapis.com/skycfg.test_proto.MessageV3" + if want != myAny.GetTypeUrl() { + t.Fatalf("to_any: wanted %q, got %q", want, myAny.GetTypeUrl()) + } + + msg := pb.MessageV3{} + err := ptypes.UnmarshalAny(myAny, &msg) + if err != nil { + log.Fatalf("to_any: could not unmarshal: %v", err) + } + + want = "some string" + if want != msg.GetFString() { + log.Fatalf("to_any: wanted %q, got %q", want, msg.GetFString()) + } +} + func TestProtoToYaml(t *testing.T) { val := skyEval(t, `proto.to_yaml(proto.package("skycfg.test_proto").MessageV3( f_string = "some string", From 0e62c3e091aae7a73bf4ec8c892b7e3966f90f29 Mon Sep 17 00:00:00 2001 From: Michael Kipper Date: Wed, 20 Feb 2019 07:41:04 -0500 Subject: [PATCH 3/4] Use gogo --- internal/go/skycfg/proto_api.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/go/skycfg/proto_api.go b/internal/go/skycfg/proto_api.go index bfb9b9c..108089f 100644 --- a/internal/go/skycfg/proto_api.go +++ b/internal/go/skycfg/proto_api.go @@ -25,9 +25,9 @@ import ( "github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes" + "github.com/gogo/protobuf/types" "go.starlark.net/starlark" - yaml "gopkg.in/yaml.v2" + "gopkg.in/yaml.v2" ) // UNSTABLE extension point for configuring how protobuf messages are loaded. @@ -242,7 +242,7 @@ func fnProtoToAny(t *starlark.Thread, fn *starlark.Builtin, args starlark.Tuple, return nil, err } - any, err := ptypes.MarshalAny(msg.msg) + any, err := types.MarshalAny(msg.msg) if err != nil { return nil, err } From 2634aa8109cf9d939aac5e55776cf48b2f86ac62 Mon Sep 17 00:00:00 2001 From: Michael Kipper Date: Wed, 20 Feb 2019 09:19:44 -0500 Subject: [PATCH 4/4] Support V2/V3/Gogo message types --- internal/go/skycfg/proto_api.go | 21 +++++++++++-- internal/go/skycfg/proto_test.go | 53 ++++++++++++++++++++++++++++++-- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/internal/go/skycfg/proto_api.go b/internal/go/skycfg/proto_api.go index 108089f..5ce1dd9 100644 --- a/internal/go/skycfg/proto_api.go +++ b/internal/go/skycfg/proto_api.go @@ -23,9 +23,11 @@ import ( "reflect" "sort" + gogo_proto "github.com/gogo/protobuf/proto" + gogo_types "github.com/gogo/protobuf/types" "github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/proto" - "github.com/gogo/protobuf/types" + "github.com/golang/protobuf/ptypes" "go.starlark.net/starlark" "gopkg.in/yaml.v2" ) @@ -236,13 +238,26 @@ func fnProtoToJson(t *starlark.Thread, fn *starlark.Builtin, args starlark.Tuple return starlark.String(jsonData), nil } +// Implementation of the `proto.to_any()` built-in function. Returns a +// skyProtoMessage with an `Any` proto.Message in it. func fnProtoToAny(t *starlark.Thread, fn *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { var msg *skyProtoMessage - if err := wantSingleProtoMessage("proto.to_any", args, kwargs, &msg); err != nil { + err := wantSingleProtoMessage("proto.to_any", args, kwargs, &msg) + if err != nil { return nil, err } - any, err := types.MarshalAny(msg.msg) + // Disambiguate between golang and gogo encoded proto messages. + var any proto.Message + if "" != proto.MessageName(msg.msg) { + // Returns a golang any.Any type. + any, err = ptypes.MarshalAny(msg.msg) + } else if "" != gogo_proto.MessageName(msg.msg) { + // Returns a gogo types.Any type. + any, err = gogo_types.MarshalAny(msg.msg) + } else { + return nil, fmt.Errorf("%s: could not get message name for %s", "proto.to_any", msg.Type()) + } if err != nil { return nil, err } diff --git a/internal/go/skycfg/proto_test.go b/internal/go/skycfg/proto_test.go index f885114..6cec10c 100644 --- a/internal/go/skycfg/proto_test.go +++ b/internal/go/skycfg/proto_test.go @@ -26,6 +26,7 @@ import ( "time" gogo_proto "github.com/gogo/protobuf/proto" + gogo_types "github.com/gogo/protobuf/types" "github.com/golang/protobuf/proto" "github.com/golang/protobuf/ptypes" "github.com/golang/protobuf/ptypes/any" @@ -290,7 +291,53 @@ func TestProtoToJsonFull(t *testing.T) { } } -func TestProtoToAny(t *testing.T) { +func TestProtoToAnyGogo(t *testing.T) { + val := skyEval(t, `proto.to_any(gogo_proto.package("skycfg.test_proto").MessageGogo( + f_string = "some string", + ))`) + myAny := val.(*skyProtoMessage).msg.(*gogo_types.Any) + + want := "type.googleapis.com/skycfg.test_proto.MessageGogo" + if want != myAny.GetTypeUrl() { + t.Fatalf("to_any: wanted %q, got %q", want, myAny.GetTypeUrl()) + } + + msg := pb.MessageGogo{} + err := gogo_types.UnmarshalAny(myAny, &msg) + if err != nil { + t.Fatalf("to_any: could not unmarshal: %v", err) + } + + want = "some string" + if want != msg.GetFString() { + t.Fatalf("to_any: wanted %q, got %q", want, msg.GetFString()) + } +} + +func TestProtoToAnyV2(t *testing.T) { + val := skyEval(t, `proto.to_any(proto.package("skycfg.test_proto").MessageV2( + f_string = "some string", + ))`) + myAny := val.(*skyProtoMessage).msg.(*any.Any) + + want := "type.googleapis.com/skycfg.test_proto.MessageV2" + if want != myAny.GetTypeUrl() { + t.Fatalf("to_any: wanted %q, got %q", want, myAny.GetTypeUrl()) + } + + msg := pb.MessageV2{} + err := ptypes.UnmarshalAny(myAny, &msg) + if err != nil { + t.Fatalf("to_any: could not unmarshal: %v", err) + } + + want = "some string" + if want != msg.GetFString() { + t.Fatalf("to_any: wanted %q, got %q", want, msg.GetFString()) + } +} + +func TestProtoToAnyV3(t *testing.T) { val := skyEval(t, `proto.to_any(proto.package("skycfg.test_proto").MessageV3( f_string = "some string", ))`) @@ -304,12 +351,12 @@ func TestProtoToAny(t *testing.T) { msg := pb.MessageV3{} err := ptypes.UnmarshalAny(myAny, &msg) if err != nil { - log.Fatalf("to_any: could not unmarshal: %v", err) + t.Fatalf("to_any: could not unmarshal: %v", err) } want = "some string" if want != msg.GetFString() { - log.Fatalf("to_any: wanted %q, got %q", want, msg.GetFString()) + t.Fatalf("to_any: wanted %q, got %q", want, msg.GetFString()) } }