blob: 1e78a41891c179af8adbd3c75a7f5baf391de406 [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.skyframe;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.devtools.build.lib.analysis.DependencyResolver;
import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
import com.google.devtools.build.lib.analysis.config.FragmentClassSet;
import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
import com.google.devtools.build.lib.causes.Cause;
import com.google.devtools.build.lib.causes.LoadingFailedCause;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.events.Event;
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.Target;
import com.google.devtools.build.lib.packages.TargetUtils;
import com.google.devtools.build.skyframe.SkyFunction.Environment;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.ValueOrException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
/**
* A dependency resolver for use within Skyframe. Loads packages lazily when possible.
*/
public final class SkyframeDependencyResolver extends DependencyResolver {
private final Environment env;
public SkyframeDependencyResolver(Environment env) {
this.env = env;
}
@Override
protected void invalidVisibilityReferenceHook(TargetAndConfiguration value, Label label) {
env.getListener().handle(
Event.error(TargetUtils.getLocationMaybe(value.getTarget()), String.format(
"Label '%s' in visibility attribute does not refer to a package group", label)));
}
@Override
protected void invalidPackageGroupReferenceHook(TargetAndConfiguration value, Label label) {
env.getListener().handle(
Event.error(TargetUtils.getLocationMaybe(value.getTarget()), String.format(
"label '%s' does not refer to a package group", label)));
}
@Override
protected void missingEdgeHook(Target from, Label to, NoSuchThingException e)
throws InterruptedException {
if (e instanceof NoSuchTargetException) {
NoSuchTargetException nste = (NoSuchTargetException) e;
if (to.equals(nste.getLabel())) {
env.getListener().handle(
Event.error(
TargetUtils.getLocationMaybe(from),
TargetUtils.formatMissingEdge(from, to, e)));
}
} else if (e instanceof NoSuchPackageException) {
NoSuchPackageException nspe = (NoSuchPackageException) e;
if (nspe.getPackageId().equals(to.getPackageIdentifier())) {
env.getListener().handle(
Event.error(
TargetUtils.getLocationMaybe(from),
TargetUtils.formatMissingEdge(from, to, e)));
}
}
}
@Nullable
@Override
protected Map<Label, Target> getTargets(
Iterable<Label> labels,
Target fromTarget,
NestedSetBuilder<Cause> rootCauses,
int labelsSizeHint)
throws InterruptedException {
Map<SkyKey, ValueOrException<NoSuchPackageException>> packages =
env.getValuesOrThrow(
Iterables.transform(labels, label -> PackageValue.key(label.getPackageIdentifier())),
NoSuchPackageException.class);
if (env.valuesMissing()) {
return null;
}
if (labels instanceof Collection) {
labelsSizeHint = ((Collection<Label>) labels).size();
} else if (labelsSizeHint <= 0) {
labelsSizeHint = 2 * packages.size();
}
// Duplicates can occur, so we can't use ImmutableMap.
HashMap<Label, Target> result = Maps.newHashMapWithExpectedSize(labelsSizeHint);
for (Label label : labels) {
PackageValue packageValue;
try {
packageValue =
Preconditions.checkNotNull(
(PackageValue) packages.get(PackageValue.key(label.getPackageIdentifier())).get(),
label);
} catch (NoSuchPackageException e) {
rootCauses.add(new LoadingFailedCause(label, e.getMessage()));
missingEdgeHook(fromTarget, label, e);
continue;
}
Package pkg = packageValue.getPackage();
try {
Target target = pkg.getTarget(label.getName());
if (pkg.containsErrors()) {
NoSuchTargetException e = new NoSuchTargetException(target);
missingEdgeHook(fromTarget, label, e);
rootCauses.add(new LoadingFailedCause(label, e.getMessage()));
}
result.put(label, target);
} catch (NoSuchTargetException e) {
rootCauses.add(new LoadingFailedCause(label, e.getMessage()));
missingEdgeHook(fromTarget, label, e);
}
}
return result;
}
@Nullable
@Override
protected List<BuildConfiguration> getConfigurations(
FragmentClassSet fragments,
Iterable<BuildOptions> buildOptions,
BuildOptions defaultBuildOptions)
throws InvalidConfigurationException, InterruptedException {
List<SkyKey> keys = new ArrayList<>();
for (BuildOptions options : buildOptions) {
keys.add(
BuildConfigurationValue.key(
fragments, BuildOptions.diffForReconstruction(defaultBuildOptions, options)));
}
Map<SkyKey, ValueOrException<InvalidConfigurationException>> configValues =
env.getValuesOrThrow(keys, InvalidConfigurationException.class);
if (env.valuesMissing()) {
return null;
}
ImmutableList.Builder<BuildConfiguration> result = ImmutableList.builder();
for (SkyKey key : keys) {
result.add(((BuildConfigurationValue) configValues.get(key).get()).getConfiguration());
}
return result.build();
}
}