blob: 680e2e331e9b99dde5d4bb62bde3a8486fa9f31e [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,
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +000056 vector<RcFile*>* rcfiles,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010057 map<string, vector<RcOption> >* rcoptions,
58 string* error) {
59 list<string> initial_import_stack;
60 initial_import_stack.push_back(filename_);
61 return Parse(
Googlere3681d12015-12-02 22:26:59 +000062 workspace, filename_, index_, rcfiles, rcoptions, &initial_import_stack,
63 error);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010064}
65
66blaze_exit_code::ExitCode OptionProcessor::RcFile::Parse(
Googlere3681d12015-12-02 22:26:59 +000067 const string& workspace,
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +000068 const string& filename_ref,
Thiago Farina2fd78902015-05-18 11:37:59 +000069 const int index,
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +000070 vector<RcFile*>* rcfiles,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010071 map<string, vector<RcOption> >* rcoptions,
72 list<string>* import_stack,
73 string* error) {
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +000074 string filename(filename_ref); // file
Chloe Calvarin78f1c852016-11-22 21:58:50 +000075 BAZEL_LOG(INFO) << "Parsing the RcFile " << filename;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010076 string contents;
Laszlo Csomor49970e02016-11-28 08:55:47 +000077 if (!blaze_util::ReadFile(filename, &contents)) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010078 // We checked for file readability before, so this is unexpected.
79 blaze_util::StringPrintf(error,
80 "Unexpected error reading .blazerc file '%s'", filename.c_str());
81 return blaze_exit_code::INTERNAL_ERROR;
82 }
83
84 // A '\' at the end of a line continues the line.
85 blaze_util::Replace("\\\r\n", "", &contents);
86 blaze_util::Replace("\\\n", "", &contents);
87 vector<string> startup_options;
88
89 vector<string> lines = blaze_util::Split(contents, '\n');
90 for (int line = 0; line < lines.size(); ++line) {
91 blaze_util::StripWhitespace(&lines[line]);
92
93 // Check for an empty line.
94 if (lines[line].empty()) {
95 continue;
96 }
97
98 vector<string> words;
99
100 // This will treat "#" as a comment, and properly
101 // quote single and double quotes, and treat '\'
102 // as an escape character.
103 // TODO(bazel-team): This function silently ignores
104 // dangling backslash escapes and missing end-quotes.
105 blaze_util::Tokenize(lines[line], '#', &words);
106
107 if (words.empty()) {
108 // Could happen if line starts with "#"
109 continue;
110 }
111
112 string command = words[0];
113
114 if (command == "import") {
Googlere3681d12015-12-02 22:26:59 +0000115 if (words.size() != 2
Julio Merino211a95c2016-08-29 11:01:35 +0000116 || (words[1].compare(0, WorkspaceLayout::WorkspacePrefixLength,
117 WorkspaceLayout::WorkspacePrefix) == 0
118 && !WorkspaceLayout::WorkspaceRelativizeRcFilePath(
Googlere3681d12015-12-02 22:26:59 +0000119 workspace, &words[1]))) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100120 blaze_util::StringPrintf(error,
121 "Invalid import declaration in .blazerc file '%s': '%s'",
122 filename.c_str(), lines[line].c_str());
123 return blaze_exit_code::BAD_ARGV;
124 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100125 if (std::find(import_stack->begin(), import_stack->end(), words[1]) !=
126 import_stack->end()) {
127 string loop;
128 for (list<string>::const_iterator imported_rc = import_stack->begin();
129 imported_rc != import_stack->end(); ++imported_rc) {
130 loop += " " + *imported_rc + "\n";
131 }
132 blaze_util::StringPrintf(error,
133 "Import loop detected:\n%s", loop.c_str());
134 return blaze_exit_code::BAD_ARGV;
135 }
136
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +0000137 rcfiles->push_back(new RcFile(words[1], rcfiles->size()));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100138 import_stack->push_back(words[1]);
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +0000139 blaze_exit_code::ExitCode parse_exit_code =
Googlere3681d12015-12-02 22:26:59 +0000140 RcFile::Parse(workspace, rcfiles->back()->Filename(),
141 rcfiles->back()->Index(),
142 rcfiles, rcoptions, import_stack, error);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100143 if (parse_exit_code != blaze_exit_code::SUCCESS) {
144 return parse_exit_code;
145 }
146 import_stack->pop_back();
147 } else {
148 for (int word = 1; word < words.size(); ++word) {
149 (*rcoptions)[command].push_back(RcOption(index, words[word]));
150 if (command == "startup") {
151 startup_options.push_back(words[word]);
152 }
153 }
154 }
155 }
156
157 if (!startup_options.empty()) {
158 string startup_args;
159 blaze_util::JoinStrings(startup_options, ' ', &startup_args);
160 fprintf(stderr, "INFO: Reading 'startup' options from %s: %s\n",
161 filename.c_str(), startup_args.c_str());
162 }
163 return blaze_exit_code::SUCCESS;
164}
165
Julio Merino28774852016-09-14 16:59:46 +0000166OptionProcessor::OptionProcessor(
167 std::unique_ptr<StartupOptions> default_startup_options) :
168 initialized_(false),
169 parsed_startup_options_(std::move(default_startup_options)) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100170}
171
Luis Fernando Pino Duque0311fc52016-11-21 13:20:50 +0000172std::unique_ptr<CommandLine> OptionProcessor::SplitCommandLine(
173 const vector<string>& args,
174 string* error) {
175 const string lowercase_product_name =
176 parsed_startup_options_->GetLowercaseProductName();
177
178 if (args.empty()) {
179 blaze_util::StringPrintf(error,
180 "Unable to split command line, args is empty");
181 return nullptr;
182 }
183
184 const string path_to_binary(args[0]);
185
186 // Process the startup options.
187 vector<string> startup_args;
188 vector<string>::size_type i = 1;
189 while (i < args.size() && IsArg(args[i])) {
190 const string current_arg(args[i]);
191 // If the current argument is a valid nullary startup option such as
192 // --master_bazelrc or --nomaster_bazelrc proceed to examine the next
193 // argument.
194 if (parsed_startup_options_->IsNullary(current_arg)) {
195 startup_args.push_back(current_arg);
196 i++;
197 } else if (parsed_startup_options_->IsUnary(current_arg)) {
198 // If the current argument is a valid unary startup option such as
199 // --bazelrc there are two cases to consider.
200
201 // The option is of the form '--bazelrc=value', hence proceed to
202 // examine the next argument.
203 if (current_arg.find("=") != string::npos) {
204 startup_args.push_back(current_arg);
205 i++;
206 } else {
207 // Otherwise, the option is of the form '--bazelrc value', hence
208 // skip the next argument and proceed to examine the argument located
209 // two places after.
210 if (i + 1 >= args.size()) {
211 blaze_util::StringPrintf(
212 error,
213 "Startup option '%s' expects a value.\n"
214 "Usage: '%s=somevalue' or '%s somevalue'.\n"
215 " For more info, run '%s help startup_options'.",
216 current_arg.c_str(), current_arg.c_str(), current_arg.c_str(),
217 lowercase_product_name.c_str());
218 return nullptr;
219 }
220 // In this case we transform it to the form '--bazelrc=value'.
221 startup_args.push_back(current_arg + string("=") + args[i + 1]);
222 i += 2;
223 }
224 } else {
225 // If the current argument is not a valid unary or nullary startup option
226 // then fail.
227 blaze_util::StringPrintf(
228 error,
229 "Unknown %s startup option: '%s'.\n"
230 " For more info, run '%s help startup_options'.",
231 lowercase_product_name.c_str(), current_arg.c_str(),
232 lowercase_product_name.c_str());
233 return nullptr;
234 }
235 }
236
237 // The command is the arg right after the startup options.
238 if (i == args.size()) {
239 return std::unique_ptr<CommandLine>(
240 new CommandLine(path_to_binary, startup_args, "", {}));
241 }
242 const string command(args[i]);
243
244 // The rest are the command arguments.
245 const vector<string> command_args(args.begin() + i + 1, args.end());
246
247 return std::unique_ptr<CommandLine>(
248 new CommandLine(path_to_binary, startup_args, command, command_args));
249}
250
Thiago Farina9bc5c342016-03-21 08:39:48 +0000251// Return the path to the user's rc file. If cmdLineRcFile != NULL,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100252// use it, dying if it is not readable. Otherwise, return the first
253// readable file called rc_basename from [workspace, $HOME]
254//
255// If no readable .blazerc file is found, return the empty string.
256blaze_exit_code::ExitCode OptionProcessor::FindUserBlazerc(
257 const char* cmdLineRcFile,
258 const string& rc_basename,
259 const string& workspace,
260 string* blaze_rc_file,
261 string* error) {
262 if (cmdLineRcFile != NULL) {
263 string rcFile = MakeAbsolute(cmdLineRcFile);
Laszlo Csomor9c951962016-11-10 13:31:27 +0000264 if (!blaze_util::CanAccess(rcFile, true, false, false)) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100265 blaze_util::StringPrintf(error,
266 "Error: Unable to read .blazerc file '%s'.", rcFile.c_str());
267 return blaze_exit_code::BAD_ARGV;
268 }
269 *blaze_rc_file = rcFile;
270 return blaze_exit_code::SUCCESS;
271 }
272
273 string workspaceRcFile = blaze_util::JoinPath(workspace, rc_basename);
Laszlo Csomor9c951962016-11-10 13:31:27 +0000274 if (blaze_util::CanAccess(workspaceRcFile, true, false, false)) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100275 *blaze_rc_file = workspaceRcFile;
276 return blaze_exit_code::SUCCESS;
277 }
278
Laszlo Csomorcefa9a22016-11-22 10:50:07 +0000279 string home = blaze::GetEnv("HOME");
280 if (home.empty()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100281 *blaze_rc_file = "";
282 return blaze_exit_code::SUCCESS;
283 }
284
285 string userRcFile = blaze_util::JoinPath(home, rc_basename);
Laszlo Csomor9c951962016-11-10 13:31:27 +0000286 if (blaze_util::CanAccess(userRcFile, true, false, false)) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100287 *blaze_rc_file = userRcFile;
288 return blaze_exit_code::SUCCESS;
289 }
290 *blaze_rc_file = "";
291 return blaze_exit_code::SUCCESS;
292}
293
294blaze_exit_code::ExitCode OptionProcessor::ParseOptions(
295 const vector<string>& args,
296 const string& workspace,
297 const string& cwd,
298 string* error) {
299 assert(!initialized_);
300 initialized_ = true;
301
302 const char* blazerc = NULL;
303 bool use_master_blazerc = true;
304
305 // Check if there is a blazerc related option given
306 args_ = args;
307 for (int i= 1; i < args.size(); i++) {
308 const char* arg_chr = args[i].c_str();
309 const char* next_arg_chr = (i + 1) < args.size()
310 ? args[i + 1].c_str()
311 : NULL;
312 if (blazerc == NULL) {
313 blazerc = GetUnaryOption(arg_chr, next_arg_chr, "--blazerc");
314 }
Damien Martin-Guillerez8cde69c2015-06-05 11:33:44 +0000315 if (blazerc == NULL) {
316 blazerc = GetUnaryOption(arg_chr, next_arg_chr, "--bazelrc");
317 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100318 if (use_master_blazerc &&
Damien Martin-Guillerez50d124b2015-06-24 15:20:09 +0000319 (GetNullaryOption(arg_chr, "--nomaster_blazerc") ||
320 GetNullaryOption(arg_chr, "--nomaster_bazelrc"))) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100321 use_master_blazerc = false;
322 }
323 }
324
Luis Fernando Pino Duquef5cf2002016-08-19 13:44:17 +0000325 blaze_exit_code::ExitCode validate_startup_options_exit_code =
Julio Merino28774852016-09-14 16:59:46 +0000326 parsed_startup_options_->ValidateStartupOptions(args, error);
Luis Fernando Pino Duquef5cf2002016-08-19 13:44:17 +0000327 if (validate_startup_options_exit_code != blaze_exit_code::SUCCESS) {
328 return validate_startup_options_exit_code;
329 }
330
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100331 // Parse depot and user blazerc files.
Nathan Harmata7d300b22015-12-21 16:10:05 +0000332 // This is a little inefficient (copying a multimap around), but it is a
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100333 // small one and this way I don't have to care about memory management.
Nathan Harmata7d300b22015-12-21 16:10:05 +0000334 vector<string> candidate_blazerc_paths;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100335 if (use_master_blazerc) {
Julio Merino211a95c2016-08-29 11:01:35 +0000336 WorkspaceLayout::FindCandidateBlazercPaths(workspace, cwd, args,
337 &candidate_blazerc_paths);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100338 }
339
340 string user_blazerc_path;
341 blaze_exit_code::ExitCode find_blazerc_exit_code = FindUserBlazerc(
Julio Merino211a95c2016-08-29 11:01:35 +0000342 blazerc, WorkspaceLayout::RcBasename(), workspace, &user_blazerc_path,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100343 error);
344 if (find_blazerc_exit_code != blaze_exit_code::SUCCESS) {
345 return find_blazerc_exit_code;
346 }
Nathan Harmata7d300b22015-12-21 16:10:05 +0000347 candidate_blazerc_paths.push_back(user_blazerc_path);
348
349 // Throw away missing files, dedupe candidate blazerc paths, and parse the
350 // blazercs, all while preserving order. Duplicates can arise if e.g. the
351 // binary's path *is* the depot path.
352 set<string> blazerc_paths;
353 for (const auto& candidate_blazerc_path : candidate_blazerc_paths) {
354 if (!candidate_blazerc_path.empty()
355 && (blazerc_paths.insert(candidate_blazerc_path).second)) {
356 blazercs_.push_back(
357 new RcFile(candidate_blazerc_path, blazercs_.size()));
358 blaze_exit_code::ExitCode parse_exit_code =
359 blazercs_.back()->Parse(workspace, &blazercs_, &rcoptions_, error);
360 if (parse_exit_code != blaze_exit_code::SUCCESS) {
361 return parse_exit_code;
362 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100363 }
364 }
365
366 blaze_exit_code::ExitCode parse_startup_options_exit_code =
367 ParseStartupOptions(error);
368 if (parse_startup_options_exit_code != blaze_exit_code::SUCCESS) {
369 return parse_startup_options_exit_code;
370 }
371
372 // Determine command
373 if (startup_args_ + 1 >= args.size()) {
374 command_ = "";
375 return blaze_exit_code::SUCCESS;
376 }
377
378 command_ = args[startup_args_ + 1];
379
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100380 AddRcfileArgsAndOptions(parsed_startup_options_->batch, cwd);
381 for (unsigned int cmd_arg = startup_args_ + 2;
382 cmd_arg < args.size(); cmd_arg++) {
383 command_arguments_.push_back(args[cmd_arg]);
384 }
385 return blaze_exit_code::SUCCESS;
386}
387
388blaze_exit_code::ExitCode OptionProcessor::ParseOptions(
389 int argc,
390 const char* argv[],
391 const string& workspace,
392 const string& cwd,
393 string* error) {
394 vector<string> args(argc);
395 for (int arg = 0; arg < argc; arg++) {
396 args[arg] = argv[arg];
397 }
398
399 return ParseOptions(args, workspace, cwd, error);
400}
401
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100402blaze_exit_code::ExitCode OptionProcessor::ParseStartupOptions(string *error) {
403 // Process rcfile startup options
404 map< string, vector<RcOption> >::const_iterator it =
405 rcoptions_.find("startup");
406 blaze_exit_code::ExitCode process_arg_exit_code;
407 bool is_space_separated;
408 if (it != rcoptions_.end()) {
409 const vector<RcOption>& startup_options = it->second;
410 int i = 0;
411 // Process all elements except the last one.
412 for (; i < startup_options.size() - 1; i++) {
413 const RcOption& option = startup_options[i];
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +0000414 const string& blazerc = blazercs_[option.rcfile_index()]->Filename();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100415 process_arg_exit_code = parsed_startup_options_->ProcessArg(
416 option.option(), startup_options[i + 1].option(), blazerc,
417 &is_space_separated, error);
418 if (process_arg_exit_code != blaze_exit_code::SUCCESS) {
419 return process_arg_exit_code;
420 }
421 if (is_space_separated) {
422 i++;
423 }
424 }
425 // Process last element, if any.
426 if (i < startup_options.size()) {
427 const RcOption& option = startup_options[i];
428 if (IsArg(option.option())) {
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +0000429 const string& blazerc = blazercs_[option.rcfile_index()]->Filename();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100430 process_arg_exit_code = parsed_startup_options_->ProcessArg(
431 option.option(), "", blazerc, &is_space_separated, error);
432 if (process_arg_exit_code != blaze_exit_code::SUCCESS) {
433 return process_arg_exit_code;
434 }
435 }
436 }
437 }
438
439 // Process command-line args next, so they override any of the same options
440 // from .blazerc. Stop on first non-arg, this includes --help
441 unsigned int i = 1;
442 if (!args_.empty()) {
443 for (; (i < args_.size() - 1) && IsArg(args_[i]); i++) {
444 process_arg_exit_code = parsed_startup_options_->ProcessArg(
445 args_[i], args_[i + 1], "", &is_space_separated, error);
446 if (process_arg_exit_code != blaze_exit_code::SUCCESS) {
447 return process_arg_exit_code;
448 }
449 if (is_space_separated) {
450 i++;
451 }
452 }
453 if (i < args_.size() && IsArg(args_[i])) {
454 process_arg_exit_code = parsed_startup_options_->ProcessArg(
455 args_[i], "", "", &is_space_separated, error);
456 if (process_arg_exit_code != blaze_exit_code::SUCCESS) {
457 return process_arg_exit_code;
458 }
459 i++;
460 }
461 }
462 startup_args_ = i -1;
463
464 return blaze_exit_code::SUCCESS;
465}
466
467// Appends the command and arguments from argc/argv to the end of arg_vector,
468// and also splices in some additional terminal and environment options between
469// the command and the arguments. NB: Keep the options added here in sync with
470// BlazeCommandDispatcher.INTERNAL_COMMAND_OPTIONS!
471void OptionProcessor::AddRcfileArgsAndOptions(bool batch, const string& cwd) {
Klaus Aehlig3c9a2262016-04-20 15:13:51 +0000472 // Provide terminal options as coming from the least important rc file.
473 command_arguments_.push_back("--rc_source=client");
474 command_arguments_.push_back("--default_override=0:common=--isatty=" +
475 ToString(IsStandardTerminal()));
476 command_arguments_.push_back(
477 "--default_override=0:common=--terminal_columns=" +
478 ToString(GetTerminalColumns()));
479
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100480 // Push the options mapping .blazerc numbers to filenames.
481 for (int i_blazerc = 0; i_blazerc < blazercs_.size(); i_blazerc++) {
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +0000482 const RcFile* blazerc = blazercs_[i_blazerc];
Dmitry Lomov78c0cc72015-08-11 16:44:21 +0000483 command_arguments_.push_back("--rc_source=" +
484 blaze::ConvertPath(blazerc->Filename()));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100485 }
486
487 // Push the option defaults
488 for (map<string, vector<RcOption> >::const_iterator it = rcoptions_.begin();
489 it != rcoptions_.end(); ++it) {
490 if (it->first == "startup") {
491 // Skip startup options, they are parsed in the C++ wrapper
492 continue;
493 }
494
495 for (int ii = 0; ii < it->second.size(); ii++) {
496 const RcOption& rcoption = it->second[ii];
Googler016baf32016-03-30 20:21:23 +0000497 command_arguments_.push_back(
Klaus Aehlig3c9a2262016-04-20 15:13:51 +0000498 "--default_override=" + ToString(rcoption.rcfile_index() + 1) + ":"
Googler016baf32016-03-30 20:21:23 +0000499 + it->first + "=" + rcoption.option());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100500 }
501 }
502
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100503 // Pass the client environment to the server in server mode.
504 if (batch) {
505 command_arguments_.push_back("--ignore_client_env");
506 } else {
507 for (char** env = environ; *env != NULL; env++) {
Yun Peng44fa4c72016-07-15 08:38:38 +0000508 string env_str(*env);
509 int pos = env_str.find("=");
510 if (pos != string::npos) {
511 string name = env_str.substr(0, pos);
Laszlo Csomor6713d382016-08-26 05:14:37 +0000512 if (name == "PATH") {
513 env_str = "PATH=" + ConvertPathList(env_str.substr(pos + 1));
514 } else if (name == "TMP") {
515 // A valid Windows path "c:/foo" is also a valid Unix path list of
516 // ["c", "/foo"] so must use ConvertPath here. See GitHub issue #1684.
517 env_str = "TMP=" + ConvertPath(env_str.substr(pos + 1));
Yun Peng44fa4c72016-07-15 08:38:38 +0000518 }
519 }
520 command_arguments_.push_back("--client_env=" + env_str);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100521 }
522 }
Dmitry Lomov78c0cc72015-08-11 16:44:21 +0000523 command_arguments_.push_back("--client_cwd=" + blaze::ConvertPath(cwd));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100524
Googler957f3742016-08-31 18:16:24 +0000525 if (IsEmacsTerminal()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100526 command_arguments_.push_back("--emacs");
527 }
528}
529
530void OptionProcessor::GetCommandArguments(vector<string>* result) const {
531 result->insert(result->end(),
532 command_arguments_.begin(),
533 command_arguments_.end());
534}
535
536const string& OptionProcessor::GetCommand() const {
537 return command_;
538}
539
Julio Merino28774852016-09-14 16:59:46 +0000540StartupOptions* OptionProcessor::GetParsedStartupOptions() const {
541 return parsed_startup_options_.get();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100542}
Han-Wen Nienhuys255cf092015-05-22 14:38:59 +0000543
544OptionProcessor::~OptionProcessor() {
545 for (auto it : blazercs_) {
546 delete it;
547 }
548}
549
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100550} // namespace blaze