blob: 03adf0570af0ae1216235321ddef284a5f24e36c [file] [log] [blame]
// Copyright 2015 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 com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.packages.Attribute;
import com.google.devtools.build.lib.packages.PackageFactory;
import com.google.devtools.build.lib.packages.RuleClass;
import com.google.devtools.build.lib.runtime.BlazeCommand;
import com.google.devtools.build.lib.runtime.BlazeCommandUtils;
import com.google.devtools.build.lib.runtime.BlazeRuntime;
import com.google.devtools.build.lib.runtime.Command;
import com.google.devtools.build.lib.runtime.CommandEnvironment;
import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
import com.google.devtools.build.lib.util.ExitCode;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.common.options.EnumConverter;
import com.google.devtools.common.options.Option;
import com.google.devtools.common.options.OptionsBase;
import com.google.devtools.common.options.OptionsParser;
import com.google.devtools.common.options.OptionsProvider;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Implementation of the dump command.
*/
@Command(allowResidue = false,
mustRunInWorkspace = false,
options = { DumpCommand.DumpOptions.class },
help = "Usage: %{product} dump <options>\n"
+ "Dumps the internal state of the %{product} server process. This command is provided "
+ "as an aid to debugging, not as a stable interface, so users should not try to "
+ "parse the output; instead, use 'query' or 'info' for this purpose.\n%{options}",
name = "dump",
shortDescription = "Dumps the internal state of the %{product} server process.")
public class DumpCommand implements BlazeCommand {
/**
* NB! Any changes to this class must be kept in sync with anyOutput variable
* value in the {@link DumpCommand#exec(CommandEnvironment,OptionsProvider)} method below.
*/
public static class DumpOptions extends OptionsBase {
@Option(name = "packages",
defaultValue = "false",
category = "verbosity",
help = "Dump package cache content.")
public boolean dumpPackages;
@Option(name = "vfs",
defaultValue = "false",
category = "verbosity",
help = "Dump virtual filesystem cache content.")
public boolean dumpVfs;
@Option(name = "action_cache",
defaultValue = "false",
category = "verbosity",
help = "Dump action cache content.")
public boolean dumpActionCache;
@Option(name = "rule_classes",
defaultValue = "false",
category = "verbosity",
help = "Dump rule classes.")
public boolean dumpRuleClasses;
@Option(name = "skyframe",
defaultValue = "off",
category = "verbosity",
converter = SkyframeDumpEnumConverter.class,
help = "Dump Skyframe graph: 'off', 'summary', or 'detailed'.")
public SkyframeDumpOption dumpSkyframe;
}
/**
* Different ways to dump information about Skyframe.
*/
public enum SkyframeDumpOption {
OFF,
SUMMARY,
DETAILED;
}
/**
* Enum converter for SkyframeDumpOption.
*/
public static class SkyframeDumpEnumConverter extends EnumConverter<SkyframeDumpOption> {
public SkyframeDumpEnumConverter() {
super(SkyframeDumpOption.class, "Skyframe Dump option");
}
}
@Override
public void editOptions(CommandEnvironment env, OptionsParser optionsParser) {}
@Override
public ExitCode exec(CommandEnvironment env, OptionsProvider options) {
BlazeRuntime runtime = env.getRuntime();
DumpOptions dumpOptions = options.getOptions(DumpOptions.class);
boolean anyOutput =
dumpOptions.dumpPackages
|| dumpOptions.dumpVfs
|| dumpOptions.dumpActionCache
|| dumpOptions.dumpRuleClasses
|| (dumpOptions.dumpSkyframe != SkyframeDumpOption.OFF);
if (!anyOutput) {
Map<String, String> categories = new HashMap<>();
categories.put("verbosity", "Options that control what internal state is dumped");
Collection<Class<? extends OptionsBase>> optionList = new ArrayList<>();
optionList.add(DumpOptions.class);
env.getReporter().getOutErr().printErrLn(BlazeCommandUtils.expandHelpTopic(
getClass().getAnnotation(Command.class).name(),
getClass().getAnnotation(Command.class).help(),
getClass(),
optionList, categories, OptionsParser.HelpVerbosity.LONG,
runtime.getProductName()));
return ExitCode.ANALYSIS_FAILURE;
}
PrintStream out = new PrintStream(env.getReporter().getOutErr().getOutputStream());
try {
out.println("Warning: this information is intended for consumption by developers");
out.println("only, and may change at any time. Script against it at your own risk!");
out.println();
boolean success = true;
if (dumpOptions.dumpPackages) {
env.getPackageManager().dump(out);
out.println();
}
if (dumpOptions.dumpVfs) {
out.println("Filesystem cache");
FileSystemUtils.dump(env.getOutputBase().getFileSystem(), out);
out.println();
}
if (dumpOptions.dumpActionCache) {
success &= dumpActionCache(env, out);
out.println();
}
if (dumpOptions.dumpRuleClasses) {
dumpRuleClasses(runtime, out);
out.println();
}
if (dumpOptions.dumpSkyframe != SkyframeDumpOption.OFF) {
success &= dumpSkyframe(
env.getSkyframeExecutor(),
dumpOptions.dumpSkyframe == SkyframeDumpOption.SUMMARY,
out);
out.println();
}
return success ? ExitCode.SUCCESS : ExitCode.ANALYSIS_FAILURE;
} finally {
out.flush();
}
}
private boolean dumpActionCache(CommandEnvironment env, PrintStream out) {
try {
env.getPersistentActionCache().dump(out);
} catch (IOException e) {
env.getReporter().handle(Event.error("Cannot dump action cache: " + e.getMessage()));
return false;
}
return true;
}
private boolean dumpSkyframe(SkyframeExecutor executor, boolean summarize, PrintStream out) {
executor.dump(summarize, out);
return true;
}
private void dumpRuleClasses(BlazeRuntime runtime, PrintStream out) {
PackageFactory factory = runtime.getPackageFactory();
List<String> ruleClassNames = new ArrayList<>(factory.getRuleClassNames());
Collections.sort(ruleClassNames);
for (String name : ruleClassNames) {
if (name.startsWith("$")) {
continue;
}
RuleClass ruleClass = factory.getRuleClass(name);
out.print(ruleClass + "(");
boolean first = true;
for (Attribute attribute : ruleClass.getAttributes()) {
if (attribute.isImplicit()) {
continue;
}
if (first) {
first = false;
} else {
out.print(", ");
}
out.print(attribute.getName());
}
out.println(")");
}
}
}