Damien Martin-Guillerez | f88f4d8 | 2015-09-25 13:56:55 +0000 | [diff] [blame] | 1 | // Copyright 2015 The Bazel Authors. All rights reserved. |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 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 | |
Eric Fellheimer | 7b8dbeb | 2015-12-30 15:21:43 +0000 | [diff] [blame] | 16 | import com.google.common.collect.ImmutableMap; |
Mark Schaller | f6e32d6 | 2015-05-19 20:27:43 +0000 | [diff] [blame] | 17 | import com.google.common.collect.ImmutableSet; |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 18 | import com.google.common.collect.Iterables; |
Lukacs Berki | 6e91eb9 | 2015-09-21 09:12:37 +0000 | [diff] [blame] | 19 | import com.google.devtools.build.lib.cmdline.Label; |
Kristina Chodorow | 73fa203 | 2015-08-28 17:57:46 +0000 | [diff] [blame] | 20 | import com.google.devtools.build.lib.cmdline.PackageIdentifier; |
Kristina Chodorow | ec5c07a | 2016-01-25 17:12:29 +0000 | [diff] [blame] | 21 | import com.google.devtools.build.lib.cmdline.RepositoryName; |
Lukacs Berki | c7106d4 | 2015-10-15 07:45:54 +0000 | [diff] [blame] | 22 | import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 23 | import com.google.devtools.build.lib.events.Event; |
Klaus Aehlig | 777b30d | 2017-02-24 16:30:15 +0000 | [diff] [blame] | 24 | import com.google.devtools.build.lib.events.ExtendedEventHandler; |
Janak Ramakrishnan | 0a4c6e4 | 2015-09-17 00:37:58 +0000 | [diff] [blame] | 25 | import com.google.devtools.build.lib.packages.BuildFileContainsErrorsException; |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 26 | import com.google.devtools.build.lib.packages.NoSuchPackageException; |
| 27 | import com.google.devtools.build.lib.packages.NoSuchTargetException; |
| 28 | import com.google.devtools.build.lib.packages.Package; |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 29 | import com.google.devtools.build.lib.packages.Target; |
Lukacs Berki | c7106d4 | 2015-10-15 07:45:54 +0000 | [diff] [blame] | 30 | import com.google.devtools.build.lib.pkgcache.PathPackageLocator; |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 31 | import com.google.devtools.build.lib.pkgcache.RecursivePackageProvider; |
Kristina Chodorow | 734e7f7 | 2016-01-29 15:04:31 +0000 | [diff] [blame] | 32 | import com.google.devtools.build.lib.rules.repository.RepositoryDirectoryValue; |
Mark Schaller | 6df8179 | 2015-12-10 18:47:47 +0000 | [diff] [blame] | 33 | import com.google.devtools.build.lib.util.Preconditions; |
Lukacs Berki | c7106d4 | 2015-10-15 07:45:54 +0000 | [diff] [blame] | 34 | import com.google.devtools.build.lib.vfs.Path; |
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.SkyFunction.Environment; |
| 38 | import com.google.devtools.build.skyframe.SkyKey; |
Lukacs Berki | c7106d4 | 2015-10-15 07:45:54 +0000 | [diff] [blame] | 39 | import java.util.ArrayList; |
| 40 | import java.util.List; |
Eric Fellheimer | 7b8dbeb | 2015-12-30 15:21:43 +0000 | [diff] [blame] | 41 | import java.util.Map; |
Lukacs Berki | c7106d4 | 2015-10-15 07:45:54 +0000 | [diff] [blame] | 42 | |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 43 | /** |
Mark Schaller | fb2d38b | 2017-03-10 23:01:45 +0000 | [diff] [blame] | 44 | * A {@link RecursivePackageProvider} backed by an {@link Environment}. Its methods may throw {@link |
| 45 | * MissingDepException} if the package values this depends on haven't been calculated and added to |
| 46 | * its environment. |
| 47 | * |
| 48 | * <p>This implementation never emits events through the {@link ExtendedEventHandler}s passed to its |
| 49 | * methods. Instead, it emits events through its environment's {@link Environment#getListener()}. |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 50 | */ |
| 51 | public final class EnvironmentBackedRecursivePackageProvider implements RecursivePackageProvider { |
| 52 | |
| 53 | private final Environment env; |
| 54 | |
| 55 | public EnvironmentBackedRecursivePackageProvider(Environment env) { |
| 56 | this.env = env; |
| 57 | } |
| 58 | |
| 59 | @Override |
Klaus Aehlig | 777b30d | 2017-02-24 16:30:15 +0000 | [diff] [blame] | 60 | public Package getPackage(ExtendedEventHandler eventHandler, PackageIdentifier packageName) |
Janak Ramakrishnan | 3c0adb2 | 2016-08-15 21:54:55 +0000 | [diff] [blame] | 61 | throws NoSuchPackageException, MissingDepException, InterruptedException { |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 62 | SkyKey pkgKey = PackageValue.key(packageName); |
Janak Ramakrishnan | 0a4c6e4 | 2015-09-17 00:37:58 +0000 | [diff] [blame] | 63 | PackageValue pkgValue = |
| 64 | (PackageValue) env.getValueOrThrow(pkgKey, NoSuchPackageException.class); |
| 65 | if (pkgValue == null) { |
| 66 | throw new MissingDepException(); |
| 67 | } |
| 68 | Package pkg = pkgValue.getPackage(); |
| 69 | if (pkg.containsErrors()) { |
| 70 | // If this is a nokeep_going build, we must shut the build down by throwing an exception. To |
| 71 | // do that, we request a node that will throw an exception, and then try to catch it and |
| 72 | // continue. This gives the framework notification to shut down the build if it should. |
| 73 | try { |
| 74 | env.getValueOrThrow( |
| 75 | PackageErrorFunction.key(packageName), BuildFileContainsErrorsException.class); |
| 76 | Preconditions.checkState(env.valuesMissing(), "Should have thrown for %s", packageName); |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 77 | throw new MissingDepException(); |
Janak Ramakrishnan | 0a4c6e4 | 2015-09-17 00:37:58 +0000 | [diff] [blame] | 78 | } catch (BuildFileContainsErrorsException e) { |
| 79 | // Expected. |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 80 | } |
| 81 | } |
Janak Ramakrishnan | 0a4c6e4 | 2015-09-17 00:37:58 +0000 | [diff] [blame] | 82 | return pkgValue.getPackage(); |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 83 | } |
| 84 | |
| 85 | @Override |
Mark Schaller | fb2d38b | 2017-03-10 23:01:45 +0000 | [diff] [blame] | 86 | public Map<PackageIdentifier, Package> bulkGetPackages(Iterable<PackageIdentifier> pkgIds) |
Klaus Aehlig | 777b30d | 2017-02-24 16:30:15 +0000 | [diff] [blame] | 87 | throws NoSuchPackageException, InterruptedException { |
Eric Fellheimer | 7b8dbeb | 2015-12-30 15:21:43 +0000 | [diff] [blame] | 88 | ImmutableMap.Builder<PackageIdentifier, Package> builder = ImmutableMap.builder(); |
| 89 | for (PackageIdentifier pkgId : pkgIds) { |
Mark Schaller | fb2d38b | 2017-03-10 23:01:45 +0000 | [diff] [blame] | 90 | builder.put(pkgId, getPackage(env.getListener(), pkgId)); |
Eric Fellheimer | 7b8dbeb | 2015-12-30 15:21:43 +0000 | [diff] [blame] | 91 | } |
| 92 | return builder.build(); |
| 93 | } |
| 94 | |
| 95 | @Override |
Klaus Aehlig | 777b30d | 2017-02-24 16:30:15 +0000 | [diff] [blame] | 96 | public boolean isPackage(ExtendedEventHandler eventHandler, PackageIdentifier packageId) |
Janak Ramakrishnan | 3c0adb2 | 2016-08-15 21:54:55 +0000 | [diff] [blame] | 97 | throws MissingDepException, InterruptedException { |
Lukacs Berki | 33aa1e1 | 2015-07-08 08:11:30 +0000 | [diff] [blame] | 98 | SkyKey packageLookupKey = PackageLookupValue.key(packageId); |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 99 | try { |
| 100 | PackageLookupValue packageLookupValue = |
| 101 | (PackageLookupValue) env.getValueOrThrow(packageLookupKey, NoSuchPackageException.class, |
| 102 | InconsistentFilesystemException.class); |
| 103 | if (packageLookupValue == null) { |
| 104 | throw new MissingDepException(); |
| 105 | } |
| 106 | return packageLookupValue.packageExists(); |
| 107 | } catch (NoSuchPackageException | InconsistentFilesystemException e) { |
Mark Schaller | fb2d38b | 2017-03-10 23:01:45 +0000 | [diff] [blame] | 108 | env.getListener().handle(Event.error(e.getMessage())); |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 109 | return false; |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | @Override |
Lukacs Berki | d72db8d | 2015-09-22 07:40:24 +0000 | [diff] [blame] | 114 | public Iterable<PathFragment> getPackagesUnderDirectory( |
Mark Schaller | fb2d38b | 2017-03-10 23:01:45 +0000 | [diff] [blame] | 115 | ExtendedEventHandler eventHandler, |
Janak Ramakrishnan | 3c0adb2 | 2016-08-15 21:54:55 +0000 | [diff] [blame] | 116 | RepositoryName repository, |
| 117 | PathFragment directory, |
Mark Schaller | f6e32d6 | 2015-05-19 20:27:43 +0000 | [diff] [blame] | 118 | ImmutableSet<PathFragment> excludedSubdirectories) |
Janak Ramakrishnan | 3c0adb2 | 2016-08-15 21:54:55 +0000 | [diff] [blame] | 119 | throws MissingDepException, InterruptedException { |
Lukacs Berki | c7106d4 | 2015-10-15 07:45:54 +0000 | [diff] [blame] | 120 | PathPackageLocator packageLocator = PrecomputedValue.PATH_PACKAGE_LOCATOR.get(env); |
| 121 | if (packageLocator == null) { |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 122 | throw new MissingDepException(); |
| 123 | } |
Lukacs Berki | c7106d4 | 2015-10-15 07:45:54 +0000 | [diff] [blame] | 124 | |
| 125 | List<Path> roots = new ArrayList<>(); |
Brian Silverman | d7d6d62 | 2016-03-17 09:53:39 +0000 | [diff] [blame] | 126 | if (repository.isMain()) { |
Lukacs Berki | c7106d4 | 2015-10-15 07:45:54 +0000 | [diff] [blame] | 127 | roots.addAll(packageLocator.getPathEntries()); |
| 128 | } else { |
Kristina Chodorow | 734e7f7 | 2016-01-29 15:04:31 +0000 | [diff] [blame] | 129 | RepositoryDirectoryValue repositoryValue = |
| 130 | (RepositoryDirectoryValue) env.getValue(RepositoryDirectoryValue.key(repository)); |
Lukacs Berki | c7106d4 | 2015-10-15 07:45:54 +0000 | [diff] [blame] | 131 | if (repositoryValue == null) { |
| 132 | throw new MissingDepException(); |
| 133 | } |
| 134 | |
| 135 | roots.add(repositoryValue.getPath()); |
| 136 | } |
| 137 | |
| 138 | NestedSetBuilder<String> packageNames = NestedSetBuilder.stableOrder(); |
| 139 | for (Path root : roots) { |
| 140 | PathFragment.checkAllPathsAreUnder(excludedSubdirectories, directory); |
| 141 | RecursivePkgValue lookup = (RecursivePkgValue) env.getValue(RecursivePkgValue.key( |
| 142 | repository, RootedPath.toRootedPath(root, directory), excludedSubdirectories)); |
| 143 | if (lookup == null) { |
| 144 | // Typically a null value from Environment.getValue(k) means that either the key k is |
| 145 | // missing a dependency or an exception was thrown during evaluation of k. Here, if this |
| 146 | // getValue call returns null in a keep_going build, it can only mean a missing dependency |
| 147 | // because RecursivePkgFunction#compute never throws. |
| 148 | // In a nokeep_going build, a lower-level exception that RecursivePkgFunction ignored may |
| 149 | // bubble up to here, but we ignore it and depend on the top-level caller to be flexible in |
| 150 | // the exception types it can accept. |
| 151 | throw new MissingDepException(); |
| 152 | } |
| 153 | |
| 154 | packageNames.addTransitive(lookup.getPackages()); |
| 155 | } |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 156 | // TODO(bazel-team): Make RecursivePkgValue return NestedSet<PathFragment> so this transform is |
| 157 | // unnecessary. |
Lukacs Berki | c7106d4 | 2015-10-15 07:45:54 +0000 | [diff] [blame] | 158 | return Iterables.transform(packageNames.build(), PathFragment.TO_PATH_FRAGMENT); |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 159 | } |
| 160 | |
| 161 | @Override |
Klaus Aehlig | 777b30d | 2017-02-24 16:30:15 +0000 | [diff] [blame] | 162 | public Target getTarget(ExtendedEventHandler eventHandler, Label label) |
Janak Ramakrishnan | 3c0adb2 | 2016-08-15 21:54:55 +0000 | [diff] [blame] | 163 | throws NoSuchPackageException, NoSuchTargetException, MissingDepException, |
| 164 | InterruptedException { |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 165 | return getPackage(eventHandler, label.getPackageIdentifier()).getTarget(label.getName()); |
| 166 | } |
| 167 | |
| 168 | /** |
| 169 | * Indicates that a missing dependency is needed before target parsing can proceed. Currently |
| 170 | * used only in skyframe to notify the framework of missing dependencies. Caught by the compute |
| 171 | * method in {@link com.google.devtools.build.lib.skyframe.TargetPatternFunction}, which then |
| 172 | * returns null in accordance with the skyframe missing dependency policy. |
| 173 | */ |
Mark Schaller | 3062abb | 2015-06-19 20:59:41 +0000 | [diff] [blame] | 174 | static class MissingDepException extends RuntimeException { |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 175 | } |
| 176 | } |