blob: 36924d5457388045ef6e8346a973c9aca3c48844 [file] [log] [blame]
// Copyright 2023 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.analysis.producers;
import static com.google.common.base.MoreObjects.toStringHelper;
import static com.google.devtools.build.lib.analysis.config.BuildConfigurationValue.configurationIdMessage;
import static com.google.devtools.build.lib.cmdline.LabelConstants.EXTERNAL_PACKAGE_IDENTIFIER;
import com.google.devtools.build.lib.analysis.AnalysisRootCauseEvent;
import com.google.devtools.build.lib.analysis.DependencyKind;
import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
import com.google.devtools.build.lib.analysis.TransitiveDependencyState;
import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
import com.google.devtools.build.lib.causes.AnalysisFailedCause;
import com.google.devtools.build.lib.causes.LoadingFailedCause;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.ExtendedEventHandler;
import com.google.devtools.build.lib.packages.NoSuchPackageException;
import com.google.devtools.build.lib.packages.NoSuchTargetException;
import com.google.devtools.build.lib.packages.NoSuchThingException;
import com.google.devtools.build.lib.packages.Package;
import com.google.devtools.build.lib.packages.RepositoryFetchException;
import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.packages.TargetUtils;
import javax.annotation.Nullable;
/**
* A dependency error caused by a missing {@link Package} or {@link Target}.
*
* <p>This class is structured this way to relay details of the error all the way out to the top
* level which has both the base {@link TargetAndConfiguration} and the {@link ExtendedEventHandler}
* references needed to construct the causes and events.
*/
public final class MissingEdgeError {
private final DependencyKind kind;
private final Label label;
private final NoSuchThingException cause;
MissingEdgeError(DependencyKind kind, Label label, NoSuchThingException cause) {
this.kind = kind;
this.label = label;
this.cause = cause;
}
/** Emits the causes and events associated with this error. */
public void emitCausesAndEvents(
TargetAndConfiguration fromNode,
TransitiveDependencyState transitiveState,
ExtendedEventHandler listener) {
Target from = fromNode.getTarget();
if (cause instanceof RepositoryFetchException) {
Label repositoryLabel;
try {
repositoryLabel =
Label.create(EXTERNAL_PACKAGE_IDENTIFIER, label.getRepository().getName());
} catch (LabelSyntaxException lse) {
// We're taking the repository name from something that was already part of a label, so it
// should be valid. If we really get into this strange we situation, better not try to be
// smart and report the original label.
repositoryLabel = label;
}
transitiveState.addTransitiveCause(
new LoadingFailedCause(repositoryLabel, cause.getDetailedExitCode()));
listener.handle(
Event.error(
TargetUtils.getLocationMaybe(from),
String.format(
"%s depends on %s in repository %s which failed to fetch. %s",
from.getLabel(), label, label.getRepository(), cause.getMessage())));
return;
}
if (cause instanceof NoSuchPackageException) {
// Blames the rule for specifying an unavailable package.
@Nullable BuildConfigurationValue configuration = fromNode.getConfiguration();
listener.post(
AnalysisRootCauseEvent.withConfigurationValue(configuration, label, cause.getMessage()));
transitiveState.addTransitiveCause(
new AnalysisFailedCause(
label, configurationIdMessage(configuration), cause.getDetailedExitCode()));
} else if (cause instanceof NoSuchTargetException) {
// If the child target was present, it already has an associated LoadingFailedCause.
if (!((NoSuchTargetException) cause).hasTarget()) {
transitiveState.addTransitiveCause(
new LoadingFailedCause(label, cause.getDetailedExitCode()));
}
}
String message;
if (DependencyKind.isToolchain(kind)) {
message =
String.format(
"Target '%s' depends on toolchain '%s', which cannot be found: %s'",
from.getLabel(), label, cause.getMessage());
} else {
message = TargetUtils.formatMissingEdge(from, label, cause, kind.getAttribute());
}
listener.handle(Event.error(TargetUtils.getLocationMaybe(from), message));
}
@Override
public String toString() {
return toStringHelper(this)
.add("kind", kind)
.add("label", label)
.add("cause", cause)
.toString();
}
}