blob: b7d8b43c7378f01c011d4e929e7ec62475fa2871 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Mark Schaller8ff5b3c2015-07-29 17:32:11 +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
tomlua155b532017-11-08 20:12:47 +010016import com.google.common.base.Preconditions;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000017import com.google.devtools.build.lib.cmdline.Label;
Mark Schaller8ff5b3c2015-07-29 17:32:11 +000018import com.google.devtools.build.lib.collect.nestedset.NestedSet;
19import com.google.devtools.build.lib.events.EventHandler;
nharmataf2b26ad2019-03-06 09:37:00 -080020import com.google.devtools.build.lib.packages.AdvertisedProviderSet;
Mark Schaller8ff5b3c2015-07-29 17:32:11 +000021import com.google.devtools.build.lib.packages.NoSuchPackageException;
22import com.google.devtools.build.lib.packages.NoSuchTargetException;
Eric Fellheimere27d0632015-09-25 21:35:26 +000023import com.google.devtools.build.lib.packages.NoSuchThingException;
shreyax246f0aa2018-02-23 07:46:54 -080024import com.google.devtools.build.lib.util.GroupedList;
25import com.google.devtools.build.skyframe.SkyFunction;
Mark Schaller8ff5b3c2015-07-29 17:32:11 +000026import com.google.devtools.build.skyframe.SkyKey;
27import com.google.devtools.build.skyframe.SkyValue;
28import com.google.devtools.build.skyframe.ValueOrException2;
Eric Fellheimere27d0632015-09-25 21:35:26 +000029import java.util.Collection;
janakrf091f9c2019-03-25 13:42:18 -070030import java.util.Comparator;
shreyax246f0aa2018-02-23 07:46:54 -080031import java.util.List;
32import java.util.Map;
Mark Schaller24ed98d2015-10-21 17:47:51 +000033import javax.annotation.Nullable;
34
Mark Schaller8ff5b3c2015-07-29 17:32:11 +000035/**
36 * This class is like {@link TransitiveTargetFunction}, but the values it returns do not contain
Mark Schaller24ed98d2015-10-21 17:47:51 +000037 * {@link NestedSet}s. It performs the side-effects of {@link TransitiveTargetFunction} (i.e.,
janakrf091f9c2019-03-25 13:42:18 -070038 * ensuring that transitive targets and their packages have been loaded). It evaluates to a {@link
39 * TransitiveTraversalValue} that contains the first error message it encountered, and a set of
40 * names of providers if the target is a rule.
Mark Schaller8ff5b3c2015-07-29 17:32:11 +000041 */
Mark Schaller24ed98d2015-10-21 17:47:51 +000042public class TransitiveTraversalFunction
janakrf091f9c2019-03-25 13:42:18 -070043 extends TransitiveBaseTraversalFunction<
44 TransitiveTraversalFunction.DeterministicErrorMessageAccumulator> {
Mark Schaller8ff5b3c2015-07-29 17:32:11 +000045
46 @Override
ulfjackdc73a1d2017-10-30 07:05:53 -040047 Label argumentFromKey(SkyKey key) {
48 return (Label) key.argument();
49 }
50
51 @Override
Mark Schaller8ff5b3c2015-07-29 17:32:11 +000052 SkyKey getKey(Label label) {
53 return TransitiveTraversalValue.key(label);
54 }
55
56 @Override
janakrf091f9c2019-03-25 13:42:18 -070057 DeterministicErrorMessageAccumulator processTarget(
58 Label label, TargetAndErrorIfAny targetAndErrorIfAny) {
Mark Schaller24ed98d2015-10-21 17:47:51 +000059 NoSuchTargetException errorIfAny = targetAndErrorIfAny.getErrorLoadingTarget();
60 String errorMessageIfAny = errorIfAny == null ? null : errorIfAny.getMessage();
janakrf091f9c2019-03-25 13:42:18 -070061 return DeterministicErrorMessageAccumulator.create(errorMessageIfAny);
Mark Schaller8ff5b3c2015-07-29 17:32:11 +000062 }
63
64 @Override
Mark Schaller24ed98d2015-10-21 17:47:51 +000065 void processDeps(
janakrf091f9c2019-03-25 13:42:18 -070066 DeterministicErrorMessageAccumulator accumulator,
Mark Schaller24ed98d2015-10-21 17:47:51 +000067 EventHandler eventHandler,
Mark Schaller8ff5b3c2015-07-29 17:32:11 +000068 TargetAndErrorIfAny targetAndErrorIfAny,
jcatercecb3a82018-05-01 14:37:48 -070069 Iterable<Map.Entry<SkyKey, ValueOrException2<NoSuchPackageException, NoSuchTargetException>>>
Mark Schaller8ff5b3c2015-07-29 17:32:11 +000070 depEntries) {
jcatercecb3a82018-05-01 14:37:48 -070071 for (Map.Entry<SkyKey, ValueOrException2<NoSuchPackageException, NoSuchTargetException>> entry :
Mark Schaller24ed98d2015-10-21 17:47:51 +000072 depEntries) {
73 TransitiveTraversalValue transitiveTraversalValue;
74 try {
75 transitiveTraversalValue = (TransitiveTraversalValue) entry.getValue().get();
76 if (transitiveTraversalValue == null) {
77 continue;
78 }
79 } catch (NoSuchPackageException | NoSuchTargetException e) {
80 accumulator.maybeSet(e.getMessage());
81 continue;
82 }
janakrf091f9c2019-03-25 13:42:18 -070083 String errorMessage = transitiveTraversalValue.getErrorMessage();
84 if (errorMessage != null) {
85 accumulator.maybeSet(errorMessage);
Mark Schaller24ed98d2015-10-21 17:47:51 +000086 }
87 }
Mark Schaller8ff5b3c2015-07-29 17:32:11 +000088 }
89
nharmataf2b26ad2019-03-06 09:37:00 -080090 @Nullable
Googler7184b6f2017-05-16 05:25:49 +020091 @Override
nharmataf2b26ad2019-03-06 09:37:00 -080092 protected AdvertisedProviderSet getAdvertisedProviderSet(
Googler7184b6f2017-05-16 05:25:49 +020093 Label toLabel,
nharmataf2b26ad2019-03-06 09:37:00 -080094 @Nullable ValueOrException2<NoSuchPackageException, NoSuchTargetException> toVal,
Googler7184b6f2017-05-16 05:25:49 +020095 Environment env) {
nharmataf2b26ad2019-03-06 09:37:00 -080096 if (toVal == null) {
97 return null;
98 }
Eric Fellheimere27d0632015-09-25 21:35:26 +000099 try {
nharmataf2b26ad2019-03-06 09:37:00 -0800100 return ((TransitiveTraversalValue) toVal.get()).getProviders();
Eric Fellheimere27d0632015-09-25 21:35:26 +0000101 } catch (NoSuchThingException e) {
nharmataf2b26ad2019-03-06 09:37:00 -0800102 // Do nothing interesting. This error was handled when we computed the corresponding
Eric Fellheimere27d0632015-09-25 21:35:26 +0000103 // TransitiveTargetValue.
nharmataf2b26ad2019-03-06 09:37:00 -0800104 return null;
Eric Fellheimere27d0632015-09-25 21:35:26 +0000105 }
106 }
107
Mark Schaller8ff5b3c2015-07-29 17:32:11 +0000108 @Override
janakrf091f9c2019-03-25 13:42:18 -0700109 SkyValue computeSkyValue(
110 TargetAndErrorIfAny targetAndErrorIfAny, DeterministicErrorMessageAccumulator accumulator) {
Mark Schaller24ed98d2015-10-21 17:47:51 +0000111 boolean targetLoadedSuccessfully = targetAndErrorIfAny.getErrorLoadingTarget() == null;
janakrf091f9c2019-03-25 13:42:18 -0700112 String errorMessage = accumulator.getErrorMessage();
Mark Schaller24ed98d2015-10-21 17:47:51 +0000113 return targetLoadedSuccessfully
janakrf091f9c2019-03-25 13:42:18 -0700114 ? TransitiveTraversalValue.forTarget(targetAndErrorIfAny.getTarget(), errorMessage)
Googler7184b6f2017-05-16 05:25:49 +0200115 : TransitiveTraversalValue.unsuccessfulTransitiveTraversal(
janakrf091f9c2019-03-25 13:42:18 -0700116 errorMessage, targetAndErrorIfAny.getTarget());
Mark Schaller8ff5b3c2015-07-29 17:32:11 +0000117 }
118
Mark Schaller6b6d8a92015-10-23 01:00:28 +0000119 @Override
120 TargetMarkerValue getTargetMarkerValue(SkyKey targetMarkerKey, Environment env)
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000121 throws NoSuchTargetException, NoSuchPackageException, InterruptedException {
Mark Schaller6b6d8a92015-10-23 01:00:28 +0000122 return TargetMarkerFunction.computeTargetMarkerValue(targetMarkerKey, env);
123 }
124
shreyax246f0aa2018-02-23 07:46:54 -0800125 @Override
126 Collection<SkyKey> getLabelDepKeys(
127 SkyFunction.Environment env, TargetAndErrorIfAny targetAndErrorIfAny)
128 throws InterruptedException {
129 // As a performance optimization we may already know the deps we are about to request from
130 // last time #compute was called. By requesting these from the environment, we can avoid
131 // repeating the label visitation step. For TransitiveTraversalFunction#compute, the label deps
132 // dependency group is requested immediately after the package.
133 //
134 // IMPORTANT: No other package values should be requested inside
135 // TransitiveTraversalFunction#compute from this point forward.
136 Collection<SkyKey> oldDepKeys = getDepsAfterLastPackageDep(env, /*offset=*/ 1);
137 return oldDepKeys == null ? super.getLabelDepKeys(env, targetAndErrorIfAny) : oldDepKeys;
138 }
139
140 @Override
141 Iterable<SkyKey> getStrictLabelAspectDepKeys(
142 SkyFunction.Environment env,
143 Map<SkyKey, ValueOrException2<NoSuchPackageException, NoSuchTargetException>> depMap,
144 TargetAndErrorIfAny targetAndErrorIfAny)
145 throws InterruptedException {
146 // As a performance optimization we may already know the deps we are about to request from
147 // last time #compute was called. By requesting these from the environment, we can avoid
148 // repeating the label visitation step. For TransitiveTraversalFunction#compute, the label
149 // aspect deps dependency group is requested two groups after the package.
150 Collection<SkyKey> oldAspectDepKeys = getDepsAfterLastPackageDep(env, /*offset=*/ 2);
151 return oldAspectDepKeys == null
152 ? super.getStrictLabelAspectDepKeys(env, depMap, targetAndErrorIfAny)
153 : oldAspectDepKeys;
154 }
155
156 @Nullable
157 private static Collection<SkyKey> getDepsAfterLastPackageDep(
158 SkyFunction.Environment env, int offset) {
159 GroupedList<SkyKey> temporaryDirectDeps = env.getTemporaryDirectDeps();
160 if (temporaryDirectDeps == null) {
161 return null;
162 }
163 int lastPackageDepIndex = getLastPackageValueIndex(temporaryDirectDeps);
164 if (lastPackageDepIndex == -1
165 || temporaryDirectDeps.listSize() <= lastPackageDepIndex + offset) {
166 return null;
167 }
168 return temporaryDirectDeps.get(lastPackageDepIndex + offset);
169 }
170
171 private static int getLastPackageValueIndex(GroupedList<SkyKey> directDeps) {
172 int directDepsNumGroups = directDeps.listSize();
173 for (int i = directDepsNumGroups - 1; i >= 0; i--) {
174 List<SkyKey> depGroup = directDeps.get(i);
175 if (depGroup.size() == 1 && depGroup.get(0).functionName().equals(SkyFunctions.PACKAGE)) {
176 return i;
177 }
178 }
179 return -1;
180 }
181
Mark Schaller24ed98d2015-10-21 17:47:51 +0000182 /**
janakrf091f9c2019-03-25 13:42:18 -0700183 * Keeps track of a deterministic error message encountered while traversing itself and its
184 * dependencies: either the error it was initialized with, or the shortest error it encounters,
185 * with ties broken alphabetically.
186 *
187 * <p>This preserves the behavior that the local target's error is the most important, and is
188 * cheap (constant-time) to compute the comparison between strings, unless they have the same
189 * length, which is unlikely.
Mark Schaller8ff5b3c2015-07-29 17:32:11 +0000190 */
janakrf091f9c2019-03-25 13:42:18 -0700191 interface DeterministicErrorMessageAccumulator {
Mark Schaller24ed98d2015-10-21 17:47:51 +0000192 @Nullable
janakrf091f9c2019-03-25 13:42:18 -0700193 String getErrorMessage();
194
195 default void maybeSet(String errorMessage) {}
196
197 static DeterministicErrorMessageAccumulator create(@Nullable String errorMessage) {
198 if (errorMessage != null) {
199 return () -> errorMessage;
200 }
201 return new UpdateableErrorMessageAccumulator();
202 }
203
204 class UpdateableErrorMessageAccumulator implements DeterministicErrorMessageAccumulator {
205 private static final Comparator<String> LENGTH_THEN_ALPHABETICAL =
206 Comparator.nullsLast(
207 Comparator.comparingInt(String::length).thenComparing(Comparator.naturalOrder()));
208
209 @Nullable private String errorMessage;
210
211 @Override
212 public void maybeSet(String errorMessage) {
213 Preconditions.checkNotNull(errorMessage);
214 if (LENGTH_THEN_ALPHABETICAL.compare(this.errorMessage, errorMessage) > 0) {
215 this.errorMessage = errorMessage;
216 }
217 }
218
219 @Nullable
220 @Override
221 public String getErrorMessage() {
222 return errorMessage;
223 }
Mark Schaller24ed98d2015-10-21 17:47:51 +0000224 }
Mark Schaller8ff5b3c2015-07-29 17:32:11 +0000225 }
226}