Damien Martin-Guillerez | f88f4d8 | 2015-09-25 13:56:55 +0000 | [diff] [blame] | 1 | // Copyright 2014 The Bazel Authors. All rights reserved. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [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 | 35e57cf | 2015-05-27 14:31:11 +0000 | [diff] [blame] | 16 | import com.google.common.cache.Cache; |
John Field | a97e17f | 2015-11-13 02:19:52 +0000 | [diff] [blame] | 17 | import com.google.common.collect.ImmutableCollection; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 18 | import com.google.common.collect.ImmutableList; |
| 19 | import com.google.common.collect.ImmutableMap; |
| 20 | import com.google.common.collect.ImmutableSet; |
| 21 | import com.google.common.collect.Iterables; |
| 22 | import com.google.common.collect.Lists; |
Janak Ramakrishnan | dfd3497 | 2015-09-22 02:53:05 +0000 | [diff] [blame] | 23 | import com.google.common.collect.Maps; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 24 | import com.google.common.collect.Sets; |
Lukacs Berki | 6e91eb9 | 2015-09-21 09:12:37 +0000 | [diff] [blame] | 25 | import com.google.devtools.build.lib.cmdline.Label; |
John Field | a97e17f | 2015-11-13 02:19:52 +0000 | [diff] [blame] | 26 | import com.google.devtools.build.lib.cmdline.LabelSyntaxException; |
Kristina Chodorow | 73fa203 | 2015-08-28 17:57:46 +0000 | [diff] [blame] | 27 | import com.google.devtools.build.lib.cmdline.PackageIdentifier; |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 28 | import com.google.devtools.build.lib.collect.nestedset.NestedSet; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 29 | import com.google.devtools.build.lib.events.Event; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 30 | import com.google.devtools.build.lib.events.Location; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 31 | import com.google.devtools.build.lib.events.StoredEventHandler; |
| 32 | import com.google.devtools.build.lib.packages.BuildFileContainsErrorsException; |
| 33 | import com.google.devtools.build.lib.packages.BuildFileNotFoundException; |
| 34 | import com.google.devtools.build.lib.packages.CachingPackageLocator; |
Nathan Harmata | c5a15d3 | 2016-02-04 23:14:29 +0000 | [diff] [blame] | 35 | import com.google.devtools.build.lib.packages.Globber; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 36 | import com.google.devtools.build.lib.packages.InvalidPackageNameException; |
| 37 | import com.google.devtools.build.lib.packages.NoSuchPackageException; |
| 38 | import com.google.devtools.build.lib.packages.Package; |
| 39 | import com.google.devtools.build.lib.packages.PackageFactory; |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 40 | import com.google.devtools.build.lib.packages.PackageFactory.LegacyGlobber; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 41 | import com.google.devtools.build.lib.packages.Preprocessor; |
Nathan Harmata | 9faad19 | 2015-10-15 18:41:24 +0000 | [diff] [blame] | 42 | import com.google.devtools.build.lib.packages.Preprocessor.AstAfterPreprocessing; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 43 | import com.google.devtools.build.lib.packages.RuleVisibility; |
| 44 | import com.google.devtools.build.lib.packages.Target; |
| 45 | import com.google.devtools.build.lib.profiler.Profiler; |
| 46 | import com.google.devtools.build.lib.profiler.ProfilerTask; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 47 | import com.google.devtools.build.lib.skyframe.GlobValue.InvalidGlobPatternException; |
| 48 | import com.google.devtools.build.lib.skyframe.SkylarkImportLookupFunction.SkylarkImportFailedException; |
| 49 | import com.google.devtools.build.lib.syntax.BuildFileAST; |
Francois-Rene Rideau | 89312fb | 2015-09-10 18:53:03 +0000 | [diff] [blame] | 50 | import com.google.devtools.build.lib.syntax.Environment.Extension; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 51 | import com.google.devtools.build.lib.syntax.EvalException; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 52 | import com.google.devtools.build.lib.syntax.ParserInputSource; |
John Field | 1ea7fc3 | 2015-12-22 19:37:19 +0000 | [diff] [blame] | 53 | import com.google.devtools.build.lib.syntax.SkylarkImport; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 54 | import com.google.devtools.build.lib.syntax.Statement; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 55 | import com.google.devtools.build.lib.util.Pair; |
Mark Schaller | 6df8179 | 2015-12-10 18:47:47 +0000 | [diff] [blame] | 56 | import com.google.devtools.build.lib.util.Preconditions; |
Nathan Harmata | 4e69824 | 2015-10-20 23:18:23 +0000 | [diff] [blame] | 57 | import com.google.devtools.build.lib.vfs.FileSystemUtils; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 58 | import com.google.devtools.build.lib.vfs.Path; |
| 59 | import com.google.devtools.build.lib.vfs.PathFragment; |
| 60 | import com.google.devtools.build.lib.vfs.RootedPath; |
| 61 | import com.google.devtools.build.skyframe.SkyFunction; |
| 62 | import com.google.devtools.build.skyframe.SkyFunctionException; |
| 63 | import com.google.devtools.build.skyframe.SkyFunctionException.Transience; |
| 64 | import com.google.devtools.build.skyframe.SkyKey; |
| 65 | import com.google.devtools.build.skyframe.SkyValue; |
John Field | a97e17f | 2015-11-13 02:19:52 +0000 | [diff] [blame] | 66 | import com.google.devtools.build.skyframe.ValueOrException2; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 67 | import com.google.devtools.build.skyframe.ValueOrException3; |
| 68 | import com.google.devtools.build.skyframe.ValueOrException4; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 69 | import java.io.IOException; |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 70 | import java.util.ArrayList; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 71 | import java.util.Collection; |
Janak Ramakrishnan | 063b488 | 2016-07-18 20:33:28 +0000 | [diff] [blame] | 72 | import java.util.Collections; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 73 | import java.util.HashMap; |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 74 | import java.util.HashSet; |
Janak Ramakrishnan | f4dd283 | 2016-10-10 23:56:01 +0000 | [diff] [blame^] | 75 | import java.util.LinkedHashMap; |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 76 | import java.util.LinkedHashSet; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 77 | import java.util.List; |
| 78 | import java.util.Map; |
| 79 | import java.util.Map.Entry; |
| 80 | import java.util.Set; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 81 | import java.util.concurrent.atomic.AtomicBoolean; |
| 82 | import java.util.concurrent.atomic.AtomicInteger; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 83 | import javax.annotation.Nullable; |
| 84 | |
| 85 | /** |
| 86 | * A SkyFunction for {@link PackageValue}s. |
| 87 | */ |
| 88 | public class PackageFunction implements SkyFunction { |
| 89 | |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 90 | private final PackageFactory packageFactory; |
| 91 | private final CachingPackageLocator packageLocator; |
Nathan Harmata | 6b253fa | 2016-05-24 15:27:18 +0000 | [diff] [blame] | 92 | private final Cache<PackageIdentifier, CacheEntryWithGlobDeps<Package.Builder>> |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 93 | packageFunctionCache; |
| 94 | private final Cache<PackageIdentifier, CacheEntryWithGlobDeps<AstAfterPreprocessing>> astCache; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 95 | private final AtomicBoolean showLoadingProgress; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 96 | private final AtomicInteger numPackagesLoaded; |
Klaus Aehlig | c6fd6bb | 2016-05-27 11:42:32 +0000 | [diff] [blame] | 97 | private final PackageProgressReceiver packageProgress; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 98 | private final Profiler profiler = Profiler.instance(); |
John Field | a97e17f | 2015-11-13 02:19:52 +0000 | [diff] [blame] | 99 | private final Label preludeLabel; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 100 | |
Janak Ramakrishnan | df0531f | 2015-09-23 17:30:04 +0000 | [diff] [blame] | 101 | // Not final only for testing. |
| 102 | @Nullable private SkylarkImportLookupFunction skylarkImportLookupFunctionForInlining; |
| 103 | |
Lukacs Berki | 5131ef9 | 2015-10-09 14:20:03 +0000 | [diff] [blame] | 104 | static final PathFragment DEFAULTS_PACKAGE_NAME = new PathFragment("tools/defaults"); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 105 | |
Janak Ramakrishnan | df0531f | 2015-09-23 17:30:04 +0000 | [diff] [blame] | 106 | public PackageFunction( |
Janak Ramakrishnan | df0531f | 2015-09-23 17:30:04 +0000 | [diff] [blame] | 107 | PackageFactory packageFactory, |
| 108 | CachingPackageLocator pkgLocator, |
| 109 | AtomicBoolean showLoadingProgress, |
Nathan Harmata | 6b253fa | 2016-05-24 15:27:18 +0000 | [diff] [blame] | 110 | Cache<PackageIdentifier, CacheEntryWithGlobDeps<Package.Builder>> packageFunctionCache, |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 111 | Cache<PackageIdentifier, CacheEntryWithGlobDeps<AstAfterPreprocessing>> astCache, |
Janak Ramakrishnan | df0531f | 2015-09-23 17:30:04 +0000 | [diff] [blame] | 112 | AtomicInteger numPackagesLoaded, |
Klaus Aehlig | c6fd6bb | 2016-05-27 11:42:32 +0000 | [diff] [blame] | 113 | @Nullable SkylarkImportLookupFunction skylarkImportLookupFunctionForInlining, |
| 114 | @Nullable PackageProgressReceiver packageProgress) { |
Janak Ramakrishnan | df0531f | 2015-09-23 17:30:04 +0000 | [diff] [blame] | 115 | this.skylarkImportLookupFunctionForInlining = skylarkImportLookupFunctionForInlining; |
Ulf Adams | fdfdd92 | 2015-09-01 08:36:29 +0000 | [diff] [blame] | 116 | // Can be null in tests. |
John Field | a97e17f | 2015-11-13 02:19:52 +0000 | [diff] [blame] | 117 | this.preludeLabel = packageFactory == null |
Ulf Adams | fdfdd92 | 2015-09-01 08:36:29 +0000 | [diff] [blame] | 118 | ? null |
John Field | a97e17f | 2015-11-13 02:19:52 +0000 | [diff] [blame] | 119 | : packageFactory.getRuleClassProvider().getPreludeLabel(); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 120 | this.packageFactory = packageFactory; |
| 121 | this.packageLocator = pkgLocator; |
| 122 | this.showLoadingProgress = showLoadingProgress; |
| 123 | this.packageFunctionCache = packageFunctionCache; |
Nathan Harmata | 9faad19 | 2015-10-15 18:41:24 +0000 | [diff] [blame] | 124 | this.astCache = astCache; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 125 | this.numPackagesLoaded = numPackagesLoaded; |
Klaus Aehlig | c6fd6bb | 2016-05-27 11:42:32 +0000 | [diff] [blame] | 126 | this.packageProgress = packageProgress; |
| 127 | } |
| 128 | |
| 129 | public PackageFunction( |
| 130 | PackageFactory packageFactory, |
| 131 | CachingPackageLocator pkgLocator, |
| 132 | AtomicBoolean showLoadingProgress, |
| 133 | Cache<PackageIdentifier, CacheEntryWithGlobDeps<Package.Builder>> packageFunctionCache, |
| 134 | Cache<PackageIdentifier, CacheEntryWithGlobDeps<AstAfterPreprocessing>> astCache, |
| 135 | AtomicInteger numPackagesLoaded, |
| 136 | @Nullable SkylarkImportLookupFunction skylarkImportLookupFunctionForInlining) { |
| 137 | this( |
| 138 | packageFactory, |
| 139 | pkgLocator, |
| 140 | showLoadingProgress, |
| 141 | packageFunctionCache, |
| 142 | astCache, |
| 143 | numPackagesLoaded, |
| 144 | skylarkImportLookupFunctionForInlining, |
| 145 | null); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 146 | } |
| 147 | |
Janak Ramakrishnan | df0531f | 2015-09-23 17:30:04 +0000 | [diff] [blame] | 148 | public void setSkylarkImportLookupFunctionForInliningForTesting( |
| 149 | SkylarkImportLookupFunction skylarkImportLookupFunctionForInlining) { |
| 150 | this.skylarkImportLookupFunctionForInlining = skylarkImportLookupFunctionForInlining; |
| 151 | } |
| 152 | |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 153 | /** An entry in {@link PackageFunction}'s internal caches. */ |
| 154 | public static class CacheEntryWithGlobDeps<T> { |
| 155 | private final T value; |
| 156 | private final Set<SkyKey> globDepKeys; |
| 157 | @Nullable |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 158 | private final LegacyGlobber legacyGlobber; |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 159 | |
| 160 | private CacheEntryWithGlobDeps(T value, Set<SkyKey> globDepKeys, |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 161 | @Nullable LegacyGlobber legacyGlobber) { |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 162 | this.value = value; |
| 163 | this.globDepKeys = globDepKeys; |
| 164 | this.legacyGlobber = legacyGlobber; |
| 165 | } |
| 166 | } |
| 167 | |
Kristina Chodorow | e121dd9 | 2015-06-17 14:24:35 +0000 | [diff] [blame] | 168 | private static void maybeThrowFilesystemInconsistency(PackageIdentifier packageIdentifier, |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 169 | Exception skyframeException, boolean packageWasInError) |
| 170 | throws InternalInconsistentFilesystemException { |
| 171 | if (!packageWasInError) { |
Kristina Chodorow | e121dd9 | 2015-06-17 14:24:35 +0000 | [diff] [blame] | 172 | throw new InternalInconsistentFilesystemException(packageIdentifier, "Encountered error '" |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 173 | + skyframeException.getMessage() + "' but didn't encounter it when doing the same thing " |
| 174 | + "earlier in the build"); |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | /** |
Janak Ramakrishnan | 3c0adb2 | 2016-08-15 21:54:55 +0000 | [diff] [blame] | 179 | * Marks the given dependencies, and returns those already present. Ignores any exception thrown |
| 180 | * while building the dependency, except for filesystem inconsistencies. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 181 | * |
| 182 | * <p>We need to mark dependencies implicitly used by the legacy package loading code, but we |
| 183 | * don't care about any skyframe errors since the package knows whether it's in error or not. |
| 184 | */ |
| 185 | private static Pair<? extends Map<PathFragment, PackageLookupValue>, Boolean> |
Janak Ramakrishnan | 3c0adb2 | 2016-08-15 21:54:55 +0000 | [diff] [blame] | 186 | getPackageLookupDepsAndPropagateInconsistentFilesystemExceptions( |
| 187 | PackageIdentifier packageIdentifier, |
| 188 | Iterable<SkyKey> depKeys, |
| 189 | Environment env, |
| 190 | boolean packageWasInError) |
| 191 | throws InternalInconsistentFilesystemException, InterruptedException { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 192 | Preconditions.checkState( |
| 193 | Iterables.all(depKeys, SkyFunctions.isSkyFunction(SkyFunctions.PACKAGE_LOOKUP)), depKeys); |
| 194 | boolean packageShouldBeInError = packageWasInError; |
| 195 | ImmutableMap.Builder<PathFragment, PackageLookupValue> builder = ImmutableMap.builder(); |
| 196 | for (Map.Entry<SkyKey, ValueOrException3<BuildFileNotFoundException, |
Nathan Harmata | ad81050 | 2015-07-29 01:33:49 +0000 | [diff] [blame] | 197 | InconsistentFilesystemException, FileSymlinkException>> entry : |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 198 | env.getValuesOrThrow(depKeys, BuildFileNotFoundException.class, |
| 199 | InconsistentFilesystemException.class, |
Nathan Harmata | ad81050 | 2015-07-29 01:33:49 +0000 | [diff] [blame] | 200 | FileSymlinkException.class).entrySet()) { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 201 | PathFragment pkgName = ((PackageIdentifier) entry.getKey().argument()).getPackageFragment(); |
| 202 | try { |
| 203 | PackageLookupValue value = (PackageLookupValue) entry.getValue().get(); |
| 204 | if (value != null) { |
| 205 | builder.put(pkgName, value); |
| 206 | } |
| 207 | } catch (BuildFileNotFoundException e) { |
Kristina Chodorow | e121dd9 | 2015-06-17 14:24:35 +0000 | [diff] [blame] | 208 | maybeThrowFilesystemInconsistency(packageIdentifier, e, packageWasInError); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 209 | } catch (InconsistentFilesystemException e) { |
Kristina Chodorow | e121dd9 | 2015-06-17 14:24:35 +0000 | [diff] [blame] | 210 | throw new InternalInconsistentFilesystemException(packageIdentifier, e); |
Nathan Harmata | ad81050 | 2015-07-29 01:33:49 +0000 | [diff] [blame] | 211 | } catch (FileSymlinkException e) { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 212 | // Legacy doesn't detect symlink cycles. |
| 213 | packageShouldBeInError = true; |
| 214 | } |
| 215 | } |
| 216 | return Pair.of(builder.build(), packageShouldBeInError); |
| 217 | } |
| 218 | |
Janak Ramakrishnan | fb040f6 | 2016-06-23 16:05:04 +0000 | [diff] [blame] | 219 | private static boolean markFileDepsAndPropagateFilesystemExceptions( |
| 220 | PackageIdentifier packageIdentifier, |
| 221 | Iterable<SkyKey> depKeys, |
| 222 | Environment env, |
| 223 | boolean packageWasInError) |
| 224 | throws InternalInconsistentFilesystemException, FileOutsidePackageRootsException, |
Janak Ramakrishnan | 3c0adb2 | 2016-08-15 21:54:55 +0000 | [diff] [blame] | 225 | SymlinkOutsidePackageRootsException, InterruptedException { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 226 | Preconditions.checkState( |
| 227 | Iterables.all(depKeys, SkyFunctions.isSkyFunction(SkyFunctions.FILE)), depKeys); |
| 228 | boolean packageShouldBeInError = packageWasInError; |
Nathan Harmata | ad81050 | 2015-07-29 01:33:49 +0000 | [diff] [blame] | 229 | for (Map.Entry<SkyKey, ValueOrException3<IOException, FileSymlinkException, |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 230 | InconsistentFilesystemException>> entry : env.getValuesOrThrow(depKeys, IOException.class, |
Nathan Harmata | ad81050 | 2015-07-29 01:33:49 +0000 | [diff] [blame] | 231 | FileSymlinkException.class, InconsistentFilesystemException.class).entrySet()) { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 232 | try { |
| 233 | entry.getValue().get(); |
Janak Ramakrishnan | fb040f6 | 2016-06-23 16:05:04 +0000 | [diff] [blame] | 234 | } catch (FileOutsidePackageRootsException | SymlinkOutsidePackageRootsException e) { |
| 235 | throw e; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 236 | } catch (IOException e) { |
Kristina Chodorow | e121dd9 | 2015-06-17 14:24:35 +0000 | [diff] [blame] | 237 | maybeThrowFilesystemInconsistency(packageIdentifier, e, packageWasInError); |
Nathan Harmata | ad81050 | 2015-07-29 01:33:49 +0000 | [diff] [blame] | 238 | } catch (FileSymlinkException e) { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 239 | // Legacy doesn't detect symlink cycles. |
| 240 | packageShouldBeInError = true; |
| 241 | } catch (InconsistentFilesystemException e) { |
Kristina Chodorow | e121dd9 | 2015-06-17 14:24:35 +0000 | [diff] [blame] | 242 | throw new InternalInconsistentFilesystemException(packageIdentifier, e); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 243 | } |
| 244 | } |
| 245 | return packageShouldBeInError; |
| 246 | } |
| 247 | |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 248 | /** |
| 249 | * These deps have already been marked (see {@link SkyframeHybridGlobber}) but we need to properly |
| 250 | * handle some errors that legacy package loading can't handle gracefully. |
| 251 | */ |
Janak Ramakrishnan | fb040f6 | 2016-06-23 16:05:04 +0000 | [diff] [blame] | 252 | private static boolean handleGlobDepsAndPropagateFilesystemExceptions( |
| 253 | PackageIdentifier packageIdentifier, |
| 254 | Iterable<SkyKey> depKeys, |
| 255 | Environment env, |
| 256 | boolean packageWasInError) |
| 257 | throws InternalInconsistentFilesystemException, FileOutsidePackageRootsException, |
Janak Ramakrishnan | 3c0adb2 | 2016-08-15 21:54:55 +0000 | [diff] [blame] | 258 | SymlinkOutsidePackageRootsException, InterruptedException { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 259 | Preconditions.checkState( |
| 260 | Iterables.all(depKeys, SkyFunctions.isSkyFunction(SkyFunctions.GLOB)), depKeys); |
| 261 | boolean packageShouldBeInError = packageWasInError; |
| 262 | for (Map.Entry<SkyKey, ValueOrException4<IOException, BuildFileNotFoundException, |
Nathan Harmata | ad81050 | 2015-07-29 01:33:49 +0000 | [diff] [blame] | 263 | FileSymlinkException, InconsistentFilesystemException>> entry : |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 264 | env.getValuesOrThrow(depKeys, IOException.class, BuildFileNotFoundException.class, |
Nathan Harmata | ad81050 | 2015-07-29 01:33:49 +0000 | [diff] [blame] | 265 | FileSymlinkException.class, InconsistentFilesystemException.class).entrySet()) { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 266 | try { |
| 267 | entry.getValue().get(); |
Janak Ramakrishnan | fb040f6 | 2016-06-23 16:05:04 +0000 | [diff] [blame] | 268 | } catch (FileOutsidePackageRootsException | SymlinkOutsidePackageRootsException e) { |
| 269 | throw e; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 270 | } catch (IOException | BuildFileNotFoundException e) { |
Kristina Chodorow | e121dd9 | 2015-06-17 14:24:35 +0000 | [diff] [blame] | 271 | maybeThrowFilesystemInconsistency(packageIdentifier, e, packageWasInError); |
Nathan Harmata | ad81050 | 2015-07-29 01:33:49 +0000 | [diff] [blame] | 272 | } catch (FileSymlinkException e) { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 273 | // Legacy doesn't detect symlink cycles. |
| 274 | packageShouldBeInError = true; |
| 275 | } catch (InconsistentFilesystemException e) { |
Kristina Chodorow | e121dd9 | 2015-06-17 14:24:35 +0000 | [diff] [blame] | 276 | throw new InternalInconsistentFilesystemException(packageIdentifier, e); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 277 | } |
| 278 | } |
| 279 | return packageShouldBeInError; |
| 280 | } |
| 281 | |
| 282 | /** |
| 283 | * Marks dependencies implicitly used by legacy package loading code, after the fact. Note that |
| 284 | * the given package might already be in error. |
| 285 | * |
Janak Ramakrishnan | fb040f6 | 2016-06-23 16:05:04 +0000 | [diff] [blame] | 286 | * <p>Most skyframe exceptions encountered here are ignored, as similar errors should have already |
| 287 | * been encountered by legacy package loading (if not, then the filesystem is inconsistent). Some |
| 288 | * exceptions that Skyframe is stricter about (disallowed access to files outside package roots) |
| 289 | * are propagated. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 290 | */ |
Janak Ramakrishnan | fb040f6 | 2016-06-23 16:05:04 +0000 | [diff] [blame] | 291 | private static boolean markDependenciesAndPropagateFilesystemExceptions( |
Janak Ramakrishnan | 0a4c6e4 | 2015-09-17 00:37:58 +0000 | [diff] [blame] | 292 | Environment env, |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 293 | Set<SkyKey> globDepKeys, |
Janak Ramakrishnan | 0a4c6e4 | 2015-09-17 00:37:58 +0000 | [diff] [blame] | 294 | Map<Label, Path> subincludes, |
| 295 | PackageIdentifier packageIdentifier, |
| 296 | boolean containsErrors) |
Janak Ramakrishnan | fb040f6 | 2016-06-23 16:05:04 +0000 | [diff] [blame] | 297 | throws InternalInconsistentFilesystemException, FileOutsidePackageRootsException, |
Janak Ramakrishnan | 3c0adb2 | 2016-08-15 21:54:55 +0000 | [diff] [blame] | 298 | SymlinkOutsidePackageRootsException, InterruptedException { |
Janak Ramakrishnan | 0a4c6e4 | 2015-09-17 00:37:58 +0000 | [diff] [blame] | 299 | boolean packageShouldBeInError = containsErrors; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 300 | |
| 301 | // TODO(bazel-team): This means that many packages will have to be preprocessed twice. Ouch! |
| 302 | // We need a better continuation mechanism to avoid repeating work. [skyframe-loading] |
| 303 | |
| 304 | // TODO(bazel-team): It would be preferable to perform I/O from the package preprocessor via |
| 305 | // Skyframe rather than add (potentially incomplete) dependencies after the fact. |
| 306 | // [skyframe-loading] |
| 307 | |
| 308 | Set<SkyKey> subincludePackageLookupDepKeys = Sets.newHashSet(); |
Janak Ramakrishnan | 0a4c6e4 | 2015-09-17 00:37:58 +0000 | [diff] [blame] | 309 | for (Label label : subincludes.keySet()) { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 310 | // Declare a dependency on the package lookup for the package giving access to the label. |
Lukacs Berki | f445ea1 | 2015-07-09 07:16:41 +0000 | [diff] [blame] | 311 | subincludePackageLookupDepKeys.add(PackageLookupValue.key(label.getPackageIdentifier())); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 312 | } |
| 313 | Pair<? extends Map<PathFragment, PackageLookupValue>, Boolean> subincludePackageLookupResult = |
Kristina Chodorow | e121dd9 | 2015-06-17 14:24:35 +0000 | [diff] [blame] | 314 | getPackageLookupDepsAndPropagateInconsistentFilesystemExceptions( |
Janak Ramakrishnan | 0a4c6e4 | 2015-09-17 00:37:58 +0000 | [diff] [blame] | 315 | packageIdentifier, subincludePackageLookupDepKeys, env, containsErrors); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 316 | Map<PathFragment, PackageLookupValue> subincludePackageLookupDeps = |
| 317 | subincludePackageLookupResult.getFirst(); |
Mark Schaller | 6fc9f88 | 2015-06-12 17:53:57 +0000 | [diff] [blame] | 318 | packageShouldBeInError |= subincludePackageLookupResult.getSecond(); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 319 | List<SkyKey> subincludeFileDepKeys = Lists.newArrayList(); |
| 320 | for (Entry<Label, Path> subincludeEntry : subincludes.entrySet()) { |
| 321 | // Ideally, we would have a direct dependency on the target with the given label, but then |
| 322 | // subincluding a file from the same package will cause a dependency cycle, since targets |
| 323 | // depend on their containing packages. |
| 324 | Label label = subincludeEntry.getKey(); |
| 325 | PackageLookupValue subincludePackageLookupValue = |
| 326 | subincludePackageLookupDeps.get(label.getPackageFragment()); |
| 327 | if (subincludePackageLookupValue != null) { |
| 328 | // Declare a dependency on the actual file that was subincluded. |
| 329 | Path subincludeFilePath = subincludeEntry.getValue(); |
Janak Ramakrishnan | 0a4c6e4 | 2015-09-17 00:37:58 +0000 | [diff] [blame] | 330 | if (subincludeFilePath != null && !subincludePackageLookupValue.packageExists()) { |
| 331 | // Legacy blaze puts a non-null path when only when the package does indeed exist. |
| 332 | throw new InternalInconsistentFilesystemException( |
| 333 | packageIdentifier, |
| 334 | String.format( |
| 335 | "Unexpected package in %s. Was it modified during the build?", |
| 336 | subincludeFilePath)); |
| 337 | } |
| 338 | if (subincludePackageLookupValue.packageExists()) { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 339 | // Sanity check for consistency of Skyframe and legacy blaze. |
| 340 | Path subincludeFilePathSkyframe = |
| 341 | subincludePackageLookupValue.getRoot().getRelative(label.toPathFragment()); |
Janak Ramakrishnan | 0a4c6e4 | 2015-09-17 00:37:58 +0000 | [diff] [blame] | 342 | if (subincludeFilePath != null |
| 343 | && !subincludeFilePathSkyframe.equals(subincludeFilePath)) { |
| 344 | throw new InternalInconsistentFilesystemException( |
| 345 | packageIdentifier, |
| 346 | String.format( |
| 347 | "Inconsistent package location for %s: '%s' vs '%s'. " |
| 348 | + "Was the source tree modified during the build?", |
| 349 | label.getPackageFragment(), |
| 350 | subincludeFilePathSkyframe, |
| 351 | subincludeFilePath)); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 352 | } |
| 353 | // The actual file may be under a different package root than the package being |
| 354 | // constructed. |
| 355 | SkyKey subincludeSkyKey = |
Janak Ramakrishnan | 0a4c6e4 | 2015-09-17 00:37:58 +0000 | [diff] [blame] | 356 | FileValue.key( |
| 357 | RootedPath.toRootedPath( |
| 358 | subincludePackageLookupValue.getRoot(), |
| 359 | label.getPackageFragment().getRelative(label.getName()))); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 360 | subincludeFileDepKeys.add(subincludeSkyKey); |
| 361 | } |
| 362 | } |
| 363 | } |
Janak Ramakrishnan | 0a4c6e4 | 2015-09-17 00:37:58 +0000 | [diff] [blame] | 364 | packageShouldBeInError |= |
Janak Ramakrishnan | fb040f6 | 2016-06-23 16:05:04 +0000 | [diff] [blame] | 365 | markFileDepsAndPropagateFilesystemExceptions( |
Janak Ramakrishnan | 0a4c6e4 | 2015-09-17 00:37:58 +0000 | [diff] [blame] | 366 | packageIdentifier, subincludeFileDepKeys, env, containsErrors); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 367 | |
Janak Ramakrishnan | 0a4c6e4 | 2015-09-17 00:37:58 +0000 | [diff] [blame] | 368 | packageShouldBeInError |= |
Janak Ramakrishnan | fb040f6 | 2016-06-23 16:05:04 +0000 | [diff] [blame] | 369 | handleGlobDepsAndPropagateFilesystemExceptions( |
Janak Ramakrishnan | 0a4c6e4 | 2015-09-17 00:37:58 +0000 | [diff] [blame] | 370 | packageIdentifier, globDepKeys, env, containsErrors); |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 371 | |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 372 | return packageShouldBeInError; |
| 373 | } |
| 374 | |
| 375 | /** |
| 376 | * Adds a dependency on the WORKSPACE file, representing it as a special type of package. |
Janak Ramakrishnan | 3c0adb2 | 2016-08-15 21:54:55 +0000 | [diff] [blame] | 377 | * |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 378 | * @throws PackageFunctionException if there is an error computing the workspace file or adding |
Janak Ramakrishnan | 3c0adb2 | 2016-08-15 21:54:55 +0000 | [diff] [blame] | 379 | * its rules to the //external package. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 380 | */ |
| 381 | private SkyValue getExternalPackage(Environment env, Path packageLookupPath) |
Janak Ramakrishnan | 3c0adb2 | 2016-08-15 21:54:55 +0000 | [diff] [blame] | 382 | throws PackageFunctionException, InterruptedException { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 383 | RootedPath workspacePath = RootedPath.toRootedPath( |
Nathan Harmata | c686fd6 | 2016-04-26 17:41:20 +0000 | [diff] [blame] | 384 | packageLookupPath, Label.EXTERNAL_PACKAGE_FILE_NAME); |
Damien Martin-Guillerez | bc8b5e0 | 2016-02-05 22:09:09 +0000 | [diff] [blame] | 385 | SkyKey workspaceKey = ExternalPackageFunction.key(workspacePath); |
Kristina Chodorow | 91876f0 | 2015-02-27 17:14:12 +0000 | [diff] [blame] | 386 | PackageValue workspace = null; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 387 | try { |
Janak Ramakrishnan | 593d656 | 2016-06-22 18:54:56 +0000 | [diff] [blame] | 388 | // This may throw a NoSuchPackageException if the WORKSPACE file was malformed or had other |
| 389 | // problems. Since this function can't add much context, we silently bubble it up. |
| 390 | workspace = |
| 391 | (PackageValue) |
| 392 | env.getValueOrThrow( |
| 393 | workspaceKey, |
| 394 | IOException.class, |
| 395 | FileSymlinkException.class, |
| 396 | InconsistentFilesystemException.class, |
| 397 | EvalException.class, |
| 398 | SkylarkImportFailedException.class); |
Nathan Harmata | ad81050 | 2015-07-29 01:33:49 +0000 | [diff] [blame] | 399 | } catch (IOException | FileSymlinkException | InconsistentFilesystemException |
John Field | bcb1bea | 2016-01-16 19:05:56 +0000 | [diff] [blame] | 400 | | EvalException | SkylarkImportFailedException e) { |
Googler | 3aae85f | 2016-04-11 14:57:06 +0000 | [diff] [blame] | 401 | throw new PackageFunctionException( |
| 402 | new NoSuchPackageException( |
| 403 | Label.EXTERNAL_PACKAGE_IDENTIFIER, |
| 404 | "Error encountered while dealing with the WORKSPACE file: " + e.getMessage()), |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 405 | Transience.PERSISTENT); |
| 406 | } |
| 407 | if (workspace == null) { |
| 408 | return null; |
| 409 | } |
| 410 | |
| 411 | Package pkg = workspace.getPackage(); |
| 412 | Event.replayEventsOn(env.getListener(), pkg.getEvents()); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 413 | |
Nathan Harmata | caa000a | 2016-06-07 17:46:19 +0000 | [diff] [blame] | 414 | packageFactory.afterDoneLoadingPackage(pkg); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 415 | return new PackageValue(pkg); |
| 416 | } |
| 417 | |
| 418 | @Override |
| 419 | public SkyValue compute(SkyKey key, Environment env) throws PackageFunctionException, |
| 420 | InterruptedException { |
| 421 | PackageIdentifier packageId = (PackageIdentifier) key.argument(); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 422 | |
| 423 | SkyKey packageLookupKey = PackageLookupValue.key(packageId); |
| 424 | PackageLookupValue packageLookupValue; |
| 425 | try { |
| 426 | packageLookupValue = (PackageLookupValue) |
| 427 | env.getValueOrThrow(packageLookupKey, BuildFileNotFoundException.class, |
| 428 | InconsistentFilesystemException.class); |
| 429 | } catch (BuildFileNotFoundException e) { |
| 430 | throw new PackageFunctionException(e, Transience.PERSISTENT); |
| 431 | } catch (InconsistentFilesystemException e) { |
| 432 | // This error is not transient from the perspective of the PackageFunction. |
| 433 | throw new PackageFunctionException( |
Googler | 3aae85f | 2016-04-11 14:57:06 +0000 | [diff] [blame] | 434 | new NoSuchPackageException(packageId, e.getMessage(), e), Transience.PERSISTENT); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 435 | } |
| 436 | if (packageLookupValue == null) { |
| 437 | return null; |
| 438 | } |
| 439 | |
| 440 | if (!packageLookupValue.packageExists()) { |
| 441 | switch (packageLookupValue.getErrorReason()) { |
| 442 | case NO_BUILD_FILE: |
| 443 | case DELETED_PACKAGE: |
Kristina Chodorow | e121dd9 | 2015-06-17 14:24:35 +0000 | [diff] [blame] | 444 | throw new PackageFunctionException(new BuildFileNotFoundException(packageId, |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 445 | packageLookupValue.getErrorMsg()), Transience.PERSISTENT); |
| 446 | case INVALID_PACKAGE_NAME: |
Kristina Chodorow | e121dd9 | 2015-06-17 14:24:35 +0000 | [diff] [blame] | 447 | throw new PackageFunctionException(new InvalidPackageNameException(packageId, |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 448 | packageLookupValue.getErrorMsg()), Transience.PERSISTENT); |
| 449 | default: |
| 450 | // We should never get here. |
Ulf Adams | 07dba94 | 2015-03-05 14:47:37 +0000 | [diff] [blame] | 451 | throw new IllegalStateException(); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 452 | } |
| 453 | } |
| 454 | |
Lukacs Berki | e19ee27 | 2015-12-10 11:34:29 +0000 | [diff] [blame] | 455 | if (packageId.equals(Label.EXTERNAL_PACKAGE_IDENTIFIER)) { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 456 | return getExternalPackage(env, packageLookupValue.getRoot()); |
| 457 | } |
Lukacs Berki | e19ee27 | 2015-12-10 11:34:29 +0000 | [diff] [blame] | 458 | SkyKey externalPackageKey = PackageValue.key(Label.EXTERNAL_PACKAGE_IDENTIFIER); |
Janak Ramakrishnan | 0a4c6e4 | 2015-09-17 00:37:58 +0000 | [diff] [blame] | 459 | PackageValue externalPackage = (PackageValue) env.getValue(externalPackageKey); |
Kristina Chodorow | 91876f0 | 2015-02-27 17:14:12 +0000 | [diff] [blame] | 460 | if (externalPackage == null) { |
| 461 | return null; |
| 462 | } |
| 463 | Package externalPkg = externalPackage.getPackage(); |
Janak Ramakrishnan | 0a4c6e4 | 2015-09-17 00:37:58 +0000 | [diff] [blame] | 464 | if (externalPkg.containsErrors()) { |
| 465 | throw new PackageFunctionException( |
Lukacs Berki | e19ee27 | 2015-12-10 11:34:29 +0000 | [diff] [blame] | 466 | new BuildFileContainsErrorsException(Label.EXTERNAL_PACKAGE_IDENTIFIER), |
Janak Ramakrishnan | 0a4c6e4 | 2015-09-17 00:37:58 +0000 | [diff] [blame] | 467 | Transience.PERSISTENT); |
| 468 | } |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 469 | |
John Cater | 9469591 | 2016-08-03 12:09:39 +0000 | [diff] [blame] | 470 | RootedPath buildFileRootedPath = packageLookupValue.getRootedPath(packageId); |
Lukacs Berki | 5131ef9 | 2015-10-09 14:20:03 +0000 | [diff] [blame] | 471 | FileValue buildFileValue = null; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 472 | Path buildFilePath = buildFileRootedPath.asPath(); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 473 | String replacementContents = null; |
Lukacs Berki | b018ee3 | 2015-10-19 08:22:23 +0000 | [diff] [blame] | 474 | |
| 475 | if (!isDefaultsPackage(packageId)) { |
| 476 | buildFileValue = getBuildFileValue(env, buildFileRootedPath); |
| 477 | if (buildFileValue == null) { |
| 478 | return null; |
| 479 | } |
| 480 | } else { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 481 | replacementContents = PrecomputedValue.DEFAULTS_PACKAGE_CONTENTS.get(env); |
| 482 | if (replacementContents == null) { |
| 483 | return null; |
| 484 | } |
| 485 | } |
| 486 | |
| 487 | RuleVisibility defaultVisibility = PrecomputedValue.DEFAULT_VISIBILITY.get(env); |
| 488 | if (defaultVisibility == null) { |
| 489 | return null; |
| 490 | } |
| 491 | |
John Field | a97e17f | 2015-11-13 02:19:52 +0000 | [diff] [blame] | 492 | SkyKey astLookupKey = ASTFileLookupValue.key(preludeLabel); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 493 | ASTFileLookupValue astLookupValue = null; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 494 | try { |
| 495 | astLookupValue = (ASTFileLookupValue) env.getValueOrThrow(astLookupKey, |
| 496 | ErrorReadingSkylarkExtensionException.class, InconsistentFilesystemException.class); |
| 497 | } catch (ErrorReadingSkylarkExtensionException | InconsistentFilesystemException e) { |
John Field | a97e17f | 2015-11-13 02:19:52 +0000 | [diff] [blame] | 498 | throw new PackageFunctionException( |
Googler | 3aae85f | 2016-04-11 14:57:06 +0000 | [diff] [blame] | 499 | new NoSuchPackageException( |
| 500 | packageId, "Error encountered while reading the prelude file: " + e.getMessage()), |
| 501 | Transience.PERSISTENT); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 502 | } |
| 503 | if (astLookupValue == null) { |
| 504 | return null; |
| 505 | } |
John Field | a97e17f | 2015-11-13 02:19:52 +0000 | [diff] [blame] | 506 | // The prelude file doesn't have to exist. If not, we substitute an empty statement list. |
| 507 | List<Statement> preludeStatements = |
| 508 | astLookupValue.lookupSuccessful() |
| 509 | ? astLookupValue.getAST().getStatements() : ImmutableList.<Statement>of(); |
Nathan Harmata | 6b253fa | 2016-05-24 15:27:18 +0000 | [diff] [blame] | 510 | CacheEntryWithGlobDeps<Package.Builder> packageBuilderAndGlobDeps = |
Han-Wen Nienhuys | dab4313 | 2015-08-06 16:44:44 +0000 | [diff] [blame] | 511 | loadPackage( |
| 512 | externalPkg, |
Han-Wen Nienhuys | dab4313 | 2015-08-06 16:44:44 +0000 | [diff] [blame] | 513 | replacementContents, |
| 514 | packageId, |
| 515 | buildFilePath, |
Nathan Harmata | 5a9b699 | 2015-10-13 19:52:41 +0000 | [diff] [blame] | 516 | buildFileValue, |
Han-Wen Nienhuys | dab4313 | 2015-08-06 16:44:44 +0000 | [diff] [blame] | 517 | defaultVisibility, |
| 518 | preludeStatements, |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 519 | packageLookupValue.getRoot(), |
Han-Wen Nienhuys | 0648018 | 2015-08-07 15:22:35 +0000 | [diff] [blame] | 520 | env); |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 521 | if (packageBuilderAndGlobDeps == null) { |
Han-Wen Nienhuys | 0648018 | 2015-08-07 15:22:35 +0000 | [diff] [blame] | 522 | return null; |
| 523 | } |
Nathan Harmata | 6b253fa | 2016-05-24 15:27:18 +0000 | [diff] [blame] | 524 | Package.Builder pkgBuilder = packageBuilderAndGlobDeps.value; |
| 525 | pkgBuilder.buildPartial(); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 526 | try { |
Nathan Harmata | 1cf8e3b | 2015-10-17 00:19:05 +0000 | [diff] [blame] | 527 | // Since the Skyframe dependencies we request below in |
Janak Ramakrishnan | fb040f6 | 2016-06-23 16:05:04 +0000 | [diff] [blame] | 528 | // markDependenciesAndPropagateFilesystemExceptions are requested independently of |
Nathan Harmata | 1cf8e3b | 2015-10-17 00:19:05 +0000 | [diff] [blame] | 529 | // the ones requested here in |
| 530 | // handleLabelsCrossingSubpackagesAndPropagateInconsistentFilesystemExceptions, we don't |
| 531 | // bother checking for missing values and instead piggyback on the env.missingValues() call |
| 532 | // for the former. This avoids a Skyframe restart. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 533 | handleLabelsCrossingSubpackagesAndPropagateInconsistentFilesystemExceptions( |
Nathan Harmata | 6b253fa | 2016-05-24 15:27:18 +0000 | [diff] [blame] | 534 | packageLookupValue.getRoot(), packageId, pkgBuilder, env); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 535 | } catch (InternalInconsistentFilesystemException e) { |
Eric Fellheimer | 35e57cf | 2015-05-27 14:31:11 +0000 | [diff] [blame] | 536 | packageFunctionCache.invalidate(packageId); |
Googler | 3aae85f | 2016-04-11 14:57:06 +0000 | [diff] [blame] | 537 | throw new PackageFunctionException( |
| 538 | e.toNoSuchPackageException(), |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 539 | e.isTransient() ? Transience.TRANSIENT : Transience.PERSISTENT); |
| 540 | } |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 541 | Set<SkyKey> globKeys = packageBuilderAndGlobDeps.globDepKeys; |
Nathan Harmata | 6b253fa | 2016-05-24 15:27:18 +0000 | [diff] [blame] | 542 | Map<Label, Path> subincludes = pkgBuilder.getSubincludes(); |
Mark Schaller | 6fc9f88 | 2015-06-12 17:53:57 +0000 | [diff] [blame] | 543 | boolean packageShouldBeConsideredInError; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 544 | try { |
| 545 | packageShouldBeConsideredInError = |
Janak Ramakrishnan | fb040f6 | 2016-06-23 16:05:04 +0000 | [diff] [blame] | 546 | markDependenciesAndPropagateFilesystemExceptions( |
Nathan Harmata | 6b253fa | 2016-05-24 15:27:18 +0000 | [diff] [blame] | 547 | env, globKeys, subincludes, packageId, pkgBuilder.containsErrors()); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 548 | } catch (InternalInconsistentFilesystemException e) { |
Eric Fellheimer | 35e57cf | 2015-05-27 14:31:11 +0000 | [diff] [blame] | 549 | packageFunctionCache.invalidate(packageId); |
Googler | 3aae85f | 2016-04-11 14:57:06 +0000 | [diff] [blame] | 550 | throw new PackageFunctionException( |
| 551 | e.toNoSuchPackageException(), |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 552 | e.isTransient() ? Transience.TRANSIENT : Transience.PERSISTENT); |
Janak Ramakrishnan | fb040f6 | 2016-06-23 16:05:04 +0000 | [diff] [blame] | 553 | } catch (FileOutsidePackageRootsException | SymlinkOutsidePackageRootsException e) { |
| 554 | packageFunctionCache.invalidate(packageId); |
| 555 | throw new PackageFunctionException( |
| 556 | new NoSuchPackageException(packageId, "Encountered file outside package roots", e), |
| 557 | Transience.PERSISTENT); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 558 | } |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 559 | if (env.valuesMissing()) { |
| 560 | return null; |
| 561 | } |
Janak Ramakrishnan | 0a4c6e4 | 2015-09-17 00:37:58 +0000 | [diff] [blame] | 562 | |
Nathan Harmata | 6b253fa | 2016-05-24 15:27:18 +0000 | [diff] [blame] | 563 | Event.replayEventsOn(env.getListener(), pkgBuilder.getEvents()); |
Nathan Harmata | 1cf8e3b | 2015-10-17 00:19:05 +0000 | [diff] [blame] | 564 | |
Janak Ramakrishnan | 0a4c6e4 | 2015-09-17 00:37:58 +0000 | [diff] [blame] | 565 | if (packageShouldBeConsideredInError) { |
Nathan Harmata | 6b253fa | 2016-05-24 15:27:18 +0000 | [diff] [blame] | 566 | pkgBuilder.setContainsErrors(); |
Janak Ramakrishnan | 0a4c6e4 | 2015-09-17 00:37:58 +0000 | [diff] [blame] | 567 | } |
Nathan Harmata | 6b253fa | 2016-05-24 15:27:18 +0000 | [diff] [blame] | 568 | Package pkg = pkgBuilder.finishBuild(); |
Janak Ramakrishnan | 0a4c6e4 | 2015-09-17 00:37:58 +0000 | [diff] [blame] | 569 | |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 570 | // We know this SkyFunction will not be called again, so we can remove the cache entry. |
Eric Fellheimer | 35e57cf | 2015-05-27 14:31:11 +0000 | [diff] [blame] | 571 | packageFunctionCache.invalidate(packageId); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 572 | |
Nathan Harmata | caa000a | 2016-06-07 17:46:19 +0000 | [diff] [blame] | 573 | packageFactory.afterDoneLoadingPackage(pkg); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 574 | return new PackageValue(pkg); |
| 575 | } |
| 576 | |
Janak Ramakrishnan | 3c0adb2 | 2016-08-15 21:54:55 +0000 | [diff] [blame] | 577 | private static FileValue getBuildFileValue(Environment env, RootedPath buildFileRootedPath) |
| 578 | throws InterruptedException { |
Lukacs Berki | b018ee3 | 2015-10-19 08:22:23 +0000 | [diff] [blame] | 579 | FileValue buildFileValue; |
| 580 | try { |
| 581 | buildFileValue = (FileValue) env.getValueOrThrow(FileValue.key(buildFileRootedPath), |
| 582 | IOException.class, FileSymlinkException.class, |
| 583 | InconsistentFilesystemException.class); |
| 584 | } catch (IOException | FileSymlinkException | InconsistentFilesystemException e) { |
| 585 | throw new IllegalStateException("Package lookup succeeded but encountered error when " |
| 586 | + "getting FileValue for BUILD file directly.", e); |
| 587 | } |
| 588 | if (buildFileValue == null) { |
| 589 | return null; |
| 590 | } |
| 591 | Preconditions.checkState(buildFileValue.exists(), |
| 592 | "Package lookup succeeded but BUILD file doesn't exist"); |
| 593 | return buildFileValue; |
| 594 | } |
| 595 | |
Han-Wen Nienhuys | dab4313 | 2015-08-06 16:44:44 +0000 | [diff] [blame] | 596 | @Nullable |
| 597 | private SkylarkImportResult discoverSkylarkImports( |
| 598 | Path buildFilePath, |
Han-Wen Nienhuys | dab4313 | 2015-08-06 16:44:44 +0000 | [diff] [blame] | 599 | PackageIdentifier packageId, |
Nathan Harmata | 9faad19 | 2015-10-15 18:41:24 +0000 | [diff] [blame] | 600 | AstAfterPreprocessing astAfterPreprocessing, |
| 601 | Environment env) |
Janak Ramakrishnan | df0531f | 2015-09-23 17:30:04 +0000 | [diff] [blame] | 602 | throws PackageFunctionException, InterruptedException { |
Han-Wen Nienhuys | dab4313 | 2015-08-06 16:44:44 +0000 | [diff] [blame] | 603 | SkylarkImportResult importResult; |
Nathan Harmata | 9faad19 | 2015-10-15 18:41:24 +0000 | [diff] [blame] | 604 | if (astAfterPreprocessing.containsAstParsingErrors) { |
Han-Wen Nienhuys | dab4313 | 2015-08-06 16:44:44 +0000 | [diff] [blame] | 605 | importResult = |
| 606 | new SkylarkImportResult( |
John Field | 1ea7fc3 | 2015-12-22 19:37:19 +0000 | [diff] [blame] | 607 | ImmutableMap.<String, Extension>of(), |
Francois-Rene Rideau | 89312fb | 2015-09-10 18:53:03 +0000 | [diff] [blame] | 608 | ImmutableList.<Label>of()); |
Han-Wen Nienhuys | dab4313 | 2015-08-06 16:44:44 +0000 | [diff] [blame] | 609 | } else { |
Michajlo Matijkiw | 2a7c802 | 2015-09-22 02:22:12 +0000 | [diff] [blame] | 610 | importResult = |
Damien Martin-Guillerez | 8ca065c2 | 2015-11-27 16:22:59 +0000 | [diff] [blame] | 611 | fetchImportsFromBuildFile( |
| 612 | buildFilePath, |
| 613 | packageId, |
| 614 | astAfterPreprocessing.ast, |
| 615 | env, |
| 616 | skylarkImportLookupFunctionForInlining); |
Han-Wen Nienhuys | dab4313 | 2015-08-06 16:44:44 +0000 | [diff] [blame] | 617 | } |
| 618 | |
| 619 | return importResult; |
| 620 | } |
| 621 | |
Han-Wen Nienhuys | 0648018 | 2015-08-07 15:22:35 +0000 | [diff] [blame] | 622 | /** |
| 623 | * Fetch the skylark loads for this BUILD file. If any of them haven't been computed yet, |
| 624 | * returns null. |
| 625 | */ |
Han-Wen Nienhuys | dab4313 | 2015-08-06 16:44:44 +0000 | [diff] [blame] | 626 | @Nullable |
Damien Martin-Guillerez | 8ca065c2 | 2015-11-27 16:22:59 +0000 | [diff] [blame] | 627 | static SkylarkImportResult fetchImportsFromBuildFile( |
Han-Wen Nienhuys | dab4313 | 2015-08-06 16:44:44 +0000 | [diff] [blame] | 628 | Path buildFilePath, |
Han-Wen Nienhuys | dab4313 | 2015-08-06 16:44:44 +0000 | [diff] [blame] | 629 | PackageIdentifier packageId, |
| 630 | BuildFileAST buildFileAST, |
Damien Martin-Guillerez | 8ca065c2 | 2015-11-27 16:22:59 +0000 | [diff] [blame] | 631 | Environment env, |
| 632 | SkylarkImportLookupFunction skylarkImportLookupFunctionForInlining) |
Janak Ramakrishnan | df0531f | 2015-09-23 17:30:04 +0000 | [diff] [blame] | 633 | throws PackageFunctionException, InterruptedException { |
Brian Silverman | d7d6d62 | 2016-03-17 09:53:39 +0000 | [diff] [blame] | 634 | Preconditions.checkArgument(!packageId.getRepository().isDefault()); |
| 635 | |
John Field | 1ea7fc3 | 2015-12-22 19:37:19 +0000 | [diff] [blame] | 636 | ImmutableList<SkylarkImport> imports = buildFileAST.getImports(); |
| 637 | Map<String, Extension> importMap = Maps.newHashMapWithExpectedSize(imports.size()); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 638 | ImmutableList.Builder<SkylarkFileDependency> fileDependencies = ImmutableList.builder(); |
John Field | 1ea7fc3 | 2015-12-22 19:37:19 +0000 | [diff] [blame] | 639 | ImmutableMap<String, Label> importPathMap; |
John Field | bcb1bea | 2016-01-16 19:05:56 +0000 | [diff] [blame] | 640 | |
John Field | a97e17f | 2015-11-13 02:19:52 +0000 | [diff] [blame] | 641 | // Find the labels corresponding to the load statements. |
| 642 | Label labelForCurrBuildFile; |
| 643 | try { |
| 644 | labelForCurrBuildFile = Label.create(packageId, "BUILD"); |
| 645 | } catch (LabelSyntaxException e) { |
| 646 | // Shouldn't happen; the Label is well-formed by construction. |
| 647 | throw new IllegalStateException(e); |
| 648 | } |
| 649 | try { |
| 650 | importPathMap = SkylarkImportLookupFunction.findLabelsForLoadStatements( |
John Field | 1ea7fc3 | 2015-12-22 19:37:19 +0000 | [diff] [blame] | 651 | imports, labelForCurrBuildFile, env); |
John Field | a97e17f | 2015-11-13 02:19:52 +0000 | [diff] [blame] | 652 | if (importPathMap == null) { |
| 653 | return null; |
| 654 | } |
| 655 | } catch (SkylarkImportFailedException e) { |
John Field | a97e17f | 2015-11-13 02:19:52 +0000 | [diff] [blame] | 656 | throw new PackageFunctionException( |
| 657 | new BuildFileContainsErrorsException(packageId, e.getMessage()), Transience.PERSISTENT); |
| 658 | } |
| 659 | |
| 660 | // Look up and load the imports. |
| 661 | ImmutableCollection<Label> importLabels = importPathMap.values(); |
| 662 | List<SkyKey> importLookupKeys = Lists.newArrayListWithExpectedSize(importLabels.size()); |
Damien Martin-Guillerez | 8ca065c2 | 2015-11-27 16:22:59 +0000 | [diff] [blame] | 663 | boolean inWorkspace = buildFilePath.getBaseName().endsWith("WORKSPACE"); |
John Field | a97e17f | 2015-11-13 02:19:52 +0000 | [diff] [blame] | 664 | for (Label importLabel : importLabels) { |
Damien Martin-Guillerez | 8ca065c2 | 2015-11-27 16:22:59 +0000 | [diff] [blame] | 665 | importLookupKeys.add(SkylarkImportLookupValue.key(importLabel, inWorkspace)); |
John Field | a97e17f | 2015-11-13 02:19:52 +0000 | [diff] [blame] | 666 | } |
| 667 | Map<SkyKey, SkyValue> skylarkImportMap = Maps.newHashMapWithExpectedSize(importPathMap.size()); |
| 668 | boolean valuesMissing = false; |
| 669 | |
| 670 | try { |
| 671 | if (skylarkImportLookupFunctionForInlining == null) { |
| 672 | // Not inlining |
| 673 | Map<SkyKey, |
| 674 | ValueOrException2< |
| 675 | SkylarkImportFailedException, |
| 676 | InconsistentFilesystemException>> skylarkLookupResults = env.getValuesOrThrow( |
| 677 | importLookupKeys, |
| 678 | SkylarkImportFailedException.class, |
| 679 | InconsistentFilesystemException.class); |
| 680 | valuesMissing = env.valuesMissing(); |
| 681 | for (Map.Entry< |
| 682 | SkyKey, |
| 683 | ValueOrException2< |
| 684 | SkylarkImportFailedException, |
| 685 | InconsistentFilesystemException>> entry : skylarkLookupResults.entrySet()) { |
| 686 | // Fetching the value will raise any deferred exceptions |
| 687 | skylarkImportMap.put(entry.getKey(), entry.getValue().get()); |
| 688 | } |
| 689 | } else { |
| 690 | // Inlining calls to SkylarkImportLookupFunction |
Janak Ramakrishnan | f4dd283 | 2016-10-10 23:56:01 +0000 | [diff] [blame^] | 691 | LinkedHashMap<Label, SkylarkImportLookupValue> alreadyVisitedImports = |
| 692 | Maps.newLinkedHashMapWithExpectedSize(importLookupKeys.size()); |
John Field | a97e17f | 2015-11-13 02:19:52 +0000 | [diff] [blame] | 693 | for (SkyKey importLookupKey : importLookupKeys) { |
Janak Ramakrishnan | f4dd283 | 2016-10-10 23:56:01 +0000 | [diff] [blame^] | 694 | SkyValue skyValue = |
| 695 | skylarkImportLookupFunctionForInlining.computeWithInlineCalls( |
| 696 | importLookupKey, env, alreadyVisitedImports); |
John Field | a97e17f | 2015-11-13 02:19:52 +0000 | [diff] [blame] | 697 | if (skyValue == null) { |
| 698 | Preconditions.checkState( |
| 699 | env.valuesMissing(), "no skylark import value for %s", importLookupKey); |
| 700 | // We continue making inline calls even if some requested values are missing, to |
| 701 | // maximize the number of dependent (non-inlined) SkyFunctions that are requested, thus |
| 702 | // avoiding a quadratic number of restarts. |
| 703 | valuesMissing = true; |
Janak Ramakrishnan | df0531f | 2015-09-23 17:30:04 +0000 | [diff] [blame] | 704 | } else { |
John Field | a97e17f | 2015-11-13 02:19:52 +0000 | [diff] [blame] | 705 | skylarkImportMap.put(importLookupKey, skyValue); |
Janak Ramakrishnan | df0531f | 2015-09-23 17:30:04 +0000 | [diff] [blame] | 706 | } |
| 707 | } |
Damien Martin-Guillerez | 8ca065c2 | 2015-11-27 16:22:59 +0000 | [diff] [blame] | 708 | |
Janak Ramakrishnan | df0531f | 2015-09-23 17:30:04 +0000 | [diff] [blame] | 709 | } |
John Field | a97e17f | 2015-11-13 02:19:52 +0000 | [diff] [blame] | 710 | } catch (SkylarkImportFailedException e) { |
John Field | a97e17f | 2015-11-13 02:19:52 +0000 | [diff] [blame] | 711 | throw new PackageFunctionException( |
| 712 | new BuildFileContainsErrorsException(packageId, e.getMessage()), Transience.PERSISTENT); |
| 713 | } catch (InconsistentFilesystemException e) { |
| 714 | throw new PackageFunctionException( |
Googler | 3aae85f | 2016-04-11 14:57:06 +0000 | [diff] [blame] | 715 | new NoSuchPackageException(packageId, e.getMessage(), e), Transience.PERSISTENT); |
Janak Ramakrishnan | df0531f | 2015-09-23 17:30:04 +0000 | [diff] [blame] | 716 | } |
John Field | bcb1bea | 2016-01-16 19:05:56 +0000 | [diff] [blame] | 717 | |
John Field | a97e17f | 2015-11-13 02:19:52 +0000 | [diff] [blame] | 718 | if (valuesMissing) { |
| 719 | // Some imports are unavailable. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 720 | return null; |
| 721 | } |
John Field | bcb1bea | 2016-01-16 19:05:56 +0000 | [diff] [blame] | 722 | |
John Field | a97e17f | 2015-11-13 02:19:52 +0000 | [diff] [blame] | 723 | // Process the loaded imports. |
John Field | 1ea7fc3 | 2015-12-22 19:37:19 +0000 | [diff] [blame] | 724 | for (Entry<String, Label> importEntry : importPathMap.entrySet()) { |
| 725 | String importString = importEntry.getKey(); |
John Field | a97e17f | 2015-11-13 02:19:52 +0000 | [diff] [blame] | 726 | Label importLabel = importEntry.getValue(); |
Damien Martin-Guillerez | 8ca065c2 | 2015-11-27 16:22:59 +0000 | [diff] [blame] | 727 | SkyKey keyForLabel = SkylarkImportLookupValue.key(importLabel, inWorkspace); |
John Field | a97e17f | 2015-11-13 02:19:52 +0000 | [diff] [blame] | 728 | SkylarkImportLookupValue importLookupValue = |
| 729 | (SkylarkImportLookupValue) skylarkImportMap.get(keyForLabel); |
John Field | 1ea7fc3 | 2015-12-22 19:37:19 +0000 | [diff] [blame] | 730 | importMap.put(importString, importLookupValue.getEnvironmentExtension()); |
John Field | a97e17f | 2015-11-13 02:19:52 +0000 | [diff] [blame] | 731 | fileDependencies.add(importLookupValue.getDependency()); |
| 732 | } |
John Field | bcb1bea | 2016-01-16 19:05:56 +0000 | [diff] [blame] | 733 | |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 734 | return new SkylarkImportResult(importMap, transitiveClosureOfLabels(fileDependencies.build())); |
| 735 | } |
| 736 | |
Damien Martin-Guillerez | 8ca065c2 | 2015-11-27 16:22:59 +0000 | [diff] [blame] | 737 | private static ImmutableList<Label> transitiveClosureOfLabels( |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 738 | ImmutableList<SkylarkFileDependency> immediateDeps) { |
| 739 | Set<Label> transitiveClosure = Sets.newHashSet(); |
| 740 | transitiveClosureOfLabels(immediateDeps, transitiveClosure); |
| 741 | return ImmutableList.copyOf(transitiveClosure); |
| 742 | } |
| 743 | |
Damien Martin-Guillerez | 8ca065c2 | 2015-11-27 16:22:59 +0000 | [diff] [blame] | 744 | private static void transitiveClosureOfLabels( |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 745 | ImmutableList<SkylarkFileDependency> immediateDeps, Set<Label> transitiveClosure) { |
| 746 | for (SkylarkFileDependency dep : immediateDeps) { |
Ulf Adams | 07dba94 | 2015-03-05 14:47:37 +0000 | [diff] [blame] | 747 | if (transitiveClosure.add(dep.getLabel())) { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 748 | transitiveClosureOfLabels(dep.getDependencies(), transitiveClosure); |
| 749 | } |
| 750 | } |
| 751 | } |
| 752 | |
| 753 | @Nullable |
| 754 | @Override |
| 755 | public String extractTag(SkyKey skyKey) { |
| 756 | return null; |
| 757 | } |
| 758 | |
| 759 | private static void handleLabelsCrossingSubpackagesAndPropagateInconsistentFilesystemExceptions( |
Nathan Harmata | 6b253fa | 2016-05-24 15:27:18 +0000 | [diff] [blame] | 760 | Path pkgRoot, PackageIdentifier pkgId, Package.Builder pkgBuilder, Environment env) |
Janak Ramakrishnan | 3c0adb2 | 2016-08-15 21:54:55 +0000 | [diff] [blame] | 761 | throws InternalInconsistentFilesystemException, InterruptedException { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 762 | Set<SkyKey> containingPkgLookupKeys = Sets.newHashSet(); |
| 763 | Map<Target, SkyKey> targetToKey = new HashMap<>(); |
| 764 | for (Target target : pkgBuilder.getTargets()) { |
| 765 | PathFragment dir = target.getLabel().toPathFragment().getParentDirectory(); |
Miguel Alcon Pinto | 2627b9f | 2015-10-01 16:02:53 +0000 | [diff] [blame] | 766 | PackageIdentifier dirId = PackageIdentifier.create(pkgId.getRepository(), dir); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 767 | if (dir.equals(pkgId.getPackageFragment())) { |
| 768 | continue; |
| 769 | } |
| 770 | SkyKey key = ContainingPackageLookupValue.key(dirId); |
| 771 | targetToKey.put(target, key); |
| 772 | containingPkgLookupKeys.add(key); |
| 773 | } |
| 774 | Map<Label, SkyKey> subincludeToKey = new HashMap<>(); |
| 775 | for (Label subincludeLabel : pkgBuilder.getSubincludeLabels()) { |
| 776 | PathFragment dir = subincludeLabel.toPathFragment().getParentDirectory(); |
Miguel Alcon Pinto | 2627b9f | 2015-10-01 16:02:53 +0000 | [diff] [blame] | 777 | PackageIdentifier dirId = PackageIdentifier.create(pkgId.getRepository(), dir); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 778 | if (dir.equals(pkgId.getPackageFragment())) { |
| 779 | continue; |
| 780 | } |
| 781 | SkyKey key = ContainingPackageLookupValue.key(dirId); |
| 782 | subincludeToKey.put(subincludeLabel, key); |
| 783 | containingPkgLookupKeys.add(ContainingPackageLookupValue.key(dirId)); |
| 784 | } |
| 785 | Map<SkyKey, ValueOrException3<BuildFileNotFoundException, InconsistentFilesystemException, |
Nathan Harmata | ad81050 | 2015-07-29 01:33:49 +0000 | [diff] [blame] | 786 | FileSymlinkException>> containingPkgLookupValues = env.getValuesOrThrow( |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 787 | containingPkgLookupKeys, BuildFileNotFoundException.class, |
Nathan Harmata | ad81050 | 2015-07-29 01:33:49 +0000 | [diff] [blame] | 788 | InconsistentFilesystemException.class, FileSymlinkException.class); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 789 | if (env.valuesMissing()) { |
| 790 | return; |
| 791 | } |
| 792 | for (Target target : ImmutableSet.copyOf(pkgBuilder.getTargets())) { |
| 793 | SkyKey key = targetToKey.get(target); |
| 794 | if (!containingPkgLookupValues.containsKey(key)) { |
| 795 | continue; |
| 796 | } |
| 797 | ContainingPackageLookupValue containingPackageLookupValue = |
| 798 | getContainingPkgLookupValueAndPropagateInconsistentFilesystemExceptions( |
Kristina Chodorow | e121dd9 | 2015-06-17 14:24:35 +0000 | [diff] [blame] | 799 | pkgId, containingPkgLookupValues.get(key), env); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 800 | if (maybeAddEventAboutLabelCrossingSubpackage(pkgBuilder, pkgRoot, target.getLabel(), |
| 801 | target.getLocation(), containingPackageLookupValue)) { |
| 802 | pkgBuilder.removeTarget(target); |
| 803 | pkgBuilder.setContainsErrors(); |
| 804 | } |
| 805 | } |
| 806 | for (Label subincludeLabel : pkgBuilder.getSubincludeLabels()) { |
| 807 | SkyKey key = subincludeToKey.get(subincludeLabel); |
| 808 | if (!containingPkgLookupValues.containsKey(key)) { |
| 809 | continue; |
| 810 | } |
| 811 | ContainingPackageLookupValue containingPackageLookupValue = |
| 812 | getContainingPkgLookupValueAndPropagateInconsistentFilesystemExceptions( |
Kristina Chodorow | e121dd9 | 2015-06-17 14:24:35 +0000 | [diff] [blame] | 813 | pkgId, containingPkgLookupValues.get(key), env); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 814 | if (maybeAddEventAboutLabelCrossingSubpackage(pkgBuilder, pkgRoot, subincludeLabel, |
| 815 | /*location=*/null, containingPackageLookupValue)) { |
| 816 | pkgBuilder.setContainsErrors(); |
| 817 | } |
| 818 | } |
| 819 | } |
| 820 | |
| 821 | @Nullable |
| 822 | private static ContainingPackageLookupValue |
Kristina Chodorow | e121dd9 | 2015-06-17 14:24:35 +0000 | [diff] [blame] | 823 | getContainingPkgLookupValueAndPropagateInconsistentFilesystemExceptions( |
| 824 | PackageIdentifier packageIdentifier, |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 825 | ValueOrException3<BuildFileNotFoundException, InconsistentFilesystemException, |
Nathan Harmata | ad81050 | 2015-07-29 01:33:49 +0000 | [diff] [blame] | 826 | FileSymlinkException> containingPkgLookupValueOrException, Environment env) |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 827 | throws InternalInconsistentFilesystemException { |
| 828 | try { |
| 829 | return (ContainingPackageLookupValue) containingPkgLookupValueOrException.get(); |
Nathan Harmata | ad81050 | 2015-07-29 01:33:49 +0000 | [diff] [blame] | 830 | } catch (BuildFileNotFoundException | FileSymlinkException e) { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 831 | env.getListener().handle(Event.error(null, e.getMessage())); |
| 832 | return null; |
| 833 | } catch (InconsistentFilesystemException e) { |
Kristina Chodorow | e121dd9 | 2015-06-17 14:24:35 +0000 | [diff] [blame] | 834 | throw new InternalInconsistentFilesystemException(packageIdentifier, e); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 835 | } |
| 836 | } |
| 837 | |
| 838 | private static boolean maybeAddEventAboutLabelCrossingSubpackage( |
Nathan Harmata | 6b253fa | 2016-05-24 15:27:18 +0000 | [diff] [blame] | 839 | Package.Builder pkgBuilder, Path pkgRoot, Label label, @Nullable Location location, |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 840 | @Nullable ContainingPackageLookupValue containingPkgLookupValue) { |
| 841 | if (containingPkgLookupValue == null) { |
| 842 | return true; |
| 843 | } |
| 844 | if (!containingPkgLookupValue.hasContainingPackage()) { |
| 845 | // The missing package here is a problem, but it's not an error from the perspective of |
| 846 | // PackageFunction. |
| 847 | return false; |
| 848 | } |
| 849 | PackageIdentifier containingPkg = containingPkgLookupValue.getContainingPackageName(); |
| 850 | if (containingPkg.equals(label.getPackageIdentifier())) { |
| 851 | // The label does not cross a subpackage boundary. |
| 852 | return false; |
| 853 | } |
Kristina Chodorow | a1a31ff | 2016-07-27 16:34:27 +0000 | [diff] [blame] | 854 | if (!containingPkg.getSourceRoot().startsWith( |
| 855 | label.getPackageIdentifier().getSourceRoot())) { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 856 | // This label is referencing an imaginary package, because the containing package should |
| 857 | // extend the label's package: if the label is //a/b:c/d, the containing package could be |
| 858 | // //a/b/c or //a/b, but should never be //a. Usually such errors will be caught earlier, but |
| 859 | // in some exceptional cases (such as a Python-aware BUILD file catching its own io |
| 860 | // exceptions), it reaches here, and we tolerate it. |
| 861 | return false; |
| 862 | } |
| 863 | PathFragment labelNameFragment = new PathFragment(label.getName()); |
| 864 | String message = String.format("Label '%s' crosses boundary of subpackage '%s'", |
| 865 | label, containingPkg); |
| 866 | Path containingRoot = containingPkgLookupValue.getContainingPackageRoot(); |
| 867 | if (pkgRoot.equals(containingRoot)) { |
| 868 | PathFragment labelNameInContainingPackage = labelNameFragment.subFragment( |
| 869 | containingPkg.getPackageFragment().segmentCount() |
| 870 | - label.getPackageFragment().segmentCount(), |
| 871 | labelNameFragment.segmentCount()); |
Brian Silverman | 8f92209 | 2016-02-01 16:10:27 +0000 | [diff] [blame] | 872 | message += " (perhaps you meant to put the colon here: '"; |
Brian Silverman | d7d6d62 | 2016-03-17 09:53:39 +0000 | [diff] [blame] | 873 | if (containingPkg.getRepository().isDefault() || containingPkg.getRepository().isMain()) { |
Brian Silverman | 8f92209 | 2016-02-01 16:10:27 +0000 | [diff] [blame] | 874 | message += "//"; |
| 875 | } |
| 876 | message += containingPkg + ":" + labelNameInContainingPackage + "'?)"; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 877 | } else { |
| 878 | message += " (have you deleted " + containingPkg + "/BUILD? " |
| 879 | + "If so, use the --deleted_packages=" + containingPkg + " option)"; |
| 880 | } |
| 881 | pkgBuilder.addEvent(Event.error(location, message)); |
| 882 | return true; |
| 883 | } |
| 884 | |
| 885 | /** |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 886 | * A {@link Globber} implemented on top of skyframe that falls back to a |
| 887 | * {@link PackageFactory.LegacyGlobber} on a skyframe cache-miss. This way we don't require a |
| 888 | * skyframe restart after a call to {@link Globber#runAsync} and before/during a call to |
| 889 | * {@link Globber#fetch}. |
| 890 | * |
| 891 | * <p>There are three advantages to this hybrid approach over the more obvious approach of solely |
| 892 | * using a {@link PackageFactory.LegacyGlobber}: |
| 893 | * <ul> |
| 894 | * <li>We trivially have the proper Skyframe {@link GlobValue} deps, whereas we would need to |
| 895 | * request them after-the-fact if we solely used a {@link PackageFactory.LegacyGlobber}. |
| 896 | * <li>We don't need to re-evaluate globs whose expression hasn't changed (e.g. in the common case |
| 897 | * of a BUILD file edit that doesn't change a glob expression), whereas legacy package loading |
| 898 | * with a {@link PackageFactory.LegacyGlobber} would naively re-evaluate globs when re-evaluating |
| 899 | * the BUILD file. |
| 900 | * <li>We don't need to re-evaluate invalidated globs *twice* (the single re-evaluation via our |
| 901 | * GlobValue deps is sufficient and optimal). See above for why the second evaluation would |
| 902 | * happen. |
| 903 | * </ul> |
| 904 | */ |
| 905 | private static class SkyframeHybridGlobber implements Globber { |
| 906 | private final PackageIdentifier packageId; |
| 907 | private final Path packageRoot; |
| 908 | private final Environment env; |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 909 | private final LegacyGlobber legacyGlobber; |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 910 | private final Set<SkyKey> globDepsRequested = Sets.newConcurrentHashSet(); |
| 911 | |
| 912 | private SkyframeHybridGlobber(PackageIdentifier packageId, Path packageRoot, Environment env, |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 913 | LegacyGlobber legacyGlobber) { |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 914 | this.packageId = packageId; |
| 915 | this.packageRoot = packageRoot; |
| 916 | this.env = env; |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 917 | this.legacyGlobber = legacyGlobber; |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 918 | } |
| 919 | |
| 920 | private Set<SkyKey> getGlobDepsRequested() { |
| 921 | return ImmutableSet.copyOf(globDepsRequested); |
| 922 | } |
| 923 | |
| 924 | private SkyKey getGlobKey(String pattern, boolean excludeDirs) throws BadGlobException { |
| 925 | try { |
| 926 | return GlobValue.key(packageId, packageRoot, pattern, excludeDirs, |
| 927 | PathFragment.EMPTY_FRAGMENT); |
| 928 | } catch (InvalidGlobPatternException e) { |
| 929 | throw new BadGlobException(e.getMessage()); |
| 930 | } |
| 931 | } |
| 932 | |
| 933 | @Override |
| 934 | public Token runAsync(List<String> includes, List<String> excludes, boolean excludeDirs) |
Janak Ramakrishnan | 3c0adb2 | 2016-08-15 21:54:55 +0000 | [diff] [blame] | 935 | throws BadGlobException, InterruptedException { |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 936 | List<SkyKey> globKeys = new ArrayList<>(includes.size() + excludes.size()); |
| 937 | LinkedHashSet<SkyKey> includesKeys = Sets.newLinkedHashSetWithExpectedSize(includes.size()); |
| 938 | LinkedHashSet<SkyKey> excludesKeys = Sets.newLinkedHashSetWithExpectedSize(excludes.size()); |
| 939 | Map<SkyKey, String> globKeyToIncludeStringMap = |
| 940 | Maps.newHashMapWithExpectedSize(includes.size()); |
| 941 | Map<SkyKey, String> globKeyToExcludeStringMap = |
| 942 | Maps.newHashMapWithExpectedSize(excludes.size()); |
| 943 | |
| 944 | for (String pattern : includes) { |
| 945 | SkyKey globKey = getGlobKey(pattern, excludeDirs); |
| 946 | globKeys.add(globKey); |
| 947 | includesKeys.add(globKey); |
| 948 | globKeyToIncludeStringMap.put(globKey, pattern); |
| 949 | } |
| 950 | for (String pattern : excludes) { |
| 951 | SkyKey globKey = getGlobKey(pattern, excludeDirs); |
| 952 | globKeys.add(globKey); |
| 953 | excludesKeys.add(globKey); |
| 954 | globKeyToExcludeStringMap.put(globKey, pattern); |
| 955 | } |
| 956 | globDepsRequested.addAll(globKeys); |
| 957 | |
| 958 | Map<SkyKey, ValueOrException4<IOException, BuildFileNotFoundException, |
| 959 | FileSymlinkCycleException, InconsistentFilesystemException>> globValueMap = |
| 960 | env.getValuesOrThrow(globKeys, IOException.class, BuildFileNotFoundException.class, |
| 961 | FileSymlinkCycleException.class, InconsistentFilesystemException.class); |
| 962 | |
| 963 | // For each missing glob, evaluate it asychronously via the delegate. |
| 964 | // |
| 965 | // TODO(bazel-team): Consider not delegating missing globs during glob prefetching - a |
| 966 | // single skyframe restart after the prefetch step is probably tolerable. |
| 967 | Collection<SkyKey> missingKeys = getMissingKeys(globKeys, globValueMap); |
| 968 | List<String> includesToDelegate = new ArrayList<>(missingKeys.size()); |
| 969 | List<String> excludesToDelegate = new ArrayList<>(missingKeys.size()); |
| 970 | for (SkyKey missingKey : missingKeys) { |
| 971 | String missingIncludePattern = globKeyToIncludeStringMap.get(missingKey); |
| 972 | if (missingIncludePattern != null) { |
| 973 | includesToDelegate.add(missingIncludePattern); |
| 974 | includesKeys.remove(missingKey); |
| 975 | } |
| 976 | String missingExcludePattern = globKeyToExcludeStringMap.get(missingKey); |
| 977 | if (missingExcludePattern != null) { |
| 978 | excludesToDelegate.add(missingExcludePattern); |
| 979 | excludesKeys.remove(missingKey); |
| 980 | } |
| 981 | } |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 982 | Token legacyIncludesToken = |
| 983 | legacyGlobber.runAsync(includesToDelegate, ImmutableList.<String>of(), excludeDirs); |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 984 | // See the HybridToken class-comment for why we pass excludesToDelegate as the includes |
| 985 | // parameter here. |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 986 | Token legacyExcludesToken = |
| 987 | legacyGlobber.runAsync(excludesToDelegate, ImmutableList.<String>of(), excludeDirs); |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 988 | |
| 989 | return new HybridToken(globValueMap, includesKeys, excludesKeys, |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 990 | legacyIncludesToken, legacyExcludesToken); |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 991 | } |
| 992 | |
| 993 | private Collection<SkyKey> getMissingKeys(Collection<SkyKey> globKeys, |
| 994 | Map<SkyKey, ValueOrException4<IOException, BuildFileNotFoundException, |
| 995 | FileSymlinkCycleException, InconsistentFilesystemException>> globValueMap) { |
| 996 | List<SkyKey> missingKeys = new ArrayList<>(globKeys.size()); |
| 997 | for (SkyKey globKey : globKeys) { |
| 998 | ValueOrException4<IOException, BuildFileNotFoundException, FileSymlinkCycleException, |
| 999 | InconsistentFilesystemException> valueOrException = globValueMap.get(globKey); |
| 1000 | if (valueOrException == null) { |
| 1001 | missingKeys.add(globKey); |
| 1002 | } |
| 1003 | try { |
| 1004 | if (valueOrException.get() == null) { |
| 1005 | missingKeys.add(globKey); |
| 1006 | } |
| 1007 | } catch (IOException | BuildFileNotFoundException | FileSymlinkCycleException |
| 1008 | | InconsistentFilesystemException doesntMatter) { |
| 1009 | continue; |
| 1010 | } |
| 1011 | } |
| 1012 | return missingKeys; |
| 1013 | } |
| 1014 | |
| 1015 | @Override |
| 1016 | public List<String> fetch(Token token) throws IOException, InterruptedException { |
| 1017 | HybridToken hybridToken = (HybridToken) token; |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 1018 | return hybridToken.resolve(legacyGlobber); |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 1019 | } |
| 1020 | |
| 1021 | @Override |
| 1022 | public void onInterrupt() { |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 1023 | legacyGlobber.onInterrupt(); |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 1024 | } |
| 1025 | |
| 1026 | @Override |
| 1027 | public void onCompletion() { |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 1028 | legacyGlobber.onCompletion(); |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 1029 | } |
| 1030 | |
| 1031 | /** |
| 1032 | * A {@link Globber.Token} that encapsulates the result of a single {@link Globber#runAsync} |
| 1033 | * call via the fetching of some globs from skyframe, and some other globs via a |
| 1034 | * {@link PackageFactory.LegacyGlobber}. We take care to properly handle 'includes' vs |
| 1035 | * 'excludes'. |
| 1036 | * |
| 1037 | * <p>That is, we evaluate {@code glob(includes, excludes)} by partitioning {@code includes} and |
| 1038 | * {@code excludes}. |
| 1039 | * |
| 1040 | * <pre> |
| 1041 | * {@code |
| 1042 | * includes = includes_sky U includes_leg |
| 1043 | * excludes = excludes_sky U excludes_leg |
| 1044 | * } |
| 1045 | * </pre> |
| 1046 | * |
| 1047 | * <p>and then noting |
| 1048 | * |
| 1049 | * <pre> |
| 1050 | * {@code |
| 1051 | * glob(includes, excludes) = |
| 1052 | * (glob(includes_sky, []) U glob(includes_leg, [])) |
| 1053 | * - (glob(excludes_sky, []) U glob(excludes_leg, [])) |
| 1054 | * } |
| 1055 | * </pre> |
| 1056 | * |
| 1057 | * <p>Importantly, we pass excludes=[] in all cases; otherwise we'd be incorrectly not |
| 1058 | * subtracting excluded glob matches from the overall list of matches. In other words, we |
| 1059 | * implement the subtractive nature of excludes ourselves in {@link #resolve}. |
| 1060 | */ |
| 1061 | private static class HybridToken extends Globber.Token { |
| 1062 | // The result of the Skyframe lookup for all the needed glob patterns. |
| 1063 | private final Map<SkyKey, ValueOrException4<IOException, BuildFileNotFoundException, |
| 1064 | FileSymlinkCycleException, InconsistentFilesystemException>> globValueMap; |
| 1065 | // The skyframe keys corresponding to the 'includes' patterns fetched from Skyframe |
| 1066 | // (this is includes_sky above). |
| 1067 | private final Iterable<SkyKey> includesGlobKeys; |
| 1068 | // The skyframe keys corresponding to the 'excludes' patterns fetched from Skyframe |
| 1069 | // (this is excludes_sky above). |
| 1070 | private final Iterable<SkyKey> excludesGlobKeys; |
| 1071 | // A token for computing includes_leg. |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 1072 | private final Token legacyIncludesToken; |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 1073 | // A token for computing excludes_leg. |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 1074 | private final Token legacyExcludesToken; |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 1075 | |
| 1076 | private HybridToken(Map<SkyKey, ValueOrException4<IOException, BuildFileNotFoundException, |
| 1077 | FileSymlinkCycleException, InconsistentFilesystemException>> globValueMap, |
| 1078 | Iterable<SkyKey> includesGlobKeys, Iterable<SkyKey> excludesGlobKeys, |
| 1079 | Token delegateIncludesToken, Token delegateExcludesToken) { |
| 1080 | this.globValueMap = globValueMap; |
| 1081 | this.includesGlobKeys = includesGlobKeys; |
| 1082 | this.excludesGlobKeys = excludesGlobKeys; |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 1083 | this.legacyIncludesToken = delegateIncludesToken; |
| 1084 | this.legacyExcludesToken = delegateExcludesToken; |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 1085 | } |
| 1086 | |
| 1087 | private List<String> resolve(Globber delegate) throws IOException, InterruptedException { |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 1088 | HashSet<String> matches = new HashSet<>(); |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 1089 | for (SkyKey includeGlobKey : includesGlobKeys) { |
| 1090 | // TODO(bazel-team): NestedSet expansion here is suboptimal. |
| 1091 | for (PathFragment match : getGlobMatches(includeGlobKey, globValueMap)) { |
| 1092 | matches.add(match.getPathString()); |
| 1093 | } |
| 1094 | } |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 1095 | matches.addAll(delegate.fetch(legacyIncludesToken)); |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 1096 | for (SkyKey excludeGlobKey : excludesGlobKeys) { |
| 1097 | for (PathFragment match : getGlobMatches(excludeGlobKey, globValueMap)) { |
| 1098 | matches.remove(match.getPathString()); |
| 1099 | } |
| 1100 | } |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 1101 | for (String delegateExcludeMatch : delegate.fetch(legacyExcludesToken)) { |
Nathan Harmata | 3ae80a7 | 2016-03-16 19:04:26 +0000 | [diff] [blame] | 1102 | matches.remove(delegateExcludeMatch); |
| 1103 | } |
Janak Ramakrishnan | 063b488 | 2016-07-18 20:33:28 +0000 | [diff] [blame] | 1104 | List<String> result = new ArrayList<>(matches); |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 1105 | // Skyframe glob results are unsorted. And we used a LegacyGlobber that doesn't sort. |
| 1106 | // Therefore, we want to unconditionally sort here. |
| 1107 | Collections.sort(result); |
Janak Ramakrishnan | 063b488 | 2016-07-18 20:33:28 +0000 | [diff] [blame] | 1108 | return result; |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 1109 | } |
| 1110 | |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 1111 | private static NestedSet<PathFragment> getGlobMatches( |
Janak Ramakrishnan | 063b488 | 2016-07-18 20:33:28 +0000 | [diff] [blame] | 1112 | SkyKey globKey, |
| 1113 | Map< |
| 1114 | SkyKey, |
| 1115 | ValueOrException4< |
| 1116 | IOException, BuildFileNotFoundException, FileSymlinkCycleException, |
| 1117 | InconsistentFilesystemException>> |
| 1118 | globValueMap) |
| 1119 | throws IOException { |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 1120 | ValueOrException4<IOException, BuildFileNotFoundException, FileSymlinkCycleException, |
| 1121 | InconsistentFilesystemException> valueOrException = |
| 1122 | Preconditions.checkNotNull(globValueMap.get(globKey), "%s should not be missing", |
| 1123 | globKey); |
| 1124 | try { |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 1125 | return Preconditions.checkNotNull((GlobValue) valueOrException.get(), |
| 1126 | "%s should not be missing", globKey).getMatches(); |
| 1127 | } catch (BuildFileNotFoundException | FileSymlinkCycleException |
| 1128 | | InconsistentFilesystemException e) { |
| 1129 | // Legacy package loading is only able to handle an IOException, so a rethrow here is the |
| 1130 | // best we can do. But after legacy package loading, PackageFunction will go through all |
| 1131 | // the skyframe deps and properly handle InconsistentFilesystemExceptions. |
| 1132 | throw new IOException(e.getMessage()); |
| 1133 | } |
| 1134 | } |
| 1135 | } |
| 1136 | } |
| 1137 | |
| 1138 | /** |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 1139 | * Constructs a {@link Package} object for the given package using legacy package loading. |
| 1140 | * Note that the returned package may be in error. |
Han-Wen Nienhuys | 0648018 | 2015-08-07 15:22:35 +0000 | [diff] [blame] | 1141 | * |
| 1142 | * <p>May return null if the computation has to be restarted. |
Nathan Harmata | 5a9b699 | 2015-10-13 19:52:41 +0000 | [diff] [blame] | 1143 | * |
Nathan Harmata | d8b6ff2 | 2015-10-20 21:54:34 +0000 | [diff] [blame] | 1144 | * <p>Exactly one of {@code replacementContents} and {@code buildFileValue} will be |
Nathan Harmata | 5a9b699 | 2015-10-13 19:52:41 +0000 | [diff] [blame] | 1145 | * non-{@code null}. The former indicates that we have a faux BUILD file with the given contents |
| 1146 | * and the latter indicates that we have a legitimate BUILD file and should actually do |
| 1147 | * preprocessing. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 1148 | */ |
Han-Wen Nienhuys | 0648018 | 2015-08-07 15:22:35 +0000 | [diff] [blame] | 1149 | @Nullable |
Nathan Harmata | 6b253fa | 2016-05-24 15:27:18 +0000 | [diff] [blame] | 1150 | private CacheEntryWithGlobDeps<Package.Builder> loadPackage( |
Han-Wen Nienhuys | dab4313 | 2015-08-06 16:44:44 +0000 | [diff] [blame] | 1151 | Package externalPkg, |
Han-Wen Nienhuys | dab4313 | 2015-08-06 16:44:44 +0000 | [diff] [blame] | 1152 | @Nullable String replacementContents, |
| 1153 | PackageIdentifier packageId, |
| 1154 | Path buildFilePath, |
Nathan Harmata | 5a9b699 | 2015-10-13 19:52:41 +0000 | [diff] [blame] | 1155 | @Nullable FileValue buildFileValue, |
Han-Wen Nienhuys | dab4313 | 2015-08-06 16:44:44 +0000 | [diff] [blame] | 1156 | RuleVisibility defaultVisibility, |
| 1157 | List<Statement> preludeStatements, |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 1158 | Path packageRoot, |
Han-Wen Nienhuys | 0648018 | 2015-08-07 15:22:35 +0000 | [diff] [blame] | 1159 | Environment env) |
Han-Wen Nienhuys | dab4313 | 2015-08-06 16:44:44 +0000 | [diff] [blame] | 1160 | throws InterruptedException, PackageFunctionException { |
Nathan Harmata | 6b253fa | 2016-05-24 15:27:18 +0000 | [diff] [blame] | 1161 | CacheEntryWithGlobDeps<Package.Builder> packageFunctionCacheEntry = |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 1162 | packageFunctionCache.getIfPresent(packageId); |
| 1163 | if (packageFunctionCacheEntry == null) { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 1164 | profiler.startTask(ProfilerTask.CREATE_PACKAGE, packageId.toString()); |
Klaus Aehlig | c6fd6bb | 2016-05-27 11:42:32 +0000 | [diff] [blame] | 1165 | if (packageProgress != null) { |
| 1166 | packageProgress.startReadPackage(packageId); |
| 1167 | } |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 1168 | try { |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 1169 | CacheEntryWithGlobDeps<AstAfterPreprocessing> astCacheEntry = |
| 1170 | astCache.getIfPresent(packageId); |
| 1171 | if (astCacheEntry == null) { |
Nathan Harmata | 5a9b699 | 2015-10-13 19:52:41 +0000 | [diff] [blame] | 1172 | if (showLoadingProgress.get()) { |
| 1173 | env.getListener().handle(Event.progress("Loading package: " + packageId)); |
| 1174 | } |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 1175 | // We use a LegacyGlobber that doesn't sort the matches for each individual glob pattern, |
| 1176 | // since we want to sort the final result anyway. |
| 1177 | LegacyGlobber legacyGlobber = packageFactory.createLegacyGlobberThatDoesntSort( |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 1178 | buildFilePath.getParentDirectory(), packageId, packageLocator); |
| 1179 | SkyframeHybridGlobber skyframeGlobber = new SkyframeHybridGlobber(packageId, packageRoot, |
| 1180 | env, legacyGlobber); |
Nathan Harmata | 9faad19 | 2015-10-15 18:41:24 +0000 | [diff] [blame] | 1181 | Preprocessor.Result preprocessingResult; |
Nathan Harmata | 5a9b699 | 2015-10-13 19:52:41 +0000 | [diff] [blame] | 1182 | if (replacementContents == null) { |
Nathan Harmata | d8b6ff2 | 2015-10-20 21:54:34 +0000 | [diff] [blame] | 1183 | Preconditions.checkNotNull(buildFileValue, packageId); |
Nathan Harmata | 4e69824 | 2015-10-20 23:18:23 +0000 | [diff] [blame] | 1184 | byte[] buildFileBytes; |
Nathan Harmata | 5a9b699 | 2015-10-13 19:52:41 +0000 | [diff] [blame] | 1185 | try { |
Nathan Harmata | 4e69824 | 2015-10-20 23:18:23 +0000 | [diff] [blame] | 1186 | buildFileBytes = buildFileValue.isSpecialFile() |
| 1187 | ? FileSystemUtils.readContent(buildFilePath) |
| 1188 | : FileSystemUtils.readWithKnownFileSize(buildFilePath, buildFileValue.getSize()); |
Nathan Harmata | 5a9b699 | 2015-10-13 19:52:41 +0000 | [diff] [blame] | 1189 | } catch (IOException e) { |
Nathan Harmata | 5a9b699 | 2015-10-13 19:52:41 +0000 | [diff] [blame] | 1190 | // Note that we did this work, so we should conservatively report this error as |
| 1191 | // transient. |
| 1192 | throw new PackageFunctionException(new BuildFileContainsErrorsException( |
| 1193 | packageId, e.getMessage()), Transience.TRANSIENT); |
| 1194 | } |
| 1195 | try { |
Nathan Harmata | 4e69824 | 2015-10-20 23:18:23 +0000 | [diff] [blame] | 1196 | preprocessingResult = packageFactory.preprocess(buildFilePath, packageId, |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 1197 | buildFileBytes, skyframeGlobber); |
Nathan Harmata | 5a9b699 | 2015-10-13 19:52:41 +0000 | [diff] [blame] | 1198 | } catch (IOException e) { |
Nathan Harmata | 5a9b699 | 2015-10-13 19:52:41 +0000 | [diff] [blame] | 1199 | throw new PackageFunctionException( |
John Field | 1ea7fc3 | 2015-12-22 19:37:19 +0000 | [diff] [blame] | 1200 | new BuildFileContainsErrorsException( |
| 1201 | packageId, "preprocessing failed" + e.getMessage(), e), Transience.TRANSIENT); |
Nathan Harmata | 5a9b699 | 2015-10-13 19:52:41 +0000 | [diff] [blame] | 1202 | } |
| 1203 | } else { |
| 1204 | ParserInputSource replacementSource = |
| 1205 | ParserInputSource.create(replacementContents, buildFilePath.asFragment()); |
| 1206 | preprocessingResult = Preprocessor.Result.noPreprocessing(replacementSource); |
Janak Ramakrishnan | ac023bb | 2015-09-15 19:37:11 +0000 | [diff] [blame] | 1207 | } |
Nathan Harmata | 9faad19 | 2015-10-15 18:41:24 +0000 | [diff] [blame] | 1208 | StoredEventHandler astParsingEventHandler = new StoredEventHandler(); |
| 1209 | BuildFileAST ast = PackageFactory.parseBuildFile(packageId, preprocessingResult.result, |
| 1210 | preludeStatements, astParsingEventHandler); |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 1211 | // If no globs were fetched during preprocessing, then there's no need to reuse the |
| 1212 | // legacy globber instance during BUILD file evaluation since the performance argument |
| 1213 | // below does not apply. |
| 1214 | Set<SkyKey> globDepsRequested = skyframeGlobber.getGlobDepsRequested(); |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 1215 | LegacyGlobber legacyGlobberToStore = globDepsRequested.isEmpty() ? null : legacyGlobber; |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 1216 | astCacheEntry = new CacheEntryWithGlobDeps<>( |
| 1217 | new AstAfterPreprocessing(preprocessingResult, ast, astParsingEventHandler), |
| 1218 | globDepsRequested, legacyGlobberToStore); |
| 1219 | astCache.put(packageId, astCacheEntry); |
Ulf Adams | d9b5121 | 2015-09-04 15:14:22 +0000 | [diff] [blame] | 1220 | } |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 1221 | AstAfterPreprocessing astAfterPreprocessing = astCacheEntry.value; |
| 1222 | Set<SkyKey> globDepsRequestedDuringPreprocessing = astCacheEntry.globDepKeys; |
Nathan Harmata | 829d118 | 2015-10-12 22:26:08 +0000 | [diff] [blame] | 1223 | SkylarkImportResult importResult; |
| 1224 | try { |
| 1225 | importResult = discoverSkylarkImports( |
Nathan Harmata | 9faad19 | 2015-10-15 18:41:24 +0000 | [diff] [blame] | 1226 | buildFilePath, |
Nathan Harmata | 9faad19 | 2015-10-15 18:41:24 +0000 | [diff] [blame] | 1227 | packageId, |
| 1228 | astAfterPreprocessing, |
| 1229 | env); |
Nathan Harmata | 829d118 | 2015-10-12 22:26:08 +0000 | [diff] [blame] | 1230 | } catch (PackageFunctionException | InterruptedException e) { |
Nathan Harmata | 9faad19 | 2015-10-15 18:41:24 +0000 | [diff] [blame] | 1231 | astCache.invalidate(packageId); |
Nathan Harmata | 829d118 | 2015-10-12 22:26:08 +0000 | [diff] [blame] | 1232 | throw e; |
| 1233 | } |
Han-Wen Nienhuys | 0648018 | 2015-08-07 15:22:35 +0000 | [diff] [blame] | 1234 | if (importResult == null) { |
| 1235 | return null; |
| 1236 | } |
Nathan Harmata | 9faad19 | 2015-10-15 18:41:24 +0000 | [diff] [blame] | 1237 | astCache.invalidate(packageId); |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 1238 | // If a legacy globber was used to evaluate globs during preprocessing, it's important that |
| 1239 | // we reuse that globber during BUILD file evaluation for performance, in the case that |
| 1240 | // globs were fetched lazily during preprocessing. See Preprocessor.Factory#considersGlobs. |
Nathan Harmata | 44e1e3a | 2016-08-23 21:22:17 +0000 | [diff] [blame] | 1241 | LegacyGlobber legacyGlobber = astCacheEntry.legacyGlobber != null |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 1242 | ? astCacheEntry.legacyGlobber |
| 1243 | : packageFactory.createLegacyGlobber( |
| 1244 | buildFilePath.getParentDirectory(), packageId, packageLocator); |
| 1245 | SkyframeHybridGlobber skyframeGlobber = new SkyframeHybridGlobber(packageId, packageRoot, |
| 1246 | env, legacyGlobber); |
Nathan Harmata | 6b253fa | 2016-05-24 15:27:18 +0000 | [diff] [blame] | 1247 | Package.Builder pkgBuilder = packageFactory.createPackageFromPreprocessingAst( |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 1248 | externalPkg, packageId, buildFilePath, astAfterPreprocessing, importResult.importMap, |
| 1249 | importResult.fileDependencies, defaultVisibility, skyframeGlobber); |
| 1250 | Set<SkyKey> globDepsRequested = ImmutableSet.<SkyKey>builder() |
| 1251 | .addAll(globDepsRequestedDuringPreprocessing) |
| 1252 | .addAll(skyframeGlobber.getGlobDepsRequested()) |
| 1253 | .build(); |
| 1254 | packageFunctionCacheEntry = |
| 1255 | new CacheEntryWithGlobDeps<>(pkgBuilder, globDepsRequested, null); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 1256 | numPackagesLoaded.incrementAndGet(); |
Klaus Aehlig | c6fd6bb | 2016-05-27 11:42:32 +0000 | [diff] [blame] | 1257 | if (packageProgress != null) { |
| 1258 | packageProgress.doneReadPackage(packageId); |
| 1259 | } |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 1260 | packageFunctionCache.put(packageId, packageFunctionCacheEntry); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 1261 | } finally { |
| 1262 | profiler.completeTask(ProfilerTask.CREATE_PACKAGE); |
| 1263 | } |
| 1264 | } |
Nathan Harmata | 3a95f35 | 2016-02-05 00:11:55 +0000 | [diff] [blame] | 1265 | return packageFunctionCacheEntry; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 1266 | } |
| 1267 | |
Googler | 3aae85f | 2016-04-11 14:57:06 +0000 | [diff] [blame] | 1268 | private static class InternalInconsistentFilesystemException extends Exception { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 1269 | private boolean isTransient; |
| 1270 | |
Googler | 3aae85f | 2016-04-11 14:57:06 +0000 | [diff] [blame] | 1271 | private PackageIdentifier packageIdentifier; |
| 1272 | |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 1273 | /** |
| 1274 | * Used to represent a filesystem inconsistency discovered outside the |
| 1275 | * {@link PackageFunction}. |
| 1276 | */ |
Kristina Chodorow | e121dd9 | 2015-06-17 14:24:35 +0000 | [diff] [blame] | 1277 | public InternalInconsistentFilesystemException(PackageIdentifier packageIdentifier, |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 1278 | InconsistentFilesystemException e) { |
Googler | 3aae85f | 2016-04-11 14:57:06 +0000 | [diff] [blame] | 1279 | super(e.getMessage(), e); |
| 1280 | this.packageIdentifier = packageIdentifier; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 1281 | // This is not a transient error from the perspective of the PackageFunction. |
| 1282 | this.isTransient = false; |
| 1283 | } |
| 1284 | |
| 1285 | /** Used to represent a filesystem inconsistency discovered by the {@link PackageFunction}. */ |
Kristina Chodorow | e121dd9 | 2015-06-17 14:24:35 +0000 | [diff] [blame] | 1286 | public InternalInconsistentFilesystemException(PackageIdentifier packageIdentifier, |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 1287 | String inconsistencyMessage) { |
Kristina Chodorow | e121dd9 | 2015-06-17 14:24:35 +0000 | [diff] [blame] | 1288 | this(packageIdentifier, new InconsistentFilesystemException(inconsistencyMessage)); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 1289 | this.isTransient = true; |
| 1290 | } |
| 1291 | |
| 1292 | public boolean isTransient() { |
| 1293 | return isTransient; |
| 1294 | } |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 1295 | |
Googler | 3aae85f | 2016-04-11 14:57:06 +0000 | [diff] [blame] | 1296 | private NoSuchPackageException toNoSuchPackageException() { |
| 1297 | return new NoSuchPackageException( |
| 1298 | packageIdentifier, this.getMessage(), (Exception) this.getCause()); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 1299 | } |
| 1300 | } |
| 1301 | |
| 1302 | /** |
| 1303 | * Used to declare all the exception types that can be wrapped in the exception thrown by |
| 1304 | * {@link PackageFunction#compute}. |
| 1305 | */ |
Damien Martin-Guillerez | 8ca065c2 | 2015-11-27 16:22:59 +0000 | [diff] [blame] | 1306 | static class PackageFunctionException extends SkyFunctionException { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 1307 | public PackageFunctionException(NoSuchPackageException e, Transience transience) { |
| 1308 | super(e, transience); |
| 1309 | } |
| 1310 | } |
| 1311 | |
| 1312 | /** A simple value class to store the result of the Skylark imports.*/ |
Damien Martin-Guillerez | 8ca065c2 | 2015-11-27 16:22:59 +0000 | [diff] [blame] | 1313 | static final class SkylarkImportResult { |
John Field | 1ea7fc3 | 2015-12-22 19:37:19 +0000 | [diff] [blame] | 1314 | final Map<String, Extension> importMap; |
Damien Martin-Guillerez | 8ca065c2 | 2015-11-27 16:22:59 +0000 | [diff] [blame] | 1315 | final ImmutableList<Label> fileDependencies; |
Francois-Rene Rideau | 89312fb | 2015-09-10 18:53:03 +0000 | [diff] [blame] | 1316 | private SkylarkImportResult( |
John Field | 1ea7fc3 | 2015-12-22 19:37:19 +0000 | [diff] [blame] | 1317 | Map<String, Extension> importMap, |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 1318 | ImmutableList<Label> fileDependencies) { |
| 1319 | this.importMap = importMap; |
| 1320 | this.fileDependencies = fileDependencies; |
| 1321 | } |
| 1322 | } |
Lukacs Berki | b018ee3 | 2015-10-19 08:22:23 +0000 | [diff] [blame] | 1323 | |
| 1324 | static boolean isDefaultsPackage(PackageIdentifier packageIdentifier) { |
Brian Silverman | d7d6d62 | 2016-03-17 09:53:39 +0000 | [diff] [blame] | 1325 | return packageIdentifier.getRepository().isMain() |
Lukacs Berki | b018ee3 | 2015-10-19 08:22:23 +0000 | [diff] [blame] | 1326 | && packageIdentifier.getPackageFragment().equals(DEFAULTS_PACKAGE_NAME); |
| 1327 | } |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 1328 | } |