Avoid unnecessary use of run_shell (#19409)

Replaces the use of `ctx.actions.run_shell` with `ctx.actions.run` by rewriting the shell script logic in the existing C++ tool being used in `run_shell`.

closes https://github.com/protocolbuffers/protobuf/issues/19408

Closes #19409

COPYBARA_INTEGRATE_REVIEW=https://github.com/protocolbuffers/protobuf/pull/19409 from freeform-andre:run_shell 52158b6e1c
PiperOrigin-RevId: 700429546
pull/19412/head
freeform-andre 3 months ago committed by Copybara-Service
parent 3773feb2fc
commit 4cfeb66691
  1. 34
      editions/defaults.bzl
  2. 124
      editions/internal_defaults_escape.cc

@ -64,32 +64,18 @@ compile_edition_defaults = rule(
)
def _embed_edition_defaults_impl(ctx):
if ctx.attr.encoding == "base64":
args = "--encoding=base64"
elif ctx.attr.encoding == "octal":
args = "--encoding=octal"
else:
fail("Unknown encoding %s" % ctx.attr.encoding)
ctx.actions.run_shell(
args = ctx.actions.args()
args.add(ctx.attr.encoding, format = "--encoding=%s")
args.add(ctx.file.defaults, format = "--defaults_path=%s")
args.add(ctx.file.template, format = "--template_path=%s")
args.add(ctx.outputs.output, format = "--output_path=%s")
args.add(ctx.attr.placeholder, format = "--placeholder=%s")
ctx.actions.run(
executable = ctx.executable._escape,
arguments = [args],
outputs = [ctx.outputs.output],
inputs = [ctx.file.defaults, ctx.file.template],
tools = [ctx.executable._escape],
command = """
DEFAULTS_RAW=$({escape} {args} < {defaults})
# Windows requires extra escaping.
DEFAULTS_ESCAPED=$(echo $DEFAULTS_RAW | sed 's/\\\\/\\\\\\\\/g' ||
echo $DEFAULTS_RAW | sed 's/\\\\\\\\/\\\\\\\\\\\\\\\\/g')
cp -f {template} {output}
# MacOS requires a backup file.
sed -i.bak \"s|{placeholder}|$DEFAULTS_ESCAPED|g\" {output}
""".format(
escape = ctx.executable._escape.path,
args = args,
defaults = ctx.file.defaults.path,
template = ctx.file.template.path,
output = ctx.outputs.output.path,
placeholder = ctx.attr.placeholder,
),
)
embed_edition_defaults = rule(

@ -1,4 +1,7 @@
#include <cstddef>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#ifdef _WIN32
@ -16,34 +19,125 @@
#if defined(_WIN32)
#include "google/protobuf/io/io_win32.h"
// DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import
// them like we do below.
// DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and
// import them like we do below.
using google::protobuf::io::win32::setmode;
#endif
ABSL_FLAG(std::string, encoding, "octal",
"The encoding to use for the output.");
ABSL_FLAG(std::string, defaults_path, "defaults_path",
"The path to the compile_edition_defaults file to embed.");
ABSL_FLAG(std::string, template_path, "template_path",
"The template to use for generating the output file.");
ABSL_FLAG(std::string, output_path, "output_path",
"The path to the the output file.");
ABSL_FLAG(
std::string, placeholder, "placeholder",
"The placeholder to replace with a serialized string in the template.");
int defaults_escape(const std::string& defaults_path,
const std::string& encoding, std::string& out_content) {
std::ifstream defaults_file(defaults_path);
if (!defaults_file.is_open()) {
std::cerr << "Could not open defaults file " << defaults_path << std::endl;
return 1;
}
int main(int argc, char *argv[]) {
absl::ParseCommandLine(argc, argv);
#ifdef _WIN32
setmode(STDIN_FILENO, _O_BINARY);
setmode(STDOUT_FILENO, _O_BINARY);
#endif
google::protobuf::FeatureSetDefaults defaults;
if (!defaults.ParseFromFileDescriptor(STDIN_FILENO)) {
std::cerr << argv[0] << ": unable to parse edition defaults." << std::endl;
if (!defaults.ParseFromIstream(&defaults_file)) {
std::cerr << "Unable to parse edition defaults " << defaults_path
<< std::endl;
defaults_file.close();
return 1;
}
std::string output;
defaults.SerializeToString(&output);
std::string encoding = absl::GetFlag(FLAGS_encoding);
defaults_file.close();
std::string content = {};
defaults.SerializeToString(&content);
if (encoding == "base64") {
std::cout << absl::Base64Escape(output);
content = absl::Base64Escape(content);
} else if (encoding == "octal") {
std::cout << absl::CEscape(output);
content = absl::CEscape(content);
} else {
ABSL_LOG(FATAL) << "Unknown encoding: " << encoding;
return 1;
}
out_content = content;
return 0;
}
int read_to_string(const std::string& path, std::string& out_content) {
std::ifstream input_file(path);
if (!input_file.is_open()) {
std::cerr << "Could not open file " << path << std::endl;
return 1;
}
std::ostringstream buffer;
buffer << input_file.rdbuf();
out_content = buffer.str();
input_file.close();
return 0;
}
int replace_placeholder(std::string& out_content,
const std::string& placeholder,
const std::string& replacement) {
size_t pos = 0;
while ((pos = out_content.find(placeholder, pos)) != std::string::npos) {
out_content.replace(pos, placeholder.length(), replacement);
pos += replacement.length();
}
return 0;
}
int write(const std::string& path, const std::string& content) {
std::ofstream output_file(path);
if (!output_file.is_open()) {
std::cerr << "Could not write to file " << path << std::endl;
return 1;
}
output_file << content;
output_file.close();
return 0;
}
int main(int argc, char* argv[]) {
absl::ParseCommandLine(argc, argv);
#ifdef _WIN32
setmode(STDOUT_FILENO, _O_BINARY);
#endif
std::string encoding = absl::GetFlag(FLAGS_encoding);
std::string defaults_path = absl::GetFlag(FLAGS_defaults_path);
std::string template_path = absl::GetFlag(FLAGS_template_path);
std::string output_path = absl::GetFlag(FLAGS_output_path);
std::string placeholder = absl::GetFlag(FLAGS_placeholder);
std::string replacement = {};
if (defaults_escape(defaults_path, encoding, replacement)) {
return 1;
}
std::string content = {};
if (read_to_string(template_path, content)) {
return 1;
}
if (replace_placeholder(content, placeholder, replacement)) {
return 1;
}
if (write(output_path, content)) {
return 1;
}
return 0;
}

Loading…
Cancel
Save