blob: 9f6875a7fe63240043a1cae939b3dfe8fd87dc8b [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.runtime.commands;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Supplier;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.analysis.BlazeVersionInfo;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.cmdline.RepositoryName;
import com.google.devtools.build.lib.packages.Attribute;
import com.google.devtools.build.lib.packages.BuildType;
import com.google.devtools.build.lib.packages.ProtoUtils;
import com.google.devtools.build.lib.packages.RuleClass;
import com.google.devtools.build.lib.packages.RuleClassProvider;
import com.google.devtools.build.lib.packages.StarlarkSemanticsOptions;
import com.google.devtools.build.lib.packages.TriState;
import com.google.devtools.build.lib.pkgcache.PackageCacheOptions;
import com.google.devtools.build.lib.query2.proto.proto2api.Build.AllowedRuleClassInfo;
import com.google.devtools.build.lib.query2.proto.proto2api.Build.AttributeDefinition;
import com.google.devtools.build.lib.query2.proto.proto2api.Build.AttributeValue;
import com.google.devtools.build.lib.query2.proto.proto2api.Build.BuildLanguage;
import com.google.devtools.build.lib.query2.proto.proto2api.Build.RuleDefinition;
import com.google.devtools.build.lib.runtime.CommandEnvironment;
import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
import com.google.devtools.build.lib.syntax.StarlarkSemantics;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.util.AbruptExitException;
import com.google.devtools.build.lib.util.ProcessUtils;
import com.google.devtools.build.lib.util.StringUtilities;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.common.options.OptionsParsingResult;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* An item that is returned by <code>blaze info</code>.
*/
public abstract class InfoItem {
protected final String name;
protected final String description;
protected final boolean hidden;
protected InfoItem(String name,
String description,
boolean hidden) {
this.name = name;
this.description = description;
this.hidden = hidden;
}
protected InfoItem(String name,
String description) {
this(name, description, false);
}
/**
* The name of the info key.
*/
public String getName() {
return name;
}
/**
* The help description of the info key.
*/
public String getDescription() {
return description;
}
/**
* Whether the key is printed when "blaze info" is invoked without arguments.
*
* <p>This is usually true for info keys that take multiple lines, thus, cannot really be
* included in the output of argumentless "blaze info".
*/
public boolean isHidden() {
return hidden;
}
/**
* Returns the value of the info key. The return value is directly printed to stdout.
*/
public abstract byte[] get(
Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException, InterruptedException;
protected static byte[] print(Object value) {
if (value instanceof byte[]) {
return (byte[]) value;
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PrintWriter writer = new PrintWriter(new OutputStreamWriter(
outputStream, StandardCharsets.UTF_8));
writer.print(value + "\n");
writer.flush();
return outputStream.toByteArray();
}
/**
* Info item for the workspace directory.
*/
public static final class WorkspaceInfoItem extends InfoItem {
public WorkspaceInfoItem() {
super("workspace",
"The working directory of the server.");
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
checkNotNull(env);
return print(env.getRuntime().getWorkspace().getWorkspace());
}
}
/**
* Info item for the install_base directory.
*/
public static final class InstallBaseInfoItem extends InfoItem {
public InstallBaseInfoItem() {
super("install_base",
"The installation base directory.",
false);
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
checkNotNull(env);
return print(env.getRuntime().getWorkspace().getInstallBase());
}
}
/**
* Info item for the output_base directory.
*/
public static final class OutputBaseInfoItem extends InfoItem {
public OutputBaseInfoItem(String productName) {
super("output_base",
"A directory for shared " + productName
+ " state as well as tool and strategy specific subdirectories.",
false);
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
checkNotNull(env);
return print(env.getRuntime().getWorkspace().getOutputBase());
}
}
/**
* Info item for the execution_root directory.
*/
public static final class ExecutionRootInfoItem extends InfoItem {
public ExecutionRootInfoItem() {
super("execution_root",
"A directory that makes all input and output files visible to the build.",
false);
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
checkNotNull(env);
return print(env.getDirectories().getExecRoot(
configurationSupplier.get().getMainRepositoryName()));
}
}
/**
* Info item for the output_path directory.
*/
public static final class OutputPathInfoItem extends InfoItem {
public OutputPathInfoItem() {
super("output_path",
"Output directory",
false);
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
checkNotNull(env);
return print(
env.getDirectories().getOutputPath(configurationSupplier.get().getMainRepositoryName()));
}
}
/**
* Info item for the {blaze,bazel}-bin directory.
*/
public static final class BlazeBinInfoItem extends InfoItem {
public BlazeBinInfoItem(String productName) {
super(productName + "-bin",
"Configuration dependent directory for binaries.",
false);
}
// This is one of the three (non-hidden) info items that require a configuration, because the
// corresponding paths contain the short name. Maybe we should recommend using the symlinks
// or make them hidden by default?
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
checkNotNull(configurationSupplier);
return print(configurationSupplier.get().getBinDirectory(RepositoryName.MAIN).getRoot());
}
}
/**
* Info item for the {blaze,bazel}-genfiles directory.
*/
public static final class BlazeGenfilesInfoItem extends InfoItem {
public BlazeGenfilesInfoItem(String productName) {
super(productName + "-genfiles",
"Configuration dependent directory for generated files.",
false);
}
// This is one of the three (non-hidden) info items that require a configuration, because the
// corresponding paths contain the short name. Maybe we should recommend using the symlinks
// or make them hidden by default?
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
checkNotNull(configurationSupplier);
return print(configurationSupplier.get().getGenfilesDirectory(RepositoryName.MAIN).getRoot());
}
}
/**
* Info item for the {blaze,bazel}-testlogs directory.
*/
public static final class BlazeTestlogsInfoItem extends InfoItem {
public BlazeTestlogsInfoItem(String productName) {
super(productName + "-testlogs",
"Configuration dependent directory for logs from a test run.",
false);
}
// This is one of the three (non-hidden) info items that require a configuration, because the
// corresponding paths contain the short name. Maybe we should recommend using the symlinks
// or make them hidden by default?
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
checkNotNull(configurationSupplier);
return print(configurationSupplier.get().getTestLogsDirectory(RepositoryName.MAIN).getRoot());
}
}
/** Info item for server_log path. */
public static class ServerLogInfoItem extends InfoItem {
private static final Logger logger = Logger.getLogger(ServerLogInfoItem.class.getName());
/**
* Constructs an info item for the server log path.
*
* @param productName name of the tool whose server log path will be queried
*/
public ServerLogInfoItem(String productName) {
super("server_log", productName + " server log path", false);
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
try {
Optional<Path> path = env.getRuntime().getServerLogPath();
return print(path.map(Path::toString).orElse(""));
} catch (IOException e) {
logger.log(Level.WARNING, "Failed to determine server log location", e);
return print("UNKNOWN LOG LOCATION");
}
}
}
/**
* Info item for release
*/
public static final class ReleaseInfoItem extends InfoItem {
public ReleaseInfoItem(String productName) {
super("release",
productName + " release identifier",
false);
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
return print(BlazeVersionInfo.instance().getReleaseName());
}
}
/**
* Info item for server_pid
*/
public static final class ServerPidInfoItem extends InfoItem {
public ServerPidInfoItem(String productName) {
super("server_pid",
productName + " process id",
false);
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
return print(ProcessUtils.getpid());
}
}
/**
* Info item for package_path
*/
public static final class PackagePathInfoItem extends InfoItem {
private final OptionsParsingResult commandOptions;
public PackagePathInfoItem(OptionsParsingResult commandOptions) {
super("package_path",
"The search path for resolving package labels.",
false);
this.commandOptions = commandOptions;
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
checkNotNull(commandOptions);
PackageCacheOptions packageCacheOptions =
commandOptions.getOptions(PackageCacheOptions.class);
return print(Joiner.on(":").join(packageCacheOptions.packagePath));
}
}
private static MemoryUsage getMemoryUsage() {
MemoryMXBean memBean = ManagementFactory.getMemoryMXBean();
return memBean.getHeapMemoryUsage();
}
/**
* Info item for the used heap size
*/
public static final class UsedHeapSizeInfoItem extends InfoItem {
public UsedHeapSizeInfoItem() {
super("used-heap-size",
"The amount of used memory in bytes. Note that this is not a "
+ "good indicator of the actual memory use, as it includes any remaining inaccessible "
+ "memory.",
false);
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
return print(StringUtilities.prettyPrintBytes(getMemoryUsage().getUsed()));
}
}
/**
* Info item for the used heap size after garbage collection
*/
public static final class UsedHeapSizeAfterGcInfoItem extends InfoItem {
public UsedHeapSizeAfterGcInfoItem() {
super("used-heap-size-after-gc",
"The amount of used memory in bytes after a call to System.gc().",
true);
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
System.gc();
return print(StringUtilities.prettyPrintBytes(getMemoryUsage().getUsed()));
}
}
/**
* Info item for the committed heap size
*/
public static final class CommitedHeapSizeInfoItem extends InfoItem {
public CommitedHeapSizeInfoItem() {
super("committed-heap-size",
"The amount of memory in bytes that is committed for the Java virtual machine to use",
false);
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
return print(StringUtilities.prettyPrintBytes(getMemoryUsage().getCommitted()));
}
}
/**
* Info item for the max heap size
*/
public static final class MaxHeapSizeInfoItem extends InfoItem {
public MaxHeapSizeInfoItem() {
super("max-heap-size",
"The maximum amount of memory in bytes that can be used for memory management.",
false);
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
return print(StringUtilities.prettyPrintBytes(getMemoryUsage().getMax()));
}
}
/**
* Info item for the gc-count
*/
public static final class GcCountInfoItem extends InfoItem {
public GcCountInfoItem() {
super("gc-count",
"Number of garbage collection runs.",
false);
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
// The documentation is not very clear on what it means to have more than
// one GC MXBean, so we just sum them up.
long gcCount = 0;
for (GarbageCollectorMXBean gcBean : ManagementFactory.getGarbageCollectorMXBeans()) {
gcCount += gcBean.getCollectionCount();
}
return print(gcCount + "");
}
}
/** Info item for the name and version of the Java runtime environment. */
public static final class JavaRuntimeInfoItem extends InfoItem {
public JavaRuntimeInfoItem() {
super("java-runtime", "Name and version of the current Java runtime environment.", false);
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
return print(
String.format(
"%s (build %s) by %s",
System.getProperty("java.runtime.name", "Unknown runtime"),
System.getProperty("java.runtime.version", "unknown"),
System.getProperty("java.vendor", "unknown")));
}
}
/** Info item for the name and version of the Java VM. */
public static final class JavaVirtualMachineInfoItem extends InfoItem {
public JavaVirtualMachineInfoItem() {
super("java-vm", "Name and version of the current Java virtual machine.", false);
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
return print(
String.format(
"%s (build %s, %s) by %s",
System.getProperty("java.vm.name", "Unknown VM"),
System.getProperty("java.vm.version", "unknown"),
System.getProperty("java.vm.info", "unknown"),
System.getProperty("java.vm.vendor", "unknown")));
}
}
/** Info item for the location of the Java runtime. */
public static final class JavaHomeInfoItem extends InfoItem {
public JavaHomeInfoItem() {
super("java-home", "Location of the current Java runtime.", false);
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
String javaHome = System.getProperty("java.home");
if (javaHome == null) {
return print("unknown");
}
// Tunnel through a Path object in order to normalize the representation of the path.
Path javaHomePath = env.getRuntime().getFileSystem().getPath(javaHome);
return print(javaHomePath.getPathString());
}
}
/** Info item for the current character encoding settings. */
public static final class CharacterEncodingInfoItem extends InfoItem {
public CharacterEncodingInfoItem() {
super(
"character-encoding",
"Information about the character encoding used by the running JVM.",
false);
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
return print(
String.format(
"file.encoding = %s, defaultCharset = %s",
System.getProperty("file.encoding", "unknown"), Charset.defaultCharset().name()));
}
}
/** Info item for the gc-time */
public static final class GcTimeInfoItem extends InfoItem {
public GcTimeInfoItem() {
super("gc-time",
"The approximate accumulated time spend on garbage collection.",
false);
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
// The documentation is not very clear on what it means to have more than
// one GC MXBean, so we just sum them up.
long gcTime = 0;
for (GarbageCollectorMXBean gcBean : ManagementFactory.getGarbageCollectorMXBeans()) {
gcTime += gcBean.getCollectionTime();
}
return print(gcTime + "ms");
}
}
/** Info item for the effective current client environment. */
public static final class ClientEnv extends InfoItem {
public ClientEnv() {
super(
"client-env",
"The specifications that need to be added to the project-specific rc file to freeze the"
+ " current client environment",
true);
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
String result = "";
for (Map.Entry<String, String> entry : env.getWhitelistedActionEnv().entrySet()) {
// TODO(bazel-team): as the syntax of our rc-files does not support to express new-lines in
// values, we produce syntax errors if the value of the entry contains a newline character.
result += "build --action_env=" + entry.getKey() + "=" + entry.getValue() + "\n";
}
for (Map.Entry<String, String> entry : env.getWhitelistedTestEnv().entrySet()) {
// TODO(bazel-team): as the syntax of our rc-files does not support to express new-lines in
// values, we produce syntax errors if the value of the entry contains a newline character.
result += "build --test_env=" + entry.getKey() + "=" + entry.getValue() + "\n";
}
return print(result);
}
}
/**
* Info item for the effective current set of Starlark semantics option values.
*
* <p>This is hidden because its output is verbose and may be multiline.
*/
public static final class StarlarkSemanticsInfoItem extends InfoItem {
private final OptionsParsingResult commandOptions;
StarlarkSemanticsInfoItem(OptionsParsingResult commandOptions) {
super(
/*name=*/ "starlark-semantics",
/*description=*/ "The effective set of Starlark semantics option values.",
/*hidden=*/ true);
this.commandOptions = commandOptions;
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env) {
StarlarkSemanticsOptions starlarkSemanticsOptions =
commandOptions.getOptions(StarlarkSemanticsOptions.class);
SkyframeExecutor skyframeExecutor = env.getBlazeWorkspace().getSkyframeExecutor();
StarlarkSemantics effectiveSkylarkSemantics =
skyframeExecutor.getEffectiveStarlarkSemantics(starlarkSemanticsOptions);
return print(effectiveSkylarkSemantics.toDeterministicString());
}
}
/**
* Info item for the default package. It is deprecated, it still works, when explicitly requested,
* but are not shown by default. It prints multi-line messages and thus don't play well with grep.
* We don't print them unless explicitly requested.
*
* @deprecated
*/
// TODO(lberki): Try to remove this using an incompatible flag.
@Deprecated
public static final class DefaultsPackageInfoItem extends InfoItem {
public DefaultsPackageInfoItem() {
super("defaults-package", "Obsolete. Retained for backwards compatibility.", true);
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env) {
checkNotNull(env);
return print("");
}
}
private static AllowedRuleClassInfo getAllowedRuleClasses(
Collection<RuleClass> ruleClasses, Attribute attr) {
AllowedRuleClassInfo.Builder info = AllowedRuleClassInfo.newBuilder();
info.setPolicy(AllowedRuleClassInfo.AllowedRuleClasses.ANY);
if (attr.isStrictLabelCheckingEnabled()
&& attr.getAllowedRuleClassesPredicate() != Predicates.<RuleClass>alwaysTrue()) {
info.setPolicy(AllowedRuleClassInfo.AllowedRuleClasses.SPECIFIED);
Predicate<RuleClass> filter = attr.getAllowedRuleClassesPredicate();
for (RuleClass otherClass : Iterables.filter(ruleClasses, filter)) {
if (!isAbstractRule(otherClass)) {
info.addAllowedRuleClass(otherClass.getName());
}
}
}
return info.build();
}
private static boolean isAbstractRule(RuleClass c) {
return c.getName().startsWith("$");
}
/**
* Returns a byte array containing a proto-buffer describing the build language.
*/
private static byte[] getBuildLanguageDefinition(RuleClassProvider provider) {
BuildLanguage.Builder resultPb = BuildLanguage.newBuilder();
Collection<RuleClass> ruleClasses = provider.getRuleClassMap().values();
for (RuleClass ruleClass : ruleClasses) {
if (isAbstractRule(ruleClass)) {
continue;
}
RuleDefinition.Builder rulePb = RuleDefinition.newBuilder();
rulePb.setName(ruleClass.getName());
for (Attribute attr : ruleClass.getAttributes()) {
Type<?> t = attr.getType();
AttributeDefinition.Builder attrPb = AttributeDefinition.newBuilder();
attrPb.setName(attr.getName());
attrPb.setType(ProtoUtils.getDiscriminatorFromType(t));
attrPb.setMandatory(attr.isMandatory());
attrPb.setAllowEmpty(!attr.isNonEmpty());
attrPb.setAllowSingleFile(attr.isSingleArtifact());
attrPb.setConfigurable(attr.isConfigurable());
attrPb.setCfgIsHost(attr.getTransitionFactory().isHost());
// Encode default value, if simple.
Object v = attr.getDefaultValueUnchecked();
if (!(v == null
|| v instanceof Attribute.ComputedDefault
|| v instanceof Attribute.SkylarkComputedDefaultTemplate
|| v instanceof Attribute.LateBoundDefault
|| v == t.getDefaultValue())) {
attrPb.setDefault(convertAttrValue(t, v));
}
attrPb.setExecutable(attr.isExecutable());
if (BuildType.isLabelType(t)) {
attrPb.setAllowedRuleClasses(getAllowedRuleClasses(ruleClasses, attr));
attrPb.setNodep(t.getLabelClass() == Type.LabelClass.NONDEP_REFERENCE);
}
rulePb.addAttribute(attrPb);
}
resultPb.addRule(rulePb);
}
return resultPb.build().toByteArray();
}
// convertAttrValue converts attribute value v of type to t an AttributeValue message.
private static AttributeValue convertAttrValue(Type<?> t, Object v) {
AttributeValue.Builder b = AttributeValue.newBuilder();
if (v instanceof Map) {
Type.DictType<?, ?> dictType = (Type.DictType<?, ?>) t;
for (Map.Entry<?, ?> entry : ((Map<?, ?>) v).entrySet()) {
b.addDictBuilder()
.setKey(entry.getKey().toString())
.setValue(convertAttrValue(dictType.getValueType(), entry.getValue()))
.build();
}
} else if (v instanceof List) {
for (Object elem : (List<?>) v) {
b.addList(convertAttrValue(t.getListElementType(), elem));
}
} else if (t == BuildType.LICENSE) {
// TODO(adonovan): need dual function of parseLicense.
// Treat as empty list for now.
} else if (t == BuildType.DISTRIBUTIONS) {
// TODO(adonovan): need dual function of parseDistributions.
// Treat as empty list for now.
} else if (t == Type.STRING) {
b.setString((String) v);
} else if (t == Type.INTEGER) {
b.setInt((Integer) v);
} else if (t == Type.BOOLEAN) {
b.setBool((Boolean) v);
} else if (t == BuildType.TRISTATE) {
b.setInt(((TriState) v).toInt());
} else if (BuildType.isLabelType(t)) { // case order matters!
b.setString(v.toString());
} else {
// No native rule attribute of this type (FilesetEntry?) has a default value.
throw new IllegalStateException("unexpected type of attribute default value: " + t);
}
return b.build();
}
/**
* Info item for the build language. It is deprecated, it still works, when
* explicitly requested, but are not shown by default. It prints multi-line messages and thus
* don't play well with grep. We don't print them unless explicitly requested.
* @Deprecated
*/
@Deprecated
public static final class BuildLanguageInfoItem extends InfoItem {
public BuildLanguageInfoItem() {
super("build-language",
"A protobuffer with the build language structure",
true);
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
checkNotNull(env);
return print(getBuildLanguageDefinition(env.getRuntime().getRuleClassProvider()));
}
}
/**
* Info item for the default package path. It is deprecated, it still works, when
* explicitly requested, but are not shown by default. It prints multi-line messages and thus
* don't play well with grep. We don't print them unless explicitly requested.
* @deprecated
*/
@Deprecated
public static final class DefaultPackagePathInfoItem extends InfoItem {
private final OptionsParsingResult commandOptions;
public DefaultPackagePathInfoItem(OptionsParsingResult commandOptions) {
super("default-package-path",
"The default package path",
true);
this.commandOptions = commandOptions;
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
throws AbruptExitException {
checkNotNull(commandOptions);
return print(Joiner.on(":").join(
commandOptions.getOptions(PackageCacheOptions.class).packagePath));
}
}
/**
* Info item for the make environment.
*/
public static class MakeInfoItem extends InfoItem {
public MakeInfoItem(String name, String description) {
super(name, description, false);
}
@Override
public String getDescription() {
return "Make environment variable '" + name + "'";
}
@Override
public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env) {
return print(description);
}
}
}