Add the --experimental_disable_external package command line option that (unsurprisingly) disables the //external package This has the side effect of allowing labels in the unnamed package to start with "external" (e.g. //:external/foo/bar) RELNOTES: None. PiperOrigin-RevId: 296237592
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/ninja/actions/NinjaGraph.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/ninja/actions/NinjaGraph.java index db819f5..42e8d8e 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/ninja/actions/NinjaGraph.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/ninja/actions/NinjaGraph.java
@@ -240,6 +240,10 @@ Environment env = ruleContext.getAnalysisEnvironment().getSkyframeEnv(); ImmutableSortedSet<String> notSymlinkedDirs = ExternalPackageUtil.getNotSymlinkedInExecrootDirectories(env); + if (env.valuesMissing()) { + return; + } + // We can compare strings because notSymlinkedDirs contains normalized directory names if (!notSymlinkedDirs.contains(outputRoot.getPathString())) { ruleContext.attributeError(
diff --git a/src/main/java/com/google/devtools/build/lib/cmdline/LabelConstants.java b/src/main/java/com/google/devtools/build/lib/cmdline/LabelConstants.java index 1608ed0..a110064 100644 --- a/src/main/java/com/google/devtools/build/lib/cmdline/LabelConstants.java +++ b/src/main/java/com/google/devtools/build/lib/cmdline/LabelConstants.java
@@ -17,9 +17,22 @@ /** Constants associated with {@code Label}s */ public class LabelConstants { + /** The subdirectory under the output base which contains external repositories. */ + public static final PathFragment EXTERNAL_REPOSITORY_LOCATION = PathFragment.create("external"); + + /** + * The path name under which external repositories are accessible if {@code + * --experimental_sibling_repository_layout} is not in effect. + */ public static final PathFragment EXTERNAL_PACKAGE_NAME = PathFragment.create("external"); + + /** + * The name of the package containing information about external repositories if {@code + * --experimental_disable_external_package} is not in effect. + */ public static final PackageIdentifier EXTERNAL_PACKAGE_IDENTIFIER = PackageIdentifier.createInMainRepo(EXTERNAL_PACKAGE_NAME); + public static final PathFragment WORKSPACE_FILE_NAME = PathFragment.create("WORKSPACE"); public static final PathFragment WORKSPACE_DOT_BAZEL_FILE_NAME = PathFragment.create("WORKSPACE.bazel");
diff --git a/src/main/java/com/google/devtools/build/lib/cmdline/RepositoryName.java b/src/main/java/com/google/devtools/build/lib/cmdline/RepositoryName.java index 5f4d455..3e14d05 100644 --- a/src/main/java/com/google/devtools/build/lib/cmdline/RepositoryName.java +++ b/src/main/java/com/google/devtools/build/lib/cmdline/RepositoryName.java
@@ -250,7 +250,7 @@ public PathFragment getSourceRoot() { return isDefault() || isMain() ? PathFragment.EMPTY_FRAGMENT - : LabelConstants.EXTERNAL_PACKAGE_NAME.getRelative(strippedName()); + : LabelConstants.EXTERNAL_REPOSITORY_LOCATION.getRelative(strippedName()); } /**
diff --git a/src/main/java/com/google/devtools/build/lib/packages/StarlarkSemanticsOptions.java b/src/main/java/com/google/devtools/build/lib/packages/StarlarkSemanticsOptions.java index 31c3218..3c82d52 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/StarlarkSemanticsOptions.java +++ b/src/main/java/com/google/devtools/build/lib/packages/StarlarkSemanticsOptions.java
@@ -215,6 +215,20 @@ public boolean experimentalRepoRemoteExec; @Option( + name = "experimental_disable_external_package", + defaultValue = "false", + documentationCategory = OptionDocumentationCategory.STARLARK_SEMANTICS, + effectTags = {OptionEffectTag.LOADING_AND_ANALYSIS, OptionEffectTag.LOSES_INCREMENTAL_STATE}, + metadataTags = { + OptionMetadataTag.EXPERIMENTAL, + }, + help = + "If set to true, the auto-generated //external package will not be available anymore. " + + "Bazel will still be unable to parse the file 'external/BUILD', but globs reaching " + + "into external/ from the unnamed package will work.") + public boolean experimentalDisableExternalPackage; + + @Option( name = "experimental_sibling_repository_layout", defaultValue = "false", documentationCategory = OptionDocumentationCategory.STARLARK_SEMANTICS, @@ -654,6 +668,7 @@ .experimentalStarlarkUnusedInputsList(experimentalStarlarkUnusedInputsList) .experimentalCcSharedLibrary(experimentalCcSharedLibrary) .experimentalRepoRemoteExec(experimentalRepoRemoteExec) + .experimentalDisableExternalPackage(experimentalDisableExternalPackage) .experimentalSiblingRepositoryLayout(experimentalSiblingRepositoryLayout) .incompatibleApplicableLicenses(incompatibleApplicableLicenses) .incompatibleBzlDisallowLoadAfterStatement(incompatibleBzlDisallowLoadAfterStatement)
diff --git a/src/main/java/com/google/devtools/build/lib/query2/ParallelSkyQueryUtils.java b/src/main/java/com/google/devtools/build/lib/query2/ParallelSkyQueryUtils.java index 24267e0..9e81dbd 100644 --- a/src/main/java/com/google/devtools/build/lib/query2/ParallelSkyQueryUtils.java +++ b/src/main/java/com/google/devtools/build/lib/query2/ParallelSkyQueryUtils.java
@@ -154,7 +154,7 @@ /*resultUniquifier=*/ env.createSkyKeyUniquifier(), context, callback); - visitor.visitAndWaitForCompletion(env.getFileStateKeysForFileFragments(fileIdentifiers)); + visitor.visitAndWaitForCompletion(env.getSkyKeysForFileFragments(fileIdentifiers)); } static QueryTaskFuture<Void> getDepsUnboundedParallel( @@ -234,4 +234,3 @@ } } } -
diff --git a/src/main/java/com/google/devtools/build/lib/query2/RBuildFilesVisitor.java b/src/main/java/com/google/devtools/build/lib/query2/RBuildFilesVisitor.java index ed5dcd5..73b638c 100644 --- a/src/main/java/com/google/devtools/build/lib/query2/RBuildFilesVisitor.java +++ b/src/main/java/com/google/devtools/build/lib/query2/RBuildFilesVisitor.java
@@ -16,7 +16,6 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.cmdline.Label; -import com.google.devtools.build.lib.cmdline.LabelConstants; import com.google.devtools.build.lib.cmdline.PackageIdentifier; import com.google.devtools.build.lib.collect.compacthashset.CompactHashSet; import com.google.devtools.build.lib.packages.Target; @@ -25,7 +24,6 @@ import com.google.devtools.build.lib.query2.engine.QueryException; import com.google.devtools.build.lib.query2.engine.QueryExpressionContext; import com.google.devtools.build.lib.query2.engine.Uniquifier; -import com.google.devtools.build.lib.skyframe.PackageValue; import com.google.devtools.build.lib.skyframe.SkyFunctions; import com.google.devtools.build.skyframe.SkyFunctionName; import com.google.devtools.build.skyframe.SkyKey; @@ -54,8 +52,6 @@ SkyFunctions.PREPARE_DEPS_OF_PATTERN, SkyFunctions.PREPARE_DEPS_OF_PATTERNS); - private static final SkyKey EXTERNAL_PACKAGE_KEY = - PackageValue.key(LabelConstants.EXTERNAL_PACKAGE_IDENTIFIER); private final SkyQueryEnvironment env; private final QueryExpressionContext<Target> context; private final Uniquifier<SkyKey> visitUniquifier; @@ -89,13 +85,6 @@ if (resultUniquifier.unique(rdep)) { keysToUseForResult.add((PackageIdentifier) rdep.argument()); } - // PackageValue(//p) has a transitive dep on the PackageValue(//external), so we need to - // make sure these dep paths are traversed. These dep paths go through the singleton - // WorkspaceNameValue(), and that node has a direct dep on PackageValue(//external), so it - // suffices to ensure we visit PackageValue(//external). - if (rdep.equals(EXTERNAL_PACKAGE_KEY)) { - keysToVisitNext.add(rdep); - } } else if (!NODES_TO_PRUNE_TRAVERSAL.contains(rdep.functionName())) { processNonPackageRdepAndDetermineVisitations(rdep, keysToVisitNext, keysToUseForResult); }
diff --git a/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java index 3678032..6f5e062 100644 --- a/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java +++ b/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java
@@ -1211,15 +1211,8 @@ return target; } - /** - * Returns package lookup keys for looking up the package root for which there may be a relevant - * (from the perspective of {@link #getRBuildFiles}) {@link FileStateValue} node in the graph for - * {@code originalFileFragment}, which is assumed to be a file path. - * - * <p>This is a helper function for {@link #getFileStateKeysForFileFragments}. - */ - private static Iterable<SkyKey> getPkgLookupKeysForFile(PathFragment originalFileFragment, - PathFragment currentPathFragment) { + private static ImmutableList<SkyKey> getDependenciesForWorkspaceFile( + PathFragment originalFileFragment, PathFragment currentPathFragment) { if (originalFileFragment.equals(currentPathFragment) && WorkspaceFileHelper.matchWorkspaceFileName(originalFileFragment)) { // TODO(mschaller): this should not be checked at runtime. These are constants! @@ -1228,10 +1221,29 @@ .getParentDirectory() .equals(PathFragment.EMPTY_FRAGMENT), LabelConstants.WORKSPACE_FILE_NAME); - return ImmutableList.of( - PackageLookupValue.key(LabelConstants.EXTERNAL_PACKAGE_IDENTIFIER), - PackageLookupValue.key(PackageIdentifier.createInMainRepo(PathFragment.EMPTY_FRAGMENT))); + // The WORKSPACE file is a transitive dependency of every package. Unfortunately, there is no + // specific SkyValue that we can use to figure out under which package path entries it lives, + // so we add another dependency that's a transitive dependency of every package. + // + // The PackageLookupValue for //external is not a good choice, because it's not requested when + // that package is built so that we can have a directory called external/ in the workspace + // (this is special-cased in PackageFunction). The principled solution would be to not rely + // on external/ and introduce a SkyValue for the concept of "the WORKSPACE file of the main + // repository", but we don't have that yet, so we improvise. + return ImmutableList.of(PackageValue.key(LabelConstants.EXTERNAL_PACKAGE_IDENTIFIER)); } + + return ImmutableList.of(); + } + + /** + * Returns package lookup keys for looking up the package root for which there may be a relevant + * (from the perspective of {@link #getRBuildFiles}) {@link FileStateValue} node in the graph for + * {@code originalFileFragment}, which is assumed to be a file path. + * + * <p>This is a helper function for {@link #getSkyKeysForFileFragments}. + */ + private static Iterable<SkyKey> getPkgLookupKeysForFile(PathFragment currentPathFragment) { PathFragment parentPathFragment = currentPathFragment.getParentDirectory(); return parentPathFragment == null ? ImmutableList.of() @@ -1240,19 +1252,26 @@ } /** - * Returns FileStateValue keys for which there may be relevant (from the perspective of {@link + * Returns SkyKeys for which there may be relevant (from the perspective of {@link * #getRBuildFiles}) FileStateValues in the graph corresponding to the given {@code * pathFragments}, which are assumed to be file paths. * - * <p>To do this, we emulate the {@link ContainingPackageLookupFunction} logic: for each given - * file path, we look for the nearest ancestor directory (starting with its parent directory), if - * any, that has a package. The {@link PackageLookupValue} for this package tells us the package - * root that we should use for the {@link RootedPath} for the {@link FileStateValue} key. + * <p>The passed in {@link PathFragment}s can be associated uniquely to a {@link FileStateValue} + * with the following logic (the same logic that's in {@link ContainingPackageLookupFunction}): + * For each given file path, we look for the nearest ancestor directory (starting with its parent + * directory), if any, that has a package. The {@link PackageLookupValue} for this package tells + * us the package root that we should use for the {@link RootedPath} for the {@link + * FileStateValue} key. + * + * <p>For the reverse graph traversal in {@link #getRBuildFiles}, we are looking for all packages + * that are transitively reverse dependencies of those {@link FileStateValue} keys. This function + * returns a collection of SkyKeys whose transitive reverse dependencies must contain the exact + * same set of packages. * * <p>Note that there may not be nodes in the graph corresponding to the returned SkyKeys. */ - protected Collection<SkyKey> getFileStateKeysForFileFragments( - Iterable<PathFragment> pathFragments) throws InterruptedException { + protected Collection<SkyKey> getSkyKeysForFileFragments(Iterable<PathFragment> pathFragments) + throws InterruptedException { Set<SkyKey> result = new HashSet<>(); Multimap<PathFragment, PathFragment> currentToOriginal = ArrayListMultimap.create(); for (PathFragment pathFragment : pathFragments) { @@ -1264,10 +1283,12 @@ for (Map.Entry<PathFragment, PathFragment> entry : currentToOriginal.entries()) { PathFragment current = entry.getKey(); PathFragment original = entry.getValue(); - for (SkyKey packageLookupKey : getPkgLookupKeysForFile(original, current)) { + for (SkyKey packageLookupKey : getPkgLookupKeysForFile(current)) { packageLookupKeysToOriginal.put(packageLookupKey, original); packageLookupKeysToCurrent.put(packageLookupKey, current); } + + result.addAll(getDependenciesForWorkspaceFile(original, current)); } Map<SkyKey, SkyValue> lookupValues = graph.getSuccessfulValues(packageLookupKeysToOriginal.keySet());
diff --git a/src/main/java/com/google/devtools/build/lib/repository/ExternalPackageUtil.java b/src/main/java/com/google/devtools/build/lib/repository/ExternalPackageUtil.java index d5d558d..5b91936 100644 --- a/src/main/java/com/google/devtools/build/lib/repository/ExternalPackageUtil.java +++ b/src/main/java/com/google/devtools/build/lib/repository/ExternalPackageUtil.java
@@ -14,14 +14,21 @@ package com.google.devtools.build.lib.repository; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSortedSet; +import com.google.common.collect.Iterables; +import com.google.devtools.build.lib.actions.FileValue; import com.google.devtools.build.lib.cmdline.LabelConstants; import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.packages.BuildFileContainsErrorsException; +import com.google.devtools.build.lib.packages.BuildFileName; import com.google.devtools.build.lib.packages.Package; import com.google.devtools.build.lib.packages.Rule; import com.google.devtools.build.lib.packages.WorkspaceFileValue; -import com.google.devtools.build.lib.skyframe.PackageLookupValue; +import com.google.devtools.build.lib.pkgcache.PathPackageLocator; +import com.google.devtools.build.lib.skyframe.PrecomputedValue; +import com.google.devtools.build.lib.vfs.PathFragment; +import com.google.devtools.build.lib.vfs.Root; import com.google.devtools.build.lib.vfs.RootedPath; import com.google.devtools.build.skyframe.SkyFunction.Environment; import com.google.devtools.build.skyframe.SkyFunctionException.Transience; @@ -68,16 +75,63 @@ return extractor.getRule(); } + private static RootedPath checkWorkspaceFile( + Environment env, Root root, PathFragment workspaceFile) throws InterruptedException { + RootedPath candidate = RootedPath.toRootedPath(root, workspaceFile); + FileValue fileValue = (FileValue) env.getValue(FileValue.key(candidate)); + if (env.valuesMissing()) { + return null; + } + + return fileValue.isFile() ? candidate : null; + } + + /** + * Returns the path of the main WORKSPACE file or null when a Skyframe restart is required. + * + * <p>Should also return null when the WORKSPACE file is not present, but then some tests break, + * so then it lies and returns the RootedPath corresponding to the last package path entry. + */ + @Nullable + public static RootedPath findWorkspaceFile(Environment env) throws InterruptedException { + PathPackageLocator packageLocator = PrecomputedValue.PATH_PACKAGE_LOCATOR.get(env); + ImmutableList<Root> packagePath = packageLocator.getPathEntries(); + for (Root candidateRoot : packagePath) { + RootedPath path = + checkWorkspaceFile( + env, candidateRoot, BuildFileName.WORKSPACE_DOT_BAZEL.getFilenameFragment()); + if (env.valuesMissing()) { + return null; + } + + if (path != null) { + return path; + } + + path = checkWorkspaceFile(env, candidateRoot, BuildFileName.WORKSPACE.getFilenameFragment()); + if (env.valuesMissing()) { + return null; + } + + if (path != null) { + return path; + } + } + + // TODO(lberki): Technically, this means that the WORKSPACE file was not found. I'd love to not + // have this here, but a lot of tests break without it because they rely on Bazel kinda working + // even if the WORKSPACE file is not present. + return RootedPath.toRootedPath( + Iterables.getLast(packagePath), BuildFileName.WORKSPACE.getFilenameFragment()); + } + /** Returns false if some SkyValues were missing. */ private static boolean iterateWorkspaceFragments( Environment env, WorkspaceFileValueProcessor processor) throws InterruptedException { - SkyKey packageLookupKey = PackageLookupValue.key(LabelConstants.EXTERNAL_PACKAGE_IDENTIFIER); - PackageLookupValue packageLookupValue = (PackageLookupValue) env.getValue(packageLookupKey); - if (packageLookupValue == null) { + RootedPath workspacePath = findWorkspaceFile(env); + if (env.valuesMissing()) { return false; } - RootedPath workspacePath = - packageLookupValue.getRootedPath(LabelConstants.EXTERNAL_PACKAGE_IDENTIFIER); SkyKey workspaceKey = WorkspaceFileValue.key(workspacePath); WorkspaceFileValue value;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java index 8b8d82f..95b211b 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java +++ b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java
@@ -533,7 +533,7 @@ } protected static Path getExternalRepositoryDirectory(BlazeDirectories directories) { - return directories.getOutputBase().getRelative(LabelConstants.EXTERNAL_PACKAGE_NAME); + return directories.getOutputBase().getRelative(LabelConstants.EXTERNAL_REPOSITORY_LOCATION); } /**
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ExternalFilesHelper.java b/src/main/java/com/google/devtools/build/lib/skyframe/ExternalFilesHelper.java index 1fcbc4e..df04a16 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/ExternalFilesHelper.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/ExternalFilesHelper.java
@@ -245,7 +245,7 @@ return FileType.EXTERNAL; } if (rootedPath.asPath().startsWith(outputBase)) { - Path externalRepoDir = outputBase.getRelative(LabelConstants.EXTERNAL_PACKAGE_NAME); + Path externalRepoDir = outputBase.getRelative(LabelConstants.EXTERNAL_REPOSITORY_LOCATION); if (rootedPath.asPath().startsWith(externalRepoDir)) { anyNonOutputExternalFilesSeen = true; return FileType.EXTERNAL_REPO;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ExternalPackageFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ExternalPackageFunction.java index 47791d5..71fa63a 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/ExternalPackageFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/ExternalPackageFunction.java
@@ -17,6 +17,7 @@ import com.google.common.collect.Interner; import com.google.devtools.build.lib.concurrent.BlazeInterners; import com.google.devtools.build.lib.packages.WorkspaceFileValue; +import com.google.devtools.build.lib.repository.ExternalPackageUtil; import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec; import com.google.devtools.build.lib.vfs.RootedPath; import com.google.devtools.build.skyframe.AbstractSkyKey; @@ -27,17 +28,23 @@ import javax.annotation.Nullable; /** - * A SkyFunction for resolving //external:* bindings. + * A SkyFunction for parsing the {@code //external} package. * * <p>This function iterates through the WorkspaceFileValue-s to get the last WorkspaceFileValue - * that will contains all the bind statements from the workspace file. + * that will contain all the bind statements from the WORKSPACE file. */ public class ExternalPackageFunction implements SkyFunction { @Nullable @Override public SkyValue compute(SkyKey skyKey, Environment env) throws InterruptedException { - RootedPath workspacePath = (RootedPath) skyKey.argument(); + RootedPath workspacePath = ExternalPackageUtil.findWorkspaceFile(env); + if (env.valuesMissing()) { + return null; + } + + // This currently cannot be null due to a hack in ExternalPackageUtil.findWorkspaceFile() + // TODO(lberki): Remove that hack and handle the case when the WORKSPACE file is not found. SkyKey key = WorkspaceFileValue.key(workspacePath); WorkspaceFileValue value = (WorkspaceFileValue) env.getValue(key); if (value == null) {
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/LocalRepositoryLookupFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/LocalRepositoryLookupFunction.java index 0e87677..86e21c1 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/LocalRepositoryLookupFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/LocalRepositoryLookupFunction.java
@@ -18,18 +18,17 @@ import com.google.common.collect.Iterables; import com.google.devtools.build.lib.actions.FileValue; import com.google.devtools.build.lib.actions.InconsistentFilesystemException; -import com.google.devtools.build.lib.cmdline.LabelConstants; import com.google.devtools.build.lib.cmdline.LabelSyntaxException; import com.google.devtools.build.lib.cmdline.RepositoryName; import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.packages.AggregatingAttributeMapper; -import com.google.devtools.build.lib.packages.BuildFileNotFoundException; import com.google.devtools.build.lib.packages.ErrorDeterminingRepositoryException; import com.google.devtools.build.lib.packages.Package; import com.google.devtools.build.lib.packages.Package.NameConflictException; import com.google.devtools.build.lib.packages.Rule; import com.google.devtools.build.lib.packages.Type; import com.google.devtools.build.lib.packages.WorkspaceFileValue; +import com.google.devtools.build.lib.repository.ExternalPackageUtil; import com.google.devtools.build.lib.rules.repository.LocalRepositoryRule; import com.google.devtools.build.lib.rules.repository.WorkspaceFileHelper; import com.google.devtools.build.lib.skyframe.PackageFunction.PackageFunctionException; @@ -136,33 +135,11 @@ private Optional<LocalRepositoryLookupValue> maybeCheckWorkspaceForRepository( Environment env, final RootedPath directory) throws InterruptedException, LocalRepositoryLookupFunctionException { - // Look up the main WORKSPACE file by the external package, to find all repositories. - PackageLookupValue externalPackageLookupValue; - try { - externalPackageLookupValue = - (PackageLookupValue) - env.getValueOrThrow( - PackageLookupValue.key(LabelConstants.EXTERNAL_PACKAGE_IDENTIFIER), - BuildFileNotFoundException.class, - InconsistentFilesystemException.class); - if (externalPackageLookupValue == null) { - return Optional.absent(); - } - } catch (BuildFileNotFoundException e) { - throw new LocalRepositoryLookupFunctionException( - new ErrorDeterminingRepositoryException( - "BuildFileNotFoundException while loading the //external package", e), - Transience.PERSISTENT); - } catch (InconsistentFilesystemException e) { - throw new LocalRepositoryLookupFunctionException( - new ErrorDeterminingRepositoryException( - "InconsistentFilesystemException while loading the //external package", e), - Transience.PERSISTENT); + RootedPath workspacePath = ExternalPackageUtil.findWorkspaceFile(env); + if (env.valuesMissing()) { + return Optional.absent(); } - RootedPath workspacePath = - externalPackageLookupValue.getRootedPath(LabelConstants.EXTERNAL_PACKAGE_IDENTIFIER); - SkyKey workspaceKey = WorkspaceFileValue.key(workspacePath); do { WorkspaceFileValue value;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java index 92454ad..a4b7240 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java
@@ -51,6 +51,7 @@ import com.google.devtools.build.lib.profiler.Profiler; import com.google.devtools.build.lib.profiler.ProfilerTask; import com.google.devtools.build.lib.profiler.SilentCloseable; +import com.google.devtools.build.lib.repository.ExternalPackageUtil; import com.google.devtools.build.lib.rules.repository.WorkspaceFileHelper; import com.google.devtools.build.lib.skyframe.GlobValue.InvalidGlobPatternException; import com.google.devtools.build.lib.skyframe.SkylarkImportLookupFunction.SkylarkImportFailedException; @@ -292,26 +293,14 @@ * @throws PackageFunctionException if there is an error computing the workspace file or adding * its rules to the //external package. */ - private SkyValue getExternalPackage(Environment env, Root packageLookupPath) + private SkyValue getExternalPackage(Environment env) throws PackageFunctionException, InterruptedException { StarlarkSemantics starlarkSemantics = PrecomputedValue.STARLARK_SEMANTICS.get(env); - if (starlarkSemantics == null) { + RootedPath workspacePath = ExternalPackageUtil.findWorkspaceFile(env); + if (env.valuesMissing()) { return null; } - RootedPath workspacePath; - try { - workspacePath = WorkspaceFileHelper.getWorkspaceRootedFile(packageLookupPath, env); - if (workspacePath == null) { - return null; - } - } catch (IOException e) { - throw new PackageFunctionException( - new NoSuchPackageException( - LabelConstants.EXTERNAL_PACKAGE_IDENTIFIER, - "Could not determine workspace file (\"WORKSPACE.bazel\" or \"WORKSPACE\"): " - + e.getMessage()), - Transience.PERSISTENT); - } + SkyKey workspaceKey = ExternalPackageFunction.key(workspacePath); PackageValue workspace = null; try { @@ -355,6 +344,9 @@ public SkyValue compute(SkyKey key, Environment env) throws PackageFunctionException, InterruptedException { PackageIdentifier packageId = (PackageIdentifier) key.argument(); + if (packageId.equals(LabelConstants.EXTERNAL_PACKAGE_IDENTIFIER)) { + return getExternalPackage(env); + } SkyKey packageLookupKey = PackageLookupValue.key(packageId); PackageLookupValue packageLookupValue; @@ -394,9 +386,6 @@ } } - if (packageId.equals(LabelConstants.EXTERNAL_PACKAGE_IDENTIFIER)) { - return getExternalPackage(env, packageLookupValue.getRoot()); - } WorkspaceNameValue workspaceNameValue = (WorkspaceNameValue) env.getValue(WorkspaceNameValue.key());
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PackageLookupFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/PackageLookupFunction.java index 187b5d8..0249681 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/PackageLookupFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/PackageLookupFunction.java
@@ -14,7 +14,7 @@ package com.google.devtools.build.lib.skyframe; import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; +import com.google.common.base.Verify; import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.actions.FileValue; import com.google.devtools.build.lib.actions.InconsistentFilesystemException; @@ -27,6 +27,7 @@ import com.google.devtools.build.lib.packages.NoSuchPackageException; import com.google.devtools.build.lib.packages.RepositoryFetchException; import com.google.devtools.build.lib.pkgcache.PathPackageLocator; +import com.google.devtools.build.lib.repository.ExternalPackageUtil; import com.google.devtools.build.lib.syntax.EvalException; import com.google.devtools.build.lib.syntax.StarlarkSemantics; import com.google.devtools.build.lib.vfs.PathFragment; @@ -71,6 +72,7 @@ public SkyValue compute(SkyKey skyKey, Environment env) throws PackageLookupFunctionException, InterruptedException { PathPackageLocator pkgLocator = PrecomputedValue.PATH_PACKAGE_LOCATOR.get(env); + StarlarkSemantics semantics = PrecomputedValue.STARLARK_SEMANTICS.get(env); PackageIdentifier packageKey = (PackageIdentifier) skyKey.argument(); @@ -87,8 +89,12 @@ if (!packageKey.getRepository().isMain()) { return computeExternalPackageLookupValue(skyKey, env, packageKey); - } else if (packageKey.equals(LabelConstants.EXTERNAL_PACKAGE_IDENTIFIER)) { - return computeWorkspacePackageLookupValue(env, pkgLocator.getPathEntries()); + } + + if (packageKey.equals(LabelConstants.EXTERNAL_PACKAGE_IDENTIFIER)) { + return semantics.experimentalDisableExternalPackage() + ? PackageLookupValue.NO_BUILD_FILE_VALUE + : computeWorkspacePackageLookupValue(env); } // Check .bazelignore file under main repository. @@ -194,30 +200,6 @@ private PackageLookupValue getPackageLookupValue( Environment env, - ImmutableList<Root> packagePathEntries, - PackageIdentifier packageIdentifier, - BuildFileName buildFileName) - throws PackageLookupFunctionException, InterruptedException { - - // TODO(bazel-team): The following is O(n^2) on the number of elements on the package path due - // to having restart the SkyFunction after every new dependency. However, if we try to batch - // the missing value keys, more dependencies than necessary will be declared. This wart can be - // fixed once we have nicer continuation support [skyframe-loading] - for (Root packagePathEntry : packagePathEntries) { - PackageLookupValue result = - getPackageLookupValue(env, packagePathEntry, packageIdentifier, buildFileName); - if (result == null) { - return null; - } - if (result != PackageLookupValue.NO_BUILD_FILE_VALUE) { - return result; - } - } - return PackageLookupValue.NO_BUILD_FILE_VALUE; - } - - private PackageLookupValue getPackageLookupValue( - Environment env, Root packagePathEntry, PackageIdentifier packageIdentifier, BuildFileName buildFileName) @@ -306,51 +288,29 @@ return false; } - private PackageLookupValue computeWorkspacePackageLookupValue( - Environment env, ImmutableList<Root> packagePathEntries) - throws PackageLookupFunctionException, InterruptedException { - PackageLookupValue resultForWorkspaceDotBazel = - getPackageLookupValue( - env, - packagePathEntries, - LabelConstants.EXTERNAL_PACKAGE_IDENTIFIER, - BuildFileName.WORKSPACE_DOT_BAZEL); - if (resultForWorkspaceDotBazel == null) { + private static PackageLookupValue computeWorkspacePackageLookupValue(Environment env) + throws InterruptedException { + RootedPath workspaceFile = ExternalPackageUtil.findWorkspaceFile(env); + if (env.valuesMissing()) { return null; } - if (resultForWorkspaceDotBazel.packageExists()) { - return resultForWorkspaceDotBazel; - } - PackageLookupValue resultForWorkspace = - getPackageLookupValue( - env, - packagePathEntries, - LabelConstants.EXTERNAL_PACKAGE_IDENTIFIER, - BuildFileName.WORKSPACE); - if (resultForWorkspace == null) { - return null; - } - if (resultForWorkspace.packageExists()) { - return resultForWorkspace; - } - // Fall back on the last package path entry if there were any and nothing else worked. - // TODO(kchodorow): get rid of this, the semantics are wrong (successful package lookup should - // mean the package exists). a bunch of tests need to be rewritten first though. - if (packagePathEntries.isEmpty()) { + + if (workspaceFile == null) { return PackageLookupValue.NO_BUILD_FILE_VALUE; + } else { + BuildFileName filename = null; + for (BuildFileName candidate : BuildFileName.values()) { + if (workspaceFile.getRootRelativePath().equals(candidate.getFilenameFragment())) { + filename = candidate; + break; + } + } + + // Otherwise ExternalPackageUtil.findWorkspaceFile() returned something whose name is not in + // BuildFileName + Verify.verify(filename != null); + return PackageLookupValue.success(workspaceFile.getRoot(), filename); } - Root lastPackagePath = packagePathEntries.get(packagePathEntries.size() - 1); - FileValue lastPackagePackagePathFileValue = - getFileValue( - RootedPath.toRootedPath(lastPackagePath, PathFragment.EMPTY_FRAGMENT), - env, - LabelConstants.EXTERNAL_PACKAGE_IDENTIFIER); - if (lastPackagePackagePathFileValue == null) { - return null; - } - return lastPackagePackagePathFileValue.exists() - ? PackageLookupValue.success(lastPackagePath, BuildFileName.WORKSPACE) - : PackageLookupValue.NO_BUILD_FILE_VALUE; } /**
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceFileFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceFileFunction.java index 4736075..0e7c87f 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceFileFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceFileFunction.java
@@ -41,9 +41,7 @@ import java.util.function.Function; import java.util.stream.Collectors; -/** - * A SkyFunction to parse WORKSPACE files. - */ +/** A SkyFunction to parse the WORKSPACE file at a given path. */ public class WorkspaceFileFunction implements SkyFunction { private final PackageFactory packageFactory; @@ -68,9 +66,9 @@ throws WorkspaceFileFunctionException, InterruptedException { WorkspaceFileKey key = (WorkspaceFileKey) skyKey.argument(); - RootedPath workspaceRoot = key.getPath(); - WorkspaceASTValue workspaceASTValue = (WorkspaceASTValue) env.getValue( - WorkspaceASTValue.key(workspaceRoot)); + RootedPath workspaceFile = key.getPath(); + WorkspaceASTValue workspaceASTValue = + (WorkspaceASTValue) env.getValue(WorkspaceASTValue.key(workspaceFile)); if (workspaceASTValue == null) { return null; } @@ -79,11 +77,9 @@ return null; } - RootedPath repoWorkspace = - RootedPath.toRootedPath(workspaceRoot.getRoot(), workspaceRoot.getRootRelativePath()); Package.Builder builder = packageFactory.newExternalPackageBuilder( - repoWorkspace, ruleClassProvider.getRunfilesPrefix(), starlarkSemantics); + workspaceFile, ruleClassProvider.getRunfilesPrefix(), starlarkSemantics); if (workspaceASTValue.getASTs().isEmpty()) { try { @@ -92,7 +88,7 @@ /* importMap = */ ImmutableMap.<String, Extension>of(), /* importToChunkMap = */ ImmutableMap.<String, Integer>of(), /* bindings = */ ImmutableMap.<String, Object>of(), - workspaceRoot, + workspaceFile, /* idx = */ 0, // first fragment /* hasNext = */ false, ImmutableMap.of(), @@ -103,7 +99,7 @@ } WorkspaceFactory parser; WorkspaceFileValue prevValue = null; - try (Mutability mutability = Mutability.create("workspace", repoWorkspace)) { + try (Mutability mutability = Mutability.create("workspace", workspaceFile)) { parser = new WorkspaceFactory( builder, @@ -118,7 +114,7 @@ if (key.getIndex() > 0) { prevValue = (WorkspaceFileValue) - env.getValue(WorkspaceFileValue.key(key.getPath(), key.getIndex() - 1)); + env.getValue(WorkspaceFileValue.key(workspaceFile, key.getIndex() - 1)); if (prevValue == null) { return null; } @@ -130,7 +126,7 @@ StarlarkFile ast = workspaceASTValue.getASTs().get(key.getIndex()); PackageFunction.SkylarkImportResult importResult = PackageFunction.fetchImportsFromBuildFile( - repoWorkspace, + workspaceFile, rootPackage, /*repoMapping=*/ ImmutableMap.of(), ast, @@ -153,7 +149,7 @@ parser.getImportMap(), createImportToChunkMap(prevValue, parser, key), parser.getVariableBindings(), - workspaceRoot, + workspaceFile, key.getIndex(), key.getIndex() < workspaceASTValue.getASTs().size() - 1, ImmutableMap.copyOf(parser.getManagedDirectories()),
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/StarlarkSemantics.java b/src/main/java/com/google/devtools/build/lib/syntax/StarlarkSemantics.java index 26bb70c..3278452 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/StarlarkSemantics.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/StarlarkSemantics.java
@@ -53,6 +53,8 @@ public static final String EXPERIMENTAL_ACTION_ARGS = "experimental_action_args"; public static final String EXPERIMENTAL_ALLOW_INCREMENTAL_REPOSITORY_UPDATES = "experimental_allow_incremental_repository_updates"; + public static final String EXPERIMENTAL_DISABLE_EXTERNAL_PACKGE = + "experimental_disable_external_package"; public static final String EXPERIMENTAL_SIBLING_REPOSITORY_LAYOUT = "experimental_sibling_repository_layout"; public static final String EXPERIMENTAL_ASPECT_OUTPUT_PROPAGATION = @@ -96,6 +98,8 @@ return experimentalActionArgs(); case FlagIdentifier.EXPERIMENTAL_ALLOW_INCREMENTAL_REPOSITORY_UPDATES: return experimentalAllowIncrementalRepositoryUpdates(); + case FlagIdentifier.EXPERIMENTAL_DISABLE_EXTERNAL_PACKGE: + return experimentalDisableExternalPackage(); case FlagIdentifier.EXPERIMENTAL_SIBLING_REPOSITORY_LAYOUT: return experimentalSiblingRepositoryLayout(); case FlagIdentifier.EXPERIMENTAL_ASPECT_OUTPUT_PROPAGATION: @@ -203,6 +207,8 @@ public abstract boolean experimentalRepoRemoteExec(); + public abstract boolean experimentalDisableExternalPackage(); + public abstract boolean experimentalSiblingRepositoryLayout(); public abstract boolean incompatibleAlwaysCheckDepsetElements(); @@ -307,6 +313,7 @@ .experimentalStarlarkUnusedInputsList(true) .experimentalCcSharedLibrary(false) .experimentalRepoRemoteExec(false) + .experimentalDisableExternalPackage(false) .experimentalSiblingRepositoryLayout(false) .incompatibleAlwaysCheckDepsetElements(false) .incompatibleApplicableLicenses(false) @@ -371,6 +378,8 @@ public abstract Builder experimentalRepoRemoteExec(boolean value); + public abstract Builder experimentalDisableExternalPackage(boolean value); + public abstract Builder experimentalSiblingRepositoryLayout(boolean value); public abstract Builder incompatibleAlwaysCheckDepsetElements(boolean value);
diff --git a/src/test/java/com/google/devtools/build/lib/packages/SkylarkSemanticsConsistencyTest.java b/src/test/java/com/google/devtools/build/lib/packages/SkylarkSemanticsConsistencyTest.java index b13f2dc..743d169 100644 --- a/src/test/java/com/google/devtools/build/lib/packages/SkylarkSemanticsConsistencyTest.java +++ b/src/test/java/com/google/devtools/build/lib/packages/SkylarkSemanticsConsistencyTest.java
@@ -121,6 +121,7 @@ // <== Add new options here in alphabetic order ==> "--debug_depset_depth=" + rand.nextBoolean(), "--experimental_action_args=" + rand.nextBoolean(), + "--experimental_disable_external_package=" + rand.nextBoolean(), "--experimental_sibling_repository_layout=" + rand.nextBoolean(), "--experimental_allow_incremental_repository_updates=" + rand.nextBoolean(), "--experimental_aspect_output_propagation=" + rand.nextBoolean(), @@ -175,6 +176,7 @@ // <== Add new options here in alphabetic order ==> .debugDepsetDepth(rand.nextBoolean()) .experimentalActionArgs(rand.nextBoolean()) + .experimentalDisableExternalPackage(rand.nextBoolean()) .experimentalSiblingRepositoryLayout(rand.nextBoolean()) .experimentalAllowIncrementalRepositoryUpdates(rand.nextBoolean()) .experimentalAspectOutputPropagation(rand.nextBoolean())
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/FileFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/FileFunctionTest.java index ea3efbf..d173a20 100644 --- a/src/test/java/com/google/devtools/build/lib/skyframe/FileFunctionTest.java +++ b/src/test/java/com/google/devtools/build/lib/skyframe/FileFunctionTest.java
@@ -391,7 +391,7 @@ public void testAbsoluteSymlinkToExternal() throws Exception { String externalPath = outputBase - .getRelative(LabelConstants.EXTERNAL_PACKAGE_NAME) + .getRelative(LabelConstants.EXTERNAL_REPOSITORY_LOCATION) .getRelative("a/b") .getPathString(); symlink("a", externalPath);
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/WorkspaceFileFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/WorkspaceFileFunctionTest.java index 69e78aa..02b80ad 100644 --- a/src/test/java/com/google/devtools/build/lib/skyframe/WorkspaceFileFunctionTest.java +++ b/src/test/java/com/google/devtools/build/lib/skyframe/WorkspaceFileFunctionTest.java
@@ -35,6 +35,7 @@ import com.google.devtools.build.lib.packages.Rule; import com.google.devtools.build.lib.packages.WorkspaceFileValue; import com.google.devtools.build.lib.packages.WorkspaceFileValue.WorkspaceFileKey; +import com.google.devtools.build.lib.pkgcache.PathPackageLocator; import com.google.devtools.build.lib.rules.repository.ManagedDirectoriesKnowledge; import com.google.devtools.build.lib.rules.repository.ManagedDirectoriesKnowledgeImpl; import com.google.devtools.build.lib.rules.repository.ManagedDirectoriesKnowledgeImpl.ManagedDirectoriesListener; @@ -53,7 +54,6 @@ import com.google.devtools.build.skyframe.SkyFunction; import com.google.devtools.build.skyframe.SkyFunctionName; import com.google.devtools.build.skyframe.SkyKey; -import com.google.devtools.build.skyframe.SkyValue; import java.io.IOException; import java.util.Objects; import java.util.Set; @@ -66,8 +66,6 @@ import org.junit.runners.JUnit4; import org.mockito.Mockito; import org.mockito.hamcrest.MockitoHamcrest; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; /** * Test for {@link WorkspaceFileFunction}. @@ -107,6 +105,11 @@ } @Override + public boolean isFile() { + return exists; + } + + @Override public ImmutableList<RootedPath> logicalChainDuringResolution() { throw new UnsupportedOperationException(); } @@ -183,46 +186,50 @@ } private SkyFunction.Environment getEnv() throws InterruptedException { + PathPackageLocator locator = Mockito.mock(PathPackageLocator.class); + Mockito.when(locator.getPathEntries()) + .thenReturn(ImmutableList.of(Root.fromPath(directories.getWorkspace()))); + SkyFunction.Environment env = Mockito.mock(SkyFunction.Environment.class); Mockito.when(env.getValue(MockitoHamcrest.argThat(new SkyKeyMatchers(FileValue.FILE)))) - .thenReturn(fakeWorkspaceFileValue); + .then( + invocation -> { + SkyKey key = (SkyKey) invocation.getArguments()[0]; + String path = ((RootedPath) key.argument()).getRootRelativePath().getPathString(); + FakeFileValue result = new FakeFileValue(); + result.setExists(path.equals("WORKSPACE")); + return result; + }); Mockito.when( env.getValue( MockitoHamcrest.argThat(new SkyKeyMatchers(WorkspaceFileValue.WORKSPACE_FILE)))) .then( - new Answer<SkyValue>() { - @Override - public SkyValue answer(InvocationOnMock invocation) throws Throwable { - SkyKey key = (SkyKey) invocation.getArguments()[0]; - return workspaceSkyFunc.compute(key, getEnv()); - } + invocation -> { + SkyKey key = (SkyKey) invocation.getArguments()[0]; + return workspaceSkyFunc.compute(key, getEnv()); }); Mockito.when( env.getValue(MockitoHamcrest.argThat(new SkyKeyMatchers(SkyFunctions.WORKSPACE_AST)))) .then( - new Answer<SkyValue>() { - @Override - public SkyValue answer(InvocationOnMock invocation) throws Throwable { - SkyKey key = (SkyKey) invocation.getArguments()[0]; - return astSkyFunc.compute(key, getEnv()); - } + invocation -> { + SkyKey key = (SkyKey) invocation.getArguments()[0]; + return astSkyFunc.compute(key, getEnv()); }); Mockito.when( env.getValue(MockitoHamcrest.argThat(new SkyKeyMatchers(SkyFunctions.PRECOMPUTED)))) .then( - new Answer<SkyValue>() { - @Override - public SkyValue answer(InvocationOnMock invocation) throws Throwable { - SkyKey key = (SkyKey) invocation.getArguments()[0]; - if (key.equals(PrecomputedValue.STARLARK_SEMANTICS.getKeyForTesting())) { - return new PrecomputedValue(StarlarkSemantics.DEFAULT_SEMANTICS); - } else if (key.equals( - RepositoryDelegatorFunction.RESOLVED_FILE_INSTEAD_OF_WORKSPACE - .getKeyForTesting())) { - return new PrecomputedValue(Optional.<RootedPath>absent()); - } else { - return null; - } + invocation -> { + SkyKey key = (SkyKey) invocation.getArguments()[0]; + if (key.equals(PrecomputedValue.STARLARK_SEMANTICS.getKeyForTesting())) { + return new PrecomputedValue(StarlarkSemantics.DEFAULT_SEMANTICS); + } else if (key.equals( + RepositoryDelegatorFunction.RESOLVED_FILE_INSTEAD_OF_WORKSPACE + .getKeyForTesting())) { + return new PrecomputedValue(Optional.<RootedPath>absent()); + } else if (key.equals(PrecomputedValue.PATH_PACKAGE_LOCATOR.getKeyForTesting())) { + return new PrecomputedValue(locator); + } else { + return null; } }); return env;
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/WorkspaceNameFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/WorkspaceNameFunctionTest.java index b290e8d..4d68c18 100644 --- a/src/test/java/com/google/devtools/build/lib/skyframe/WorkspaceNameFunctionTest.java +++ b/src/test/java/com/google/devtools/build/lib/skyframe/WorkspaceNameFunctionTest.java
@@ -68,12 +68,10 @@ reporter.removeHandler(failFastHandler); scratch.deleteFile("WORKSPACE"); FileSystemUtils.ensureSymbolicLink(scratch.resolve("WORKSPACE"), "WORKSPACE"); - // Transitive errors from WorkspaceNameValue should manifest themselves as - // NoSuchPackageExceptions. assertThatEvaluationResult(eval()) .hasErrorEntryForKeyThat(key) .hasExceptionThat() - .isInstanceOf(NoSuchPackageException.class); + .isInstanceOf(FileSymlinkCycleException.class); } @Test
diff --git a/src/test/shell/bazel/execroot_test.sh b/src/test/shell/bazel/execroot_test.sh index f0b842c..9c312e8 100755 --- a/src/test/shell/bazel/execroot_test.sh +++ b/src/test/shell/bazel/execroot_test.sh
@@ -144,4 +144,68 @@ } +function test_external_directory_globs() { + touch WORKSPACE + + mkdir -p external/a external/c + echo file_ab > external/a/b + echo file_cd > external/c/d + echo file_e > external/e + touch external/a/b external/c/d external/e + + cat > BUILD <<'EOF' +filegroup(name='f', srcs=glob(["**/*"])) +genrule(name="g", srcs=[":f"], outs=["go"], cmd="cat $(locations :f) > $@") +EOF + + bazel build //:g \ + --experimental_disable_external_package \ + --experimental_sibling_repository_layout \ + || fail "build failed" + assert_contains file_ab bazel-bin/go + assert_contains file_cd bazel-bin/go + assert_contains file_e bazel-bin/go +} + +function test_cc_smoke_with_new_layouts() { + touch WORKSPACE + mkdir -p external/a + cat > external/a/BUILD <<EOF +cc_binary(name='a', srcs=['a.cc']) +EOF + + cat > external/a/a.cc <<EOF +int main(void) { + return 0; +} +EOF + + bazel build //external/a:a \ + --experimental_disable_external_package \ + --experimental_sibling_repository_layout \ + || fail "build failed" +} + +function test_java_smoke_with_new_layouts() { + touch WORKSPACE + mkdir -p external/java/a + cat > external/java/a/BUILD <<EOF +java_binary(name='a', srcs=['A.java']) +EOF + + cat > external/java/a/A.java << EOF +package a; +public class A { + public static void main(String[] args) { + System.out.println("hello world"); + } +} +EOF + + bazel build //external/java/a:a \ + --experimental_disable_external_package \ + --experimental_sibling_repository_layout \ + || fail "build failed" +} + run_suite "execution root tests"