blob: e23b2bc75b6377d7b801c9d9f07ded8b3cca17b2 [file] [log] [blame]
// Copyright 2014 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.lib.actions;
import com.google.auto.value.AutoValue;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.packages.Rule;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Strings used to express requirements on action execution environments.
*
* <ol>
* If you are adding a new execution requirement, pay attention to the following:
* <li>If its name starts with one of the supported prefixes, then it can be also used as a tag on
* a target and will be propagated to the execution requirements, see for prefixes {@link
* com.google.devtools.build.lib.packages.TargetUtils#getExecutionInfo(Rule)}
* <li>If this is a potentially conflicting execution requirements, e.g. you are adding a pair
* 'requires-x' and 'block-x', you MUST take care of a potential conflict in the Executor that
* is using new execution requirements. As an example, see {@link
* Spawns#requiresNetwork(com.google.devtools.build.lib.actions.Spawn, boolean)}.
* </ol>
*/
public class ExecutionRequirements {
/** An execution requirement that can be split into a key and a value part using a regex. */
@AutoValue
public abstract static class ParseableRequirement {
/**
* Thrown when a {@link ParseableRequirement} feels responsible for a tag, but the {@link
* #validator()} method returns an error.
*/
public static class ValidationException extends Exception {
private final String tagValue;
/**
* Creates a new {@link ValidationException}.
*
* @param tagValue the erroneous value that was parsed from the tag.
* @param errorMsg an error message that tells the user what's wrong with the value.
*/
public ValidationException(String tagValue, String errorMsg) {
super(errorMsg);
this.tagValue = tagValue;
}
/**
* Returns the erroneous value of the parsed tag.
*
* <p>Useful to put in error messages shown to the user.
*/
public String getTagValue() {
return tagValue;
}
}
/**
* Create a new parseable execution requirement definition.
*
* <p>If a tag doesn't match the detectionPattern, it will be ignored. If a tag matches the
* detectionPattern, but not the validationPattern, it is assumed that the value is somehow
* wrong (e.g. the user put a float or random string where we expected an integer).
*
* @param userFriendlyName a human readable name of the tag and its format, e.g. "cpu:<int>"
* @param detectionPattern a regex that will be used to detect whether a tag matches this
* execution requirement. It should have one capture group that grabs the value of the tag.
* This should be general enough to permit even wrong value types. Example: "cpu:(.+)".
* @param validator a Function that will be used to validate the value of the tag. It should
* return null if the value is fine to use or a human-friendly error message describing why
* the value is not valid.
*/
static ParseableRequirement create(
String userFriendlyName, Pattern detectionPattern, Function<String, String> validator) {
return new AutoValue_ExecutionRequirements_ParseableRequirement(
userFriendlyName, detectionPattern, validator);
}
public abstract String userFriendlyName();
public abstract Pattern detectionPattern();
public abstract Function<String, String> validator();
/**
* Returns the parsed value from a tag, if this {@link ParseableRequirement} detects that it is
* responsible for it, otherwise returns {@code null}.
*
* @throws ValidationException if the value parsed out of the tag doesn't pass the validator.
*/
public String parseIfMatches(String tag) throws ValidationException {
Matcher matcher = detectionPattern().matcher(tag);
if (!matcher.matches()) {
return null;
}
String tagValue = matcher.group(1);
String errorMsg = validator().apply(tagValue);
if (errorMsg != null) {
throw new ValidationException(tagValue, errorMsg);
}
return tagValue;
}
}
/** If specified, the timeout of this action in seconds. Must be decimal integer. */
public static final String TIMEOUT = "timeout";
/** If an action would not successfully run other than on Darwin. */
public static final String REQUIRES_DARWIN = "requires-darwin";
/** Whether we should disable prefetching of inputs before running a local action. */
public static final String DISABLE_LOCAL_PREFETCH = "disable-local-prefetch";
/** How many hardware threads an action requires for execution. */
public static final ParseableRequirement CPU =
ParseableRequirement.create(
"cpu:<int>",
Pattern.compile("cpu:(.+)"),
s -> {
Preconditions.checkNotNull(s);
int value;
try {
value = Integer.parseInt(s);
} catch (NumberFormatException e) {
return "can't be parsed as an integer";
}
// De-and-reserialize & compare to only allow canonical integer formats.
if (!Integer.toString(value).equals(s)) {
return "must be in canonical format (e.g. '4' instead of '+04')";
}
if (value < 1) {
return "can't be zero or negative";
}
return null;
});
/** If an action supports running in persistent worker mode. */
public static final String SUPPORTS_WORKERS = "supports-workers";
public static final String SUPPORTS_MULTIPLEX_WORKERS = "supports-multiplex-workers";
public static final ImmutableMap<String, String> WORKER_MODE_ENABLED =
ImmutableMap.of(SUPPORTS_WORKERS, "1");
/**
* Requires local execution without sandboxing for a spawn.
*
* <p>This tag is deprecated; use no-cache, no-remote, or no-sandbox instead.
*/
public static final String LOCAL = "local";
/**
* Disables local and remote caching for a spawn, but note that the local action cache may still
* apply.
*
* <p>This tag can also be set on an action, in which case it completely disables all caching for
* that action, but note that action-generated spawns may still be cached, unless they also carry
* this tag.
*/
public static final String NO_CACHE = "no-cache";
/** Disables remote caching of a spawn. Note: does not disable remote execution */
public static final String NO_REMOTE_CACHE = "no-remote-cache";
/** Disables remote execution of a spawn. Note: does not disable remote caching */
public static final String NO_REMOTE_EXEC = "no-remote-exec";
/**
* Disables both remote execution and remote caching of a spawn. This is the equivalent of using
* no-remote-cache and no-remote-exec together.
*/
public static final String NO_REMOTE = "no-remote";
/** Disables local execution of a spawn. */
public static final String NO_LOCAL = "no-local";
/** Disables local sandboxing of a spawn. */
public static final String LEGACY_NOSANDBOX = "nosandbox";
/** Disables local sandboxing of a spawn. */
public static final String NO_SANDBOX = "no-sandbox";
/**
* Set for Xcode-related rules. Used for quality control to make sure that all Xcode-dependent
* rules propagate the necessary configurations. Begins with "supports" so as not to be filtered
* out for Bazel by {@code TargetUtils}.
*/
public static final String REQUIREMENTS_SET = "supports-xcode-requirements-set";
/**
* Enables networking for a spawn if possible (only if sandboxing is enabled and if the sandbox
* supports it).
*/
public static final String REQUIRES_NETWORK = "requires-network";
/**
* Disables networking for a spawn if possible (only if sandboxing is enabled and if the sandbox
* supports it).
*/
public static final String BLOCK_NETWORK = "block-network";
/**
* On linux, if sandboxing is enabled, ensures that a spawn is run with uid 0, i.e., root. Has no
* effect otherwise.
*/
public static final String REQUIRES_FAKEROOT = "requires-fakeroot";
/** Suppress CLI reporting for this spawn - it's part of another action. */
public static final String DO_NOT_REPORT = "internal-do-not-report";
/** Use this to request eager fetching of a single remote output into local memory. */
public static final String REMOTE_EXECUTION_INLINE_OUTPUTS = "internal-inline-outputs";
}