blob: 4a3d93ec3cf6fe85574000639fee5571ea11ffa0 [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.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.concurrent.BatchCallback;
import com.google.devtools.build.lib.concurrent.MultisetSemaphore;
import com.google.devtools.build.lib.packages.OutputFile;
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.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 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 {
TargetPatternValue.TargetPatternKey patternKey =
((TargetPatternValue.TargetPatternKey) key.argument());
TargetPattern parsedPattern = patternKey.getParsedPattern();
IgnoredPackagePrefixesValue ignoredPackagePrefixes =
(IgnoredPackagePrefixesValue)
env.getValue(IgnoredPackagePrefixesValue.key(parsedPattern.getRepository()));
if (ignoredPackagePrefixes == null) {
return null;
}
ImmutableSet<PathFragment> ignoredPatterns = ignoredPackagePrefixes.getPatterns();
ResolvedTargets<Target> resolvedTargets;
try {
EnvironmentBackedRecursivePackageProvider provider =
new EnvironmentBackedRecursivePackageProvider(env);
RecursivePackageProviderBackedTargetPatternResolver resolver =
new RecursivePackageProviderBackedTargetPatternResolver(
provider,
env.getListener(),
patternKey.getPolicy(),
MultisetSemaphore.<PackageIdentifier>unbounded(),
SimplePackageIdentifierBatchingCallback::new);
ImmutableSet<PathFragment> excludedSubdirectories = patternKey.getExcludedSubdirectories();
ResolvedTargets.Builder<Target> resolvedTargetsBuilder = ResolvedTargets.builder();
BatchCallback<Target, RuntimeException> callback =
new BatchCallback<Target, RuntimeException>() {
@Override
public void process(Iterable<Target> partialResult) {
for (Target target : partialResult) {
// TODO(b/156899726): This will go away as soon as we remove implicit outputs from
// cc_library completely. The only
// downside to doing this is that implicit outputs won't be listed when doing
// somepackage:* for the handful of cases still on the allowlist. This is only a
// google internal problem and the scale of it is acceptable in the short term
// while cleaning up the allowlist.
if (target instanceof OutputFile
&& ((OutputFile) target)
.getGeneratingRule()
.getRuleClass()
.equals("cc_library")) {
continue;
}
resolvedTargetsBuilder.add(target);
}
}
};
parsedPattern.eval(
resolver,
() -> ignoredPatterns,
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);
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);
}
}
}