blob: f7340db783672e56eb7a07304943a99f74dfbc75 [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"
Han-Wen Nienhuys36fbe632015-04-21 13:58:08 +000029#include "src/main/cpp/util/strings.h"
Julio Merino211a95c2016-08-29 11:01:35 +000030#include "src/main/cpp/workspace_layout.h"
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010031
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010032// On OSX, there apparently is no header that defines this.
33extern char **environ;
34
35namespace blaze {
36
Thiago Farina80bb0f22016-10-17 15:57:13 +000037using std::list;
38using std::map;
39using std::set;
40using std::string;
41using std::vector;
42
Julio Merino211a95c2016-08-29 11:01:35 +000043constexpr char WorkspaceLayout::WorkspacePrefix[];
Googlere3681d12015-12-02 22:26:59 +000044
Thiago Farina2e4c2aa2015-06-12 07:18:20 +000045OptionProcessor::RcOption::RcOption(int rcfile_index, const string& option)
46 : rcfile_index_(rcfile_index), option_(option) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010047}
48
Thiago Farina2e4c2aa2015-06-12 07:18:20 +000049OptionProcessor::RcFile::RcFile(const string& filename, int index)
50 : filename_(filename), index_(index) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010051}
52
53blaze_exit_code::ExitCode OptionProcessor::RcFile::Parse(
Googlere3681d12015-12-02 22:26:59 +000054 const string& workspace,
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +000055 vector<RcFile*>* rcfiles,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010056 map<string, vector<RcOption> >* rcoptions,
57 string* error) {
58 list<string> initial_import_stack;
59 initial_import_stack.push_back(filename_);
60 return Parse(
Googlere3681d12015-12-02 22:26:59 +000061 workspace, filename_, index_, rcfiles, rcoptions, &initial_import_stack,
62 error);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010063}
64
65blaze_exit_code::ExitCode OptionProcessor::RcFile::Parse(
Googlere3681d12015-12-02 22:26:59 +000066 const string& workspace,
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +000067 const string& filename_ref,
Thiago Farina2fd78902015-05-18 11:37:59 +000068 const int index,
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +000069 vector<RcFile*>* rcfiles,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010070 map<string, vector<RcOption> >* rcoptions,
71 list<string>* import_stack,
72 string* error) {
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +000073 string filename(filename_ref); // file
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010074 string contents;
75 if (!ReadFile(filename, &contents)) {
76 // We checked for file readability before, so this is unexpected.
77 blaze_util::StringPrintf(error,
78 "Unexpected error reading .blazerc file '%s'", filename.c_str());
79 return blaze_exit_code::INTERNAL_ERROR;
80 }
81
82 // A '\' at the end of a line continues the line.
83 blaze_util::Replace("\\\r\n", "", &contents);
84 blaze_util::Replace("\\\n", "", &contents);
85 vector<string> startup_options;
86
87 vector<string> lines = blaze_util::Split(contents, '\n');
88 for (int line = 0; line < lines.size(); ++line) {
89 blaze_util::StripWhitespace(&lines[line]);
90
91 // Check for an empty line.
92 if (lines[line].empty()) {
93 continue;
94 }
95
96 vector<string> words;
97
98 // This will treat "#" as a comment, and properly
99 // quote single and double quotes, and treat '\'
100 // as an escape character.
101 // TODO(bazel-team): This function silently ignores
102 // dangling backslash escapes and missing end-quotes.
103 blaze_util::Tokenize(lines[line], '#', &words);
104
105 if (words.empty()) {
106 // Could happen if line starts with "#"
107 continue;
108 }
109
110 string command = words[0];
111
112 if (command == "import") {
Googlere3681d12015-12-02 22:26:59 +0000113 if (words.size() != 2
Julio Merino211a95c2016-08-29 11:01:35 +0000114 || (words[1].compare(0, WorkspaceLayout::WorkspacePrefixLength,
115 WorkspaceLayout::WorkspacePrefix) == 0
116 && !WorkspaceLayout::WorkspaceRelativizeRcFilePath(
Googlere3681d12015-12-02 22:26:59 +0000117 workspace, &words[1]))) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100118 blaze_util::StringPrintf(error,
119 "Invalid import declaration in .blazerc file '%s': '%s'",
120 filename.c_str(), lines[line].c_str());
121 return blaze_exit_code::BAD_ARGV;
122 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100123 if (std::find(import_stack->begin(), import_stack->end(), words[1]) !=
124 import_stack->end()) {
125 string loop;
126 for (list<string>::const_iterator imported_rc = import_stack->begin();
127 imported_rc != import_stack->end(); ++imported_rc) {
128 loop += " " + *imported_rc + "\n";
129 }
130 blaze_util::StringPrintf(error,
131 "Import loop detected:\n%s", loop.c_str());
132 return blaze_exit_code::BAD_ARGV;
133 }
134
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +0000135 rcfiles->push_back(new RcFile(words[1], rcfiles->size()));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100136 import_stack->push_back(words[1]);
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +0000137 blaze_exit_code::ExitCode parse_exit_code =
Googlere3681d12015-12-02 22:26:59 +0000138 RcFile::Parse(workspace, rcfiles->back()->Filename(),
139 rcfiles->back()->Index(),
140 rcfiles, rcoptions, import_stack, error);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100141 if (parse_exit_code != blaze_exit_code::SUCCESS) {
142 return parse_exit_code;
143 }
144 import_stack->pop_back();
145 } else {
146 for (int word = 1; word < words.size(); ++word) {
147 (*rcoptions)[command].push_back(RcOption(index, words[word]));
148 if (command == "startup") {
149 startup_options.push_back(words[word]);
150 }
151 }
152 }
153 }
154
155 if (!startup_options.empty()) {
156 string startup_args;
157 blaze_util::JoinStrings(startup_options, ' ', &startup_args);
158 fprintf(stderr, "INFO: Reading 'startup' options from %s: %s\n",
159 filename.c_str(), startup_args.c_str());
160 }
161 return blaze_exit_code::SUCCESS;
162}
163
Julio Merino28774852016-09-14 16:59:46 +0000164OptionProcessor::OptionProcessor(
165 std::unique_ptr<StartupOptions> default_startup_options) :
166 initialized_(false),
167 parsed_startup_options_(std::move(default_startup_options)) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100168}
169
Luis Fernando Pino Duque0311fc52016-11-21 13:20:50 +0000170std::unique_ptr<CommandLine> OptionProcessor::SplitCommandLine(
171 const vector<string>& args,
172 string* error) {
173 const string lowercase_product_name =
174 parsed_startup_options_->GetLowercaseProductName();
175
176 if (args.empty()) {
177 blaze_util::StringPrintf(error,
178 "Unable to split command line, args is empty");
179 return nullptr;
180 }
181
182 const string path_to_binary(args[0]);
183
184 // Process the startup options.
185 vector<string> startup_args;
186 vector<string>::size_type i = 1;
187 while (i < args.size() && IsArg(args[i])) {
188 const string current_arg(args[i]);
189 // If the current argument is a valid nullary startup option such as
190 // --master_bazelrc or --nomaster_bazelrc proceed to examine the next
191 // argument.
192 if (parsed_startup_options_->IsNullary(current_arg)) {
193 startup_args.push_back(current_arg);
194 i++;
195 } else if (parsed_startup_options_->IsUnary(current_arg)) {
196 // If the current argument is a valid unary startup option such as
197 // --bazelrc there are two cases to consider.
198
199 // The option is of the form '--bazelrc=value', hence proceed to
200 // examine the next argument.
201 if (current_arg.find("=") != string::npos) {
202 startup_args.push_back(current_arg);
203 i++;
204 } else {
205 // Otherwise, the option is of the form '--bazelrc value', hence
206 // skip the next argument and proceed to examine the argument located
207 // two places after.
208 if (i + 1 >= args.size()) {
209 blaze_util::StringPrintf(
210 error,
211 "Startup option '%s' expects a value.\n"
212 "Usage: '%s=somevalue' or '%s somevalue'.\n"
213 " For more info, run '%s help startup_options'.",
214 current_arg.c_str(), current_arg.c_str(), current_arg.c_str(),
215 lowercase_product_name.c_str());
216 return nullptr;
217 }
218 // In this case we transform it to the form '--bazelrc=value'.
219 startup_args.push_back(current_arg + string("=") + args[i + 1]);
220 i += 2;
221 }
222 } else {
223 // If the current argument is not a valid unary or nullary startup option
224 // then fail.
225 blaze_util::StringPrintf(
226 error,
227 "Unknown %s startup option: '%s'.\n"
228 " For more info, run '%s help startup_options'.",
229 lowercase_product_name.c_str(), current_arg.c_str(),
230 lowercase_product_name.c_str());
231 return nullptr;
232 }
233 }
234
235 // The command is the arg right after the startup options.
236 if (i == args.size()) {
237 return std::unique_ptr<CommandLine>(
238 new CommandLine(path_to_binary, startup_args, "", {}));
239 }
240 const string command(args[i]);
241
242 // The rest are the command arguments.
243 const vector<string> command_args(args.begin() + i + 1, args.end());
244
245 return std::unique_ptr<CommandLine>(
246 new CommandLine(path_to_binary, startup_args, command, command_args));
247}
248
Thiago Farina9bc5c342016-03-21 08:39:48 +0000249// Return the path to the user's rc file. If cmdLineRcFile != NULL,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100250// use it, dying if it is not readable. Otherwise, return the first
251// readable file called rc_basename from [workspace, $HOME]
252//
253// If no readable .blazerc file is found, return the empty string.
254blaze_exit_code::ExitCode OptionProcessor::FindUserBlazerc(
255 const char* cmdLineRcFile,
256 const string& rc_basename,
257 const string& workspace,
258 string* blaze_rc_file,
259 string* error) {
260 if (cmdLineRcFile != NULL) {
261 string rcFile = MakeAbsolute(cmdLineRcFile);
Laszlo Csomor9c951962016-11-10 13:31:27 +0000262 if (!blaze_util::CanAccess(rcFile, true, false, false)) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100263 blaze_util::StringPrintf(error,
264 "Error: Unable to read .blazerc file '%s'.", rcFile.c_str());
265 return blaze_exit_code::BAD_ARGV;
266 }
267 *blaze_rc_file = rcFile;
268 return blaze_exit_code::SUCCESS;
269 }
270
271 string workspaceRcFile = blaze_util::JoinPath(workspace, rc_basename);
Laszlo Csomor9c951962016-11-10 13:31:27 +0000272 if (blaze_util::CanAccess(workspaceRcFile, true, false, false)) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100273 *blaze_rc_file = workspaceRcFile;
274 return blaze_exit_code::SUCCESS;
275 }
276
Laszlo Csomorcefa9a22016-11-22 10:50:07 +0000277 string home = blaze::GetEnv("HOME");
278 if (home.empty()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100279 *blaze_rc_file = "";
280 return blaze_exit_code::SUCCESS;
281 }
282
283 string userRcFile = blaze_util::JoinPath(home, rc_basename);
Laszlo Csomor9c951962016-11-10 13:31:27 +0000284 if (blaze_util::CanAccess(userRcFile, true, false, false)) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100285 *blaze_rc_file = userRcFile;
286 return blaze_exit_code::SUCCESS;
287 }
288 *blaze_rc_file = "";
289 return blaze_exit_code::SUCCESS;
290}
291
292blaze_exit_code::ExitCode OptionProcessor::ParseOptions(
293 const vector<string>& args,
294 const string& workspace,
295 const string& cwd,
296 string* error) {
297 assert(!initialized_);
298 initialized_ = true;
299
300 const char* blazerc = NULL;
301 bool use_master_blazerc = true;
302
303 // Check if there is a blazerc related option given
304 args_ = args;
305 for (int i= 1; i < args.size(); i++) {
306 const char* arg_chr = args[i].c_str();
307 const char* next_arg_chr = (i + 1) < args.size()
308 ? args[i + 1].c_str()
309 : NULL;
310 if (blazerc == NULL) {
311 blazerc = GetUnaryOption(arg_chr, next_arg_chr, "--blazerc");
312 }
Damien Martin-Guillerez8cde69c2015-06-05 11:33:44 +0000313 if (blazerc == NULL) {
314 blazerc = GetUnaryOption(arg_chr, next_arg_chr, "--bazelrc");
315 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100316 if (use_master_blazerc &&
Damien Martin-Guillerez50d124b2015-06-24 15:20:09 +0000317 (GetNullaryOption(arg_chr, "--nomaster_blazerc") ||
318 GetNullaryOption(arg_chr, "--nomaster_bazelrc"))) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100319 use_master_blazerc = false;
320 }
321 }
322
Luis Fernando Pino Duquef5cf2002016-08-19 13:44:17 +0000323 blaze_exit_code::ExitCode validate_startup_options_exit_code =
Julio Merino28774852016-09-14 16:59:46 +0000324 parsed_startup_options_->ValidateStartupOptions(args, error);
Luis Fernando Pino Duquef5cf2002016-08-19 13:44:17 +0000325 if (validate_startup_options_exit_code != blaze_exit_code::SUCCESS) {
326 return validate_startup_options_exit_code;
327 }
328
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100329 // Parse depot and user blazerc files.
Nathan Harmata7d300b22015-12-21 16:10:05 +0000330 // This is a little inefficient (copying a multimap around), but it is a
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100331 // small one and this way I don't have to care about memory management.
Nathan Harmata7d300b22015-12-21 16:10:05 +0000332 vector<string> candidate_blazerc_paths;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100333 if (use_master_blazerc) {
Julio Merino211a95c2016-08-29 11:01:35 +0000334 WorkspaceLayout::FindCandidateBlazercPaths(workspace, cwd, args,
335 &candidate_blazerc_paths);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100336 }
337
338 string user_blazerc_path;
339 blaze_exit_code::ExitCode find_blazerc_exit_code = FindUserBlazerc(
Julio Merino211a95c2016-08-29 11:01:35 +0000340 blazerc, WorkspaceLayout::RcBasename(), workspace, &user_blazerc_path,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100341 error);
342 if (find_blazerc_exit_code != blaze_exit_code::SUCCESS) {
343 return find_blazerc_exit_code;
344 }
Nathan Harmata7d300b22015-12-21 16:10:05 +0000345 candidate_blazerc_paths.push_back(user_blazerc_path);
346
347 // Throw away missing files, dedupe candidate blazerc paths, and parse the
348 // blazercs, all while preserving order. Duplicates can arise if e.g. the
349 // binary's path *is* the depot path.
350 set<string> blazerc_paths;
351 for (const auto& candidate_blazerc_path : candidate_blazerc_paths) {
352 if (!candidate_blazerc_path.empty()
353 && (blazerc_paths.insert(candidate_blazerc_path).second)) {
354 blazercs_.push_back(
355 new RcFile(candidate_blazerc_path, blazercs_.size()));
356 blaze_exit_code::ExitCode parse_exit_code =
357 blazercs_.back()->Parse(workspace, &blazercs_, &rcoptions_, error);
358 if (parse_exit_code != blaze_exit_code::SUCCESS) {
359 return parse_exit_code;
360 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100361 }
362 }
363
364 blaze_exit_code::ExitCode parse_startup_options_exit_code =
365 ParseStartupOptions(error);
366 if (parse_startup_options_exit_code != blaze_exit_code::SUCCESS) {
367 return parse_startup_options_exit_code;
368 }
369
370 // Determine command
371 if (startup_args_ + 1 >= args.size()) {
372 command_ = "";
373 return blaze_exit_code::SUCCESS;
374 }
375
376 command_ = args[startup_args_ + 1];
377
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100378 AddRcfileArgsAndOptions(parsed_startup_options_->batch, cwd);
379 for (unsigned int cmd_arg = startup_args_ + 2;
380 cmd_arg < args.size(); cmd_arg++) {
381 command_arguments_.push_back(args[cmd_arg]);
382 }
383 return blaze_exit_code::SUCCESS;
384}
385
386blaze_exit_code::ExitCode OptionProcessor::ParseOptions(
387 int argc,
388 const char* argv[],
389 const string& workspace,
390 const string& cwd,
391 string* error) {
392 vector<string> args(argc);
393 for (int arg = 0; arg < argc; arg++) {
394 args[arg] = argv[arg];
395 }
396
397 return ParseOptions(args, workspace, cwd, error);
398}
399
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100400blaze_exit_code::ExitCode OptionProcessor::ParseStartupOptions(string *error) {
401 // Process rcfile startup options
402 map< string, vector<RcOption> >::const_iterator it =
403 rcoptions_.find("startup");
404 blaze_exit_code::ExitCode process_arg_exit_code;
405 bool is_space_separated;
406 if (it != rcoptions_.end()) {
407 const vector<RcOption>& startup_options = it->second;
408 int i = 0;
409 // Process all elements except the last one.
410 for (; i < startup_options.size() - 1; i++) {
411 const RcOption& option = startup_options[i];
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +0000412 const string& blazerc = blazercs_[option.rcfile_index()]->Filename();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100413 process_arg_exit_code = parsed_startup_options_->ProcessArg(
414 option.option(), startup_options[i + 1].option(), blazerc,
415 &is_space_separated, error);
416 if (process_arg_exit_code != blaze_exit_code::SUCCESS) {
417 return process_arg_exit_code;
418 }
419 if (is_space_separated) {
420 i++;
421 }
422 }
423 // Process last element, if any.
424 if (i < startup_options.size()) {
425 const RcOption& option = startup_options[i];
426 if (IsArg(option.option())) {
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +0000427 const string& blazerc = blazercs_[option.rcfile_index()]->Filename();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100428 process_arg_exit_code = parsed_startup_options_->ProcessArg(
429 option.option(), "", blazerc, &is_space_separated, error);
430 if (process_arg_exit_code != blaze_exit_code::SUCCESS) {
431 return process_arg_exit_code;
432 }
433 }
434 }
435 }
436
437 // Process command-line args next, so they override any of the same options
438 // from .blazerc. Stop on first non-arg, this includes --help
439 unsigned int i = 1;
440 if (!args_.empty()) {
441 for (; (i < args_.size() - 1) && IsArg(args_[i]); i++) {
442 process_arg_exit_code = parsed_startup_options_->ProcessArg(
443 args_[i], args_[i + 1], "", &is_space_separated, error);
444 if (process_arg_exit_code != blaze_exit_code::SUCCESS) {
445 return process_arg_exit_code;
446 }
447 if (is_space_separated) {
448 i++;
449 }
450 }
451 if (i < args_.size() && IsArg(args_[i])) {
452 process_arg_exit_code = parsed_startup_options_->ProcessArg(
453 args_[i], "", "", &is_space_separated, error);
454 if (process_arg_exit_code != blaze_exit_code::SUCCESS) {
455 return process_arg_exit_code;
456 }
457 i++;
458 }
459 }
460 startup_args_ = i -1;
461
462 return blaze_exit_code::SUCCESS;
463}
464
465// Appends the command and arguments from argc/argv to the end of arg_vector,
466// and also splices in some additional terminal and environment options between
467// the command and the arguments. NB: Keep the options added here in sync with
468// BlazeCommandDispatcher.INTERNAL_COMMAND_OPTIONS!
469void OptionProcessor::AddRcfileArgsAndOptions(bool batch, const string& cwd) {
Klaus Aehlig3c9a2262016-04-20 15:13:51 +0000470 // Provide terminal options as coming from the least important rc file.
471 command_arguments_.push_back("--rc_source=client");
472 command_arguments_.push_back("--default_override=0:common=--isatty=" +
473 ToString(IsStandardTerminal()));
474 command_arguments_.push_back(
475 "--default_override=0:common=--terminal_columns=" +
476 ToString(GetTerminalColumns()));
477
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100478 // Push the options mapping .blazerc numbers to filenames.
479 for (int i_blazerc = 0; i_blazerc < blazercs_.size(); i_blazerc++) {
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +0000480 const RcFile* blazerc = blazercs_[i_blazerc];
Dmitry Lomov78c0cc72015-08-11 16:44:21 +0000481 command_arguments_.push_back("--rc_source=" +
482 blaze::ConvertPath(blazerc->Filename()));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100483 }
484
485 // Push the option defaults
486 for (map<string, vector<RcOption> >::const_iterator it = rcoptions_.begin();
487 it != rcoptions_.end(); ++it) {
488 if (it->first == "startup") {
489 // Skip startup options, they are parsed in the C++ wrapper
490 continue;
491 }
492
493 for (int ii = 0; ii < it->second.size(); ii++) {
494 const RcOption& rcoption = it->second[ii];
Googler016baf32016-03-30 20:21:23 +0000495 command_arguments_.push_back(
Klaus Aehlig3c9a2262016-04-20 15:13:51 +0000496 "--default_override=" + ToString(rcoption.rcfile_index() + 1) + ":"
Googler016baf32016-03-30 20:21:23 +0000497 + it->first + "=" + rcoption.option());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100498 }
499 }
500
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100501 // Pass the client environment to the server in server mode.
502 if (batch) {
503 command_arguments_.push_back("--ignore_client_env");
504 } else {
505 for (char** env = environ; *env != NULL; env++) {
Yun Peng44fa4c72016-07-15 08:38:38 +0000506 string env_str(*env);
507 int pos = env_str.find("=");
508 if (pos != string::npos) {
509 string name = env_str.substr(0, pos);
Laszlo Csomor6713d382016-08-26 05:14:37 +0000510 if (name == "PATH") {
511 env_str = "PATH=" + ConvertPathList(env_str.substr(pos + 1));
512 } else if (name == "TMP") {
513 // A valid Windows path "c:/foo" is also a valid Unix path list of
514 // ["c", "/foo"] so must use ConvertPath here. See GitHub issue #1684.
515 env_str = "TMP=" + ConvertPath(env_str.substr(pos + 1));
Yun Peng44fa4c72016-07-15 08:38:38 +0000516 }
517 }
518 command_arguments_.push_back("--client_env=" + env_str);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100519 }
520 }
Dmitry Lomov78c0cc72015-08-11 16:44:21 +0000521 command_arguments_.push_back("--client_cwd=" + blaze::ConvertPath(cwd));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100522
Googler957f3742016-08-31 18:16:24 +0000523 if (IsEmacsTerminal()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100524 command_arguments_.push_back("--emacs");
525 }
526}
527
528void OptionProcessor::GetCommandArguments(vector<string>* result) const {
529 result->insert(result->end(),
530 command_arguments_.begin(),
531 command_arguments_.end());
532}
533
534const string& OptionProcessor::GetCommand() const {
535 return command_;
536}
537
Julio Merino28774852016-09-14 16:59:46 +0000538StartupOptions* OptionProcessor::GetParsedStartupOptions() const {
539 return parsed_startup_options_.get();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100540}
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +0000541
542OptionProcessor::~OptionProcessor() {
543 for (auto it : blazercs_) {
544 delete it;
545 }
546}
547
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100548} // namespace blaze