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