blob: b195308dcb1de3198e70fbe6d2608351d1e4990c [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.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.PackageIdentifier;
import com.google.devtools.build.lib.cmdline.ResolvedTargets;
import com.google.devtools.build.lib.cmdline.TargetParsingException;
import com.google.devtools.build.lib.cmdline.TargetPattern;
import com.google.devtools.build.lib.collect.compacthashset.CompactHashSet;
import com.google.devtools.build.lib.concurrent.MultisetSemaphore;
import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.pkgcache.AbstractRecursivePackageProvider.MissingDepException;
import com.google.devtools.build.lib.pkgcache.ParsingFailedEvent;
import com.google.devtools.build.lib.util.BatchCallback;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.skyframe.SkyFunction;
import com.google.devtools.build.skyframe.SkyFunctionException;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
import java.util.Set;
import javax.annotation.Nullable;
/**
* TargetPatternFunction translates a target pattern (eg, "foo/...") into a set of resolved
* Targets.
*/
public class TargetPatternFunction implements SkyFunction {
public TargetPatternFunction() {
}
@Override
public SkyValue compute(SkyKey key, Environment env) throws TargetPatternFunctionException,
InterruptedException {
BlacklistedPackagePrefixesValue blacklisted =
(BlacklistedPackagePrefixesValue) env.getValue(BlacklistedPackagePrefixesValue.key());
if (env.valuesMissing()) {
return null;
}
TargetPatternValue.TargetPatternKey patternKey =
((TargetPatternValue.TargetPatternKey) key.argument());
ResolvedTargets<Target> resolvedTargets;
try {
EnvironmentBackedRecursivePackageProvider provider =
new EnvironmentBackedRecursivePackageProvider(env);
RecursivePackageProviderBackedTargetPatternResolver resolver =
new RecursivePackageProviderBackedTargetPatternResolver(
provider,
env.getListener(),
patternKey.getPolicy(),
MultisetSemaphore.<PackageIdentifier>unbounded());
TargetPattern parsedPattern = patternKey.getParsedPattern();
ImmutableSet<PathFragment> excludedSubdirectories = patternKey.getExcludedSubdirectories();
final Set<Target> results = CompactHashSet.create();
BatchCallback<Target, RuntimeException> callback =
new BatchCallback<Target, RuntimeException>() {
@Override
public void process(Iterable<Target> partialResult) {
Iterables.addAll(results, partialResult);
}
};
parsedPattern.eval(
resolver,
blacklisted.getPatterns(),
excludedSubdirectories,
callback,
// The exception type here has to match the one on the BatchCallback. Since the callback
// defined above never throws, the exact type here is not really relevant.
RuntimeException.class);
ResolvedTargets.Builder<Target> resolvedTargetsBuilder =
ResolvedTargets.<Target>builder().addAll(results);
if (provider.encounteredPackageErrors()) {
resolvedTargetsBuilder.setError();
}
resolvedTargets = resolvedTargetsBuilder.build();
} catch (TargetParsingException e) {
env.getListener().post(new ParsingFailedEvent(patternKey.getPattern(), e.getMessage()));
throw new TargetPatternFunctionException(e);
} catch (MissingDepException e) {
// The EnvironmentBackedRecursivePackageProvider constructed above might throw
// MissingDepException to signal when it has a dependency on a missing Environment value.
// Note that MissingDepException extends RuntimeException because the methods called
// on EnvironmentBackedRecursivePackageProvider all belong to an interface shared with other
// implementations that are unconcerned with MissingDepExceptions.
return null;
}
Preconditions.checkNotNull(resolvedTargets, key);
ResolvedTargets.Builder<Label> resolvedLabelsBuilder = ResolvedTargets.builder();
if (resolvedTargets.hasError()) {
resolvedLabelsBuilder.setError();
}
for (Target target : resolvedTargets.getTargets()) {
resolvedLabelsBuilder.add(target.getLabel());
}
for (Target target : resolvedTargets.getFilteredTargets()) {
resolvedLabelsBuilder.remove(target.getLabel());
}
return new TargetPatternValue(resolvedLabelsBuilder.build());
}
@Nullable
@Override
public String extractTag(SkyKey skyKey) {
return null;
}
/**
* Used to declare all the exception types that can be wrapped in the exception thrown by
* {@link TargetPatternFunction#compute}.
*/
private static final class TargetPatternFunctionException extends SkyFunctionException {
public TargetPatternFunctionException(TargetParsingException e) {
super(e, Transience.PERSISTENT);
}
}
}