blob: 5c1cc7d9ddfcecb50cb77a2d50d42be04a108f2d [file] [log] [blame]
Mark Schallerb889cf32015-03-17 20:55:30 +00001// Copyright 2015 Google Inc. All rights reserved.
2//
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.base.Preconditions;
Mark Schallerd7311e02015-07-07 16:36:09 +000017import com.google.common.collect.ImmutableList;
18import com.google.common.collect.ImmutableMap;
Mark Schallerf6e32d62015-05-19 20:27:43 +000019import com.google.common.collect.ImmutableSet;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000020import com.google.devtools.build.lib.cmdline.Label;
Kristina Chodorow73fa2032015-08-28 17:57:46 +000021import com.google.devtools.build.lib.cmdline.PackageIdentifier;
Mark Schallerd7311e02015-07-07 16:36:09 +000022import com.google.devtools.build.lib.cmdline.TargetPattern;
23import com.google.devtools.build.lib.cmdline.TargetPattern.Type;
Mark Schallerb889cf32015-03-17 20:55:30 +000024import com.google.devtools.build.lib.events.Event;
25import com.google.devtools.build.lib.events.EventHandler;
26import com.google.devtools.build.lib.packages.BuildFileNotFoundException;
27import com.google.devtools.build.lib.packages.NoSuchPackageException;
28import com.google.devtools.build.lib.packages.NoSuchTargetException;
29import com.google.devtools.build.lib.packages.Package;
Mark Schallerb889cf32015-03-17 20:55:30 +000030import com.google.devtools.build.lib.packages.Target;
Mark Schallerd7311e02015-07-07 16:36:09 +000031import com.google.devtools.build.lib.pkgcache.FilteringPolicies;
32import com.google.devtools.build.lib.pkgcache.FilteringPolicy;
Mark Schallerb889cf32015-03-17 20:55:30 +000033import com.google.devtools.build.lib.pkgcache.RecursivePackageProvider;
Mark Schallerd7311e02015-07-07 16:36:09 +000034import com.google.devtools.build.lib.skyframe.TargetPatternValue.TargetPatternKey;
Mark Schallerb889cf32015-03-17 20:55:30 +000035import com.google.devtools.build.lib.vfs.PathFragment;
36import com.google.devtools.build.lib.vfs.RootedPath;
37import com.google.devtools.build.skyframe.SkyKey;
38import com.google.devtools.build.skyframe.WalkableGraph;
39
Mark Schallerd7311e02015-07-07 16:36:09 +000040/**
41 * A {@link RecursivePackageProvider} backed by a {@link WalkableGraph}, used by
42 * {@code SkyQueryEnvironment} to look up the packages and targets matching the universe that's
43 * been preloaded in {@code graph}.
44 * */
Mark Schallerb889cf32015-03-17 20:55:30 +000045public final class GraphBackedRecursivePackageProvider implements RecursivePackageProvider {
46
47 private final WalkableGraph graph;
Mark Schallerd7311e02015-07-07 16:36:09 +000048 private final ImmutableList<TargetPatternKey> universeTargetPatternKeys;
Mark Schallerb889cf32015-03-17 20:55:30 +000049
Mark Schallerd7311e02015-07-07 16:36:09 +000050 public GraphBackedRecursivePackageProvider(WalkableGraph graph,
51 ImmutableList<TargetPatternKey> universeTargetPatternKeys) {
52 this.graph = Preconditions.checkNotNull(graph);
53 this.universeTargetPatternKeys = Preconditions.checkNotNull(universeTargetPatternKeys);
Mark Schallerb889cf32015-03-17 20:55:30 +000054 }
55
56 @Override
57 public Package getPackage(EventHandler eventHandler, PackageIdentifier packageName)
58 throws NoSuchPackageException {
59 SkyKey pkgKey = PackageValue.key(packageName);
60
61 PackageValue pkgValue;
62 if (graph.exists(pkgKey)) {
63 pkgValue = (PackageValue) graph.getValue(pkgKey);
64 if (pkgValue == null) {
Janak Ramakrishnan0a4c6e42015-09-17 00:37:58 +000065 throw (NoSuchPackageException)
66 Preconditions.checkNotNull(graph.getException(pkgKey), pkgKey);
Mark Schallerb889cf32015-03-17 20:55:30 +000067 }
68 } else {
69 // If the package key does not exist in the graph, then it must not correspond to any package,
70 // because the SkyQuery environment has already loaded the universe.
Kristina Chodorowe121dd92015-06-17 14:24:35 +000071 throw new BuildFileNotFoundException(packageName, "BUILD file not found on package path");
Mark Schallerb889cf32015-03-17 20:55:30 +000072 }
73 return pkgValue.getPackage();
74 }
75
76 @Override
Lukacs Berki33aa1e12015-07-08 08:11:30 +000077 public boolean isPackage(EventHandler eventHandler, PackageIdentifier packageName) {
78 SkyKey packageLookupKey = PackageLookupValue.key(packageName);
Mark Schallerb889cf32015-03-17 20:55:30 +000079 if (!graph.exists(packageLookupKey)) {
80 // If the package lookup key does not exist in the graph, then it must not correspond to any
81 // package, because the SkyQuery environment has already loaded the universe.
82 return false;
83 }
84 PackageLookupValue packageLookupValue = (PackageLookupValue) graph.getValue(packageLookupKey);
85 if (packageLookupValue == null) {
86 Exception exception = Preconditions.checkNotNull(graph.getException(packageLookupKey),
87 "During package lookup for '%s', got null for exception", packageName);
88 if (exception instanceof NoSuchPackageException
89 || exception instanceof InconsistentFilesystemException) {
90 eventHandler.handle(Event.error(exception.getMessage()));
91 return false;
92 } else {
93 throw new IllegalStateException("During package lookup for '" + packageName
94 + "', got unexpected exception type", exception);
95 }
96 }
97 return packageLookupValue.packageExists();
98 }
99
100 @Override
Mark Schallerf6e32d62015-05-19 20:27:43 +0000101 public Iterable<PathFragment> getPackagesUnderDirectory(RootedPath directory,
102 ImmutableSet<PathFragment> excludedSubdirectories) {
Mark Schallerd7311e02015-07-07 16:36:09 +0000103 PathFragment.checkAllPathsAreUnder(excludedSubdirectories, directory.getRelativePath());
104
105 // Find the filtering policy of a TargetsBelowDirectory pattern, if any, in the universe that
106 // contains this directory.
107 FilteringPolicy filteringPolicy = null;
108 for (TargetPatternKey patternKey : universeTargetPatternKeys) {
109 TargetPattern pattern = patternKey.getParsedPattern();
110 boolean isTBD = pattern.getType().equals(Type.TARGETS_BELOW_DIRECTORY);
111 if (isTBD && pattern.containsBelowDirectory(directory.getRelativePath().getPathString())) {
112 filteringPolicy =
113 pattern.getRulesOnly() ? FilteringPolicies.RULES_ONLY : FilteringPolicies.NO_FILTER;
114 break;
115 }
Mark Schallerb889cf32015-03-17 20:55:30 +0000116 }
Mark Schallerd7311e02015-07-07 16:36:09 +0000117
118 // If we found a TargetsBelowDirectory pattern in the universe that contains this directory,
119 // then we can look for packages in and under it in the graph. If we didn't find one, then the
120 // directory wasn't in the universe, so return an empty list.
121 ImmutableList.Builder<PathFragment> builder = ImmutableList.builder();
122 if (filteringPolicy != null) {
123 collectPackagesUnder(directory, excludedSubdirectories, builder, filteringPolicy);
124 }
125 return builder.build();
126 }
127
128 private void collectPackagesUnder(RootedPath directory,
129 ImmutableSet<PathFragment> excludedSubdirectories,
130 ImmutableList.Builder<PathFragment> builder, FilteringPolicy policy) {
131 SkyKey key =
132 PrepareDepsOfTargetsUnderDirectoryValue.key(directory, excludedSubdirectories, policy);
133 // If the key does not exist in the graph, because the SkyQuery environment has
134 // already loaded the universe, and we found a TargetsBelowDirectory pattern in the universe
135 // that contained it, then we know the directory does not exist in the universe.
136 if (!graph.exists(key)) {
137 return;
138 }
139
140 // If the key exists in the graph, then it must have a value and must not have an exception,
141 // because PrepareDepsOfTargetsUnderDirectoryFunction#compute never throws.
142 PrepareDepsOfTargetsUnderDirectoryValue prepDepsValue =
143 (PrepareDepsOfTargetsUnderDirectoryValue) Preconditions.checkNotNull(graph.getValue(key));
144 if (prepDepsValue.isDirectoryPackage()) {
145 builder.add(directory.getRelativePath());
146 }
147 ImmutableMap<RootedPath, Boolean> subdirectoryTransitivelyContainsPackages =
148 prepDepsValue.getSubdirectoryTransitivelyContainsPackages();
149 for (RootedPath subdirectory : subdirectoryTransitivelyContainsPackages.keySet()) {
150 if (subdirectoryTransitivelyContainsPackages.get(subdirectory)) {
151 PathFragment subdirectoryRelativePath = subdirectory.getRelativePath();
152 ImmutableSet<PathFragment> excludedSubdirectoriesBeneathThisSubdirectory =
153 PathFragment.filterPathsStartingWith(excludedSubdirectories, subdirectoryRelativePath);
154 collectPackagesUnder(subdirectory, excludedSubdirectoriesBeneathThisSubdirectory, builder,
155 policy);
156 }
157 }
Mark Schallerb889cf32015-03-17 20:55:30 +0000158 }
159
160 @Override
161 public Target getTarget(EventHandler eventHandler, Label label)
162 throws NoSuchPackageException, NoSuchTargetException {
163 return getPackage(eventHandler, label.getPackageIdentifier()).getTarget(label.getName());
164 }
165}