blob: b419c77e035b0bd4dc416eb119b77d5d8d06a770 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002//
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 Schaller66b35f32015-05-19 21:19:37 +000016import com.google.common.collect.ImmutableList;
17import com.google.common.collect.ImmutableSet;
18import com.google.common.collect.Iterables;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000019import com.google.devtools.build.lib.cmdline.Label;
Lukacs Berkia6434362015-09-15 13:56:14 +000020import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010021import com.google.devtools.build.lib.cmdline.ResolvedTargets;
22import com.google.devtools.build.lib.cmdline.ResolvedTargets.Builder;
Mark Schaller66b35f32015-05-19 21:19:37 +000023import com.google.devtools.build.lib.cmdline.TargetParsingException;
24import com.google.devtools.build.lib.cmdline.TargetPattern;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010025import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
26import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
Mark Schaller20c2d032015-06-18 16:51:03 +000027import com.google.devtools.build.lib.pkgcache.FilteringPolicies;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010028import com.google.devtools.build.lib.pkgcache.FilteringPolicy;
Mark Schaller6df81792015-12-10 18:47:47 +000029import com.google.devtools.build.lib.util.Preconditions;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010030import com.google.devtools.build.skyframe.SkyKey;
31import com.google.devtools.build.skyframe.SkyValue;
32
33import java.io.IOException;
34import java.io.ObjectInputStream;
35import java.io.ObjectOutputStream;
36import java.io.Serializable;
37import java.util.ArrayList;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010038import java.util.List;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010039import java.util.Objects;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010040
41/**
42 * A value referring to a computed set of resolved targets. This is used for the results of target
43 * pattern parsing.
44 */
45@Immutable
46@ThreadSafe
47public final class TargetPatternValue implements SkyValue {
48
Nathan Harmata3fae3662015-04-22 20:10:48 +000049 private ResolvedTargets<Label> targets;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010050
Nathan Harmata3fae3662015-04-22 20:10:48 +000051 TargetPatternValue(ResolvedTargets<Label> targets) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010052 this.targets = Preconditions.checkNotNull(targets);
53 }
54
55 private void writeObject(ObjectOutputStream out) throws IOException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010056 List<String> ts = new ArrayList<>();
57 List<String> filteredTs = new ArrayList<>();
Nathan Harmata3fae3662015-04-22 20:10:48 +000058 for (Label target : targets.getTargets()) {
59 ts.add(target.toString());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010060 }
Nathan Harmata3fae3662015-04-22 20:10:48 +000061 for (Label target : targets.getFilteredTargets()) {
62 filteredTs.add(target.toString());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010063 }
64
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010065 out.writeObject(ts);
66 out.writeObject(filteredTs);
67 }
68
Nathan Harmata3fae3662015-04-22 20:10:48 +000069 private Label labelFromString(String labelString) {
70 try {
71 return Label.parseAbsolute(labelString);
Lukacs Berkia6434362015-09-15 13:56:14 +000072 } catch (LabelSyntaxException e) {
Nathan Harmata3fae3662015-04-22 20:10:48 +000073 throw new IllegalStateException(e);
74 }
75 }
76
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010077 @SuppressWarnings("unchecked")
78 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010079 List<String> ts = (List<String>) in.readObject();
80 List<String> filteredTs = (List<String>) in.readObject();
81
Nathan Harmata3fae3662015-04-22 20:10:48 +000082 Builder<Label> builder = ResolvedTargets.<Label>builder();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010083 for (String labelString : ts) {
Nathan Harmata3fae3662015-04-22 20:10:48 +000084 builder.add(labelFromString(labelString));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010085 }
86
87 for (String labelString : filteredTs) {
Nathan Harmata3fae3662015-04-22 20:10:48 +000088 builder.remove(labelFromString(labelString));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010089 }
90 this.targets = builder.build();
91 }
92
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010093 @SuppressWarnings("unused")
94 private void readObjectNoData() {
95 throw new IllegalStateException();
96 }
97
98 /**
Mark Schaller66b35f32015-05-19 21:19:37 +000099 * Create a target pattern {@link SkyKey}. Throws {@link TargetParsingException} if the provided
100 * {@code pattern} cannot be parsed.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100101 *
Mark Schaller66b35f32015-05-19 21:19:37 +0000102 * @param pattern The pattern, eg "-foo/biz...". If the first character is "-", the pattern is
103 * treated as a negative pattern.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100104 * @param policy The filtering policy, eg "only return test targets"
105 * @param offset The offset to apply to relative target patterns.
106 */
107 @ThreadSafe
Mark Schaller66b35f32015-05-19 21:19:37 +0000108 public static SkyKey key(String pattern, FilteringPolicy policy, String offset)
109 throws TargetParsingException {
110 return Iterables.getOnlyElement(keys(ImmutableList.of(pattern), policy, offset)).getSkyKey();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100111 }
112
113 /**
Mark Schaller66b35f32015-05-19 21:19:37 +0000114 * Returns an iterable of {@link TargetPatternSkyKeyOrException}, with {@link TargetPatternKey}
Mark Schaller20c2d032015-06-18 16:51:03 +0000115 * arguments, in the same order as the list of patterns provided as input. If a provided pattern
116 * fails to parse, the element in the returned iterable corresponding to it will throw when its
117 * {@link TargetPatternSkyKeyOrException#getSkyKey} method is called.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100118 *
Mark Schaller66b35f32015-05-19 21:19:37 +0000119 * @param patterns The list of patterns, eg "-foo/biz...". If a pattern's first character is "-",
120 * it is treated as a negative pattern.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100121 * @param policy The filtering policy, eg "only return test targets"
122 * @param offset The offset to apply to relative target patterns.
123 */
124 @ThreadSafe
Mark Schaller66b35f32015-05-19 21:19:37 +0000125 public static Iterable<TargetPatternSkyKeyOrException> keys(List<String> patterns,
126 FilteringPolicy policy, String offset) {
127 TargetPattern.Parser parser = new TargetPattern.Parser(offset);
128 ImmutableList.Builder<TargetPatternSkyKeyOrException> builder = ImmutableList.builder();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100129 for (String pattern : patterns) {
Mark Schaller66b35f32015-05-19 21:19:37 +0000130 boolean positive = !pattern.startsWith("-");
131 String absoluteValueOfPattern = positive ? pattern : pattern.substring(1);
Mark Schaller20c2d032015-06-18 16:51:03 +0000132 TargetPattern targetPattern;
Mark Schaller66b35f32015-05-19 21:19:37 +0000133 try {
Mark Schaller20c2d032015-06-18 16:51:03 +0000134 targetPattern = parser.parse(absoluteValueOfPattern);
Mark Schaller66b35f32015-05-19 21:19:37 +0000135 } catch (TargetParsingException e) {
136 builder.add(new TargetPatternSkyKeyException(e, absoluteValueOfPattern));
Mark Schaller20c2d032015-06-18 16:51:03 +0000137 continue;
Mark Schaller66b35f32015-05-19 21:19:37 +0000138 }
Mark Schaller20c2d032015-06-18 16:51:03 +0000139 TargetPatternKey targetPatternKey = new TargetPatternKey(targetPattern,
140 positive ? policy : FilteringPolicies.NO_FILTER, /*isNegative=*/!positive, offset,
141 ImmutableSet.<String>of());
142 SkyKey skyKey = new SkyKey(SkyFunctions.TARGET_PATTERN, targetPatternKey);
143 builder.add(new TargetPatternSkyKeyValue(skyKey));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100144 }
Mark Schaller66b35f32015-05-19 21:19:37 +0000145 return builder.build();
146 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100147
Nathan Harmata3fae3662015-04-22 20:10:48 +0000148 public ResolvedTargets<Label> getTargets() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100149 return targets;
150 }
151
152 /**
Mark Schaller248f0442015-05-19 17:59:36 +0000153 * A TargetPatternKey is a tuple of pattern (eg, "foo/..."), filtering policy, a relative pattern
Mark Schaller66b35f32015-05-19 21:19:37 +0000154 * offset, whether it is a positive or negative match, and a set of excluded subdirectories.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100155 */
156 @ThreadSafe
Mark Schaller248f0442015-05-19 17:59:36 +0000157 public static class TargetPatternKey implements Serializable {
Mark Schaller66b35f32015-05-19 21:19:37 +0000158
159 private final TargetPattern parsedPattern;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100160 private final FilteringPolicy policy;
161 private final boolean isNegative;
162
163 private final String offset;
Mark Schaller66b35f32015-05-19 21:19:37 +0000164 private final ImmutableSet<String> excludedSubdirectories;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100165
Mark Schaller66b35f32015-05-19 21:19:37 +0000166 public TargetPatternKey(TargetPattern parsedPattern, FilteringPolicy policy,
167 boolean isNegative, String offset, ImmutableSet<String> excludedSubdirectories) {
168 this.parsedPattern = Preconditions.checkNotNull(parsedPattern);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100169 this.policy = Preconditions.checkNotNull(policy);
170 this.isNegative = isNegative;
171 this.offset = offset;
Mark Schaller66b35f32015-05-19 21:19:37 +0000172 this.excludedSubdirectories = Preconditions.checkNotNull(excludedSubdirectories);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100173 }
174
175 public String getPattern() {
Mark Schaller66b35f32015-05-19 21:19:37 +0000176 return parsedPattern.getOriginalPattern();
177 }
178
179 public TargetPattern getParsedPattern() {
180 return parsedPattern;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100181 }
182
183 public boolean isNegative() {
184 return isNegative;
185 }
186
187 public FilteringPolicy getPolicy() {
188 return policy;
189 }
190
191 public String getOffset() {
192 return offset;
193 }
194
Mark Schaller66b35f32015-05-19 21:19:37 +0000195 public ImmutableSet<String> getExcludedSubdirectories() {
196 return excludedSubdirectories;
197 }
198
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100199 @Override
200 public String toString() {
Mark Schaller66b35f32015-05-19 21:19:37 +0000201 return (isNegative ? "-" : "") + parsedPattern.getOriginalPattern();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100202 }
203
204 @Override
205 public int hashCode() {
Mark Schaller66b35f32015-05-19 21:19:37 +0000206 return Objects.hash(parsedPattern, isNegative, policy, offset,
207 excludedSubdirectories);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100208 }
209
210 @Override
211 public boolean equals(Object obj) {
Mark Schaller248f0442015-05-19 17:59:36 +0000212 if (!(obj instanceof TargetPatternKey)) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100213 return false;
214 }
Mark Schaller248f0442015-05-19 17:59:36 +0000215 TargetPatternKey other = (TargetPatternKey) obj;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100216
Mark Schaller66b35f32015-05-19 21:19:37 +0000217 return other.isNegative == this.isNegative && other.parsedPattern.equals(this.parsedPattern)
218 && other.offset.equals(this.offset) && other.policy.equals(this.policy)
219 && other.excludedSubdirectories.equals(this.excludedSubdirectories);
220 }
221 }
222
223 /**
224 * Wrapper for a target pattern {@link SkyKey} or the {@link TargetParsingException} thrown when
225 * trying to compute it.
226 */
227 public interface TargetPatternSkyKeyOrException {
228
229 /**
230 * Returns the stored {@link SkyKey} or throws {@link TargetParsingException} if one was thrown
231 * when computing the key.
232 */
233 SkyKey getSkyKey() throws TargetParsingException;
234
235 /**
236 * Returns the pattern that resulted in the stored {@link SkyKey} or {@link
237 * TargetParsingException}.
238 */
239 String getOriginalPattern();
240 }
241
242 private static final class TargetPatternSkyKeyValue implements TargetPatternSkyKeyOrException {
243
244 private final SkyKey value;
245
246 private TargetPatternSkyKeyValue(SkyKey value) {
247 this.value = value;
248 }
249
250 @Override
251 public SkyKey getSkyKey() throws TargetParsingException {
252 return value;
253 }
254
255 @Override
256 public String getOriginalPattern() {
257 return ((TargetPatternKey) value.argument()).getPattern();
258 }
259 }
260
261 private static final class TargetPatternSkyKeyException implements
262 TargetPatternSkyKeyOrException {
263
264 private final TargetParsingException exception;
265 private final String originalPattern;
266
267 private TargetPatternSkyKeyException(TargetParsingException exception, String originalPattern) {
268 this.exception = exception;
269 this.originalPattern = originalPattern;
270 }
271
272 @Override
273 public SkyKey getSkyKey() throws TargetParsingException {
274 throw exception;
275 }
276
277 @Override
278 public String getOriginalPattern() {
279 return originalPattern;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100280 }
281 }
282}