Skip to content

Commit 60a858f

Browse files
zhangskzcopybara-github
authored andcommitted
Add --option_dependencies flag to protoc
PiperOrigin-RevId: 758810204
1 parent a7eb8cc commit 60a858f

File tree

4 files changed

+349
-19
lines changed

4 files changed

+349
-19
lines changed

src/google/protobuf/compiler/command_line_interface.cc

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,12 @@ using google::protobuf::io::win32::setmode;
121121
using google::protobuf::io::win32::write;
122122
#endif
123123

124-
static const char* kDefaultDirectDependenciesViolationMsg =
124+
constexpr absl::string_view kDefaultDirectDependenciesViolationMsg =
125125
"File is imported but not declared in --direct_dependencies: %s";
126126

127+
constexpr absl::string_view kDefaultOptionDependenciesViolationMsg =
128+
"File is option imported but not declared in --option_dependencies: %s";
129+
127130
// Returns true if the text begins with a Windows-style absolute path, starting
128131
// with a drive letter. Example: "C:\foo".
129132
static bool StartsWithWindowsAbsolutePath(absl::string_view text) {
@@ -958,7 +961,9 @@ const char* const CommandLineInterface::kPathSeparator = ":";
958961

959962
CommandLineInterface::CommandLineInterface()
960963
: direct_dependencies_violation_msg_(
961-
kDefaultDirectDependenciesViolationMsg) {}
964+
kDefaultDirectDependenciesViolationMsg),
965+
option_dependencies_violation_msg_(
966+
kDefaultOptionDependenciesViolationMsg) {}
962967

963968
CommandLineInterface::~CommandLineInterface() = default;
964969

@@ -1645,6 +1650,26 @@ bool CommandLineInterface::ParseInputFiles(
16451650
break;
16461651
}
16471652
}
1653+
1654+
// Enforce --option_dependencies.
1655+
if (option_dependencies_explicitly_set_) {
1656+
bool indirect_option_imports = false;
1657+
for (int i = 0; i < parsed_file->option_dependency_count(); ++i) {
1658+
if (option_dependencies_.find(parsed_file->option_dependency_name(i)) ==
1659+
option_dependencies_.end()) {
1660+
indirect_option_imports = true;
1661+
std::cerr << parsed_file->name() << ": "
1662+
<< absl::StrReplaceAll(
1663+
option_dependencies_violation_msg_,
1664+
{{"%s", parsed_file->option_dependency_name(i)}})
1665+
<< std::endl;
1666+
}
1667+
}
1668+
if (indirect_option_imports) {
1669+
result = false;
1670+
break;
1671+
}
1672+
}
16481673
}
16491674
descriptor_pool->ClearDirectInputFiles();
16501675
return result;
@@ -1658,6 +1683,8 @@ void CommandLineInterface::Clear() {
16581683
input_files_.clear();
16591684
direct_dependencies_.clear();
16601685
direct_dependencies_violation_msg_ = kDefaultDirectDependenciesViolationMsg;
1686+
option_dependencies_.clear();
1687+
option_dependencies_violation_msg_ = kDefaultOptionDependenciesViolationMsg;
16611688
output_directives_.clear();
16621689
codec_type_.clear();
16631690
descriptor_set_in_names_.clear();
@@ -2139,7 +2166,23 @@ CommandLineInterface::InterpretArgument(const std::string& name,
21392166

21402167
} else if (name == "--direct_dependencies_violation_msg") {
21412168
direct_dependencies_violation_msg_ = value;
2169+
} else if (name == "--option_dependencies") {
2170+
if (option_dependencies_explicitly_set_) {
2171+
std::cerr << name
2172+
<< " may only be passed once. To specify multiple "
2173+
"option dependencies, pass them all as a single "
2174+
"parameter separated by ':'."
2175+
<< std::endl;
2176+
return PARSE_ARGUMENT_FAIL;
2177+
}
21422178

2179+
option_dependencies_explicitly_set_ = true;
2180+
std::vector<std::string> direct =
2181+
absl::StrSplit(value, ':', absl::SkipEmpty());
2182+
ABSL_DCHECK(option_dependencies_.empty());
2183+
option_dependencies_.insert(direct.begin(), direct.end());
2184+
} else if (name == "--option_dependencies_violation_msg") {
2185+
option_dependencies_violation_msg_ = value;
21432186
} else if (name == "--descriptor_set_in") {
21442187
if (!descriptor_set_in_names_.empty()) {
21452188
std::cerr << name
@@ -2520,7 +2563,13 @@ Parse PROTO_FILES and generate output based on the options given:
25202563
are counted as occupied fields numbers.
25212564
--enable_codegen_trace Enables tracing which parts of protoc are
25222565
responsible for what codegen output. Not supported
2523-
by all backends or on all platforms.)";
2566+
by all backends or on all platforms.
2567+
--direct_dependencies A colon delimited list of imports that are
2568+
allowed to be used in "import"
2569+
declarations, when explictily provided.
2570+
--option_dependencies A colon delimited list of imports that are
2571+
allowed to be used in "import option"
2572+
declarations, when explicitly provided.)";
25242573
std::cout << R"(
25252574
--notices Show notice file and exit.)";
25262575
if (!plugin_prefix_.empty()) {

src/google/protobuf/compiler/command_line_interface.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,16 @@ class PROTOC_EXPORT CommandLineInterface {
423423
// presented to the user. "%s" will be replaced with the violating import.
424424
std::string direct_dependencies_violation_msg_;
425425

426+
// Names of proto files which are allowed to be option imported. Used by build
427+
// systems to enforce option-depend-on-what-you-option-import.
428+
absl::flat_hash_set<std::string> option_dependencies_;
429+
bool option_dependencies_explicitly_set_ = false;
430+
431+
// If there's a violation of option-depend-on-what-you-option-import, this
432+
// string will be presented to the user. "%s" will be replaced with the
433+
// violating import.
434+
std::string option_dependencies_violation_msg_;
435+
426436
// output_directives_ lists all the files we are supposed to output and what
427437
// generator to use for each.
428438
struct OutputDirective {

src/google/protobuf/compiler/command_line_interface_tester.cc

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,9 @@ void CommandLineInterfaceTester::ExpectNoErrors() {
130130
void CommandLineInterfaceTester::ExpectErrorText(
131131
absl::string_view expected_text) {
132132
EXPECT_NE(0, return_code_);
133-
EXPECT_THAT(captured_stderr_,
134-
HasSubstr(absl::StrReplaceAll(expected_text,
135-
{{"$tmpdir", temp_directory_}})));
133+
EXPECT_EQ(captured_stderr_,
134+
absl::StrReplaceAll(expected_text, {{"$tmpdir", temp_directory_}}));
136135
}
137-
138136
void CommandLineInterfaceTester::ExpectErrorSubstring(
139137
absl::string_view expected_substring) {
140138
EXPECT_NE(0, return_code_);

0 commit comments

Comments
 (0)