use of com.google.devtools.build.lib.query2.output.QueryOptions in project bazel by bazelbuild.
the class XmlOutputFormatter method createPostFactoStreamCallback.
@Override
public OutputFormatterCallback<Target> createPostFactoStreamCallback(final OutputStream out, final QueryOptions options) {
return new OutputFormatterCallback<Target>() {
private Document doc;
private Element queryElem;
@Override
public void start() {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
doc = factory.newDocumentBuilder().newDocument();
} catch (ParserConfigurationException e) {
// This shouldn't be possible: all the configuration is hard-coded.
throw new IllegalStateException("XML output failed", e);
}
doc.setXmlVersion("1.1");
queryElem = doc.createElement("query");
queryElem.setAttribute("version", "2");
doc.appendChild(queryElem);
}
@Override
public void processOutput(Iterable<Target> partialResult) throws IOException, InterruptedException {
for (Target target : partialResult) {
queryElem.appendChild(createTargetElement(doc, target));
}
}
@Override
public void close(boolean failFast) throws IOException {
if (!failFast) {
try {
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(new DOMSource(doc), new StreamResult(out));
} catch (TransformerFactoryConfigurationError | TransformerException e) {
// This shouldn't be possible: all the configuration is hard-coded.
throw new IllegalStateException("XML output failed", e);
}
}
}
};
}
use of com.google.devtools.build.lib.query2.output.QueryOptions in project bazel by bazelbuild.
the class QueryCommand method exec.
/**
* Exit codes:
* 0 on successful evaluation.
* 1 if query evaluation did not complete.
* 2 if query parsing failed.
* 3 if errors were reported but evaluation produced a partial result
* (only when --keep_going is in effect.)
*/
@Override
public ExitCode exec(CommandEnvironment env, OptionsProvider options) {
BlazeRuntime runtime = env.getRuntime();
QueryOptions queryOptions = options.getOptions(QueryOptions.class);
try {
env.setupPackageCache(options, runtime.getDefaultsPackageContent());
} catch (InterruptedException e) {
env.getReporter().handle(Event.error("query interrupted"));
return ExitCode.INTERRUPTED;
} catch (AbruptExitException e) {
env.getReporter().handle(Event.error(null, "Unknown error: " + e.getMessage()));
return e.getExitCode();
}
String query;
if (!options.getResidue().isEmpty()) {
if (!queryOptions.queryFile.isEmpty()) {
env.getReporter().handle(Event.error("Command-line query and --query_file cannot both be specified"));
return ExitCode.COMMAND_LINE_ERROR;
}
query = Joiner.on(' ').join(options.getResidue());
} else if (!queryOptions.queryFile.isEmpty()) {
// Works for absolute or relative query file.
Path residuePath = env.getWorkingDirectory().getRelative(queryOptions.queryFile);
try {
query = new String(FileSystemUtils.readContent(residuePath), StandardCharsets.UTF_8);
} catch (IOException e) {
env.getReporter().handle(Event.error("I/O error reading from " + residuePath.getPathString()));
return ExitCode.COMMAND_LINE_ERROR;
}
} else {
env.getReporter().handle(Event.error(String.format("missing query expression. Type '%s help query' for syntax and help", runtime.getProductName())));
return ExitCode.COMMAND_LINE_ERROR;
}
Iterable<OutputFormatter> formatters = runtime.getQueryOutputFormatters();
OutputFormatter formatter = OutputFormatter.getFormatter(formatters, queryOptions.outputFormat);
if (formatter == null) {
env.getReporter().handle(Event.error(String.format("Invalid output format '%s'. Valid values are: %s", queryOptions.outputFormat, OutputFormatter.formatterNames(formatters))));
return ExitCode.COMMAND_LINE_ERROR;
}
Set<Setting> settings = queryOptions.toSettings();
boolean streamResults = QueryOutputUtils.shouldStreamResults(queryOptions, formatter);
QueryEvalResult result;
AbstractBlazeQueryEnvironment<Target> queryEnv = newQueryEnvironment(env, queryOptions.keepGoing, !streamResults, queryOptions.universeScope, queryOptions.loadingPhaseThreads, settings);
// 1. Parse and transform query:
QueryExpression expr;
try {
expr = QueryExpression.parse(query, queryEnv);
} catch (QueryException e) {
env.getReporter().handle(Event.error(null, "Error while parsing '" + query + "': " + e.getMessage()));
return ExitCode.COMMAND_LINE_ERROR;
}
expr = queryEnv.transformParsedQuery(expr);
OutputStream out = env.getReporter().getOutErr().getOutputStream();
ThreadSafeOutputFormatterCallback<Target> callback;
if (streamResults) {
disableAnsiCharactersFiltering(env);
// 2. Evaluate expression:
StreamedFormatter streamedFormatter = ((StreamedFormatter) formatter);
streamedFormatter.setOptions(queryOptions, queryOptions.aspectDeps.createResolver(env.getPackageManager(), env.getReporter()));
callback = streamedFormatter.createStreamCallback(out, queryOptions, queryEnv);
} else {
callback = QueryUtil.newOrderedAggregateAllOutputFormatterCallback();
}
boolean catastrophe = true;
try {
result = queryEnv.evaluateQuery(expr, callback);
catastrophe = false;
} catch (QueryException e) {
catastrophe = false;
// Keep consistent with reportBuildFileError()
env.getReporter().handle(Event.error(e.getMessage() == null ? e.toString() : e.getMessage()));
return ExitCode.ANALYSIS_FAILURE;
} catch (InterruptedException e) {
catastrophe = false;
IOException ioException = callback.getIoException();
if (ioException == null || ioException instanceof ClosedByInterruptException) {
env.getReporter().handle(Event.error("query interrupted"));
return ExitCode.INTERRUPTED;
} else {
env.getReporter().handle(Event.error("I/O error: " + e.getMessage()));
return ExitCode.LOCAL_ENVIRONMENTAL_ERROR;
}
} catch (IOException e) {
catastrophe = false;
env.getReporter().handle(Event.error("I/O error: " + e.getMessage()));
return ExitCode.LOCAL_ENVIRONMENTAL_ERROR;
} finally {
if (!catastrophe) {
try {
out.flush();
} catch (IOException e) {
env.getReporter().handle(Event.error("Failed to flush query results: " + e.getMessage()));
return ExitCode.LOCAL_ENVIRONMENTAL_ERROR;
}
}
}
env.getEventBus().post(new NoBuildEvent());
if (!streamResults) {
disableAnsiCharactersFiltering(env);
// 3. Output results:
try {
Set<Target> targets = ((AggregateAllOutputFormatterCallback<Target>) callback).getResult();
QueryOutputUtils.output(queryOptions, result, targets, formatter, env.getReporter().getOutErr().getOutputStream(), queryOptions.aspectDeps.createResolver(env.getPackageManager(), env.getReporter()));
} catch (ClosedByInterruptException | InterruptedException e) {
env.getReporter().handle(Event.error("query interrupted"));
return ExitCode.INTERRUPTED;
} catch (IOException e) {
env.getReporter().handle(Event.error("I/O error: " + e.getMessage()));
return ExitCode.LOCAL_ENVIRONMENTAL_ERROR;
} finally {
try {
out.flush();
} catch (IOException e) {
env.getReporter().handle(Event.error("Failed to flush query results: " + e.getMessage()));
return ExitCode.LOCAL_ENVIRONMENTAL_ERROR;
}
}
}
if (result.isEmpty()) {
env.getReporter().handle(Event.info("Empty results"));
}
return result.getSuccess() ? ExitCode.SUCCESS : ExitCode.PARTIAL_ANALYSIS_FAILURE;
}
use of com.google.devtools.build.lib.query2.output.QueryOptions in project bazel by bazelbuild.
the class QueryOutputUtils method output.
public static void output(QueryOptions queryOptions, QueryEvalResult result, Set<Target> targetsResult, OutputFormatter formatter, OutputStream outputStream, AspectResolver aspectResolver) throws IOException, InterruptedException {
/*
* This is not really streaming, but we are using the streaming interface for writing into the
* output everything in one batch. This happens when the QueryEnvironment does not
* support streaming but we don't care about ordered results.
*/
boolean orderedResults = !shouldStreamResults(queryOptions, formatter);
if (orderedResults) {
formatter.output(queryOptions, ((DigraphQueryEvalResult<Target>) result).getGraph().extractSubgraph(targetsResult), outputStream, aspectResolver);
} else {
StreamedFormatter streamedFormatter = (StreamedFormatter) formatter;
streamedFormatter.setOptions(queryOptions, aspectResolver);
OutputFormatterCallback.processAllTargets(streamedFormatter.createPostFactoStreamCallback(outputStream, queryOptions), targetsResult);
}
}
use of com.google.devtools.build.lib.query2.output.QueryOptions in project bazel by bazelbuild.
the class GenQuery method create.
@Override
@Nullable
public ConfiguredTarget create(RuleContext ruleContext) throws InterruptedException, RuleErrorException {
Artifact outputArtifact = ruleContext.createOutputArtifact();
// The query string
final String query = ruleContext.attributes().get("expression", Type.STRING);
OptionsParser optionsParser = OptionsParser.newOptionsParser(QueryOptions.class);
optionsParser.setAllowResidue(false);
try {
optionsParser.parse(ruleContext.attributes().get("opts", Type.STRING_LIST));
} catch (OptionsParsingException e) {
ruleContext.attributeError("opts", "error while parsing query options: " + e.getMessage());
return null;
}
// Parsed query options
QueryOptions queryOptions = optionsParser.getOptions(QueryOptions.class);
if (queryOptions.keepGoing) {
ruleContext.attributeError("opts", "option --keep_going is not allowed");
return null;
}
if (!queryOptions.universeScope.isEmpty()) {
ruleContext.attributeError("opts", "option --universe_scope is not allowed");
return null;
}
if (optionsParser.containsExplicitOption("order_results")) {
ruleContext.attributeError("opts", "option --order_results is not allowed");
return null;
}
if (optionsParser.containsExplicitOption("noorder_results")) {
ruleContext.attributeError("opts", "option --noorder_results is not allowed");
return null;
}
if (optionsParser.containsExplicitOption("order_output")) {
ruleContext.attributeError("opts", "option --order_output is not allowed");
return null;
}
// Force results to be deterministic.
queryOptions.orderOutput = OrderOutput.FULL;
// force relative_locations to true so it has a deterministic output across machines.
queryOptions.relativeLocations = true;
final byte[] result = executeQuery(ruleContext, queryOptions, getScope(ruleContext), query);
if (result == null || ruleContext.hasErrors()) {
return null;
}
ruleContext.registerAction(new QueryResultAction(ruleContext.getActionOwner(), outputArtifact, result));
NestedSet<Artifact> filesToBuild = NestedSetBuilder.create(Order.STABLE_ORDER, outputArtifact);
return new RuleConfiguredTargetBuilder(ruleContext).setFilesToBuild(filesToBuild).add(RunfilesProvider.class, RunfilesProvider.simple(new Runfiles.Builder(ruleContext.getWorkspaceName(), ruleContext.getConfiguration().legacyExternalRunfiles()).addTransitiveArtifacts(filesToBuild).build())).build();
}
use of com.google.devtools.build.lib.query2.output.QueryOptions in project bazel by bazelbuild.
the class GenQuery method doQuery.
@SuppressWarnings("unchecked")
@Nullable
private byte[] doQuery(QueryOptions queryOptions, PackageProvider packageProvider, Predicate<Label> labelFilter, TargetPatternEvaluator evaluator, String query, RuleContext ruleContext) throws InterruptedException {
DigraphQueryEvalResult<Target> queryResult;
OutputFormatter formatter;
AggregateAllOutputFormatterCallback<Target> targets = QueryUtil.newOrderedAggregateAllOutputFormatterCallback();
try {
Set<Setting> settings = queryOptions.toSettings();
// Turns out, if we have two targets with a cycle of length 2 were one of
// the edges is of type NODEP_LABEL type, the targets both show up in
// each other's result for deps(X) when the query is executed using
// 'blaze query'. This obviously does not fly when doing the query as a
// part of the build, thus, there is a slight discrepancy between the
// behavior of the query engine in these two use cases.
settings.add(Setting.NO_NODEP_DEPS);
ImmutableList<OutputFormatter> outputFormatters = QUERY_OUTPUT_FORMATTERS.get(ruleContext.getAnalysisEnvironment().getSkyframeEnv());
// This is a precomputed value so it should have been injected by the rules module by the
// time we get there.
formatter = OutputFormatter.getFormatter(Preconditions.checkNotNull(outputFormatters), queryOptions.outputFormat);
// All the packages are already loaded at this point, so there is no need
// to start up many threads. 4 are started up to make good use of multiple
// cores.
BlazeQueryEnvironment queryEnvironment = (BlazeQueryEnvironment) QUERY_ENVIRONMENT_FACTORY.create(/*transitivePackageLoader=*/
null, /*graph=*/
null, packageProvider, evaluator, /*keepGoing=*/
false, ruleContext.attributes().get("strict", Type.BOOLEAN), /*orderedResults=*/
!QueryOutputUtils.shouldStreamResults(queryOptions, formatter), /*universeScope=*/
ImmutableList.<String>of(), /*loadingPhaseThreads=*/
4, labelFilter, getEventHandler(ruleContext), settings, ImmutableList.<QueryFunction>of(), /*packagePath=*/
null, /*blockUniverseEvaluationErrors=*/
false);
queryResult = (DigraphQueryEvalResult<Target>) queryEnvironment.evaluateQuery(query, targets);
} catch (SkyframeRestartQueryException e) {
// inconsistent from run to run, and make detecting legitimate errors more difficult.
return null;
} catch (QueryException e) {
ruleContext.ruleError("query failed: " + e.getMessage());
return null;
} catch (IOException e) {
throw new RuntimeException(e);
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try {
QueryOutputUtils.output(queryOptions, queryResult, targets.getResult(), formatter, outputStream, queryOptions.aspectDeps.createResolver(packageProvider, getEventHandler(ruleContext)));
} catch (ClosedByInterruptException e) {
throw new InterruptedException(e.getMessage());
} catch (IOException e) {
throw new RuntimeException(e);
}
return outputStream.toByteArray();
}
Aggregations