Use a CommandLine struct to store the command line parsed by the OptionProcessor.
This replaces the startup_args_, command_ and command_argument members to allow a more consistent representation of the command line throughout the class.
PiperOrigin-RevId: 161408010
diff --git a/src/main/cpp/blaze.cc b/src/main/cpp/blaze.cc
index f9acc8a..a77504b 100644
--- a/src/main/cpp/blaze.cc
+++ b/src/main/cpp/blaze.cc
@@ -640,8 +640,8 @@
globals->options->product_name.c_str());
}
string command = globals->option_processor->GetCommand();
- vector<string> command_arguments;
- globals->option_processor->GetCommandArguments(&command_arguments);
+ const vector<string> command_arguments =
+ globals->option_processor->GetCommandArguments();
if (!command_arguments.empty() && command == "shutdown") {
string product = globals->options->product_name;
@@ -1604,7 +1604,13 @@
AddLoggingArgs(&arg_vector);
}
- globals->option_processor->GetCommandArguments(&arg_vector);
+ const vector<string> command_args =
+ globals->option_processor->GetCommandArguments();
+ if (!command_args.empty()) {
+ arg_vector.insert(arg_vector.end(),
+ command_args.begin(),
+ command_args.end());
+ }
command_server::RunRequest request;
request.set_cookie(request_cookie_);
diff --git a/src/main/cpp/option_processor.cc b/src/main/cpp/option_processor.cc
index db19d3f..fc6d8b1 100644
--- a/src/main/cpp/option_processor.cc
+++ b/src/main/cpp/option_processor.cc
@@ -169,14 +169,12 @@
OptionProcessor::OptionProcessor(
const WorkspaceLayout* workspace_layout,
std::unique_ptr<StartupOptions> default_startup_options)
- : initialized_(false),
- workspace_layout_(workspace_layout),
+ : workspace_layout_(workspace_layout),
parsed_startup_options_(std::move(default_startup_options)) {
}
std::unique_ptr<CommandLine> OptionProcessor::SplitCommandLine(
- const vector<string>& args,
- string* error) {
+ const vector<string>& args, string* error) const {
const string lowercase_product_name =
parsed_startup_options_->GetLowercaseProductName();
@@ -299,6 +297,7 @@
}
namespace internal {
+
vector<string> DedupeBlazercPaths(const vector<string>& paths) {
set<string> canonical_paths;
vector<string> result;
@@ -314,6 +313,7 @@
}
return result;
}
+
} // namespace internal
// Parses the arguments provided in args using the workspace path and the
@@ -323,24 +323,19 @@
const string& workspace,
const string& cwd,
string* error) {
- assert(!initialized_);
- initialized_ = true;
- args_ = args;
- std::unique_ptr<CommandLine> cmd_line = SplitCommandLine(args, error);
- if (cmd_line == nullptr) {
+ cmd_line_ = SplitCommandLine(args, error);
+ if (cmd_line_ == nullptr) {
return blaze_exit_code::BAD_ARGV;
}
- explicit_command_arguments_ = cmd_line->command_args;
-
- const char* blazerc = SearchUnaryOption(cmd_line->startup_args, "--blazerc");
+ const char* blazerc = SearchUnaryOption(cmd_line_->startup_args, "--blazerc");
if (blazerc == NULL) {
- blazerc = SearchUnaryOption(cmd_line->startup_args, "--bazelrc");
+ blazerc = SearchUnaryOption(cmd_line_->startup_args, "--bazelrc");
}
bool use_master_blazerc = true;
- if (SearchNullaryOption(cmd_line->startup_args, "--nomaster_blazerc") ||
- SearchNullaryOption(cmd_line->startup_args, "--nomaster_bazelrc")) {
+ if (SearchNullaryOption(cmd_line_->startup_args, "--nomaster_blazerc") ||
+ SearchNullaryOption(cmd_line_->startup_args, "--nomaster_bazelrc")) {
use_master_blazerc = false;
}
@@ -350,7 +345,7 @@
vector<string> candidate_blazerc_paths;
if (use_master_blazerc) {
workspace_layout_->FindCandidateBlazercPaths(
- workspace, cwd, cmd_line->path_to_binary, cmd_line->startup_args,
+ workspace, cwd, cmd_line_->path_to_binary, cmd_line_->startup_args,
&candidate_blazerc_paths);
}
@@ -386,20 +381,8 @@
return parse_startup_options_exit_code;
}
- // Once we're done with startup options the next arg is the command.
- if (startup_args_ + 1 >= args.size()) {
- command_ = "";
- return blaze_exit_code::SUCCESS;
- }
- command_ = args[startup_args_ + 1];
-
- AddRcfileArgsAndOptions(cwd);
-
- // The rest of the args are the command options.
- for (unsigned int cmd_arg = startup_args_ + 2;
- cmd_arg < args.size(); cmd_arg++) {
- command_arguments_.push_back(args[cmd_arg]);
- }
+ blazerc_and_env_command_args_ = GetBlazercAndEnvCommandArgs(
+ cwd, blazercs_, rcoptions_);
return blaze_exit_code::SUCCESS;
}
@@ -417,69 +400,28 @@
return ParseOptions(args, workspace, cwd, error);
}
-blaze_exit_code::ExitCode OptionProcessor::ParseStartupOptions(string *error) {
- // Process rcfile startup options
- map< string, vector<RcOption> >::const_iterator it =
- rcoptions_.find("startup");
- blaze_exit_code::ExitCode process_arg_exit_code;
- bool is_space_separated;
- if (it != rcoptions_.end()) {
- const vector<RcOption>& startup_options = it->second;
- int i = 0;
- // Process all elements except the last one.
- for (; i < startup_options.size() - 1; i++) {
- const RcOption& option = startup_options[i];
- const string& blazerc = blazercs_[option.rcfile_index()]->Filename();
- process_arg_exit_code = parsed_startup_options_->ProcessArg(
- option.option(), startup_options[i + 1].option(), blazerc,
- &is_space_separated, error);
- if (process_arg_exit_code != blaze_exit_code::SUCCESS) {
- return process_arg_exit_code;
- }
- if (is_space_separated) {
- i++;
- }
- }
- // Process last element, if any.
- if (i < startup_options.size()) {
- const RcOption& option = startup_options[i];
- if (IsArg(option.option())) {
- const string& blazerc = blazercs_[option.rcfile_index()]->Filename();
- process_arg_exit_code = parsed_startup_options_->ProcessArg(
- option.option(), "", blazerc, &is_space_separated, error);
- if (process_arg_exit_code != blaze_exit_code::SUCCESS) {
- return process_arg_exit_code;
- }
- }
+blaze_exit_code::ExitCode OptionProcessor::ParseStartupOptions(
+ std::string *error) {
+ std::vector<RcStartupFlag> rcstartup_flags;
+
+ auto iter = rcoptions_.find("startup");
+ if (iter != rcoptions_.end()) {
+ const vector<RcOption>& startup_rcoptions = iter->second;
+ for (const RcOption& option : startup_rcoptions) {
+ rcstartup_flags.push_back(
+ RcStartupFlag(blazercs_[option.rcfile_index()]->Filename(),
+ option.option()));
}
}
- // Process command-line args next, so they override any of the same options
- // from .blazerc. Stop on first non-arg, this includes --help
- unsigned int i = 1;
- if (!args_.empty()) {
- for (; (i < args_.size() - 1) && IsArg(args_[i]); i++) {
- process_arg_exit_code = parsed_startup_options_->ProcessArg(
- args_[i], args_[i + 1], "", &is_space_separated, error);
- if (process_arg_exit_code != blaze_exit_code::SUCCESS) {
- return process_arg_exit_code;
- }
- if (is_space_separated) {
- i++;
- }
+ for (const std::string& arg : cmd_line_->startup_args) {
+ if (!IsArg(arg)) {
+ break;
}
- if (i < args_.size() && IsArg(args_[i])) {
- process_arg_exit_code = parsed_startup_options_->ProcessArg(
- args_[i], "", "", &is_space_separated, error);
- if (process_arg_exit_code != blaze_exit_code::SUCCESS) {
- return process_arg_exit_code;
- }
- i++;
- }
+ rcstartup_flags.push_back(RcStartupFlag("", arg));
}
- startup_args_ = i -1;
- return blaze_exit_code::SUCCESS;
+ return parsed_startup_options_->ProcessArgs(rcstartup_flags, error);
}
static bool IsValidEnvName(const char* p) {
@@ -532,39 +474,34 @@
}
#endif // defined(COMPILER_MSVC)
-// Appends the command and arguments from argc/argv to the end of arg_vector,
-// and also splices in some additional terminal and environment options between
-// the command and the arguments. NB: Keep the options added here in sync with
+// IMPORTANT: Keep the options added here in sync with
// BlazeCommandDispatcher.INTERNAL_COMMAND_OPTIONS!
-void OptionProcessor::AddRcfileArgsAndOptions(const string& cwd) {
+std::vector<std::string> OptionProcessor::GetBlazercAndEnvCommandArgs(
+ const std::string& cwd,
+ const std::vector<RcFile*>& blazercs,
+ const std::map<std::string, std::vector<RcOption>>& rcoptions) {
// Provide terminal options as coming from the least important rc file.
- command_arguments_.push_back("--rc_source=client");
- command_arguments_.push_back("--default_override=0:common=--is_stderr_atty=" +
- ToString(IsStderrStandardTerminal()));
- command_arguments_.push_back(
- "--default_override=0:common=--terminal_columns=" +
- ToString(GetStderrTerminalColumns()));
+ std::vector<std::string> result = {
+ "--rc_source=client",
+ "--default_override=0:common=--is_stderr_atty=" +
+ ToString(IsStderrStandardTerminal()),
+ "--default_override=0:common=--terminal_columns=" +
+ ToString(GetStderrTerminalColumns())};
// Push the options mapping .blazerc numbers to filenames.
- for (int i_blazerc = 0; i_blazerc < blazercs_.size(); i_blazerc++) {
- const RcFile* blazerc = blazercs_[i_blazerc];
- command_arguments_.push_back("--rc_source=" +
- blaze::ConvertPath(blazerc->Filename()));
+ for (const RcFile* blazerc : blazercs) {
+ result.push_back("--rc_source=" + blaze::ConvertPath(blazerc->Filename()));
}
- // Push the option defaults
- for (map<string, vector<RcOption> >::const_iterator it = rcoptions_.begin();
- it != rcoptions_.end(); ++it) {
- if (it->first == "startup") {
- // Skip startup options, they are parsed in the C++ wrapper
- continue;
- }
-
- for (int ii = 0; ii < it->second.size(); ii++) {
- const RcOption& rcoption = it->second[ii];
- command_arguments_.push_back(
- "--default_override=" + ToString(rcoption.rcfile_index() + 1) + ":"
- + it->first + "=" + rcoption.option());
+ // Process RcOptions exept for the startup flags that are already parsed
+ // by the client and shouldn't be handled by defult_overrides.
+ for (auto it = rcoptions.begin(); it != rcoptions.end(); ++it) {
+ if (it->first != "startup") {
+ for (const RcOption& rcoption : it->second) {
+ result.push_back(
+ "--default_override=" + ToString(rcoption.rcfile_index() + 1) + ":"
+ + it->first + "=" + rcoption.option());
+ }
}
}
@@ -573,31 +510,44 @@
string env_str(*env);
if (IsValidEnvName(*env)) {
PreprocessEnvString(&env_str);
- command_arguments_.push_back("--client_env=" + env_str);
+ result.push_back("--client_env=" + env_str);
}
}
- command_arguments_.push_back("--client_cwd=" + blaze::ConvertPath(cwd));
+ result.push_back("--client_cwd=" + blaze::ConvertPath(cwd));
if (IsEmacsTerminal()) {
- command_arguments_.push_back("--emacs");
+ result.push_back("--emacs");
}
+ return result;
}
-void OptionProcessor::GetCommandArguments(vector<string>* result) const {
- result->insert(result->end(),
- command_arguments_.begin(),
- command_arguments_.end());
+std::vector<std::string> OptionProcessor::GetCommandArguments() const {
+ assert(cmd_line_ != nullptr);
+ // When the user didn't specify a command, the server expects the command
+ // arguments to be empty in order to display the help message.
+ if (cmd_line_->command.empty()) {
+ return {};
+ }
+
+ std::vector<std::string> command_args = blazerc_and_env_command_args_;
+ command_args.insert(command_args.end(),
+ cmd_line_->command_args.begin(),
+ cmd_line_->command_args.end());
+ return command_args;
}
std::vector<std::string> OptionProcessor::GetExplicitCommandArguments() const {
- return explicit_command_arguments_;
+ assert(cmd_line_ != nullptr);
+ return cmd_line_->command_args;
}
-const string& OptionProcessor::GetCommand() const {
- return command_;
+std::string OptionProcessor::GetCommand() const {
+ assert(cmd_line_ != nullptr);
+ return cmd_line_->command;
}
StartupOptions* OptionProcessor::GetParsedStartupOptions() const {
+ assert(parsed_startup_options_ != NULL);
return parsed_startup_options_.get();
}
diff --git a/src/main/cpp/option_processor.h b/src/main/cpp/option_processor.h
index af32dca..f572003 100644
--- a/src/main/cpp/option_processor.h
+++ b/src/main/cpp/option_processor.h
@@ -75,7 +75,7 @@
// remains untouched.
std::unique_ptr<CommandLine> SplitCommandLine(
const std::vector<std::string>& args,
- std::string* error);
+ std::string* error) const;
// Parse a command line and the appropriate blazerc files. This should be
// invoked only once per OptionProcessor object.
@@ -91,13 +91,13 @@
// Get the Blaze command to be executed.
// Returns an empty string if no command was found on the command line.
- const std::string& GetCommand() const;
+ std::string GetCommand() const;
// Gets the arguments to the command. This is put together from the default
// options specified in the blazerc file(s), the command line, and various
// bits and pieces of information about the environment the blaze binary is
// executed in.
- void GetCommandArguments(std::vector<std::string>* result) const;
+ std::vector<std::string> GetCommandArguments() const;
// Gets the arguments explicitly provided by the user's command line.
std::vector<std::string> GetExplicitCommandArguments() const;
@@ -145,31 +145,30 @@
int index_;
};
- void AddRcfileArgsAndOptions(const std::string& cwd);
blaze_exit_code::ExitCode ParseStartupOptions(std::string* error);
+ static std::vector<std::string> GetBlazercAndEnvCommandArgs(
+ const std::string& cwd,
+ const std::vector<RcFile*>& blazercs,
+ const std::map<std::string, std::vector<RcOption>>& rcoptions);
+
// The list of parsed rc files, this field is initialized by ParseOptions.
std::vector<RcFile*> blazercs_;
- std::map<std::string, std::vector<RcOption> > rcoptions_;
- // The original args given by the user, this field is initialized by
- // ParseOptions.
- std::vector<std::string> args_;
- // The index in args where the last startup option occurs, this field is
- // initialized by ParseOptions.
- unsigned int startup_args_;
- // The command found in args, this field is initialized by ParseOptions.
- std::string command_;
- // The list of command options. This is put together from the default
- // options specified in the bazelrc file(s), the command line, and various
- // bits and pieces of information about the environment the bazel binary is
- // executed in. This field is initialized by ParseOptions.
- std::vector<std::string> command_arguments_;
- // The list of command options found in args, this field is initialized by
- // ParseOptions.
- std::vector<std::string> explicit_command_arguments_;
- // Whether ParseOptions has been called.
- bool initialized_;
+
+ // A map representing the flags parsed from the bazelrc files.
+ // A key is a command (e.g. 'build', 'startup') and its value is an ordered
+ // list of RcOptions.
+ std::map<std::string, std::vector<RcOption>> rcoptions_;
+
+ // An ordered list of command args that contain information about the
+ // execution environment and the flags passed via the bazelrc files.
+ std::vector<std::string> blazerc_and_env_command_args_;
+
+ // The command line constructed after calling ParseOptions.
+ std::unique_ptr<CommandLine> cmd_line_;
+
const WorkspaceLayout* workspace_layout_;
+
// The startup options parsed from args, this field is initialized by
// ParseOptions.
std::unique_ptr<StartupOptions> parsed_startup_options_;
diff --git a/src/main/cpp/startup_options.cc b/src/main/cpp/startup_options.cc
index 21e0815..d54dbb2 100644
--- a/src/main/cpp/startup_options.cc
+++ b/src/main/cpp/startup_options.cc
@@ -376,6 +376,30 @@
return blaze_exit_code::SUCCESS;
}
+blaze_exit_code::ExitCode StartupOptions::ProcessArgs(
+ const std::vector<RcStartupFlag>& rcstartup_flags,
+ std::string *error) {
+ std::vector<RcStartupFlag>::size_type i = 0;
+ while (i < rcstartup_flags.size()) {
+ bool is_space_separated;
+ const bool is_last_elem = i == rcstartup_flags.size() - 1;
+ const blaze_exit_code::ExitCode process_arg_exit_code =
+ ProcessArg(rcstartup_flags[i].value,
+ is_last_elem ? "" : rcstartup_flags[i + 1].value,
+ rcstartup_flags[i].source,
+ &is_space_separated,
+ error);
+ if (process_arg_exit_code != blaze_exit_code::SUCCESS) {
+ return process_arg_exit_code;
+ }
+ if (is_space_separated) {
+ i++;
+ }
+ i++;
+ }
+ return blaze_exit_code::SUCCESS;
+}
+
blaze_exit_code::ExitCode StartupOptions::ProcessArgExtra(
const char *arg, const char *next_arg, const string &rcfile,
const char **value, bool *is_processed, string *error) {
diff --git a/src/main/cpp/startup_options.h b/src/main/cpp/startup_options.h
index 4b6d2b9..81cfe78 100644
--- a/src/main/cpp/startup_options.h
+++ b/src/main/cpp/startup_options.h
@@ -18,6 +18,7 @@
#include <memory>
#include <set>
#include <string>
+#include <utility>
#include <vector>
#include "src/main/cpp/util/exit_code.h"
@@ -60,6 +61,18 @@
const std::string name_;
};
+// A startup flag parsed from a bazelrc file.
+// For instance, RcStartupFlag("somepath/.bazelrc", "--foo") is used to
+// represent that the line "startup --foo" was found when parsing
+// "somepath/.bazelrc".
+struct RcStartupFlag {
+ const std::string source;
+ const std::string value;
+ RcStartupFlag(const std::string& source_arg,
+ const std::string& value_arg)
+ : source(source_arg), value(value_arg) {}
+};
+
// This class holds the parsed startup options for Blaze.
// These options and their defaults must be kept in sync with those in
// src/main/java/com/google/devtools/build/lib/runtime/BlazeServerStartupOptions.java.
@@ -96,6 +109,11 @@
bool *is_space_separated,
std::string *error);
+ // Process an ordered list of RcStartupFlags using ProcessArg.
+ blaze_exit_code::ExitCode ProcessArgs(
+ const std::vector<RcStartupFlag>& rcstartup_flags,
+ std::string *error);
+
// Adds any other options needed to result.
//
// TODO(jmmv): Now that we support site-specific options via subclasses of
diff --git a/src/test/cpp/option_processor_test.cc b/src/test/cpp/option_processor_test.cc
index da7c743..ab8ea59 100644
--- a/src/test/cpp/option_processor_test.cc
+++ b/src/test/cpp/option_processor_test.cc
@@ -59,8 +59,8 @@
std::string error;
const std::unique_ptr<CommandLine> result =
option_processor_->SplitCommandLine(args, &error);
- ASSERT_EQ(nullptr, result);
ASSERT_EQ(expected_error, error);
+ ASSERT_EQ(nullptr, result);
}
void SuccessfulSplitStartupOptionsTest(const std::vector<std::string>& args,
@@ -90,7 +90,8 @@
"--flag", "//my:target", "--flag2=42"};
std::string error;
ASSERT_EQ(blaze_exit_code::SUCCESS,
- option_processor_->ParseOptions(args, workspace_, cwd_, &error));
+ option_processor_->ParseOptions(args, workspace_, cwd_, &error))
+ << error;
ASSERT_EQ("", error);
ASSERT_EQ(1,
@@ -113,8 +114,10 @@
"--flag", "//my:target", "--flag2=42"};
std::string error;
ASSERT_EQ(blaze_exit_code::SUCCESS,
- option_processor_->ParseOptions(args, workspace_, cwd_, &error));
+ option_processor_->ParseOptions(args, workspace_, cwd_, &error))
+ << error;
+ ASSERT_EQ("", error);
ASSERT_EQ(1,
option_processor_->GetParsedStartupOptions()->host_jvm_args.size());
EXPECT_EQ("MyParam",
@@ -131,7 +134,9 @@
const std::vector<std::string> args = {"bazel"};
std::string error;
ASSERT_EQ(blaze_exit_code::SUCCESS,
- option_processor_->ParseOptions(args, workspace_, cwd_, &error));
+ option_processor_->ParseOptions(args, workspace_, cwd_, &error))
+ << error;
+ ASSERT_EQ("", error);
EXPECT_EQ("", option_processor_->GetCommand());
@@ -145,7 +150,9 @@
"--nobatch", "--host_jvm_args=MyParam", "--host_jvm_args", "42"};
std::string error;
ASSERT_EQ(blaze_exit_code::SUCCESS,
- option_processor_->ParseOptions(args, workspace_, cwd_, &error));
+ option_processor_->ParseOptions(args, workspace_, cwd_, &error))
+ << error;
+ ASSERT_EQ("", error);
ASSERT_EQ(2,
option_processor_->GetParsedStartupOptions()->host_jvm_args.size());
@@ -175,7 +182,8 @@
" For more info, run 'bazel help startup_options'.";
std::string error;
ASSERT_NE(blaze_exit_code::SUCCESS,
- option_processor_->ParseOptions(args, workspace_, cwd_, &error));
+ option_processor_->ParseOptions(args, workspace_, cwd_, &error))
+ << error;
ASSERT_EQ(expected_error, error);
}
@@ -199,7 +207,8 @@
"build"};
std::string error;
ASSERT_EQ(blaze_exit_code::SUCCESS,
- option_processor_->ParseOptions(args, workspace_, cwd_, &error));
+ option_processor_->ParseOptions(args, workspace_, cwd_, &error))
+ << error;
EXPECT_EQ(123, option_processor_->GetParsedStartupOptions()->max_idle_secs);
}