blob: 115a0f54457d70a9281ac7cb1abca8f99b331dc7 [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
Mark Schallerf6e32d62015-05-19 20:27:43 +000016import com.google.common.collect.ImmutableSet;
Mark Schallerb889cf32015-03-17 20:55:30 +000017import com.google.common.collect.Iterables;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000018import com.google.devtools.build.lib.cmdline.Label;
Kristina Chodorow73fa2032015-08-28 17:57:46 +000019import com.google.devtools.build.lib.cmdline.PackageIdentifier;
Lukacs Berkid72db8d2015-09-22 07:40:24 +000020import com.google.devtools.build.lib.cmdline.PackageIdentifier.RepositoryName;
Lukacs Berkic7106d42015-10-15 07:45:54 +000021import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
Mark Schallerb889cf32015-03-17 20:55:30 +000022import com.google.devtools.build.lib.events.Event;
23import com.google.devtools.build.lib.events.EventHandler;
Janak Ramakrishnan0a4c6e42015-09-17 00:37:58 +000024import com.google.devtools.build.lib.packages.BuildFileContainsErrorsException;
Mark Schallerb889cf32015-03-17 20:55:30 +000025import com.google.devtools.build.lib.packages.NoSuchPackageException;
26import com.google.devtools.build.lib.packages.NoSuchTargetException;
27import com.google.devtools.build.lib.packages.Package;
Mark Schallerb889cf32015-03-17 20:55:30 +000028import com.google.devtools.build.lib.packages.Target;
Lukacs Berkic7106d42015-10-15 07:45:54 +000029import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
Mark Schallerb889cf32015-03-17 20:55:30 +000030import com.google.devtools.build.lib.pkgcache.RecursivePackageProvider;
Mark Schaller6df81792015-12-10 18:47:47 +000031import com.google.devtools.build.lib.util.Preconditions;
Lukacs Berkic7106d42015-10-15 07:45:54 +000032import com.google.devtools.build.lib.vfs.Path;
Mark Schallerb889cf32015-03-17 20:55:30 +000033import com.google.devtools.build.lib.vfs.PathFragment;
34import com.google.devtools.build.lib.vfs.RootedPath;
35import com.google.devtools.build.skyframe.SkyFunction.Environment;
36import com.google.devtools.build.skyframe.SkyKey;
37
Lukacs Berkic7106d42015-10-15 07:45:54 +000038import java.util.ArrayList;
39import java.util.List;
40
Mark Schallerb889cf32015-03-17 20:55:30 +000041/**
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 Schallerb889cf32015-03-17 20:55:30 +000045 */
46public 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 Ramakrishnan0a4c6e42015-09-17 00:37:58 +000058 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 Schallerb889cf32015-03-17 20:55:30 +000072 throw new MissingDepException();
Janak Ramakrishnan0a4c6e42015-09-17 00:37:58 +000073 } catch (BuildFileContainsErrorsException e) {
74 // Expected.
Mark Schallerb889cf32015-03-17 20:55:30 +000075 }
76 }
Janak Ramakrishnan0a4c6e42015-09-17 00:37:58 +000077 return pkgValue.getPackage();
Mark Schallerb889cf32015-03-17 20:55:30 +000078 }
79
80 @Override
Lukacs Berki33aa1e12015-07-08 08:11:30 +000081 public boolean isPackage(EventHandler eventHandler, PackageIdentifier packageId)
Mark Schallerb889cf32015-03-17 20:55:30 +000082 throws MissingDepException {
Lukacs Berki33aa1e12015-07-08 08:11:30 +000083 SkyKey packageLookupKey = PackageLookupValue.key(packageId);
Mark Schallerb889cf32015-03-17 20:55:30 +000084 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 Berkid72db8d2015-09-22 07:40:24 +000099 public Iterable<PathFragment> getPackagesUnderDirectory(
Lukacs Berkic7106d42015-10-15 07:45:54 +0000100 RepositoryName repository, PathFragment directory,
Mark Schallerf6e32d62015-05-19 20:27:43 +0000101 ImmutableSet<PathFragment> excludedSubdirectories)
Mark Schallerb889cf32015-03-17 20:55:30 +0000102 throws MissingDepException {
Lukacs Berkic7106d42015-10-15 07:45:54 +0000103 PathPackageLocator packageLocator = PrecomputedValue.PATH_PACKAGE_LOCATOR.get(env);
104 if (packageLocator == null) {
Mark Schallerb889cf32015-03-17 20:55:30 +0000105 throw new MissingDepException();
106 }
Lukacs Berkic7106d42015-10-15 07:45:54 +0000107
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 Schallerb889cf32015-03-17 20:55:30 +0000139 // TODO(bazel-team): Make RecursivePkgValue return NestedSet<PathFragment> so this transform is
140 // unnecessary.
Lukacs Berkic7106d42015-10-15 07:45:54 +0000141 return Iterables.transform(packageNames.build(), PathFragment.TO_PATH_FRAGMENT);
Mark Schallerb889cf32015-03-17 20:55:30 +0000142 }
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 Schaller3062abb2015-06-19 20:59:41 +0000156 static class MissingDepException extends RuntimeException {
Mark Schallerb889cf32015-03-17 20:55:30 +0000157 }
158}