blob: 0b7eaf9d7d5d6856844a7d508f00b6a6414b2c6a [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2015 The Bazel Authors. All rights reserved.
Mark Schallerb889cf32015-03-17 20:55:30 +00002//
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
Eric Fellheimer7b8dbeb2015-12-30 15:21:43 +000016import com.google.common.collect.ImmutableMap;
Mark Schallerf6e32d62015-05-19 20:27:43 +000017import com.google.common.collect.ImmutableSet;
Mark Schallerb889cf32015-03-17 20:55:30 +000018import com.google.common.collect.Iterables;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000019import com.google.devtools.build.lib.cmdline.Label;
Kristina Chodorow73fa2032015-08-28 17:57:46 +000020import com.google.devtools.build.lib.cmdline.PackageIdentifier;
Kristina Chodorowec5c07a2016-01-25 17:12:29 +000021import com.google.devtools.build.lib.cmdline.RepositoryName;
Lukacs Berkic7106d42015-10-15 07:45:54 +000022import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
Mark Schallerb889cf32015-03-17 20:55:30 +000023import com.google.devtools.build.lib.events.Event;
Klaus Aehlig777b30d2017-02-24 16:30:15 +000024import com.google.devtools.build.lib.events.ExtendedEventHandler;
Janak Ramakrishnan0a4c6e42015-09-17 00:37:58 +000025import com.google.devtools.build.lib.packages.BuildFileContainsErrorsException;
Mark Schallerb889cf32015-03-17 20:55:30 +000026import com.google.devtools.build.lib.packages.NoSuchPackageException;
27import com.google.devtools.build.lib.packages.NoSuchTargetException;
28import com.google.devtools.build.lib.packages.Package;
Mark Schallerb889cf32015-03-17 20:55:30 +000029import com.google.devtools.build.lib.packages.Target;
Lukacs Berkic7106d42015-10-15 07:45:54 +000030import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
Mark Schallerb889cf32015-03-17 20:55:30 +000031import com.google.devtools.build.lib.pkgcache.RecursivePackageProvider;
Kristina Chodorow734e7f72016-01-29 15:04:31 +000032import com.google.devtools.build.lib.rules.repository.RepositoryDirectoryValue;
Mark Schaller6df81792015-12-10 18:47:47 +000033import com.google.devtools.build.lib.util.Preconditions;
Lukacs Berkic7106d42015-10-15 07:45:54 +000034import com.google.devtools.build.lib.vfs.Path;
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.SkyFunction.Environment;
38import com.google.devtools.build.skyframe.SkyKey;
Lukacs Berkic7106d42015-10-15 07:45:54 +000039import java.util.ArrayList;
40import java.util.List;
Eric Fellheimer7b8dbeb2015-12-30 15:21:43 +000041import java.util.Map;
Lukacs Berkic7106d42015-10-15 07:45:54 +000042
Mark Schallerb889cf32015-03-17 20:55:30 +000043/**
Mark Schallerfb2d38b2017-03-10 23:01:45 +000044 * 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 Schallerb889cf32015-03-17 20:55:30 +000050 */
51public 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 Aehlig777b30d2017-02-24 16:30:15 +000060 public Package getPackage(ExtendedEventHandler eventHandler, PackageIdentifier packageName)
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +000061 throws NoSuchPackageException, MissingDepException, InterruptedException {
Mark Schallerb889cf32015-03-17 20:55:30 +000062 SkyKey pkgKey = PackageValue.key(packageName);
Janak Ramakrishnan0a4c6e42015-09-17 00:37:58 +000063 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 Schallerb889cf32015-03-17 20:55:30 +000077 throw new MissingDepException();
Janak Ramakrishnan0a4c6e42015-09-17 00:37:58 +000078 } catch (BuildFileContainsErrorsException e) {
79 // Expected.
Mark Schallerb889cf32015-03-17 20:55:30 +000080 }
81 }
Janak Ramakrishnan0a4c6e42015-09-17 00:37:58 +000082 return pkgValue.getPackage();
Mark Schallerb889cf32015-03-17 20:55:30 +000083 }
84
85 @Override
Mark Schallerfb2d38b2017-03-10 23:01:45 +000086 public Map<PackageIdentifier, Package> bulkGetPackages(Iterable<PackageIdentifier> pkgIds)
Klaus Aehlig777b30d2017-02-24 16:30:15 +000087 throws NoSuchPackageException, InterruptedException {
Eric Fellheimer7b8dbeb2015-12-30 15:21:43 +000088 ImmutableMap.Builder<PackageIdentifier, Package> builder = ImmutableMap.builder();
89 for (PackageIdentifier pkgId : pkgIds) {
Mark Schallerfb2d38b2017-03-10 23:01:45 +000090 builder.put(pkgId, getPackage(env.getListener(), pkgId));
Eric Fellheimer7b8dbeb2015-12-30 15:21:43 +000091 }
92 return builder.build();
93 }
94
95 @Override
Klaus Aehlig777b30d2017-02-24 16:30:15 +000096 public boolean isPackage(ExtendedEventHandler eventHandler, PackageIdentifier packageId)
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +000097 throws MissingDepException, InterruptedException {
Lukacs Berki33aa1e12015-07-08 08:11:30 +000098 SkyKey packageLookupKey = PackageLookupValue.key(packageId);
Mark Schallerb889cf32015-03-17 20:55:30 +000099 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 Schallerfb2d38b2017-03-10 23:01:45 +0000108 env.getListener().handle(Event.error(e.getMessage()));
Mark Schallerb889cf32015-03-17 20:55:30 +0000109 return false;
110 }
111 }
112
113 @Override
Lukacs Berkid72db8d2015-09-22 07:40:24 +0000114 public Iterable<PathFragment> getPackagesUnderDirectory(
Mark Schallerfb2d38b2017-03-10 23:01:45 +0000115 ExtendedEventHandler eventHandler,
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000116 RepositoryName repository,
117 PathFragment directory,
Mark Schallerf6e32d62015-05-19 20:27:43 +0000118 ImmutableSet<PathFragment> excludedSubdirectories)
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000119 throws MissingDepException, InterruptedException {
Lukacs Berkic7106d42015-10-15 07:45:54 +0000120 PathPackageLocator packageLocator = PrecomputedValue.PATH_PACKAGE_LOCATOR.get(env);
121 if (packageLocator == null) {
Mark Schallerb889cf32015-03-17 20:55:30 +0000122 throw new MissingDepException();
123 }
Lukacs Berkic7106d42015-10-15 07:45:54 +0000124
125 List<Path> roots = new ArrayList<>();
Brian Silvermand7d6d622016-03-17 09:53:39 +0000126 if (repository.isMain()) {
Lukacs Berkic7106d42015-10-15 07:45:54 +0000127 roots.addAll(packageLocator.getPathEntries());
128 } else {
Kristina Chodorow734e7f72016-01-29 15:04:31 +0000129 RepositoryDirectoryValue repositoryValue =
130 (RepositoryDirectoryValue) env.getValue(RepositoryDirectoryValue.key(repository));
Lukacs Berkic7106d42015-10-15 07:45:54 +0000131 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 Schallerb889cf32015-03-17 20:55:30 +0000156 // TODO(bazel-team): Make RecursivePkgValue return NestedSet<PathFragment> so this transform is
157 // unnecessary.
Lukacs Berkic7106d42015-10-15 07:45:54 +0000158 return Iterables.transform(packageNames.build(), PathFragment.TO_PATH_FRAGMENT);
Mark Schallerb889cf32015-03-17 20:55:30 +0000159 }
160
161 @Override
Klaus Aehlig777b30d2017-02-24 16:30:15 +0000162 public Target getTarget(ExtendedEventHandler eventHandler, Label label)
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000163 throws NoSuchPackageException, NoSuchTargetException, MissingDepException,
164 InterruptedException {
Mark Schallerb889cf32015-03-17 20:55:30 +0000165 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 Schaller3062abb2015-06-19 20:59:41 +0000174 static class MissingDepException extends RuntimeException {
Mark Schallerb889cf32015-03-17 20:55:30 +0000175 }
176}