blob: fcda217c467e168a6b9accd0732aeeea11ab2ada [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;
Eric Fellheimere27d0632015-09-25 21:35:26 +000017import com.google.common.collect.ImmutableList;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000018import com.google.devtools.build.lib.cmdline.Label;
Mark Schaller8ff5b3c2015-07-29 17:32:11 +000019import com.google.devtools.build.lib.collect.nestedset.NestedSet;
20import com.google.devtools.build.lib.events.EventHandler;
Eric Fellheimerb5c98842015-08-12 23:24:21 +000021import com.google.devtools.build.lib.packages.AspectDefinition;
Eric Fellheimerb5c98842015-08-12 23:24:21 +000022import com.google.devtools.build.lib.packages.Attribute;
Dmitry Lomov940ea072016-01-21 22:34:14 +000023import com.google.devtools.build.lib.packages.DependencyFilter;
Mark Schaller8ff5b3c2015-07-29 17:32:11 +000024import com.google.devtools.build.lib.packages.NoSuchPackageException;
25import com.google.devtools.build.lib.packages.NoSuchTargetException;
Eric Fellheimere27d0632015-09-25 21:35:26 +000026import com.google.devtools.build.lib.packages.NoSuchThingException;
Dmitry Lomov6231d082015-11-02 17:17:20 +000027import com.google.devtools.build.lib.packages.Rule;
Mark Schaller24ed98d2015-10-21 17:47:51 +000028import com.google.devtools.build.lib.skyframe.TransitiveTraversalFunction.FirstErrorMessageAccumulator;
shreyax246f0aa2018-02-23 07:46:54 -080029import com.google.devtools.build.lib.util.GroupedList;
30import com.google.devtools.build.skyframe.SkyFunction;
Mark Schaller8ff5b3c2015-07-29 17:32:11 +000031import com.google.devtools.build.skyframe.SkyKey;
32import com.google.devtools.build.skyframe.SkyValue;
33import com.google.devtools.build.skyframe.ValueOrException2;
Eric Fellheimere27d0632015-09-25 21:35:26 +000034import java.util.Collection;
shreyax246f0aa2018-02-23 07:46:54 -080035import java.util.List;
36import java.util.Map;
Mark Schaller24ed98d2015-10-21 17:47:51 +000037import javax.annotation.Nullable;
38
Mark Schaller8ff5b3c2015-07-29 17:32:11 +000039/**
40 * This class is like {@link TransitiveTargetFunction}, but the values it returns do not contain
Mark Schaller24ed98d2015-10-21 17:47:51 +000041 * {@link NestedSet}s. It performs the side-effects of {@link TransitiveTargetFunction} (i.e.,
42 * ensuring that transitive targets and their packages have been loaded). It evaluates to a
43 * {@link TransitiveTraversalValue} that contains the first error message it encountered, and a
44 * set of names of providers if the target is a rule.
Mark Schaller8ff5b3c2015-07-29 17:32:11 +000045 */
Mark Schaller24ed98d2015-10-21 17:47:51 +000046public class TransitiveTraversalFunction
47 extends TransitiveBaseTraversalFunction<FirstErrorMessageAccumulator> {
Mark Schaller8ff5b3c2015-07-29 17:32:11 +000048
49 @Override
ulfjackdc73a1d2017-10-30 07:05:53 -040050 Label argumentFromKey(SkyKey key) {
51 return (Label) key.argument();
52 }
53
54 @Override
Mark Schaller8ff5b3c2015-07-29 17:32:11 +000055 SkyKey getKey(Label label) {
56 return TransitiveTraversalValue.key(label);
57 }
58
59 @Override
Mark Schaller24ed98d2015-10-21 17:47:51 +000060 FirstErrorMessageAccumulator processTarget(Label label, TargetAndErrorIfAny targetAndErrorIfAny) {
61 NoSuchTargetException errorIfAny = targetAndErrorIfAny.getErrorLoadingTarget();
62 String errorMessageIfAny = errorIfAny == null ? null : errorIfAny.getMessage();
63 return new FirstErrorMessageAccumulator(errorMessageIfAny);
Mark Schaller8ff5b3c2015-07-29 17:32:11 +000064 }
65
66 @Override
Mark Schaller24ed98d2015-10-21 17:47:51 +000067 void processDeps(
68 FirstErrorMessageAccumulator accumulator,
69 EventHandler eventHandler,
Mark Schaller8ff5b3c2015-07-29 17:32:11 +000070 TargetAndErrorIfAny targetAndErrorIfAny,
jcatercecb3a82018-05-01 14:37:48 -070071 Iterable<Map.Entry<SkyKey, ValueOrException2<NoSuchPackageException, NoSuchTargetException>>>
Mark Schaller8ff5b3c2015-07-29 17:32:11 +000072 depEntries) {
jcatercecb3a82018-05-01 14:37:48 -070073 for (Map.Entry<SkyKey, ValueOrException2<NoSuchPackageException, NoSuchTargetException>> entry :
Mark Schaller24ed98d2015-10-21 17:47:51 +000074 depEntries) {
75 TransitiveTraversalValue transitiveTraversalValue;
76 try {
77 transitiveTraversalValue = (TransitiveTraversalValue) entry.getValue().get();
78 if (transitiveTraversalValue == null) {
79 continue;
80 }
81 } catch (NoSuchPackageException | NoSuchTargetException e) {
82 accumulator.maybeSet(e.getMessage());
83 continue;
84 }
85 String firstErrorMessage = transitiveTraversalValue.getFirstErrorMessage();
86 if (firstErrorMessage != null) {
87 accumulator.maybeSet(firstErrorMessage);
88 }
89 }
Mark Schaller8ff5b3c2015-07-29 17:32:11 +000090 }
91
Googler7184b6f2017-05-16 05:25:49 +020092 @Override
93 protected Collection<Label> getAspectLabels(
94 Rule fromRule,
95 Attribute attr,
96 Label toLabel,
97 ValueOrException2<NoSuchPackageException, NoSuchTargetException> toVal,
98 Environment env) {
Eric Fellheimere27d0632015-09-25 21:35:26 +000099 try {
100 if (toVal == null) {
101 return ImmutableList.of();
102 }
103 TransitiveTraversalValue traversalVal = (TransitiveTraversalValue) toVal.get();
104 if (traversalVal == null || traversalVal.getProviders() == null) {
105 return ImmutableList.of();
106 }
107 // Retrieve the providers of the dep from the TransitiveTraversalValue, so we can avoid
108 // issuing a dep on its defining Package.
Lukacs Berki549bfce2016-04-22 15:29:12 +0000109 return AspectDefinition.visitAspectsIfRequired(fromRule, attr,
Dmitry Lomovb91d3922017-01-09 20:12:57 +0000110 traversalVal.getProviders(),
Dmitry Lomov940ea072016-01-21 22:34:14 +0000111 DependencyFilter.ALL_DEPS).values();
Eric Fellheimere27d0632015-09-25 21:35:26 +0000112 } catch (NoSuchThingException e) {
113 // Do nothing. This error was handled when we computed the corresponding
114 // TransitiveTargetValue.
115 return ImmutableList.of();
116 }
117 }
118
Mark Schaller8ff5b3c2015-07-29 17:32:11 +0000119 @Override
Lukacs Berki549bfce2016-04-22 15:29:12 +0000120 SkyValue computeSkyValue(TargetAndErrorIfAny targetAndErrorIfAny,
121 FirstErrorMessageAccumulator accumulator) {
Mark Schaller24ed98d2015-10-21 17:47:51 +0000122 boolean targetLoadedSuccessfully = targetAndErrorIfAny.getErrorLoadingTarget() == null;
123 String firstErrorMessage = accumulator.getFirstErrorMessage();
124 return targetLoadedSuccessfully
125 ? TransitiveTraversalValue.forTarget(targetAndErrorIfAny.getTarget(), firstErrorMessage)
Googler7184b6f2017-05-16 05:25:49 +0200126 : TransitiveTraversalValue.unsuccessfulTransitiveTraversal(
127 firstErrorMessage, targetAndErrorIfAny.getTarget());
Mark Schaller8ff5b3c2015-07-29 17:32:11 +0000128 }
129
Mark Schaller6b6d8a92015-10-23 01:00:28 +0000130 @Override
131 TargetMarkerValue getTargetMarkerValue(SkyKey targetMarkerKey, Environment env)
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000132 throws NoSuchTargetException, NoSuchPackageException, InterruptedException {
Mark Schaller6b6d8a92015-10-23 01:00:28 +0000133 return TargetMarkerFunction.computeTargetMarkerValue(targetMarkerKey, env);
134 }
135
shreyax246f0aa2018-02-23 07:46:54 -0800136 @Override
137 Collection<SkyKey> getLabelDepKeys(
138 SkyFunction.Environment env, TargetAndErrorIfAny targetAndErrorIfAny)
139 throws InterruptedException {
140 // As a performance optimization we may already know the deps we are about to request from
141 // last time #compute was called. By requesting these from the environment, we can avoid
142 // repeating the label visitation step. For TransitiveTraversalFunction#compute, the label deps
143 // dependency group is requested immediately after the package.
144 //
145 // IMPORTANT: No other package values should be requested inside
146 // TransitiveTraversalFunction#compute from this point forward.
147 Collection<SkyKey> oldDepKeys = getDepsAfterLastPackageDep(env, /*offset=*/ 1);
148 return oldDepKeys == null ? super.getLabelDepKeys(env, targetAndErrorIfAny) : oldDepKeys;
149 }
150
151 @Override
152 Iterable<SkyKey> getStrictLabelAspectDepKeys(
153 SkyFunction.Environment env,
154 Map<SkyKey, ValueOrException2<NoSuchPackageException, NoSuchTargetException>> depMap,
155 TargetAndErrorIfAny targetAndErrorIfAny)
156 throws InterruptedException {
157 // As a performance optimization we may already know the deps we are about to request from
158 // last time #compute was called. By requesting these from the environment, we can avoid
159 // repeating the label visitation step. For TransitiveTraversalFunction#compute, the label
160 // aspect deps dependency group is requested two groups after the package.
161 Collection<SkyKey> oldAspectDepKeys = getDepsAfterLastPackageDep(env, /*offset=*/ 2);
162 return oldAspectDepKeys == null
163 ? super.getStrictLabelAspectDepKeys(env, depMap, targetAndErrorIfAny)
164 : oldAspectDepKeys;
165 }
166
167 @Nullable
168 private static Collection<SkyKey> getDepsAfterLastPackageDep(
169 SkyFunction.Environment env, int offset) {
170 GroupedList<SkyKey> temporaryDirectDeps = env.getTemporaryDirectDeps();
171 if (temporaryDirectDeps == null) {
172 return null;
173 }
174 int lastPackageDepIndex = getLastPackageValueIndex(temporaryDirectDeps);
175 if (lastPackageDepIndex == -1
176 || temporaryDirectDeps.listSize() <= lastPackageDepIndex + offset) {
177 return null;
178 }
179 return temporaryDirectDeps.get(lastPackageDepIndex + offset);
180 }
181
182 private static int getLastPackageValueIndex(GroupedList<SkyKey> directDeps) {
183 int directDepsNumGroups = directDeps.listSize();
184 for (int i = directDepsNumGroups - 1; i >= 0; i--) {
185 List<SkyKey> depGroup = directDeps.get(i);
186 if (depGroup.size() == 1 && depGroup.get(0).functionName().equals(SkyFunctions.PACKAGE)) {
187 return i;
188 }
189 }
190 return -1;
191 }
192
Mark Schaller24ed98d2015-10-21 17:47:51 +0000193 /**
194 * Keeps track of the first error message encountered while traversing itself and its
195 * dependencies.
Mark Schaller8ff5b3c2015-07-29 17:32:11 +0000196 */
Mark Schaller24ed98d2015-10-21 17:47:51 +0000197 static class FirstErrorMessageAccumulator {
Mark Schaller8ff5b3c2015-07-29 17:32:11 +0000198
Mark Schaller24ed98d2015-10-21 17:47:51 +0000199 @Nullable private String firstErrorMessage;
200
201 public FirstErrorMessageAccumulator(@Nullable String firstErrorMessage) {
202 this.firstErrorMessage = firstErrorMessage;
203 }
204
205 /** Remembers {@param errorMessage} if it is the first error message. */
206 void maybeSet(String errorMessage) {
207 Preconditions.checkNotNull(errorMessage);
208 if (firstErrorMessage == null) {
209 firstErrorMessage = errorMessage;
210 }
211 }
212
213 @Nullable
214 String getFirstErrorMessage() {
215 return firstErrorMessage;
216 }
Mark Schaller8ff5b3c2015-07-29 17:32:11 +0000217 }
218}