blob: d8ec359515f77939c6611b335b9639ba8d116259 [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,
78 const char *key) {
79 if (args.empty()) {
80 return NULL;
81 }
82
83 vector<string>::size_type i = 0;
84 for (; i < args.size() - 1; ++i) {
Luis Fernando Pino Duqued56e1c62017-03-24 18:04:00 +000085 if (args[i] == "--") {
86 return NULL;
87 }
Luis Fernando Pino Duqued5e008c2016-12-08 16:59:16 +000088 const char* result = GetUnaryOption(args[i].c_str(),
89 args[i + 1].c_str(),
90 key);
91 if (result != NULL) {
92 return result;
93 }
94 }
95 return GetUnaryOption(args[i].c_str(), NULL, key);
96}
97
ajmichael1b3569a2018-01-24 07:43:32 -080098bool SearchNullaryOption(const vector<string>& args,
99 const string& flag_name,
100 const bool default_value) {
101 const string positive_flag = "--" + flag_name;
102 const string negative_flag = "--no" + flag_name;
103 bool result = default_value;
Luis Fernando Pino Duqued5e008c2016-12-08 16:59:16 +0000104 for (vector<string>::size_type i = 0; i < args.size(); i++) {
Luis Fernando Pino Duqued56e1c62017-03-24 18:04:00 +0000105 if (args[i] == "--") {
ajmichael1b3569a2018-01-24 07:43:32 -0800106 break;
Luis Fernando Pino Duqued56e1c62017-03-24 18:04:00 +0000107 }
ajmichael1b3569a2018-01-24 07:43:32 -0800108 if (GetNullaryOption(args[i].c_str(), positive_flag.c_str())) {
109 result = true;
110 } else if (GetNullaryOption(args[i].c_str(), negative_flag.c_str())) {
111 result = false;
Luis Fernando Pino Duqued5e008c2016-12-08 16:59:16 +0000112 }
113 }
ajmichael1b3569a2018-01-24 07:43:32 -0800114 return result;
lpino4ed3db62017-08-10 16:25:54 +0200115}
116
Luis Fernando Pino Duque0311fc52016-11-21 13:20:50 +0000117bool IsArg(const string& arg) {
118 return blaze_util::starts_with(arg, "-") && (arg != "--help")
119 && (arg != "-help") && (arg != "-h");
120}
121
ccalvarin755278d2018-06-07 11:05:54 -0700122std::string AbsolutePathFromFlag(const std::string& value) {
123 if (value.empty()) {
124 return blaze_util::GetCwd();
125 } else {
126 return blaze_util::MakeAbsolute(value);
127 }
128}
129
mschallerfd37b512017-07-11 18:21:36 +0200130void LogWait(unsigned int elapsed_seconds, unsigned int wait_seconds) {
131 SigPrintf("WARNING: Waiting for server process to terminate "
132 "(waited %d seconds, waiting at most %d)\n",
133 elapsed_seconds, wait_seconds);
134}
135
136bool AwaitServerProcessTermination(int pid, const string& output_base,
137 unsigned int wait_seconds) {
138 uint64_t st = GetMillisecondsMonotonic();
139 const unsigned int first_seconds = 5;
140 bool logged_first = false;
141 const unsigned int second_seconds = 10;
142 bool logged_second = false;
143 const unsigned int third_seconds = 30;
144 bool logged_third = false;
145
146 while (VerifyServerProcess(pid, output_base)) {
147 TrySleep(100);
148 uint64_t elapsed_millis = GetMillisecondsMonotonic() - st;
149 if (!logged_first && elapsed_millis > first_seconds * 1000) {
150 LogWait(first_seconds, wait_seconds);
151 logged_first = true;
152 }
153 if (!logged_second && elapsed_millis > second_seconds * 1000) {
154 LogWait(second_seconds, wait_seconds);
155 logged_second = true;
156 }
157 if (!logged_third && elapsed_millis > third_seconds * 1000) {
158 LogWait(third_seconds, wait_seconds);
159 logged_third = true;
160 }
161 if (elapsed_millis > wait_seconds * 1000) {
162 SigPrintf("INFO: Waited %d seconds for server process (pid=%d) to"
163 " terminate.\n",
164 wait_seconds, pid);
165 return false;
166 }
167 }
168 return true;
169}
170
ccalvarin9eea0f92018-03-21 15:32:30 -0700171// For now, we don't have the client set up to log to a file. If --client_debug
172// is passed, however, all BAZEL_LOG statements will be output to stderr.
173// If/when we switch to logging these to a file, care will have to be taken to
174// either log to both stderr and the file in the case of --client_debug, or be
175// ok that these log lines will only go to one stream.
176void SetDebugLog(bool enabled) {
177 if (enabled) {
178 blaze_util::SetLoggingOutputStreamToStderr();
179 } else {
180 blaze_util::SetLoggingOutputStream(nullptr);
Dmitry Lomov891f5402017-07-19 12:26:39 +0200181 }
Dmitry Lomov891f5402017-07-19 12:26:39 +0200182}
183
lberkid3d37f02018-04-18 11:44:14 -0700184void WithEnvVars::SetEnvVars(const map<string, EnvVarValue>& vars) {
185 for (const auto& var : vars) {
186 switch (var.second.action) {
187 case EnvVarAction::UNSET:
188 UnsetEnv(var.first);
189 break;
190
191 case EnvVarAction::SET:
192 SetEnv(var.first, var.second.value);
193 break;
194
195 default:
196 assert(false);
197 }
198 }
199}
200
201WithEnvVars::WithEnvVars(const map<string, EnvVarValue>& vars) {
202 for (const auto& v : vars) {
203 if (ExistsEnv(v.first)) {
204 _old_values[v.first] = EnvVarValue(EnvVarAction::SET, GetEnv(v.first));
205 } else {
206 _old_values[v.first] = EnvVarValue(EnvVarAction::UNSET, "");
207 }
208 }
209
210 SetEnvVars(vars);
211}
212
213WithEnvVars::~WithEnvVars() {
214 SetEnvVars(_old_values);
215}
216
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100217} // namespace blaze