blob: e776281b7508608fe3a6a01a67c4f7107bbf69fa [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2015 The Bazel Authors. All rights reserved.
Mark Schaller7b0bc0a2015-06-30 23:57:45 +00002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14package com.google.devtools.build.lib.skyframe;
15
Mark Schallerd7311e02015-07-07 16:36:09 +000016import com.google.common.base.Preconditions;
Mark Schaller7b0bc0a2015-06-30 23:57:45 +000017import com.google.common.collect.ImmutableList;
18import com.google.common.collect.ImmutableSet;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000019import com.google.devtools.build.lib.cmdline.Label;
Kristina Chodorow73fa2032015-08-28 17:57:46 +000020import com.google.devtools.build.lib.cmdline.PackageIdentifier;
Lukacs Berkid72db8d2015-09-22 07:40:24 +000021import com.google.devtools.build.lib.cmdline.PackageIdentifier.RepositoryName;
Mark Schaller7b0bc0a2015-06-30 23:57:45 +000022import com.google.devtools.build.lib.cmdline.ResolvedTargets;
23import com.google.devtools.build.lib.cmdline.TargetParsingException;
24import com.google.devtools.build.lib.cmdline.TargetPattern;
25import com.google.devtools.build.lib.cmdline.TargetPatternResolver;
26import com.google.devtools.build.lib.events.Event;
27import com.google.devtools.build.lib.packages.NoSuchPackageException;
28import com.google.devtools.build.lib.packages.NoSuchTargetException;
29import com.google.devtools.build.lib.packages.NoSuchThingException;
30import com.google.devtools.build.lib.packages.Package;
Mark Schaller7b0bc0a2015-06-30 23:57:45 +000031import com.google.devtools.build.lib.packages.Target;
32import com.google.devtools.build.lib.pkgcache.FilteringPolicies;
33import com.google.devtools.build.lib.pkgcache.FilteringPolicy;
34import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
35import com.google.devtools.build.lib.pkgcache.TargetPatternResolverUtil;
36import com.google.devtools.build.lib.skyframe.EnvironmentBackedRecursivePackageProvider.MissingDepException;
Mark Schaller7b0bc0a2015-06-30 23:57:45 +000037import com.google.devtools.build.lib.vfs.Path;
38import com.google.devtools.build.lib.vfs.PathFragment;
39import com.google.devtools.build.lib.vfs.RootedPath;
40import com.google.devtools.build.skyframe.SkyFunction;
41import com.google.devtools.build.skyframe.SkyFunctionException;
42import com.google.devtools.build.skyframe.SkyKey;
43import com.google.devtools.build.skyframe.SkyValue;
44
Lukacs Berkic7106d42015-10-15 07:45:54 +000045import java.util.ArrayList;
46import java.util.List;
Mark Schaller7b0bc0a2015-06-30 23:57:45 +000047import java.util.concurrent.atomic.AtomicReference;
48
49import javax.annotation.Nullable;
50
51/**
52 * PrepareDepsOfPatternFunction ensures the graph loads targets matching the pattern and its
53 * transitive dependencies.
54 */
55public class PrepareDepsOfPatternFunction implements SkyFunction {
56
57 private final AtomicReference<PathPackageLocator> pkgPath;
58
59 public PrepareDepsOfPatternFunction(AtomicReference<PathPackageLocator> pkgPath) {
60 this.pkgPath = pkgPath;
61 }
62
63 @Nullable
64 @Override
65 public SkyValue compute(SkyKey key, Environment env)
66 throws SkyFunctionException, InterruptedException {
67 TargetPatternValue.TargetPatternKey patternKey =
68 ((TargetPatternValue.TargetPatternKey) key.argument());
Mark Schallerd7311e02015-07-07 16:36:09 +000069
70 // DepsOfPatternPreparer below expects to be able to ignore the filtering policy from the
71 // TargetPatternKey, which should be valid because PrepareDepsOfPatternValue.keys
72 // unconditionally creates TargetPatternKeys with the NO_FILTER filtering policy. (Compare
73 // with SkyframeTargetPatternEvaluator, which can create TargetPatternKeys with other
74 // filtering policies like FILTER_TESTS or FILTER_MANUAL.) This check makes sure that the
75 // key's filtering policy is NO_FILTER as expected.
76 Preconditions.checkState(patternKey.getPolicy().equals(FilteringPolicies.NO_FILTER),
77 patternKey.getPolicy());
78
Mark Schaller7b0bc0a2015-06-30 23:57:45 +000079 try {
80 TargetPattern parsedPattern = patternKey.getParsedPattern();
Mark Schallerd7311e02015-07-07 16:36:09 +000081 DepsOfPatternPreparer preparer = new DepsOfPatternPreparer(env, pkgPath.get());
Mark Schaller7b0bc0a2015-06-30 23:57:45 +000082 ImmutableSet<String> excludedSubdirectories = patternKey.getExcludedSubdirectories();
83 parsedPattern.eval(preparer, excludedSubdirectories);
84 } catch (TargetParsingException e) {
85 throw new PrepareDepsOfPatternFunctionException(e);
86 } catch (MissingDepException e) {
87 // The DepsOfPatternPreparer constructed above might throw MissingDepException to signal
88 // when it has a dependency on a missing Environment value.
89 return null;
90 }
91 return PrepareDepsOfPatternValue.INSTANCE;
92 }
93
94 @Nullable
95 @Override
96 public String extractTag(SkyKey skyKey) {
97 return null;
98 }
99
100 /**
101 * Used to declare all the exception types that can be wrapped in the exception thrown by {@link
102 * PrepareDepsOfPatternFunction#compute}.
103 */
104 private static final class PrepareDepsOfPatternFunctionException extends SkyFunctionException {
105
106 public PrepareDepsOfPatternFunctionException(TargetParsingException e) {
107 super(e, Transience.PERSISTENT);
108 }
109 }
110
111 /**
Ulf Adams3ab82f72015-09-04 12:10:53 +0000112 * A {@link TargetPatternResolver} backed by an {@link
113 * com.google.devtools.build.skyframe.SkyFunction.Environment} whose methods do not actually
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000114 * return resolved targets, but that ensures the graph loads the matching targets <b>and</b> their
115 * transitive dependencies. Its methods may throw {@link MissingDepException} if the package
116 * values this depends on haven't been calculated and added to its environment.
117 */
118 static class DepsOfPatternPreparer implements TargetPatternResolver<Void> {
119
120 private final EnvironmentBackedRecursivePackageProvider packageProvider;
121 private final Environment env;
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000122 private final PathPackageLocator pkgPath;
123
Mark Schallerd7311e02015-07-07 16:36:09 +0000124 public DepsOfPatternPreparer(Environment env, PathPackageLocator pkgPath) {
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000125 this.env = env;
126 this.packageProvider = new EnvironmentBackedRecursivePackageProvider(env);
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000127 this.pkgPath = pkgPath;
128 }
129
130 @Override
131 public void warn(String msg) {
132 env.getListener().handle(Event.warn(msg));
133 }
134
135 @Override
Lukacs Berki960dc272015-09-24 07:48:36 +0000136 public Void getTargetOrNull(Label label) throws InterruptedException {
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000137 // Note:
138 // This method is used in just one place, TargetPattern.TargetsInPackage#getWildcardConflict.
139 // Returning null tells #getWildcardConflict that there is not a target with a name like
140 // "all" or "all-targets", which means that TargetPattern.TargetsInPackage will end up
141 // calling DepsOfTargetPreparer#getTargetsInPackage.
142 // TODO (bazel-team): Consider replacing this with an isTarget method on the interface.
143 return null;
144 }
145
146 @Override
Lukacs Berki960dc272015-09-24 07:48:36 +0000147 public ResolvedTargets<Void> getExplicitTarget(Label label)
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000148 throws TargetParsingException, InterruptedException {
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000149 try {
150 Target target = packageProvider.getTarget(env.getListener(), label);
Mark Schaller8ff5b3c2015-07-29 17:32:11 +0000151 SkyKey key = TransitiveTraversalValue.key(target.getLabel());
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000152 SkyValue token =
153 env.getValueOrThrow(key, NoSuchPackageException.class, NoSuchTargetException.class);
154 if (token == null) {
155 throw new MissingDepException();
156 }
157 return ResolvedTargets.empty();
158 } catch (NoSuchThingException e) {
159 throw new TargetParsingException(e.getMessage(), e);
160 }
161 }
162
163 @Override
Lukacs Berki10e3b2b2015-09-22 07:58:20 +0000164 public ResolvedTargets<Void> getTargetsInPackage(String originalPattern,
165 PackageIdentifier packageIdentifier, boolean rulesOnly) throws TargetParsingException {
Mark Schallerd7311e02015-07-07 16:36:09 +0000166 FilteringPolicy policy =
167 rulesOnly ? FilteringPolicies.RULES_ONLY : FilteringPolicies.NO_FILTER;
Lukacs Berki10e3b2b2015-09-22 07:58:20 +0000168 return getTargetsInPackage(originalPattern, packageIdentifier, policy);
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000169 }
170
171 private ResolvedTargets<Void> getTargetsInPackage(String originalPattern,
Lukacs Berki10e3b2b2015-09-22 07:58:20 +0000172 PackageIdentifier packageIdentifier, FilteringPolicy policy)
Ulf Adams3ab82f72015-09-04 12:10:53 +0000173 throws TargetParsingException {
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000174 try {
Lukacs Berki10e3b2b2015-09-22 07:58:20 +0000175 Package pkg = packageProvider.getPackage(env.getListener(), packageIdentifier);
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000176 ResolvedTargets<Target> packageTargets =
177 TargetPatternResolverUtil.resolvePackageTargets(pkg, policy);
178 ImmutableList.Builder<SkyKey> builder = ImmutableList.builder();
179 for (Target target : packageTargets.getTargets()) {
Mark Schaller8ff5b3c2015-07-29 17:32:11 +0000180 builder.add(TransitiveTraversalValue.key(target.getLabel()));
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000181 }
182 ImmutableList<SkyKey> skyKeys = builder.build();
183 env.getValuesOrThrow(skyKeys, NoSuchPackageException.class, NoSuchTargetException.class);
184 if (env.valuesMissing()) {
185 throw new MissingDepException();
186 }
187 return ResolvedTargets.empty();
188 } catch (NoSuchThingException e) {
189 String message = TargetPatternResolverUtil.getParsingErrorMessage(
190 "package contains errors", originalPattern);
191 throw new TargetParsingException(message, e);
192 }
193 }
194
195 @Override
Lukacs Berki10e3b2b2015-09-22 07:58:20 +0000196 public boolean isPackage(PackageIdentifier packageIdentifier) {
197 return packageProvider.isPackage(env.getListener(), packageIdentifier);
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000198 }
199
200 @Override
201 public String getTargetKind(Void target) {
202 // Note:
203 // This method is used in just one place, TargetPattern.TargetsInPackage#getWildcardConflict.
204 // Because DepsOfPatternPreparer#getTargetOrNull always returns null, this method is never
205 // called.
206 throw new UnsupportedOperationException();
207 }
208
209 @Override
Lukacs Berkid72db8d2015-09-22 07:40:24 +0000210 public ResolvedTargets<Void> findTargetsBeneathDirectory(RepositoryName repository,
211 String originalPattern, String directory, boolean rulesOnly,
212 ImmutableSet<String> excludedSubdirectories)
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000213 throws TargetParsingException, InterruptedException {
Mark Schallerd7311e02015-07-07 16:36:09 +0000214 FilteringPolicy policy =
215 rulesOnly ? FilteringPolicies.RULES_ONLY : FilteringPolicies.NO_FILTER;
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000216 ImmutableSet<PathFragment> excludedPathFragments =
217 TargetPatternResolverUtil.getPathFragments(excludedSubdirectories);
218 PathFragment pathFragment = TargetPatternResolverUtil.getPathFragment(directory);
Lukacs Berkic7106d42015-10-15 07:45:54 +0000219 List<Path> roots = new ArrayList<>();
220 if (repository.isDefault()) {
221 roots.addAll(pkgPath.getPathEntries());
222 } else {
223 RepositoryValue repositoryValue =
224 (RepositoryValue) env.getValue(RepositoryValue.key(repository));
225 if (repositoryValue == null) {
226 throw new MissingDepException();
227 }
228
229 roots.add(repositoryValue.getPath());
230 }
231
232 for (Path root : roots) {
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000233 RootedPath rootedPath = RootedPath.toRootedPath(root, pathFragment);
Lukacs Berkid72db8d2015-09-22 07:40:24 +0000234 SkyValue token = env.getValue(PrepareDepsOfTargetsUnderDirectoryValue.key(
235 repository, rootedPath, excludedPathFragments, policy));
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000236 if (token == null) {
237 // A null token value means there is a missing dependency, because RecursivePkgFunction
238 // never throws.
239 throw new MissingDepException();
240 }
241 }
242 return ResolvedTargets.empty();
243 }
244 }
245}