blob: 14c83edda0c383a1fc0d8ea8d28df45cbbd0a57e [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
16import com.google.common.collect.ImmutableList;
17import com.google.common.collect.ImmutableSet;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000018import com.google.devtools.build.lib.cmdline.Label;
Kristina Chodorow73fa2032015-08-28 17:57:46 +000019import com.google.devtools.build.lib.cmdline.PackageIdentifier;
Lukacs Berkid72db8d2015-09-22 07:40:24 +000020import com.google.devtools.build.lib.cmdline.PackageIdentifier.RepositoryName;
Mark Schaller7b0bc0a2015-06-30 23:57:45 +000021import com.google.devtools.build.lib.cmdline.ResolvedTargets;
22import com.google.devtools.build.lib.cmdline.TargetParsingException;
23import com.google.devtools.build.lib.cmdline.TargetPattern;
24import com.google.devtools.build.lib.cmdline.TargetPatternResolver;
25import com.google.devtools.build.lib.events.Event;
26import com.google.devtools.build.lib.packages.NoSuchPackageException;
27import com.google.devtools.build.lib.packages.NoSuchTargetException;
28import com.google.devtools.build.lib.packages.NoSuchThingException;
29import com.google.devtools.build.lib.packages.Package;
Mark Schaller7b0bc0a2015-06-30 23:57:45 +000030import com.google.devtools.build.lib.packages.Target;
31import com.google.devtools.build.lib.pkgcache.FilteringPolicies;
32import com.google.devtools.build.lib.pkgcache.FilteringPolicy;
33import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
34import com.google.devtools.build.lib.pkgcache.TargetPatternResolverUtil;
35import com.google.devtools.build.lib.skyframe.EnvironmentBackedRecursivePackageProvider.MissingDepException;
Janak Ramakrishnan5b5f22a2016-01-07 17:07:29 +000036import com.google.devtools.build.lib.util.BatchCallback;
Janak Ramakrishnan006ab492016-01-07 17:39:41 +000037import com.google.devtools.build.lib.util.BatchCallback.NullCallback;
Mark Schaller6df81792015-12-10 18:47:47 +000038import com.google.devtools.build.lib.util.Preconditions;
Mark Schaller7b0bc0a2015-06-30 23:57:45 +000039import com.google.devtools.build.lib.vfs.Path;
40import com.google.devtools.build.lib.vfs.PathFragment;
41import com.google.devtools.build.lib.vfs.RootedPath;
42import com.google.devtools.build.skyframe.SkyFunction;
43import com.google.devtools.build.skyframe.SkyFunctionException;
44import com.google.devtools.build.skyframe.SkyKey;
45import com.google.devtools.build.skyframe.SkyValue;
46
Lukacs Berkic7106d42015-10-15 07:45:54 +000047import java.util.ArrayList;
48import java.util.List;
Mark Schaller7b0bc0a2015-06-30 23:57:45 +000049import java.util.concurrent.atomic.AtomicReference;
50
51import javax.annotation.Nullable;
52
53/**
54 * PrepareDepsOfPatternFunction ensures the graph loads targets matching the pattern and its
55 * transitive dependencies.
56 */
57public class PrepareDepsOfPatternFunction implements SkyFunction {
58
59 private final AtomicReference<PathPackageLocator> pkgPath;
60
61 public PrepareDepsOfPatternFunction(AtomicReference<PathPackageLocator> pkgPath) {
62 this.pkgPath = pkgPath;
63 }
64
65 @Nullable
66 @Override
67 public SkyValue compute(SkyKey key, Environment env)
68 throws SkyFunctionException, InterruptedException {
69 TargetPatternValue.TargetPatternKey patternKey =
70 ((TargetPatternValue.TargetPatternKey) key.argument());
Mark Schallerd7311e02015-07-07 16:36:09 +000071
72 // DepsOfPatternPreparer below expects to be able to ignore the filtering policy from the
73 // TargetPatternKey, which should be valid because PrepareDepsOfPatternValue.keys
74 // unconditionally creates TargetPatternKeys with the NO_FILTER filtering policy. (Compare
75 // with SkyframeTargetPatternEvaluator, which can create TargetPatternKeys with other
76 // filtering policies like FILTER_TESTS or FILTER_MANUAL.) This check makes sure that the
77 // key's filtering policy is NO_FILTER as expected.
78 Preconditions.checkState(patternKey.getPolicy().equals(FilteringPolicies.NO_FILTER),
79 patternKey.getPolicy());
80
Mark Schaller7b0bc0a2015-06-30 23:57:45 +000081 try {
82 TargetPattern parsedPattern = patternKey.getParsedPattern();
Mark Schallerd7311e02015-07-07 16:36:09 +000083 DepsOfPatternPreparer preparer = new DepsOfPatternPreparer(env, pkgPath.get());
Janak Ramakrishnan3d9441b2016-01-13 17:38:29 +000084 ImmutableSet<PathFragment> excludedSubdirectories = patternKey.getExcludedSubdirectories();
Janak Ramakrishnan006ab492016-01-07 17:39:41 +000085 parsedPattern.<Void, RuntimeException>eval(
86 preparer, excludedSubdirectories, NullCallback.<Void>instance());
Mark Schaller7b0bc0a2015-06-30 23:57:45 +000087 } catch (TargetParsingException e) {
88 throw new PrepareDepsOfPatternFunctionException(e);
89 } catch (MissingDepException e) {
90 // The DepsOfPatternPreparer constructed above might throw MissingDepException to signal
91 // when it has a dependency on a missing Environment value.
92 return null;
93 }
94 return PrepareDepsOfPatternValue.INSTANCE;
95 }
96
97 @Nullable
98 @Override
99 public String extractTag(SkyKey skyKey) {
100 return null;
101 }
102
103 /**
104 * Used to declare all the exception types that can be wrapped in the exception thrown by {@link
105 * PrepareDepsOfPatternFunction#compute}.
106 */
107 private static final class PrepareDepsOfPatternFunctionException extends SkyFunctionException {
108
109 public PrepareDepsOfPatternFunctionException(TargetParsingException e) {
110 super(e, Transience.PERSISTENT);
111 }
112 }
113
114 /**
Ulf Adams3ab82f72015-09-04 12:10:53 +0000115 * A {@link TargetPatternResolver} backed by an {@link
116 * com.google.devtools.build.skyframe.SkyFunction.Environment} whose methods do not actually
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000117 * return resolved targets, but that ensures the graph loads the matching targets <b>and</b> their
118 * transitive dependencies. Its methods may throw {@link MissingDepException} if the package
119 * values this depends on haven't been calculated and added to its environment.
120 */
121 static class DepsOfPatternPreparer implements TargetPatternResolver<Void> {
122
123 private final EnvironmentBackedRecursivePackageProvider packageProvider;
124 private final Environment env;
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000125 private final PathPackageLocator pkgPath;
126
Mark Schallerd7311e02015-07-07 16:36:09 +0000127 public DepsOfPatternPreparer(Environment env, PathPackageLocator pkgPath) {
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000128 this.env = env;
129 this.packageProvider = new EnvironmentBackedRecursivePackageProvider(env);
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000130 this.pkgPath = pkgPath;
131 }
132
133 @Override
134 public void warn(String msg) {
135 env.getListener().handle(Event.warn(msg));
136 }
137
138 @Override
Lukacs Berki960dc272015-09-24 07:48:36 +0000139 public Void getTargetOrNull(Label label) throws InterruptedException {
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000140 // Note:
141 // This method is used in just one place, TargetPattern.TargetsInPackage#getWildcardConflict.
142 // Returning null tells #getWildcardConflict that there is not a target with a name like
143 // "all" or "all-targets", which means that TargetPattern.TargetsInPackage will end up
144 // calling DepsOfTargetPreparer#getTargetsInPackage.
145 // TODO (bazel-team): Consider replacing this with an isTarget method on the interface.
146 return null;
147 }
148
149 @Override
Lukacs Berki960dc272015-09-24 07:48:36 +0000150 public ResolvedTargets<Void> getExplicitTarget(Label label)
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000151 throws TargetParsingException, InterruptedException {
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000152 try {
153 Target target = packageProvider.getTarget(env.getListener(), label);
Mark Schaller8ff5b3c2015-07-29 17:32:11 +0000154 SkyKey key = TransitiveTraversalValue.key(target.getLabel());
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000155 SkyValue token =
156 env.getValueOrThrow(key, NoSuchPackageException.class, NoSuchTargetException.class);
157 if (token == null) {
158 throw new MissingDepException();
159 }
160 return ResolvedTargets.empty();
161 } catch (NoSuchThingException e) {
162 throw new TargetParsingException(e.getMessage(), e);
163 }
164 }
165
166 @Override
Lukacs Berki10e3b2b2015-09-22 07:58:20 +0000167 public ResolvedTargets<Void> getTargetsInPackage(String originalPattern,
168 PackageIdentifier packageIdentifier, boolean rulesOnly) throws TargetParsingException {
Mark Schallerd7311e02015-07-07 16:36:09 +0000169 FilteringPolicy policy =
170 rulesOnly ? FilteringPolicies.RULES_ONLY : FilteringPolicies.NO_FILTER;
Lukacs Berki10e3b2b2015-09-22 07:58:20 +0000171 return getTargetsInPackage(originalPattern, packageIdentifier, policy);
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000172 }
173
174 private ResolvedTargets<Void> getTargetsInPackage(String originalPattern,
Lukacs Berki10e3b2b2015-09-22 07:58:20 +0000175 PackageIdentifier packageIdentifier, FilteringPolicy policy)
Ulf Adams3ab82f72015-09-04 12:10:53 +0000176 throws TargetParsingException {
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000177 try {
Lukacs Berki10e3b2b2015-09-22 07:58:20 +0000178 Package pkg = packageProvider.getPackage(env.getListener(), packageIdentifier);
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000179 ResolvedTargets<Target> packageTargets =
180 TargetPatternResolverUtil.resolvePackageTargets(pkg, policy);
181 ImmutableList.Builder<SkyKey> builder = ImmutableList.builder();
182 for (Target target : packageTargets.getTargets()) {
Mark Schaller8ff5b3c2015-07-29 17:32:11 +0000183 builder.add(TransitiveTraversalValue.key(target.getLabel()));
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000184 }
185 ImmutableList<SkyKey> skyKeys = builder.build();
186 env.getValuesOrThrow(skyKeys, NoSuchPackageException.class, NoSuchTargetException.class);
187 if (env.valuesMissing()) {
188 throw new MissingDepException();
189 }
190 return ResolvedTargets.empty();
191 } catch (NoSuchThingException e) {
192 String message = TargetPatternResolverUtil.getParsingErrorMessage(
193 "package contains errors", originalPattern);
194 throw new TargetParsingException(message, e);
195 }
196 }
197
198 @Override
Lukacs Berki10e3b2b2015-09-22 07:58:20 +0000199 public boolean isPackage(PackageIdentifier packageIdentifier) {
200 return packageProvider.isPackage(env.getListener(), packageIdentifier);
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000201 }
202
203 @Override
204 public String getTargetKind(Void target) {
205 // Note:
206 // This method is used in just one place, TargetPattern.TargetsInPackage#getWildcardConflict.
207 // Because DepsOfPatternPreparer#getTargetOrNull always returns null, this method is never
208 // called.
209 throw new UnsupportedOperationException();
210 }
211
212 @Override
Janak Ramakrishnan5b5f22a2016-01-07 17:07:29 +0000213 public <E extends Exception> void findTargetsBeneathDirectory(
214 RepositoryName repository,
215 String originalPattern,
216 String directory,
217 boolean rulesOnly,
Janak Ramakrishnan3d9441b2016-01-13 17:38:29 +0000218 ImmutableSet<PathFragment> excludedSubdirectories,
Janak Ramakrishnan5b5f22a2016-01-07 17:07:29 +0000219 BatchCallback<Void, E> callback)
220 throws TargetParsingException, E, InterruptedException {
Mark Schallerd7311e02015-07-07 16:36:09 +0000221 FilteringPolicy policy =
222 rulesOnly ? FilteringPolicies.RULES_ONLY : FilteringPolicies.NO_FILTER;
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000223 PathFragment pathFragment = TargetPatternResolverUtil.getPathFragment(directory);
Lukacs Berkic7106d42015-10-15 07:45:54 +0000224 List<Path> roots = new ArrayList<>();
225 if (repository.isDefault()) {
226 roots.addAll(pkgPath.getPathEntries());
227 } else {
228 RepositoryValue repositoryValue =
229 (RepositoryValue) env.getValue(RepositoryValue.key(repository));
230 if (repositoryValue == null) {
231 throw new MissingDepException();
232 }
233
234 roots.add(repositoryValue.getPath());
235 }
236
237 for (Path root : roots) {
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000238 RootedPath rootedPath = RootedPath.toRootedPath(root, pathFragment);
Janak Ramakrishnan3d9441b2016-01-13 17:38:29 +0000239 SkyValue token =
240 env.getValue(
241 PrepareDepsOfTargetsUnderDirectoryValue.key(
242 repository, rootedPath, excludedSubdirectories, policy));
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000243 if (token == null) {
244 // A null token value means there is a missing dependency, because RecursivePkgFunction
245 // never throws.
246 throw new MissingDepException();
247 }
248 }
Mark Schaller7b0bc0a2015-06-30 23:57:45 +0000249 }
250 }
251}