diff --git a/upbc/BUILD b/upbc/BUILD index 40f4ed9eeb..b4d47970af 100644 --- a/upbc/BUILD +++ b/upbc/BUILD @@ -25,6 +25,7 @@ load( "//bazel:build_defs.bzl", + "UPB_DEFAULT_COPTS", "UPB_DEFAULT_CPPOPTS", ) load( @@ -133,6 +134,31 @@ cc_library( ], ) +cc_library( + name = "upbdev", + srcs = [ + "code_generator_request.c", + "code_generator_request.h", + "upbdev.c", + ], + hdrs = [ + "upbdev.h", + ], + copts = UPB_DEFAULT_COPTS, + visibility = ["//visibility:public"], + deps = [ + ":code_generator_request_upb_proto", + ":code_generator_request_upb_proto_reflection", + ":plugin_upb_proto", + ":plugin_upb_proto_reflection", + "//:base", + "//:json", + "//:mem", + "//:port", + "//:reflection", + ], +) + cc_binary( name = "protoc-gen-upb", srcs = ["protoc-gen-upb.cc"], @@ -169,8 +195,6 @@ cc_binary( cc_binary( name = "protoc-gen-upbdev", srcs = [ - "code_generator_request.c", - "code_generator_request.h", "protoc-gen-upbdev.cc", "subprocess.cc", "subprocess.h", @@ -182,16 +206,9 @@ cc_binary( }), visibility = ["//visibility:public"], deps = [ - ":code_generator_request_upb_proto", - ":code_generator_request_upb_proto_reflection", ":plugin_upb_proto", - ":plugin_upb_proto_reflection", - "//:json", - "//:mini_table", - "//:mini_table_internal", + ":upbdev", "//:port", - "//:reflection", - "//:upb", "@com_google_absl//absl/strings", ], ) diff --git a/upbc/code_generator_request.h b/upbc/code_generator_request.h index 1d01927fee..fc10e8a9e0 100644 --- a/upbc/code_generator_request.h +++ b/upbc/code_generator_request.h @@ -28,8 +28,8 @@ #ifndef UPBC_CODE_GENERATOR_REQUEST_H_ #define UPBC_CODE_GENERATOR_REQUEST_H_ +#include "upb/mem/arena.h" #include "upb/reflection/def.h" -#include "upb/upb.h" #include "upbc/code_generator_request.upb.h" // Must be last. diff --git a/upbc/protoc-gen-upbdev.cc b/upbc/protoc-gen-upbdev.cc index ca79a40574..61e2fdd574 100644 --- a/upbc/protoc-gen-upbdev.cc +++ b/upbc/protoc-gen-upbdev.cc @@ -23,75 +23,19 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include - #include #include #include "google/protobuf/compiler/plugin.upb.h" -#include "google/protobuf/compiler/plugin.upbdefs.h" -#include "upb/json/decode.h" -#include "upb/json/encode.h" -#include "upb/reflection/def.h" -#include "upb/upb.h" -#include "upbc/code_generator_request.h" -#include "upbc/code_generator_request.upb.h" -#include "upbc/code_generator_request.upbdefs.h" #include "upbc/subprocess.h" +#include "upbc/upbdev.h" static constexpr char kDefaultPlugin[] = "protoc_dart_plugin"; -static std::string JsonEncode(const upbc_CodeGeneratorRequest* request, - upb_Arena* a) { - upb_DefPool* s = upb_DefPool_New(); - const upb_MessageDef* m = upbc_CodeGeneratorRequest_getmsgdef(s); - - upb_Status status; - upb_Status_Clear(&status); - - const size_t json_size = upb_JsonEncode(request, m, s, 0, NULL, 0, &status); - assert(upb_Status_IsOk(&status)); - - char* json_buf = (char*)upb_Arena_Malloc(a, json_size + 1); - - (void)upb_JsonEncode(request, m, s, 0, json_buf, json_size + 1, &status); - assert(upb_Status_IsOk(&status)); - - upb_DefPool_Free(s); - - return std::string(json_buf, json_size); -} - -static google_protobuf_compiler_CodeGeneratorResponse* JsonDecode( - const std::string& json, upb_Arena* a) { - google_protobuf_compiler_CodeGeneratorResponse* response = - google_protobuf_compiler_CodeGeneratorResponse_new(a); - - upb_DefPool* s = upb_DefPool_New(); - const upb_MessageDef* m = google_protobuf_compiler_CodeGeneratorResponse_getmsgdef(s); - - upb_Status status; - upb_Status_Clear(&status); - - (void)upb_JsonDecode(json.c_str(), json.size(), response, m, s, 0, a, - &status); - assert(upb_Status_IsOk(&status)); - - upb_DefPool_Free(s); - - return response; -} - -static std::string Serialize( - const google_protobuf_compiler_CodeGeneratorResponse* response, upb_Arena* a) { - size_t len = 0; - const char* buf = - google_protobuf_compiler_CodeGeneratorResponse_serialize(response, a, &len); - return std::string(buf, len); -} - int main() { upb_Arena* a = upb_Arena_New(); + upb_Status status; + upb_Status_Clear(&status); // Read (binary) stdin into a string. const std::string input = {std::istreambuf_iterator(std::cin), @@ -108,22 +52,20 @@ int main() { plugin = std::string(param.data, param.size); } - // Wrap the request inside a upbc_CodeGeneratorRequest. - upb_Status status; - upb_Status_Clear(&status); - auto outer_request = upbc_MakeCodeGeneratorRequest(inner_request, a, &status); + // Wrap the request inside a upbc_CodeGeneratorRequest and JSON-encode it. + const upb_StringView sv = + upbdev_ProcessInput(input.data(), input.size(), a, &status); if (!upb_Status_IsOk(&status)) { std::cerr << status.msg << std::endl; return -1; } - const std::string json_request = JsonEncode(outer_request, a); - // Launch the subprocess. upbc::Subprocess subprocess; subprocess.Start(plugin, upbc::Subprocess::SEARCH_PATH); // Exchange JSON strings with the subprocess. + const std::string json_request = std::string(sv.data, sv.size); std::string json_response, error; const bool ok = subprocess.Communicate(json_request, &json_response, &error); if (!ok) { @@ -133,11 +75,14 @@ int main() { } // Decode and serialize the JSON response. - const auto response = JsonDecode(json_response, a); - const std::string output = Serialize(response, a); + const auto response = upbdev_ProcessOutput(json_response.data(), + json_response.size(), a, &status); + if (!upb_Status_IsOk(&status)) { + std::cerr << status.msg << std::endl; + return -1; + } - // Question: Is this sufficient for sending reliably to stdout? - std::cout << output; + std::cout << std::string(response.data, response.size); upb_Arena_Free(a); return 0; diff --git a/upbc/subprocess.cc b/upbc/subprocess.cc index 41ee7e57a2..9087d0faa9 100644 --- a/upbc/subprocess.cc +++ b/upbc/subprocess.cc @@ -42,9 +42,8 @@ #endif #include "absl/strings/substitute.h" -#include "upb/upb.h" -/* Must be last. */ +// Must be last. #include "upb/port/def.inc" namespace upbc { diff --git a/upbc/upbdev.c b/upbc/upbdev.c new file mode 100644 index 0000000000..8aa62f5507 --- /dev/null +++ b/upbc/upbdev.c @@ -0,0 +1,102 @@ +// Copyright (c) 2009-2022, Google LLC +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of Google LLC nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "upbc/upbdev.h" + +#include + +#include "google/protobuf/compiler/plugin.upb.h" +#include "google/protobuf/compiler/plugin.upbdefs.h" +#include "upb/base/status.h" +#include "upb/json/decode.h" +#include "upb/json/encode.h" +#include "upb/mem/arena.h" +#include "upbc/code_generator_request.h" +#include "upbc/code_generator_request.upb.h" +#include "upbc/code_generator_request.upbdefs.h" + +static google_protobuf_compiler_CodeGeneratorResponse* upbc_JsonDecode( + const char* data, size_t size, upb_Arena* a, upb_Status* status) { + google_protobuf_compiler_CodeGeneratorResponse* response = + google_protobuf_compiler_CodeGeneratorResponse_new(a); + + upb_DefPool* s = upb_DefPool_New(); + const upb_MessageDef* m = google_protobuf_compiler_CodeGeneratorResponse_getmsgdef(s); + + (void)upb_JsonDecode(data, size, response, m, s, 0, a, status); + if (!upb_Status_IsOk(status)) return NULL; + + upb_DefPool_Free(s); + + return response; +} + +static upb_StringView upbc_JsonEncode(const upbc_CodeGeneratorRequest* request, + upb_Arena* a, upb_Status* status) { + upb_StringView out = {.data = NULL, .size = 0}; + + upb_DefPool* s = upb_DefPool_New(); + const upb_MessageDef* m = upbc_CodeGeneratorRequest_getmsgdef(s); + + out.size = upb_JsonEncode(request, m, s, 0, NULL, 0, status); + if (!upb_Status_IsOk(status)) goto done; + + char* data = (char*)upb_Arena_Malloc(a, out.size + 1); + + (void)upb_JsonEncode(request, m, s, 0, data, out.size + 1, status); + if (!upb_Status_IsOk(status)) goto done; + + out.data = (const char*)data; + +done: + upb_DefPool_Free(s); + return out; +} + +upb_StringView upbdev_ProcessInput(const char* buf, size_t size, upb_Arena* a, + upb_Status* status) { + upb_StringView out = {.data = NULL, .size = 0}; + + google_protobuf_compiler_CodeGeneratorRequest* inner_request = + google_protobuf_compiler_CodeGeneratorRequest_parse(buf, size, a); + + const upbc_CodeGeneratorRequest* outer_request = + upbc_MakeCodeGeneratorRequest(inner_request, a, status); + if (upb_Status_IsOk(status)) out = upbc_JsonEncode(outer_request, a, status); + + return out; +} + +upb_StringView upbdev_ProcessOutput(const char* buf, size_t size, upb_Arena* a, + upb_Status* status) { + upb_StringView out = {.data = NULL, .size = 0}; + + int response = upbc_JsonDecode(buf, size, a, status); + if (upb_Status_IsOk(status)) { + out.data = + google_protobuf_compiler_CodeGeneratorResponse_serialize(response, a, &out.size); + } + return out; +} diff --git a/upbc/upbdev.h b/upbc/upbdev.h new file mode 100644 index 0000000000..0ee768a7b4 --- /dev/null +++ b/upbc/upbdev.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2009-2022, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UPBC_UPBDEV_H_ +#define UPBC_UPBDEV_H_ + +#include "upb/base/status.h" +#include "upb/base/string_view.h" +#include "upb/mem/arena.h" + +// Must be last. +#include "upb/port/def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +// Consume |buf|, deserialize it to a Code_Generator_Request proto, construct a +// upbc_Code_Generator_Request, and return it as a JSON-encoded string. +upb_StringView upbdev_ProcessInput(const char* buf, size_t size, upb_Arena* a, + upb_Status* status); + +// Deserialize |buf| from JSON then serialize it to wire format and return. +upb_StringView upbdev_ProcessOutput(const char* buf, size_t size, upb_Arena* a, + upb_Status* status); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port/undef.inc" + +#endif // UPBC_UPBDEV_H_