blob: 24d51c542379b90b0998867e06a96b442324aff4 [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
15package com.google.devtools.build.lib.util;
16
17import com.google.common.base.Objects;
jhorvitzd5f96eb2020-10-26 13:55:27 -070018import com.google.errorprone.annotations.Immutable;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010019import java.util.Collection;
20import java.util.HashMap;
mschallercb9fbc02020-02-11 13:56:21 -080021import javax.annotation.Nullable;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010022
23/**
jhorvitzd5f96eb2020-10-26 13:55:27 -070024 * Anything marked FAILURE is generally from a problem with the source code under consideration. In
25 * these cases, a re-run in an identical client should produce an identical return code all things
26 * being constant.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010027 *
jhorvitzd5f96eb2020-10-26 13:55:27 -070028 * <p>Anything marked as an ERROR is generally a problem unrelated to the source code itself. It is
29 * either something wrong with the user's command line or the user's machine or environment.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010030 *
jhorvitzd5f96eb2020-10-26 13:55:27 -070031 * <p>Note that these exit codes should be kept consistent with the codes returned by Blaze's
32 * launcher in //devtools/blaze/main:blaze.cc Blaze exit codes should be consistently classified as
33 * permanent vs. transient (i.e. retriable) vs. unknown transient/permanent because users, in
34 * particular infrastructure users, will use the exit code to decide whether the request should be
35 * retried or not.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010036 */
jhorvitzd5f96eb2020-10-26 13:55:27 -070037@Immutable
38public final class ExitCode {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010039 // Tracks all exit codes defined here and elsewhere in Bazel.
40 private static final HashMap<Integer, ExitCode> exitCodeRegistry = new HashMap<>();
41
42 public static final ExitCode SUCCESS = ExitCode.create(0, "SUCCESS");
43 public static final ExitCode BUILD_FAILURE = ExitCode.create(1, "BUILD_FAILURE");
44 public static final ExitCode PARSING_FAILURE = ExitCode.createUnregistered(1, "PARSING_FAILURE");
45 public static final ExitCode COMMAND_LINE_ERROR = ExitCode.create(2, "COMMAND_LINE_ERROR");
46 public static final ExitCode TESTS_FAILED = ExitCode.create(3, "TESTS_FAILED");
47 public static final ExitCode PARTIAL_ANALYSIS_FAILURE =
48 ExitCode.createUnregistered(3, "PARTIAL_ANALYSIS_FAILURE");
49 public static final ExitCode NO_TESTS_FOUND = ExitCode.create(4, "NO_TESTS_FOUND");
50 public static final ExitCode RUN_FAILURE = ExitCode.create(6, "RUN_FAILURE");
51 public static final ExitCode ANALYSIS_FAILURE = ExitCode.create(7, "ANALYSIS_FAILURE");
52 public static final ExitCode INTERRUPTED = ExitCode.create(8, "INTERRUPTED");
ccalvarin6c8166e2018-07-23 09:17:26 -070053 public static final ExitCode LOCK_HELD_NOBLOCK_FOR_LOCK =
54 ExitCode.create(9, "LOCK_HELD_NOBLOCK_FOR_LOCK");
ulfjack24e3d7a2017-06-06 08:01:09 -040055
56 public static final ExitCode REMOTE_ENVIRONMENTAL_ERROR =
57 ExitCode.createInfrastructureFailure(32, "REMOTE_ENVIRONMENTAL_ERROR");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010058 public static final ExitCode OOM_ERROR = ExitCode.createInfrastructureFailure(33, "OOM_ERROR");
ulfjack24e3d7a2017-06-06 08:01:09 -040059
60 public static final ExitCode REMOTE_ERROR =
61 ExitCode.createInfrastructureFailure(34, "REMOTE_ERROR");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010062 public static final ExitCode LOCAL_ENVIRONMENTAL_ERROR =
63 ExitCode.createInfrastructureFailure(36, "LOCAL_ENVIRONMENTAL_ERROR");
64 public static final ExitCode BLAZE_INTERNAL_ERROR =
65 ExitCode.createInfrastructureFailure(37, "BLAZE_INTERNAL_ERROR");
felly25689422019-02-08 08:54:37 -080066 public static final ExitCode TRANSIENT_BUILD_EVENT_SERVICE_UPLOAD_ERROR =
buchgrfb303452017-05-12 08:19:23 -040067 ExitCode.createInfrastructureFailure(38, "PUBLISH_ERROR");
Chi Wang99cff332023-02-14 05:01:31 -080068 public static final ExitCode REMOTE_CACHE_EVICTED =
69 ExitCode.createInfrastructureFailure(39, "REMOTE_CACHE_EVICTED");
felly25689422019-02-08 08:54:37 -080070 public static final ExitCode PERSISTENT_BUILD_EVENT_SERVICE_UPLOAD_ERROR =
71 ExitCode.create(45, "PERSISTENT_BUILD_EVENT_SERVICE_UPLOAD_ERROR");
wyv00bd2912021-07-21 04:20:13 -070072 public static final ExitCode EXTERNAL_DEPS_ERROR = ExitCode.create(48, "EXTERNAL_DEPS_ERROR");
ulfjack24e3d7a2017-06-06 08:01:09 -040073
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010074 /**
75 * Creates and returns an ExitCode. Requires a unique exit code number.
76 *
77 * @param code the int value for this exit code
78 * @param name a human-readable description
79 */
80 public static ExitCode create(int code, String name) {
81 return new ExitCode(code, name, /*infrastructureFailure=*/false, /*register=*/true);
82 }
83
84 /**
85 * Creates and returns an ExitCode that represents an infrastructure failure.
86 *
87 * @param code the int value for this exit code
88 * @param name a human-readable description
89 */
90 public static ExitCode createInfrastructureFailure(int code, String name) {
91 return new ExitCode(code, name, /*infrastructureFailure=*/true, /*register=*/true);
92 }
93
94 /**
95 * Creates and returns an ExitCode that has the same numeric code as another ExitCode. This is to
96 * allow the duplicate error codes listed above to be registered, but is private to prevent other
97 * users from creating duplicate error codes in the future.
98 *
99 * @param code the int value for this exit code
100 * @param name a human-readable description
101 */
102 private static ExitCode createUnregistered(int code, String name) {
103 return new ExitCode(code, name, /*infrastructureFailure=*/false, /*register=*/false);
104 }
105
106 /**
107 * Add the given exit code to the registry.
108 *
109 * @param exitCode the exit code to register
110 * @throws IllegalStateException if the numeric exit code is already in the registry.
111 */
112 private static void register(ExitCode exitCode) {
113 synchronized (exitCodeRegistry) {
114 int codeNum = exitCode.getNumericExitCode();
115 if (exitCodeRegistry.containsKey(codeNum)) {
116 throw new IllegalStateException(
117 "Exit code " + codeNum + " (" + exitCode.name + ") already registered");
118 }
119 exitCodeRegistry.put(codeNum, exitCode);
120 }
121 }
122
123 /**
124 * Returns all registered ExitCodes.
125 */
126 public static Collection<ExitCode> values() {
127 synchronized (exitCodeRegistry) {
128 return exitCodeRegistry.values();
129 }
130 }
131
mschallercb9fbc02020-02-11 13:56:21 -0800132 /**
133 * Returns a registered {@link ExitCode} with the given {@code code}.
134 *
135 * <p>Note that there *are* unregistered ExitCodes. This will never return them.
136 */
137 @Nullable
138 static ExitCode forCode(int code) {
139 synchronized (exitCodeRegistry) {
140 return exitCodeRegistry.get(code);
141 }
142 }
143
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100144 private final int numericExitCode;
145 private final String name;
146 private final boolean infrastructureFailure;
147
148 /**
149 * Whenever a new exit code is created, it is registered (to prevent exit codes with identical
150 * numeric codes from being created). However, there are some exit codes in this file that have
151 * duplicate numeric codes, so these are not registered.
152 */
153 private ExitCode(int exitCode, String name, boolean infrastructureFailure, boolean register) {
154 this.numericExitCode = exitCode;
155 this.name = name;
156 this.infrastructureFailure = infrastructureFailure;
157 if (register) {
158 ExitCode.register(this);
159 }
160 }
161
162 @Override
163 public int hashCode() {
164 return Objects.hashCode(numericExitCode, name, infrastructureFailure);
165 }
166
167 @Override
168 public boolean equals(Object object) {
169 if (object instanceof ExitCode) {
170 ExitCode that = (ExitCode) object;
171 return this.numericExitCode == that.numericExitCode
172 && this.name.equals(that.name)
173 && this.infrastructureFailure == that.infrastructureFailure;
174 }
175 return false;
176 }
177
178 /**
179 * Returns the human-readable name for this exit code. Not guaranteed to be stable, use the
180 * numeric exit code for that.
181 */
182 @Override
183 public String toString() {
184 return name;
185 }
186
187 /**
188 * Returns the error's int value.
189 */
190 public int getNumericExitCode() {
191 return numericExitCode;
192 }
193
194 /**
195 * Returns the human-readable name.
196 */
197 public String name() {
198 return name;
199 }
200
201 /**
202 * Returns true if the current exit code represents a failure of Blaze infrastructure,
203 * vs. a build failure.
204 */
205 public boolean isInfrastructureFailure() {
206 return infrastructureFailure;
207 }
208}