blob: 2c3f7a208cb681b48b10d3925811296ac9b76f29 [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/blaze_util.h"
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010016
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010017#include <fcntl.h>
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010018#include <stdarg.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
lberkid3d37f02018-04-18 11:44:14 -070022#include <cassert>
ccalvarin9eea0f92018-03-21 15:32:30 -070023#include <iostream>
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010024
Dmitry Lomov78c0cc72015-08-11 16:44:21 +000025#include "src/main/cpp/blaze_util_platform.h"
Han-Wen Nienhuys36fbe632015-04-21 13:58:08 +000026#include "src/main/cpp/util/errors.h"
Thiago Farina7f9357f2015-04-23 13:57:43 +000027#include "src/main/cpp/util/exit_code.h"
Han-Wen Nienhuys36fbe632015-04-21 13:58:08 +000028#include "src/main/cpp/util/file.h"
ccalvarin9eea0f92018-03-21 15:32:30 -070029#include "src/main/cpp/util/logging.h"
Han-Wen Nienhuys36fbe632015-04-21 13:58:08 +000030#include "src/main/cpp/util/numbers.h"
ccalvarin755278d2018-06-07 11:05:54 -070031#include "src/main/cpp/util/path_platform.h"
Thiago Farinafdc7f982015-04-27 23:01:34 +000032#include "src/main/cpp/util/port.h"
ccalvarin9eea0f92018-03-21 15:32:30 -070033#include "src/main/cpp/util/strings.h"
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010034
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010035namespace blaze {
36
lberkid3d37f02018-04-18 11:44:14 -070037using std::map;
Thiago Farina80bb0f22016-10-17 15:57:13 +000038using std::string;
39using std::vector;
40
Thiago Farina048bbfc2016-09-21 08:20:41 +000041const char kServerPidFile[] = "server.pid.txt";
Lukacs Berkid9da60f2016-04-26 11:40:24 +000042
mschallerfd37b512017-07-11 18:21:36 +020043const unsigned int kPostShutdownGracePeriodSeconds = 60;
44
45const unsigned int kPostKillGracePeriodSeconds = 10;
46
Thiago Farina2fd78902015-05-18 11:37:59 +000047const char* GetUnaryOption(const char *arg,
48 const char *next_arg,
49 const char *key) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010050 const char *value = blaze_util::var_strprefix(arg, key);
51 if (value == NULL) {
52 return NULL;
53 } else if (value[0] == '=') {
54 return value + 1;
55 } else if (value[0]) {
56 return NULL; // trailing garbage in key name
57 }
58
59 return next_arg;
60}
61
62bool GetNullaryOption(const char *arg, const char *key) {
63 const char *value = blaze_util::var_strprefix(arg, key);
64 if (value == NULL) {
65 return false;
66 } else if (value[0] == '=') {
ccalvarin8448f572018-04-06 12:42:09 -070067 BAZEL_DIE(blaze_exit_code::BAD_ARGV)
68 << "In argument '" << arg << "': option '" << key
69 << "' does not take a value.";
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010070 } else if (value[0]) {
71 return false; // trailing garbage in key name
72 }
73
74 return true;
75}
76
Luis Fernando Pino Duqued5e008c2016-12-08 16:59:16 +000077const char* SearchUnaryOption(const vector<string>& args,
laszlocsomor392f24a2019-08-07 05:56:23 -070078 const char *key, bool warn_if_dupe) {
Luis Fernando Pino Duqued5e008c2016-12-08 16:59:16 +000079 if (args.empty()) {
80 return NULL;
81 }
82
laszlocsomor392f24a2019-08-07 05:56:23 -070083 const char* value = nullptr;
84 bool found_dupe = false; // true if 'key' was found twice
Luis Fernando Pino Duqued5e008c2016-12-08 16:59:16 +000085 vector<string>::size_type i = 0;
laszlocsomor392f24a2019-08-07 05:56:23 -070086
87 // Examine the first N-1 arguments. (N-1 because we examine the i'th and
88 // i+1'th together, in case a flag is defined "--name value" style and not
89 // "--name=value" style.)
Luis Fernando Pino Duqued5e008c2016-12-08 16:59:16 +000090 for (; i < args.size() - 1; ++i) {
Luis Fernando Pino Duqued56e1c62017-03-24 18:04:00 +000091 if (args[i] == "--") {
laszlocsomor392f24a2019-08-07 05:56:23 -070092 // If the current argument is "--", all following args are target names.
93 // If 'key' was not found, 'value' is nullptr and we can return that.
94 // If 'key' was found exactly once, then 'value' has the value and again
95 // we can return that.
96 // If 'key' was found more than once then we could not have reached this
97 // line, because we would have broken out of the loop when 'key' was found
98 // the second time.
99 return value;
Luis Fernando Pino Duqued56e1c62017-03-24 18:04:00 +0000100 }
Luis Fernando Pino Duqued5e008c2016-12-08 16:59:16 +0000101 const char* result = GetUnaryOption(args[i].c_str(),
102 args[i + 1].c_str(),
103 key);
104 if (result != NULL) {
laszlocsomor392f24a2019-08-07 05:56:23 -0700105 // 'key' was found and 'result' has its value.
106 if (value) {
107 // 'key' was found once before, because 'value' is not empty.
108 found_dupe = true;
109 break;
110 } else {
111 // 'key' was not found before, so store the value in 'value'.
112 value = result;
113 }
Luis Fernando Pino Duqued5e008c2016-12-08 16:59:16 +0000114 }
115 }
laszlocsomor392f24a2019-08-07 05:56:23 -0700116
117 if (value) {
118 // 'value' is not empty, so 'key' was found at least once in the first N-1
119 // arguments.
120 if (warn_if_dupe) {
121 if (!found_dupe) {
122 // We did not find a duplicate in the first N-1 arguments. Examine the
123 // last argument, it may be a duplicate.
124 found_dupe = (GetUnaryOption(args[i].c_str(), NULL, key) != nullptr);
125 }
126 if (found_dupe) {
127 BAZEL_LOG(WARNING) << key << " is given more than once, "
128 << "only the first occurrence is used";
129 }
130 }
131 return value;
132 } else {
133 // 'value' is empty, so 'key' was not yet found in the first N-1 arguments.
134 // If 'key' is in the last argument, we'll parse and return the value from
135 // that, and if it isn't, we'll return NULL.
136 return GetUnaryOption(args[i].c_str(), NULL, key);
137 }
Luis Fernando Pino Duqued5e008c2016-12-08 16:59:16 +0000138}
139
ajmichael1b3569a2018-01-24 07:43:32 -0800140bool SearchNullaryOption(const vector<string>& args,
141 const string& flag_name,
142 const bool default_value) {
143 const string positive_flag = "--" + flag_name;
144 const string negative_flag = "--no" + flag_name;
145 bool result = default_value;
Luis Fernando Pino Duqued5e008c2016-12-08 16:59:16 +0000146 for (vector<string>::size_type i = 0; i < args.size(); i++) {
Luis Fernando Pino Duqued56e1c62017-03-24 18:04:00 +0000147 if (args[i] == "--") {
ajmichael1b3569a2018-01-24 07:43:32 -0800148 break;
Luis Fernando Pino Duqued56e1c62017-03-24 18:04:00 +0000149 }
ajmichael1b3569a2018-01-24 07:43:32 -0800150 if (GetNullaryOption(args[i].c_str(), positive_flag.c_str())) {
151 result = true;
152 } else if (GetNullaryOption(args[i].c_str(), negative_flag.c_str())) {
153 result = false;
Luis Fernando Pino Duqued5e008c2016-12-08 16:59:16 +0000154 }
155 }
ajmichael1b3569a2018-01-24 07:43:32 -0800156 return result;
lpino4ed3db62017-08-10 16:25:54 +0200157}
158
Luis Fernando Pino Duque0311fc52016-11-21 13:20:50 +0000159bool IsArg(const string& arg) {
160 return blaze_util::starts_with(arg, "-") && (arg != "--help")
161 && (arg != "-help") && (arg != "-h");
162}
163
ccalvarin755278d2018-06-07 11:05:54 -0700164std::string AbsolutePathFromFlag(const std::string& value) {
165 if (value.empty()) {
166 return blaze_util::GetCwd();
167 } else {
168 return blaze_util::MakeAbsolute(value);
169 }
170}
171
mschallerfd37b512017-07-11 18:21:36 +0200172void LogWait(unsigned int elapsed_seconds, unsigned int wait_seconds) {
173 SigPrintf("WARNING: Waiting for server process to terminate "
174 "(waited %d seconds, waiting at most %d)\n",
175 elapsed_seconds, wait_seconds);
176}
177
laszlocsomor6f665392019-08-27 08:15:51 -0700178bool AwaitServerProcessTermination(int pid, const blaze_util::Path& output_base,
mschallerfd37b512017-07-11 18:21:36 +0200179 unsigned int wait_seconds) {
180 uint64_t st = GetMillisecondsMonotonic();
181 const unsigned int first_seconds = 5;
182 bool logged_first = false;
183 const unsigned int second_seconds = 10;
184 bool logged_second = false;
185 const unsigned int third_seconds = 30;
186 bool logged_third = false;
187
188 while (VerifyServerProcess(pid, output_base)) {
189 TrySleep(100);
190 uint64_t elapsed_millis = GetMillisecondsMonotonic() - st;
191 if (!logged_first && elapsed_millis > first_seconds * 1000) {
192 LogWait(first_seconds, wait_seconds);
193 logged_first = true;
194 }
195 if (!logged_second && elapsed_millis > second_seconds * 1000) {
196 LogWait(second_seconds, wait_seconds);
197 logged_second = true;
198 }
199 if (!logged_third && elapsed_millis > third_seconds * 1000) {
200 LogWait(third_seconds, wait_seconds);
201 logged_third = true;
202 }
203 if (elapsed_millis > wait_seconds * 1000) {
204 SigPrintf("INFO: Waited %d seconds for server process (pid=%d) to"
205 " terminate.\n",
206 wait_seconds, pid);
207 return false;
208 }
209 }
210 return true;
211}
212
ccalvarin9eea0f92018-03-21 15:32:30 -0700213// For now, we don't have the client set up to log to a file. If --client_debug
214// is passed, however, all BAZEL_LOG statements will be output to stderr.
215// If/when we switch to logging these to a file, care will have to be taken to
216// either log to both stderr and the file in the case of --client_debug, or be
217// ok that these log lines will only go to one stream.
218void SetDebugLog(bool enabled) {
219 if (enabled) {
220 blaze_util::SetLoggingOutputStreamToStderr();
221 } else {
222 blaze_util::SetLoggingOutputStream(nullptr);
Dmitry Lomov891f5402017-07-19 12:26:39 +0200223 }
Dmitry Lomov891f5402017-07-19 12:26:39 +0200224}
225
Laszlo Csomor0d107492019-03-13 09:04:27 -0700226bool IsRunningWithinTest() { return ExistsEnv("TEST_TMPDIR"); }
Laszlo Csomor9b83bd72018-12-17 08:42:44 -0800227
lberkid3d37f02018-04-18 11:44:14 -0700228void WithEnvVars::SetEnvVars(const map<string, EnvVarValue>& vars) {
229 for (const auto& var : vars) {
230 switch (var.second.action) {
231 case EnvVarAction::UNSET:
232 UnsetEnv(var.first);
233 break;
234
235 case EnvVarAction::SET:
236 SetEnv(var.first, var.second.value);
237 break;
238
239 default:
240 assert(false);
241 }
242 }
243}
244
245WithEnvVars::WithEnvVars(const map<string, EnvVarValue>& vars) {
246 for (const auto& v : vars) {
247 if (ExistsEnv(v.first)) {
248 _old_values[v.first] = EnvVarValue(EnvVarAction::SET, GetEnv(v.first));
249 } else {
250 _old_values[v.first] = EnvVarValue(EnvVarAction::UNSET, "");
251 }
252 }
253
254 SetEnvVars(vars);
255}
256
257WithEnvVars::~WithEnvVars() {
258 SetEnvVars(_old_values);
259}
260
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100261} // namespace blaze