upb: begin to delete the old Dart v2 plugin code
PiperOrigin-RevId: 628090572pull/16644/head
parent
047fc7673e
commit
7a1c926ef3
|
@ -409,27 +409,3 @@ proto_lang_toolchain(
|
|||
runtime = "//upb:generated_reflection_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "protoc-gen-upbdev",
|
||||
srcs = [
|
||||
"protoc-gen-upbdev.cc",
|
||||
"subprocess.cc",
|
||||
"subprocess.h",
|
||||
],
|
||||
copts = UPB_DEFAULT_CPPOPTS,
|
||||
target_compatible_with = select({
|
||||
"@platforms//os:windows": ["@platforms//:incompatible"],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":plugin_upb_proto",
|
||||
":upbdev",
|
||||
"//upb:base",
|
||||
"//upb:mem",
|
||||
"//upb:port",
|
||||
"@com_google_absl//absl/log:absl_log",
|
||||
"@com_google_absl//absl/strings",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 Google LLC. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "google/protobuf/compiler/plugin.upb.h"
|
||||
#include "upb/base/status.h"
|
||||
#include "upb/base/string_view.h"
|
||||
#include "upb/mem/arena.h"
|
||||
#include "upb_generator/subprocess.h"
|
||||
#include "upb_generator/upbdev.h"
|
||||
|
||||
static constexpr char kDefaultPlugin[] = "protoc_dart_plugin";
|
||||
|
||||
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<char>(std::cin),
|
||||
std::istreambuf_iterator<char>()};
|
||||
|
||||
// Parse the request.
|
||||
auto inner_request = google_protobuf_compiler_CodeGeneratorRequest_parse(
|
||||
input.c_str(), input.size(), a);
|
||||
|
||||
// Check the request for a plugin name.
|
||||
std::string plugin = kDefaultPlugin;
|
||||
if (google_protobuf_compiler_CodeGeneratorRequest_has_parameter(inner_request)) {
|
||||
auto param = google_protobuf_compiler_CodeGeneratorRequest_parameter(inner_request);
|
||||
plugin = std::string(param.data, param.size);
|
||||
}
|
||||
|
||||
// Wrap the request inside a upb_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 << '\n';
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Launch the subprocess.
|
||||
upb::generator::Subprocess subprocess;
|
||||
subprocess.Start(plugin, upb::generator::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) {
|
||||
// Dump the JSON request to stderr if we can't launch the next plugin.
|
||||
std::cerr << json_request << '\n';
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Decode, serialize, and write the JSON response.
|
||||
upbdev_ProcessOutput(json_response.data(), json_response.size(), a, &status);
|
||||
if (!upb_Status_IsOk(&status)) {
|
||||
std::cerr << status.msg << '\n';
|
||||
return -1;
|
||||
}
|
||||
|
||||
upb_Arena_Free(a);
|
||||
return 0;
|
||||
}
|
|
@ -1,444 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 Google LLC. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
// Shamelessly copied from the protobuf compiler's subprocess.cc
|
||||
// except this version passes strings instead of Messages.
|
||||
|
||||
#include "upb_generator/subprocess.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#ifndef _MSVC_LANG
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#include "absl/log/absl_log.h"
|
||||
#include "absl/strings/substitute.h"
|
||||
|
||||
// Must be last.
|
||||
#include "upb/port/def.inc"
|
||||
|
||||
namespace upb {
|
||||
namespace generator {
|
||||
|
||||
namespace {
|
||||
char* portable_strdup(const char* s) {
|
||||
char* ns = (char*)malloc(strlen(s) + 1);
|
||||
if (ns != nullptr) {
|
||||
strcpy(ns, s);
|
||||
}
|
||||
return ns;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
static void CloseHandleOrDie(HANDLE handle) {
|
||||
if (!CloseHandle(handle)) {
|
||||
ABSL_LOG(FATAL) << "CloseHandle: "
|
||||
<< Subprocess::Win32ErrorMessage(GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
Subprocess::Subprocess()
|
||||
: process_start_error_(ERROR_SUCCESS),
|
||||
child_handle_(nullptr),
|
||||
child_stdin_(nullptr),
|
||||
child_stdout_(nullptr) {}
|
||||
|
||||
Subprocess::~Subprocess() {
|
||||
if (child_stdin_ != nullptr) {
|
||||
CloseHandleOrDie(child_stdin_);
|
||||
}
|
||||
if (child_stdout_ != nullptr) {
|
||||
CloseHandleOrDie(child_stdout_);
|
||||
}
|
||||
}
|
||||
|
||||
void Subprocess::Start(const std::string& program, SearchMode search_mode) {
|
||||
// Create the pipes.
|
||||
HANDLE stdin_pipe_read;
|
||||
HANDLE stdin_pipe_write;
|
||||
HANDLE stdout_pipe_read;
|
||||
HANDLE stdout_pipe_write;
|
||||
|
||||
if (!CreatePipe(&stdin_pipe_read, &stdin_pipe_write, nullptr, 0)) {
|
||||
ABSL_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError());
|
||||
}
|
||||
if (!CreatePipe(&stdout_pipe_read, &stdout_pipe_write, nullptr, 0)) {
|
||||
ABSL_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError());
|
||||
}
|
||||
|
||||
// Make child side of the pipes inheritable.
|
||||
if (!SetHandleInformation(stdin_pipe_read, HANDLE_FLAG_INHERIT,
|
||||
HANDLE_FLAG_INHERIT)) {
|
||||
ABSL_LOG(FATAL) << "SetHandleInformation: "
|
||||
<< Win32ErrorMessage(GetLastError());
|
||||
}
|
||||
if (!SetHandleInformation(stdout_pipe_write, HANDLE_FLAG_INHERIT,
|
||||
HANDLE_FLAG_INHERIT)) {
|
||||
ABSL_LOG(FATAL) << "SetHandleInformation: "
|
||||
<< Win32ErrorMessage(GetLastError());
|
||||
}
|
||||
|
||||
// Setup STARTUPINFO to redirect handles.
|
||||
STARTUPINFOA startup_info;
|
||||
ZeroMemory(&startup_info, sizeof(startup_info));
|
||||
startup_info.cb = sizeof(startup_info);
|
||||
startup_info.dwFlags = STARTF_USESTDHANDLES;
|
||||
startup_info.hStdInput = stdin_pipe_read;
|
||||
startup_info.hStdOutput = stdout_pipe_write;
|
||||
startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
|
||||
|
||||
if (startup_info.hStdError == INVALID_HANDLE_VALUE) {
|
||||
ABSL_LOG(FATAL) << "GetStdHandle: " << Win32ErrorMessage(GetLastError());
|
||||
}
|
||||
|
||||
// Invoking cmd.exe allows for '.bat' files from the path as well as '.exe'.
|
||||
// Using a malloc'ed string because CreateProcess() can mutate its second
|
||||
// parameter.
|
||||
char* command_line =
|
||||
portable_strdup(("cmd.exe /c \"" + program + "\"").c_str());
|
||||
|
||||
// Create the process.
|
||||
PROCESS_INFORMATION process_info;
|
||||
|
||||
if (CreateProcessA((search_mode == SEARCH_PATH) ? nullptr : program.c_str(),
|
||||
(search_mode == SEARCH_PATH) ? command_line : nullptr,
|
||||
nullptr, // process security attributes
|
||||
nullptr, // thread security attributes
|
||||
TRUE, // inherit handles?
|
||||
0, // obscure creation flags
|
||||
nullptr, // environment (inherit from parent)
|
||||
nullptr, // current directory (inherit from parent)
|
||||
&startup_info, &process_info)) {
|
||||
child_handle_ = process_info.hProcess;
|
||||
CloseHandleOrDie(process_info.hThread);
|
||||
child_stdin_ = stdin_pipe_write;
|
||||
child_stdout_ = stdout_pipe_read;
|
||||
} else {
|
||||
process_start_error_ = GetLastError();
|
||||
CloseHandleOrDie(stdin_pipe_write);
|
||||
CloseHandleOrDie(stdout_pipe_read);
|
||||
}
|
||||
|
||||
CloseHandleOrDie(stdin_pipe_read);
|
||||
CloseHandleOrDie(stdout_pipe_write);
|
||||
free(command_line);
|
||||
}
|
||||
|
||||
bool Subprocess::Communicate(const std::string& input_data,
|
||||
std::string* output_data, std::string* error) {
|
||||
if (process_start_error_ != ERROR_SUCCESS) {
|
||||
*error = Win32ErrorMessage(process_start_error_);
|
||||
return false;
|
||||
}
|
||||
|
||||
GOOGLE_CHECK(child_handle_ != nullptr) << "Must call Start() first.";
|
||||
|
||||
int input_pos = 0;
|
||||
|
||||
while (child_stdout_ != nullptr) {
|
||||
HANDLE handles[2];
|
||||
int handle_count = 0;
|
||||
|
||||
if (child_stdin_ != nullptr) {
|
||||
handles[handle_count++] = child_stdin_;
|
||||
}
|
||||
if (child_stdout_ != nullptr) {
|
||||
handles[handle_count++] = child_stdout_;
|
||||
}
|
||||
|
||||
DWORD wait_result =
|
||||
WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
|
||||
|
||||
HANDLE signaled_handle = nullptr;
|
||||
if (wait_result >= WAIT_OBJECT_0 &&
|
||||
wait_result < WAIT_OBJECT_0 + handle_count) {
|
||||
signaled_handle = handles[wait_result - WAIT_OBJECT_0];
|
||||
} else if (wait_result == WAIT_FAILED) {
|
||||
ABSL_LOG(FATAL) << "WaitForMultipleObjects: "
|
||||
<< Win32ErrorMessage(GetLastError());
|
||||
} else {
|
||||
ABSL_LOG(FATAL) << "WaitForMultipleObjects: Unexpected return code: "
|
||||
<< wait_result;
|
||||
}
|
||||
|
||||
if (signaled_handle == child_stdin_) {
|
||||
DWORD n;
|
||||
if (!WriteFile(child_stdin_, input_data.data() + input_pos,
|
||||
input_data.size() - input_pos, &n, nullptr)) {
|
||||
// Child closed pipe. Presumably it will report an error later.
|
||||
// Pretend we're done for now.
|
||||
input_pos = input_data.size();
|
||||
} else {
|
||||
input_pos += n;
|
||||
}
|
||||
|
||||
if (input_pos == input_data.size()) {
|
||||
// We're done writing. Close.
|
||||
CloseHandleOrDie(child_stdin_);
|
||||
child_stdin_ = nullptr;
|
||||
}
|
||||
} else if (signaled_handle == child_stdout_) {
|
||||
char buffer[4096];
|
||||
DWORD n;
|
||||
|
||||
if (!ReadFile(child_stdout_, buffer, sizeof(buffer), &n, nullptr)) {
|
||||
// We're done reading. Close.
|
||||
CloseHandleOrDie(child_stdout_);
|
||||
child_stdout_ = nullptr;
|
||||
} else {
|
||||
output_data->append(buffer, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (child_stdin_ != nullptr) {
|
||||
// Child did not finish reading input before it closed the output.
|
||||
// Presumably it exited with an error.
|
||||
CloseHandleOrDie(child_stdin_);
|
||||
child_stdin_ = nullptr;
|
||||
}
|
||||
|
||||
DWORD wait_result = WaitForSingleObject(child_handle_, INFINITE);
|
||||
|
||||
if (wait_result == WAIT_FAILED) {
|
||||
ABSL_LOG(FATAL) << "WaitForSingleObject: "
|
||||
<< Win32ErrorMessage(GetLastError());
|
||||
} else if (wait_result != WAIT_OBJECT_0) {
|
||||
ABSL_LOG(FATAL) << "WaitForSingleObject: Unexpected return code: "
|
||||
<< wait_result;
|
||||
}
|
||||
|
||||
DWORD exit_code;
|
||||
if (!GetExitCodeProcess(child_handle_, &exit_code)) {
|
||||
ABSL_LOG(FATAL) << "GetExitCodeProcess: "
|
||||
<< Win32ErrorMessage(GetLastError());
|
||||
}
|
||||
|
||||
CloseHandleOrDie(child_handle_);
|
||||
child_handle_ = nullptr;
|
||||
|
||||
if (exit_code != 0) {
|
||||
*error = absl::Substitute("Plugin failed with status code $0.", exit_code);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string Subprocess::Win32ErrorMessage(DWORD error_code) {
|
||||
char* message;
|
||||
|
||||
// WTF?
|
||||
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr, error_code,
|
||||
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
|
||||
(LPSTR)&message, // NOT A BUG!
|
||||
0, nullptr);
|
||||
|
||||
std::string result = message;
|
||||
LocalFree(message);
|
||||
return result;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
#else // _WIN32
|
||||
|
||||
Subprocess::Subprocess()
|
||||
: child_pid_(-1), child_stdin_(-1), child_stdout_(-1) {}
|
||||
|
||||
Subprocess::~Subprocess() {
|
||||
if (child_stdin_ != -1) {
|
||||
close(child_stdin_);
|
||||
}
|
||||
if (child_stdout_ != -1) {
|
||||
close(child_stdout_);
|
||||
}
|
||||
}
|
||||
|
||||
void Subprocess::Start(const std::string& program, SearchMode search_mode) {
|
||||
// Note that we assume that there are no other threads, thus we don't have to
|
||||
// do crazy stuff like using socket pairs or avoiding libc locks.
|
||||
|
||||
// [0] is read end, [1] is write end.
|
||||
int stdin_pipe[2];
|
||||
int stdout_pipe[2];
|
||||
|
||||
int p0 = pipe(stdin_pipe);
|
||||
int p1 = pipe(stdout_pipe);
|
||||
UPB_ASSERT(p0 != -1);
|
||||
UPB_ASSERT(p1 != -1);
|
||||
|
||||
char* argv[2] = {portable_strdup(program.c_str()), nullptr};
|
||||
|
||||
child_pid_ = fork();
|
||||
if (child_pid_ == -1) {
|
||||
std::cerr << "fork: " << strerror(errno);
|
||||
} else if (child_pid_ == 0) {
|
||||
// We are the child.
|
||||
dup2(stdin_pipe[0], STDIN_FILENO);
|
||||
dup2(stdout_pipe[1], STDOUT_FILENO);
|
||||
|
||||
close(stdin_pipe[0]);
|
||||
close(stdin_pipe[1]);
|
||||
close(stdout_pipe[0]);
|
||||
close(stdout_pipe[1]);
|
||||
|
||||
switch (search_mode) {
|
||||
case SEARCH_PATH:
|
||||
execvp(argv[0], argv);
|
||||
break;
|
||||
case EXACT_NAME:
|
||||
execv(argv[0], argv);
|
||||
break;
|
||||
}
|
||||
|
||||
// Write directly to STDERR_FILENO to avoid stdio code paths that may do
|
||||
// stuff that is unsafe here.
|
||||
int ignored;
|
||||
ignored = write(STDERR_FILENO, argv[0], strlen(argv[0]));
|
||||
const char* message =
|
||||
": program not found or is not executable\n"
|
||||
"Please specify a program using absolute path or make sure "
|
||||
"the program is available in your PATH system variable\n";
|
||||
ignored = write(STDERR_FILENO, message, strlen(message));
|
||||
(void)ignored;
|
||||
|
||||
// Must use _exit() rather than exit() to avoid flushing output buffers
|
||||
// that will also be flushed by the parent.
|
||||
_exit(1);
|
||||
} else {
|
||||
free(argv[0]);
|
||||
|
||||
close(stdin_pipe[0]);
|
||||
close(stdout_pipe[1]);
|
||||
|
||||
child_stdin_ = stdin_pipe[1];
|
||||
child_stdout_ = stdout_pipe[0];
|
||||
}
|
||||
}
|
||||
|
||||
bool Subprocess::Communicate(const std::string& input_data,
|
||||
std::string* output_data, std::string* error) {
|
||||
if (child_stdin_ == -1) {
|
||||
std::cerr << "Must call Start() first." << '\n';
|
||||
UPB_ASSERT(child_stdin_ != -1);
|
||||
}
|
||||
|
||||
// The "sighandler_t" typedef is GNU-specific, so define our own.
|
||||
typedef void SignalHandler(int);
|
||||
|
||||
// Make sure SIGPIPE is disabled so that if the child dies it doesn't kill us.
|
||||
SignalHandler* old_pipe_handler = signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
int input_pos = 0;
|
||||
int max_fd = std::max(child_stdin_, child_stdout_);
|
||||
|
||||
while (child_stdout_ != -1) {
|
||||
fd_set read_fds;
|
||||
fd_set write_fds;
|
||||
FD_ZERO(&read_fds);
|
||||
FD_ZERO(&write_fds);
|
||||
if (child_stdout_ != -1) {
|
||||
FD_SET(child_stdout_, &read_fds);
|
||||
}
|
||||
if (child_stdin_ != -1) {
|
||||
FD_SET(child_stdin_, &write_fds);
|
||||
}
|
||||
|
||||
if (select(max_fd + 1, &read_fds, &write_fds, nullptr, nullptr) < 0) {
|
||||
if (errno == EINTR) {
|
||||
// Interrupted by signal. Try again.
|
||||
continue;
|
||||
} else {
|
||||
std::cerr << "select: " << strerror(errno) << '\n';
|
||||
UPB_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (child_stdin_ != -1 && FD_ISSET(child_stdin_, &write_fds)) {
|
||||
int n = write(child_stdin_, input_data.data() + input_pos,
|
||||
input_data.size() - input_pos);
|
||||
if (n < 0) {
|
||||
// Child closed pipe. Presumably it will report an error later.
|
||||
// Pretend we're done for now.
|
||||
input_pos = input_data.size();
|
||||
} else {
|
||||
input_pos += n;
|
||||
}
|
||||
|
||||
if (input_pos == (int)input_data.size()) {
|
||||
// We're done writing. Close.
|
||||
close(child_stdin_);
|
||||
child_stdin_ = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (child_stdout_ != -1 && FD_ISSET(child_stdout_, &read_fds)) {
|
||||
char buffer[4096];
|
||||
int n = read(child_stdout_, buffer, sizeof(buffer));
|
||||
|
||||
if (n > 0) {
|
||||
output_data->append(buffer, (size_t)n);
|
||||
} else {
|
||||
// We're done reading. Close.
|
||||
close(child_stdout_);
|
||||
child_stdout_ = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (child_stdin_ != -1) {
|
||||
// Child did not finish reading input before it closed the output.
|
||||
// Presumably it exited with an error.
|
||||
close(child_stdin_);
|
||||
child_stdin_ = -1;
|
||||
}
|
||||
|
||||
int status;
|
||||
while (waitpid(child_pid_, &status, 0) == -1) {
|
||||
if (errno != EINTR) {
|
||||
std::cerr << "waitpid: " << strerror(errno) << '\n';
|
||||
UPB_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Restore SIGPIPE handling.
|
||||
signal(SIGPIPE, old_pipe_handler);
|
||||
|
||||
if (WIFEXITED(status)) {
|
||||
if (WEXITSTATUS(status) != 0) {
|
||||
int error_code = WEXITSTATUS(status);
|
||||
*error =
|
||||
absl::Substitute("Plugin failed with status code $0.", error_code);
|
||||
return false;
|
||||
}
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
int signal = WTERMSIG(status);
|
||||
*error = absl::Substitute("Plugin killed by signal $0.", signal);
|
||||
return false;
|
||||
} else {
|
||||
*error = "Neither WEXITSTATUS nor WTERMSIG is true?";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // !_WIN32
|
||||
|
||||
} // namespace generator
|
||||
} // namespace upb
|
|
@ -1,81 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 Google LLC. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
// Shamelessly copied from the protobuf compiler's subprocess.h
|
||||
// except this version passes strings instead of Messages.
|
||||
|
||||
#ifndef THIRD_PARTY_UPB_UPB_GENERATOR_H_
|
||||
#define THIRD_PARTY_UPB_UPB_GENERATOR_H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN // right...
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#else // _WIN32
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif // !_WIN32
|
||||
#include <string>
|
||||
|
||||
namespace upb {
|
||||
namespace generator {
|
||||
|
||||
// Utility class for launching sub-processes.
|
||||
class Subprocess {
|
||||
public:
|
||||
Subprocess();
|
||||
~Subprocess();
|
||||
|
||||
enum SearchMode {
|
||||
SEARCH_PATH, // Use PATH environment variable.
|
||||
EXACT_NAME // Program is an exact file name; don't use the PATH.
|
||||
};
|
||||
|
||||
// Start the subprocess. Currently we don't provide a way to specify
|
||||
// arguments as protoc plugins don't have any.
|
||||
void Start(const std::string& program, SearchMode search_mode);
|
||||
|
||||
// Pipe the input message to the subprocess's stdin, then close the pipe.
|
||||
// Meanwhile, read from the subprocess's stdout and copy into *output.
|
||||
// All this is done carefully to avoid deadlocks.
|
||||
// Returns true if successful. On any sort of error, returns false and sets
|
||||
// *error to a description of the problem.
|
||||
bool Communicate(const std::string& input_data, std::string* output_data,
|
||||
std::string* error);
|
||||
|
||||
#ifdef _WIN32
|
||||
// Given an error code, returns a human-readable error message. This is
|
||||
// defined here so that CommandLineInterface can share it.
|
||||
static std::string Win32ErrorMessage(DWORD error_code);
|
||||
#endif
|
||||
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
DWORD process_start_error_;
|
||||
HANDLE child_handle_;
|
||||
|
||||
// The file handles for our end of the child's pipes. We close each and
|
||||
// set it to NULL when no longer needed.
|
||||
HANDLE child_stdin_;
|
||||
HANDLE child_stdout_;
|
||||
|
||||
#else // _WIN32
|
||||
pid_t child_pid_;
|
||||
|
||||
// The file descriptors for our end of the child's pipes. We close each and
|
||||
// set it to -1 when no longer needed.
|
||||
int child_stdin_;
|
||||
int child_stdout_;
|
||||
|
||||
#endif // !_WIN32
|
||||
};
|
||||
|
||||
} // namespace generator
|
||||
} // namespace upb
|
||||
|
||||
#endif // THIRD_PARTY_UPB_UPB_GENERATOR_H_
|
|
@ -83,8 +83,9 @@ upb_StringView upbdev_ProcessInput(const char* buf, size_t size,
|
|||
return upbc_JsonEncode(outer_request, arena, status);
|
||||
}
|
||||
|
||||
upb_StringView upbdev_ProcessOutput(const char* buf, size_t size,
|
||||
upb_Arena* arena, upb_Status* status) {
|
||||
static upb_StringView upbdev_ProcessOutput(const char* buf, size_t size,
|
||||
upb_Arena* arena,
|
||||
upb_Status* status) {
|
||||
upb_StringView out = {.data = NULL, .size = 0};
|
||||
|
||||
const google_protobuf_compiler_CodeGeneratorResponse* response =
|
||||
|
|
|
@ -25,11 +25,6 @@ UPB_API upb_StringView upbdev_ProcessInput(const char* buf, size_t size,
|
|||
upb_Arena* arena,
|
||||
upb_Status* status);
|
||||
|
||||
// Decode |buf| from JSON, serialize to wire format, and return it.
|
||||
UPB_API upb_StringView upbdev_ProcessOutput(const char* buf, size_t size,
|
||||
upb_Arena* arena,
|
||||
upb_Status* status);
|
||||
|
||||
// Decode |buf| from JSON, serialize to wire format, and write it to stdout.
|
||||
UPB_API void upbdev_ProcessStdout(const char* buf, size_t size,
|
||||
upb_Arena* arena, upb_Status* status);
|
||||
|
|
Loading…
Reference in New Issue