Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 1 | // 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. |
| 14 | package com.google.devtools.build.lib.skyframe; |
| 15 | |
| 16 | import com.google.common.base.Preconditions; |
Mark Schaller | d7311e0 | 2015-07-07 16:36:09 +0000 | [diff] [blame] | 17 | import com.google.common.collect.ImmutableList; |
| 18 | import com.google.common.collect.ImmutableMap; |
Mark Schaller | f6e32d6 | 2015-05-19 20:27:43 +0000 | [diff] [blame] | 19 | import com.google.common.collect.ImmutableSet; |
Lukacs Berki | 6e91eb9 | 2015-09-21 09:12:37 +0000 | [diff] [blame^] | 20 | import com.google.devtools.build.lib.cmdline.Label; |
Kristina Chodorow | 73fa203 | 2015-08-28 17:57:46 +0000 | [diff] [blame] | 21 | import com.google.devtools.build.lib.cmdline.PackageIdentifier; |
Mark Schaller | d7311e0 | 2015-07-07 16:36:09 +0000 | [diff] [blame] | 22 | import com.google.devtools.build.lib.cmdline.TargetPattern; |
| 23 | import com.google.devtools.build.lib.cmdline.TargetPattern.Type; |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 24 | import com.google.devtools.build.lib.events.Event; |
| 25 | import com.google.devtools.build.lib.events.EventHandler; |
| 26 | import com.google.devtools.build.lib.packages.BuildFileNotFoundException; |
| 27 | import com.google.devtools.build.lib.packages.NoSuchPackageException; |
| 28 | import com.google.devtools.build.lib.packages.NoSuchTargetException; |
| 29 | import com.google.devtools.build.lib.packages.Package; |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 30 | import com.google.devtools.build.lib.packages.Target; |
Mark Schaller | d7311e0 | 2015-07-07 16:36:09 +0000 | [diff] [blame] | 31 | import com.google.devtools.build.lib.pkgcache.FilteringPolicies; |
| 32 | import com.google.devtools.build.lib.pkgcache.FilteringPolicy; |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 33 | import com.google.devtools.build.lib.pkgcache.RecursivePackageProvider; |
Mark Schaller | d7311e0 | 2015-07-07 16:36:09 +0000 | [diff] [blame] | 34 | import com.google.devtools.build.lib.skyframe.TargetPatternValue.TargetPatternKey; |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 35 | import com.google.devtools.build.lib.vfs.PathFragment; |
| 36 | import com.google.devtools.build.lib.vfs.RootedPath; |
| 37 | import com.google.devtools.build.skyframe.SkyKey; |
| 38 | import com.google.devtools.build.skyframe.WalkableGraph; |
| 39 | |
Mark Schaller | d7311e0 | 2015-07-07 16:36:09 +0000 | [diff] [blame] | 40 | /** |
| 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 Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 45 | public final class GraphBackedRecursivePackageProvider implements RecursivePackageProvider { |
| 46 | |
| 47 | private final WalkableGraph graph; |
Mark Schaller | d7311e0 | 2015-07-07 16:36:09 +0000 | [diff] [blame] | 48 | private final ImmutableList<TargetPatternKey> universeTargetPatternKeys; |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 49 | |
Mark Schaller | d7311e0 | 2015-07-07 16:36:09 +0000 | [diff] [blame] | 50 | public GraphBackedRecursivePackageProvider(WalkableGraph graph, |
| 51 | ImmutableList<TargetPatternKey> universeTargetPatternKeys) { |
| 52 | this.graph = Preconditions.checkNotNull(graph); |
| 53 | this.universeTargetPatternKeys = Preconditions.checkNotNull(universeTargetPatternKeys); |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 54 | } |
| 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 Ramakrishnan | 0a4c6e4 | 2015-09-17 00:37:58 +0000 | [diff] [blame] | 65 | throw (NoSuchPackageException) |
| 66 | Preconditions.checkNotNull(graph.getException(pkgKey), pkgKey); |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 67 | } |
| 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 Chodorow | e121dd9 | 2015-06-17 14:24:35 +0000 | [diff] [blame] | 71 | throw new BuildFileNotFoundException(packageName, "BUILD file not found on package path"); |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 72 | } |
| 73 | return pkgValue.getPackage(); |
| 74 | } |
| 75 | |
| 76 | @Override |
Lukacs Berki | 33aa1e1 | 2015-07-08 08:11:30 +0000 | [diff] [blame] | 77 | public boolean isPackage(EventHandler eventHandler, PackageIdentifier packageName) { |
| 78 | SkyKey packageLookupKey = PackageLookupValue.key(packageName); |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 79 | 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 Schaller | f6e32d6 | 2015-05-19 20:27:43 +0000 | [diff] [blame] | 101 | public Iterable<PathFragment> getPackagesUnderDirectory(RootedPath directory, |
| 102 | ImmutableSet<PathFragment> excludedSubdirectories) { |
Mark Schaller | d7311e0 | 2015-07-07 16:36:09 +0000 | [diff] [blame] | 103 | 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 Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 116 | } |
Mark Schaller | d7311e0 | 2015-07-07 16:36:09 +0000 | [diff] [blame] | 117 | |
| 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 Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 158 | } |
| 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 | } |