blob: 94d2d3f7f042e8f2d94c73bc5fa86e4a99e92522 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Han-Wen Nienhuys36fbe632015-04-21 13:58:08 +000015#include "src/main/cpp/option_processor.h"
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010016
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010020#include <algorithm>
21#include <cassert>
Nathan Harmata7d300b22015-12-21 16:10:05 +000022#include <set>
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010023#include <utility>
24
Han-Wen Nienhuys36fbe632015-04-21 13:58:08 +000025#include "src/main/cpp/blaze_util.h"
26#include "src/main/cpp/blaze_util_platform.h"
27#include "src/main/cpp/util/file.h"
Laszlo Csomor9c951962016-11-10 13:31:27 +000028#include "src/main/cpp/util/file_platform.h"
Chloe Calvarin78f1c852016-11-22 21:58:50 +000029#include "src/main/cpp/util/logging.h"
Han-Wen Nienhuys36fbe632015-04-21 13:58:08 +000030#include "src/main/cpp/util/strings.h"
Julio Merino211a95c2016-08-29 11:01:35 +000031#include "src/main/cpp/workspace_layout.h"
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010032
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010033// On OSX, there apparently is no header that defines this.
34extern char **environ;
35
36namespace blaze {
37
Thiago Farina80bb0f22016-10-17 15:57:13 +000038using std::list;
39using std::map;
40using std::set;
41using std::string;
42using std::vector;
43
Julio Merino211a95c2016-08-29 11:01:35 +000044constexpr char WorkspaceLayout::WorkspacePrefix[];
Googlere3681d12015-12-02 22:26:59 +000045
Thiago Farina2e4c2aa2015-06-12 07:18:20 +000046OptionProcessor::RcOption::RcOption(int rcfile_index, const string& option)
47 : rcfile_index_(rcfile_index), option_(option) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010048}
49
Thiago Farina2e4c2aa2015-06-12 07:18:20 +000050OptionProcessor::RcFile::RcFile(const string& filename, int index)
51 : filename_(filename), index_(index) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010052}
53
54blaze_exit_code::ExitCode OptionProcessor::RcFile::Parse(
Googlere3681d12015-12-02 22:26:59 +000055 const string& workspace,
Julio Merinoe3e3bfa2016-12-08 22:22:12 +000056 const WorkspaceLayout* workspace_layout,
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +000057 vector<RcFile*>* rcfiles,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010058 map<string, vector<RcOption> >* rcoptions,
59 string* error) {
60 list<string> initial_import_stack;
61 initial_import_stack.push_back(filename_);
62 return Parse(
Julio Merinoe3e3bfa2016-12-08 22:22:12 +000063 workspace, filename_, index_, workspace_layout,
64 rcfiles, rcoptions, &initial_import_stack,
Googlere3681d12015-12-02 22:26:59 +000065 error);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010066}
67
68blaze_exit_code::ExitCode OptionProcessor::RcFile::Parse(
Googlere3681d12015-12-02 22:26:59 +000069 const string& workspace,
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +000070 const string& filename_ref,
Thiago Farina2fd78902015-05-18 11:37:59 +000071 const int index,
Julio Merinoe3e3bfa2016-12-08 22:22:12 +000072 const WorkspaceLayout* workspace_layout,
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +000073 vector<RcFile*>* rcfiles,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010074 map<string, vector<RcOption> >* rcoptions,
75 list<string>* import_stack,
76 string* error) {
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +000077 string filename(filename_ref); // file
Chloe Calvarin78f1c852016-11-22 21:58:50 +000078 BAZEL_LOG(INFO) << "Parsing the RcFile " << filename;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010079 string contents;
Laszlo Csomor49970e02016-11-28 08:55:47 +000080 if (!blaze_util::ReadFile(filename, &contents)) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010081 // We checked for file readability before, so this is unexpected.
82 blaze_util::StringPrintf(error,
83 "Unexpected error reading .blazerc file '%s'", filename.c_str());
84 return blaze_exit_code::INTERNAL_ERROR;
85 }
86
87 // A '\' at the end of a line continues the line.
88 blaze_util::Replace("\\\r\n", "", &contents);
89 blaze_util::Replace("\\\n", "", &contents);
90 vector<string> startup_options;
91
92 vector<string> lines = blaze_util::Split(contents, '\n');
93 for (int line = 0; line < lines.size(); ++line) {
94 blaze_util::StripWhitespace(&lines[line]);
95
96 // Check for an empty line.
97 if (lines[line].empty()) {
98 continue;
99 }
100
101 vector<string> words;
102
103 // This will treat "#" as a comment, and properly
104 // quote single and double quotes, and treat '\'
105 // as an escape character.
106 // TODO(bazel-team): This function silently ignores
107 // dangling backslash escapes and missing end-quotes.
108 blaze_util::Tokenize(lines[line], '#', &words);
109
110 if (words.empty()) {
111 // Could happen if line starts with "#"
112 continue;
113 }
114
115 string command = words[0];
116
117 if (command == "import") {
Googlere3681d12015-12-02 22:26:59 +0000118 if (words.size() != 2
Julio Merinoe3e3bfa2016-12-08 22:22:12 +0000119 || (words[1].compare(0, workspace_layout->WorkspacePrefixLength,
120 workspace_layout->WorkspacePrefix) == 0
121 && !workspace_layout->WorkspaceRelativizeRcFilePath(
Googlere3681d12015-12-02 22:26:59 +0000122 workspace, &words[1]))) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100123 blaze_util::StringPrintf(error,
124 "Invalid import declaration in .blazerc file '%s': '%s'",
125 filename.c_str(), lines[line].c_str());
126 return blaze_exit_code::BAD_ARGV;
127 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100128 if (std::find(import_stack->begin(), import_stack->end(), words[1]) !=
129 import_stack->end()) {
130 string loop;
131 for (list<string>::const_iterator imported_rc = import_stack->begin();
132 imported_rc != import_stack->end(); ++imported_rc) {
133 loop += " " + *imported_rc + "\n";
134 }
135 blaze_util::StringPrintf(error,
136 "Import loop detected:\n%s", loop.c_str());
137 return blaze_exit_code::BAD_ARGV;
138 }
139
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +0000140 rcfiles->push_back(new RcFile(words[1], rcfiles->size()));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100141 import_stack->push_back(words[1]);
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +0000142 blaze_exit_code::ExitCode parse_exit_code =
Googlere3681d12015-12-02 22:26:59 +0000143 RcFile::Parse(workspace, rcfiles->back()->Filename(),
Julio Merinoe3e3bfa2016-12-08 22:22:12 +0000144 rcfiles->back()->Index(), workspace_layout,
Googlere3681d12015-12-02 22:26:59 +0000145 rcfiles, rcoptions, import_stack, error);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100146 if (parse_exit_code != blaze_exit_code::SUCCESS) {
147 return parse_exit_code;
148 }
149 import_stack->pop_back();
150 } else {
151 for (int word = 1; word < words.size(); ++word) {
152 (*rcoptions)[command].push_back(RcOption(index, words[word]));
153 if (command == "startup") {
154 startup_options.push_back(words[word]);
155 }
156 }
157 }
158 }
159
160 if (!startup_options.empty()) {
161 string startup_args;
162 blaze_util::JoinStrings(startup_options, ' ', &startup_args);
163 fprintf(stderr, "INFO: Reading 'startup' options from %s: %s\n",
164 filename.c_str(), startup_args.c_str());
165 }
166 return blaze_exit_code::SUCCESS;
167}
168
Julio Merino28774852016-09-14 16:59:46 +0000169OptionProcessor::OptionProcessor(
Julio Merinoe3e3bfa2016-12-08 22:22:12 +0000170 const WorkspaceLayout* workspace_layout,
171 std::unique_ptr<StartupOptions> default_startup_options)
172 : initialized_(false),
173 workspace_layout_(workspace_layout),
174 parsed_startup_options_(std::move(default_startup_options)) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100175}
176
Luis Fernando Pino Duque0311fc52016-11-21 13:20:50 +0000177std::unique_ptr<CommandLine> OptionProcessor::SplitCommandLine(
178 const vector<string>& args,
179 string* error) {
180 const string lowercase_product_name =
181 parsed_startup_options_->GetLowercaseProductName();
182
183 if (args.empty()) {
184 blaze_util::StringPrintf(error,
185 "Unable to split command line, args is empty");
186 return nullptr;
187 }
188
189 const string path_to_binary(args[0]);
190
191 // Process the startup options.
192 vector<string> startup_args;
193 vector<string>::size_type i = 1;
194 while (i < args.size() && IsArg(args[i])) {
195 const string current_arg(args[i]);
196 // If the current argument is a valid nullary startup option such as
197 // --master_bazelrc or --nomaster_bazelrc proceed to examine the next
198 // argument.
199 if (parsed_startup_options_->IsNullary(current_arg)) {
200 startup_args.push_back(current_arg);
201 i++;
202 } else if (parsed_startup_options_->IsUnary(current_arg)) {
203 // If the current argument is a valid unary startup option such as
204 // --bazelrc there are two cases to consider.
205
206 // The option is of the form '--bazelrc=value', hence proceed to
207 // examine the next argument.
208 if (current_arg.find("=") != string::npos) {
209 startup_args.push_back(current_arg);
210 i++;
211 } else {
212 // Otherwise, the option is of the form '--bazelrc value', hence
213 // skip the next argument and proceed to examine the argument located
214 // two places after.
215 if (i + 1 >= args.size()) {
216 blaze_util::StringPrintf(
217 error,
218 "Startup option '%s' expects a value.\n"
219 "Usage: '%s=somevalue' or '%s somevalue'.\n"
220 " For more info, run '%s help startup_options'.",
221 current_arg.c_str(), current_arg.c_str(), current_arg.c_str(),
222 lowercase_product_name.c_str());
223 return nullptr;
224 }
225 // In this case we transform it to the form '--bazelrc=value'.
226 startup_args.push_back(current_arg + string("=") + args[i + 1]);
227 i += 2;
228 }
229 } else {
230 // If the current argument is not a valid unary or nullary startup option
231 // then fail.
232 blaze_util::StringPrintf(
233 error,
Luis Fernando Pino Duqued5e008c2016-12-08 16:59:16 +0000234 "Unknown startup option: '%s'.\n"
Luis Fernando Pino Duque0311fc52016-11-21 13:20:50 +0000235 " For more info, run '%s help startup_options'.",
Luis Fernando Pino Duqued5e008c2016-12-08 16:59:16 +0000236 current_arg.c_str(), lowercase_product_name.c_str());
Luis Fernando Pino Duque0311fc52016-11-21 13:20:50 +0000237 return nullptr;
238 }
239 }
240
241 // The command is the arg right after the startup options.
242 if (i == args.size()) {
243 return std::unique_ptr<CommandLine>(
244 new CommandLine(path_to_binary, startup_args, "", {}));
245 }
246 const string command(args[i]);
247
248 // The rest are the command arguments.
249 const vector<string> command_args(args.begin() + i + 1, args.end());
250
251 return std::unique_ptr<CommandLine>(
252 new CommandLine(path_to_binary, startup_args, command, command_args));
253}
254
Thiago Farina9bc5c342016-03-21 08:39:48 +0000255// Return the path to the user's rc file. If cmdLineRcFile != NULL,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100256// use it, dying if it is not readable. Otherwise, return the first
257// readable file called rc_basename from [workspace, $HOME]
258//
259// If no readable .blazerc file is found, return the empty string.
260blaze_exit_code::ExitCode OptionProcessor::FindUserBlazerc(
261 const char* cmdLineRcFile,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100262 const string& workspace,
263 string* blaze_rc_file,
264 string* error) {
Julio Merino726ca5a2017-01-20 14:05:26 +0000265 const string rc_basename =
266 "." + parsed_startup_options_->GetLowercaseProductName() + "rc";
267
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100268 if (cmdLineRcFile != NULL) {
269 string rcFile = MakeAbsolute(cmdLineRcFile);
Laszlo Csomor00549b42017-01-11 09:12:10 +0000270 if (!blaze_util::CanReadFile(rcFile)) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100271 blaze_util::StringPrintf(error,
Julio Merino726ca5a2017-01-20 14:05:26 +0000272 "Error: Unable to read %s file '%s'.", rc_basename.c_str(),
273 rcFile.c_str());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100274 return blaze_exit_code::BAD_ARGV;
275 }
276 *blaze_rc_file = rcFile;
277 return blaze_exit_code::SUCCESS;
278 }
279
280 string workspaceRcFile = blaze_util::JoinPath(workspace, rc_basename);
Laszlo Csomor00549b42017-01-11 09:12:10 +0000281 if (blaze_util::CanReadFile(workspaceRcFile)) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100282 *blaze_rc_file = workspaceRcFile;
283 return blaze_exit_code::SUCCESS;
284 }
285
Laszlo Csomorcefa9a22016-11-22 10:50:07 +0000286 string home = blaze::GetEnv("HOME");
287 if (home.empty()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100288 *blaze_rc_file = "";
289 return blaze_exit_code::SUCCESS;
290 }
291
292 string userRcFile = blaze_util::JoinPath(home, rc_basename);
Laszlo Csomor00549b42017-01-11 09:12:10 +0000293 if (blaze_util::CanReadFile(userRcFile)) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100294 *blaze_rc_file = userRcFile;
295 return blaze_exit_code::SUCCESS;
296 }
297 *blaze_rc_file = "";
298 return blaze_exit_code::SUCCESS;
299}
300
301blaze_exit_code::ExitCode OptionProcessor::ParseOptions(
302 const vector<string>& args,
303 const string& workspace,
304 const string& cwd,
305 string* error) {
306 assert(!initialized_);
307 initialized_ = true;
308
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100309 args_ = args;
Luis Fernando Pino Duqued5e008c2016-12-08 16:59:16 +0000310 // Check if there is a blazerc related option given
311 std::unique_ptr<CommandLine> cmdLine = SplitCommandLine(args, error);
312 if (cmdLine == nullptr) {
313 return blaze_exit_code::BAD_ARGV;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100314 }
315
Luis Fernando Pino Duqued5e008c2016-12-08 16:59:16 +0000316 const char* blazerc = SearchUnaryOption(cmdLine->startup_args, "--blazerc");
317 if (blazerc == NULL) {
318 blazerc = SearchUnaryOption(cmdLine->startup_args, "--bazelrc");
319 }
320
321 bool use_master_blazerc = true;
322 if (SearchNullaryOption(cmdLine->startup_args, "--nomaster_blazerc") ||
323 SearchNullaryOption(cmdLine->startup_args, "--nomaster_bazelrc")) {
324 use_master_blazerc = false;
Luis Fernando Pino Duquef5cf2002016-08-19 13:44:17 +0000325 }
326
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100327 // Parse depot and user blazerc files.
Nathan Harmata7d300b22015-12-21 16:10:05 +0000328 vector<string> candidate_blazerc_paths;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100329 if (use_master_blazerc) {
Julio Merinoe3e3bfa2016-12-08 22:22:12 +0000330 workspace_layout_->FindCandidateBlazercPaths(
Luis Fernando Pino Duqued5e008c2016-12-08 16:59:16 +0000331 workspace, cwd, cmdLine->path_to_binary, cmdLine->startup_args,
332 &candidate_blazerc_paths);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100333 }
334
335 string user_blazerc_path;
336 blaze_exit_code::ExitCode find_blazerc_exit_code = FindUserBlazerc(
Julio Merino726ca5a2017-01-20 14:05:26 +0000337 blazerc, workspace, &user_blazerc_path, error);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100338 if (find_blazerc_exit_code != blaze_exit_code::SUCCESS) {
339 return find_blazerc_exit_code;
340 }
Nathan Harmata7d300b22015-12-21 16:10:05 +0000341 candidate_blazerc_paths.push_back(user_blazerc_path);
342
343 // Throw away missing files, dedupe candidate blazerc paths, and parse the
344 // blazercs, all while preserving order. Duplicates can arise if e.g. the
345 // binary's path *is* the depot path.
346 set<string> blazerc_paths;
347 for (const auto& candidate_blazerc_path : candidate_blazerc_paths) {
348 if (!candidate_blazerc_path.empty()
349 && (blazerc_paths.insert(candidate_blazerc_path).second)) {
350 blazercs_.push_back(
351 new RcFile(candidate_blazerc_path, blazercs_.size()));
352 blaze_exit_code::ExitCode parse_exit_code =
Julio Merinoe3e3bfa2016-12-08 22:22:12 +0000353 blazercs_.back()->Parse(workspace, workspace_layout_, &blazercs_,
354 &rcoptions_, error);
Nathan Harmata7d300b22015-12-21 16:10:05 +0000355 if (parse_exit_code != blaze_exit_code::SUCCESS) {
356 return parse_exit_code;
357 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100358 }
359 }
360
361 blaze_exit_code::ExitCode parse_startup_options_exit_code =
362 ParseStartupOptions(error);
363 if (parse_startup_options_exit_code != blaze_exit_code::SUCCESS) {
364 return parse_startup_options_exit_code;
365 }
366
367 // Determine command
368 if (startup_args_ + 1 >= args.size()) {
369 command_ = "";
370 return blaze_exit_code::SUCCESS;
371 }
372
373 command_ = args[startup_args_ + 1];
374
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100375 AddRcfileArgsAndOptions(parsed_startup_options_->batch, cwd);
376 for (unsigned int cmd_arg = startup_args_ + 2;
377 cmd_arg < args.size(); cmd_arg++) {
378 command_arguments_.push_back(args[cmd_arg]);
379 }
380 return blaze_exit_code::SUCCESS;
381}
382
383blaze_exit_code::ExitCode OptionProcessor::ParseOptions(
384 int argc,
385 const char* argv[],
386 const string& workspace,
387 const string& cwd,
388 string* error) {
389 vector<string> args(argc);
390 for (int arg = 0; arg < argc; arg++) {
391 args[arg] = argv[arg];
392 }
393
394 return ParseOptions(args, workspace, cwd, error);
395}
396
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100397blaze_exit_code::ExitCode OptionProcessor::ParseStartupOptions(string *error) {
398 // Process rcfile startup options
399 map< string, vector<RcOption> >::const_iterator it =
400 rcoptions_.find("startup");
401 blaze_exit_code::ExitCode process_arg_exit_code;
402 bool is_space_separated;
403 if (it != rcoptions_.end()) {
404 const vector<RcOption>& startup_options = it->second;
405 int i = 0;
406 // Process all elements except the last one.
407 for (; i < startup_options.size() - 1; i++) {
408 const RcOption& option = startup_options[i];
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +0000409 const string& blazerc = blazercs_[option.rcfile_index()]->Filename();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100410 process_arg_exit_code = parsed_startup_options_->ProcessArg(
411 option.option(), startup_options[i + 1].option(), blazerc,
412 &is_space_separated, error);
413 if (process_arg_exit_code != blaze_exit_code::SUCCESS) {
414 return process_arg_exit_code;
415 }
416 if (is_space_separated) {
417 i++;
418 }
419 }
420 // Process last element, if any.
421 if (i < startup_options.size()) {
422 const RcOption& option = startup_options[i];
423 if (IsArg(option.option())) {
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +0000424 const string& blazerc = blazercs_[option.rcfile_index()]->Filename();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100425 process_arg_exit_code = parsed_startup_options_->ProcessArg(
426 option.option(), "", blazerc, &is_space_separated, error);
427 if (process_arg_exit_code != blaze_exit_code::SUCCESS) {
428 return process_arg_exit_code;
429 }
430 }
431 }
432 }
433
434 // Process command-line args next, so they override any of the same options
435 // from .blazerc. Stop on first non-arg, this includes --help
436 unsigned int i = 1;
437 if (!args_.empty()) {
438 for (; (i < args_.size() - 1) && IsArg(args_[i]); i++) {
439 process_arg_exit_code = parsed_startup_options_->ProcessArg(
440 args_[i], args_[i + 1], "", &is_space_separated, error);
441 if (process_arg_exit_code != blaze_exit_code::SUCCESS) {
442 return process_arg_exit_code;
443 }
444 if (is_space_separated) {
445 i++;
446 }
447 }
448 if (i < args_.size() && IsArg(args_[i])) {
449 process_arg_exit_code = parsed_startup_options_->ProcessArg(
450 args_[i], "", "", &is_space_separated, error);
451 if (process_arg_exit_code != blaze_exit_code::SUCCESS) {
452 return process_arg_exit_code;
453 }
454 i++;
455 }
456 }
457 startup_args_ = i -1;
458
459 return blaze_exit_code::SUCCESS;
460}
461
462// Appends the command and arguments from argc/argv to the end of arg_vector,
463// and also splices in some additional terminal and environment options between
464// the command and the arguments. NB: Keep the options added here in sync with
465// BlazeCommandDispatcher.INTERNAL_COMMAND_OPTIONS!
466void OptionProcessor::AddRcfileArgsAndOptions(bool batch, const string& cwd) {
Klaus Aehlig3c9a2262016-04-20 15:13:51 +0000467 // Provide terminal options as coming from the least important rc file.
468 command_arguments_.push_back("--rc_source=client");
469 command_arguments_.push_back("--default_override=0:common=--isatty=" +
470 ToString(IsStandardTerminal()));
471 command_arguments_.push_back(
472 "--default_override=0:common=--terminal_columns=" +
473 ToString(GetTerminalColumns()));
474
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100475 // Push the options mapping .blazerc numbers to filenames.
476 for (int i_blazerc = 0; i_blazerc < blazercs_.size(); i_blazerc++) {
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +0000477 const RcFile* blazerc = blazercs_[i_blazerc];
Dmitry Lomov78c0cc72015-08-11 16:44:21 +0000478 command_arguments_.push_back("--rc_source=" +
479 blaze::ConvertPath(blazerc->Filename()));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100480 }
481
482 // Push the option defaults
483 for (map<string, vector<RcOption> >::const_iterator it = rcoptions_.begin();
484 it != rcoptions_.end(); ++it) {
485 if (it->first == "startup") {
486 // Skip startup options, they are parsed in the C++ wrapper
487 continue;
488 }
489
490 for (int ii = 0; ii < it->second.size(); ii++) {
491 const RcOption& rcoption = it->second[ii];
Googler016baf32016-03-30 20:21:23 +0000492 command_arguments_.push_back(
Klaus Aehlig3c9a2262016-04-20 15:13:51 +0000493 "--default_override=" + ToString(rcoption.rcfile_index() + 1) + ":"
Googler016baf32016-03-30 20:21:23 +0000494 + it->first + "=" + rcoption.option());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100495 }
496 }
497
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100498 // Pass the client environment to the server in server mode.
499 if (batch) {
500 command_arguments_.push_back("--ignore_client_env");
501 } else {
502 for (char** env = environ; *env != NULL; env++) {
Yun Peng44fa4c72016-07-15 08:38:38 +0000503 string env_str(*env);
504 int pos = env_str.find("=");
505 if (pos != string::npos) {
506 string name = env_str.substr(0, pos);
Laszlo Csomor6713d382016-08-26 05:14:37 +0000507 if (name == "PATH") {
508 env_str = "PATH=" + ConvertPathList(env_str.substr(pos + 1));
509 } else if (name == "TMP") {
510 // A valid Windows path "c:/foo" is also a valid Unix path list of
511 // ["c", "/foo"] so must use ConvertPath here. See GitHub issue #1684.
512 env_str = "TMP=" + ConvertPath(env_str.substr(pos + 1));
Yun Peng44fa4c72016-07-15 08:38:38 +0000513 }
514 }
515 command_arguments_.push_back("--client_env=" + env_str);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100516 }
517 }
Dmitry Lomov78c0cc72015-08-11 16:44:21 +0000518 command_arguments_.push_back("--client_cwd=" + blaze::ConvertPath(cwd));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100519
Googler957f3742016-08-31 18:16:24 +0000520 if (IsEmacsTerminal()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100521 command_arguments_.push_back("--emacs");
522 }
523}
524
525void OptionProcessor::GetCommandArguments(vector<string>* result) const {
526 result->insert(result->end(),
527 command_arguments_.begin(),
528 command_arguments_.end());
529}
530
531const string& OptionProcessor::GetCommand() const {
532 return command_;
533}
534
Julio Merino28774852016-09-14 16:59:46 +0000535StartupOptions* OptionProcessor::GetParsedStartupOptions() const {
536 return parsed_startup_options_.get();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100537}
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +0000538
539OptionProcessor::~OptionProcessor() {
540 for (auto it : blazercs_) {
541 delete it;
542 }
543}
544
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100545} // namespace blaze