diff options
Diffstat (limited to 'src')
10 files changed, 166 insertions, 31 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java b/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java index 2f5f70f01d..e7c4ac468c 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java @@ -283,7 +283,8 @@ public class BuildView { ImmutableList.<ConfiguredTarget>of(), ImmutableList.<ConfiguredTarget>of(), null, - ImmutableMap.<PackageIdentifier, Path>of()); + ImmutableMap.<PackageIdentifier, Path>of(), + ""); private final ImmutableList<ConfiguredTarget> targetsToBuild; @Nullable private final ImmutableList<ConfiguredTarget> targetsToTest; @@ -295,6 +296,7 @@ public class BuildView { @Nullable private final TopLevelArtifactContext topLevelContext; private final ImmutableList<AspectValue> aspects; private final ImmutableMap<PackageIdentifier, Path> packageRoots; + private final String workspaceName; private AnalysisResult( Collection<ConfiguredTarget> targetsToBuild, @@ -306,7 +308,8 @@ public class BuildView { Collection<ConfiguredTarget> parallelTests, Collection<ConfiguredTarget> exclusiveTests, TopLevelArtifactContext topLevelContext, - ImmutableMap<PackageIdentifier, Path> packageRoots) { + ImmutableMap<PackageIdentifier, Path> packageRoots, + String workspaceName) { this.targetsToBuild = ImmutableList.copyOf(targetsToBuild); this.aspects = ImmutableList.copyOf(aspects); this.targetsToTest = targetsToTest == null ? null : ImmutableList.copyOf(targetsToTest); @@ -317,6 +320,7 @@ public class BuildView { this.exclusiveTests = ImmutableSet.copyOf(exclusiveTests); this.topLevelContext = topLevelContext; this.packageRoots = packageRoots; + this.workspaceName = workspaceName; } /** @@ -386,6 +390,10 @@ public class BuildView { public TopLevelArtifactContext getTopLevelContext() { return topLevelContext; } + + public String getWorkspaceName() { + return workspaceName; + } } @@ -602,7 +610,8 @@ public class BuildView { parallelTests, exclusiveTests, topLevelOptions, - skyframeAnalysisResult.getPackageRoots()); + skyframeAnalysisResult.getPackageRoots(), + loadingResult.getWorkspaceName()); } private static NestedSet<Artifact> getBaselineCoverageArtifacts( diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/ExecutionTool.java b/src/main/java/com/google/devtools/build/lib/buildtool/ExecutionTool.java index 1f54bcc0b5..cf838bce49 100644 --- a/src/main/java/com/google/devtools/build/lib/buildtool/ExecutionTool.java +++ b/src/main/java/com/google/devtools/build/lib/buildtool/ExecutionTool.java @@ -51,7 +51,6 @@ import com.google.devtools.build.lib.actions.SimpleActionContextProvider; import com.google.devtools.build.lib.actions.SpawnActionContext; import com.google.devtools.build.lib.actions.TestExecException; import com.google.devtools.build.lib.actions.cache.ActionCache; -import com.google.devtools.build.lib.analysis.BuildView; import com.google.devtools.build.lib.analysis.BuildView.AnalysisResult; import com.google.devtools.build.lib.analysis.ConfiguredTarget; import com.google.devtools.build.lib.analysis.SymlinkTreeActionContext; @@ -94,7 +93,6 @@ import com.google.devtools.build.lib.vfs.FileSystemUtils; import com.google.devtools.build.lib.vfs.ModifiedFileSet; import com.google.devtools.build.lib.vfs.Path; import com.google.devtools.build.lib.vfs.PathFragment; - import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; @@ -341,7 +339,7 @@ public class ExecutionTool { TopLevelArtifactContext topLevelArtifactContext) throws BuildFailedException, InterruptedException, TestExecException, AbruptExitException { Stopwatch timer = Stopwatch.createStarted(); - prepare(packageRoots); + prepare(packageRoots, analysisResult.getWorkspaceName()); ActionGraph actionGraph = analysisResult.getActionGraph(); @@ -363,9 +361,10 @@ public class ExecutionTool { if (targetConfigurations.size() == 1) { String productName = runtime.getProductName(); OutputDirectoryLinksUtils.createOutputDirectoryLinks( - env.getWorkspaceName(), env.getWorkspace(), getExecRoot(), - env.getOutputPath(), getReporter(), targetConfiguration, - request.getBuildOptions().getSymlinkPrefix(productName), productName); + env.getWorkspaceName(), env.getWorkspace(), + getExecRoot(), env.getOutputPath(), getReporter(), + targetConfiguration, request.getBuildOptions().getSymlinkPrefix(productName), + productName); } ActionCache actionCache = getActionCache(); @@ -499,7 +498,7 @@ public class ExecutionTool { } } - private void prepare(ImmutableMap<PackageIdentifier, Path> packageRoots) + private void prepare(ImmutableMap<PackageIdentifier, Path> packageRoots, String workspaceName) throws ExecutorInitException { // Prepare for build. Profiler.instance().markPhase(ProfilePhase.PREPARE); @@ -510,7 +509,8 @@ public class ExecutionTool { // Plant the symlink forest. try { new SymlinkForest( - packageRoots, getExecRoot(), runtime.getProductName()).plantSymlinkForest(); + packageRoots, getExecRoot(), runtime.getProductName(), workspaceName) + .plantSymlinkForest(); } catch (IOException e) { throw new ExecutorInitException("Source forest creation failed", e); } diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/SymlinkForest.java b/src/main/java/com/google/devtools/build/lib/buildtool/SymlinkForest.java index 5c8ff90565..9d57a44466 100644 --- a/src/main/java/com/google/devtools/build/lib/buildtool/SymlinkForest.java +++ b/src/main/java/com/google/devtools/build/lib/buildtool/SymlinkForest.java @@ -43,13 +43,16 @@ class SymlinkForest { private final ImmutableMap<PackageIdentifier, Path> packageRoots; private final Path workspace; + private final String workspaceName; private final String productName; private final String[] prefixes; SymlinkForest( - ImmutableMap<PackageIdentifier, Path> packageRoots, Path workspace, String productName) { + ImmutableMap<PackageIdentifier, Path> packageRoots, Path workspace, String productName, + String workspaceName) { this.packageRoots = packageRoots; this.workspace = workspace; + this.workspaceName = workspaceName; this.productName = productName; this.prefixes = new String[] { ".", "_", productName + "-"}; } @@ -216,6 +219,23 @@ class SymlinkForest { } } } + + symlinkCorrectWorkspaceName(); + } + + /** + * Right now, the execution root is under the basename of the source directory, not the name + * defined in the WORKSPACE file. Thus, this adds a symlink with the WORKSPACE's workspace name + * to the old-style execution root. + * TODO(kchodorow): get rid of this once exec root is always under the WORKSPACE's workspace + * name. + * @throws IOException + */ + private void symlinkCorrectWorkspaceName() throws IOException { + Path correctDirectory = workspace.getParentDirectory().getRelative(workspaceName); + if (!correctDirectory.exists()) { + correctDirectory.createSymbolicLink(workspace); + } } private static PackageIdentifier getParent(PackageIdentifier packageIdentifier) { diff --git a/src/main/java/com/google/devtools/build/lib/pkgcache/LegacyLoadingPhaseRunner.java b/src/main/java/com/google/devtools/build/lib/pkgcache/LegacyLoadingPhaseRunner.java index 09698e6176..741e1be26a 100644 --- a/src/main/java/com/google/devtools/build/lib/pkgcache/LegacyLoadingPhaseRunner.java +++ b/src/main/java/com/google/devtools/build/lib/pkgcache/LegacyLoadingPhaseRunner.java @@ -27,6 +27,7 @@ import com.google.devtools.build.lib.cmdline.TargetParsingException; import com.google.devtools.build.lib.events.DelegatingEventHandler; import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.events.EventHandler; +import com.google.devtools.build.lib.packages.NoSuchPackageException; import com.google.devtools.build.lib.packages.NoSuchThingException; import com.google.devtools.build.lib.packages.NonconfigurableAttributeMapper; import com.google.devtools.build.lib.packages.Rule; @@ -213,7 +214,7 @@ public final class LegacyLoadingPhaseRunner extends LoadingPhaseRunner { */ private LoadingResult doSimpleLoadingPhase(EventHandler eventHandler, EventBus eventBus, ResolvedTargets<Target> targets, ImmutableSet<Target> testsToRun, boolean keepGoing) - throws LoadingFailedException { + throws InterruptedException, LoadingFailedException { Stopwatch timer = preLoadingLogging(eventHandler); ImmutableSet<Target> targetsToLoad = targets.getTargets(); @@ -226,7 +227,7 @@ public final class LegacyLoadingPhaseRunner extends LoadingPhaseRunner { postLoadingLogging(eventBus, targetsToLoad, expandedResult.getTargets(), timer); return new LoadingResult(targets.hasError(), expandedResult.hasError(), - expandedResult.getTargets(), testsToRun); + expandedResult.getTargets(), testsToRun, getWorkspaceName(eventHandler)); } /** @@ -254,10 +255,9 @@ public final class LegacyLoadingPhaseRunner extends LoadingPhaseRunner { freeMemoryAfterLoading(callback, pkgLoader.getVisitedPackageNames()); postLoadingLogging(eventBus, baseResult.getTargets(), expandedResult.getTargets(), timer); - LoadingResult loadingResult = new LoadingResult(targets.hasError(), + return new LoadingResult(targets.hasError(), !baseResult.isSuccesful() || expandedResult.hasError(), - expandedResult.getTargets(), testsToRun); - return loadingResult; + expandedResult.getTargets(), testsToRun, getWorkspaceName(eventHandler)); } private Stopwatch preLoadingLogging(EventHandler eventHandler) { @@ -445,4 +445,14 @@ public final class LegacyLoadingPhaseRunner extends LoadingPhaseRunner { } } } + + private String getWorkspaceName(EventHandler eventHandler) + throws InterruptedException, LoadingFailedException { + try { + return packageManager.getPackage(eventHandler, Label.EXTERNAL_PACKAGE_IDENTIFIER) + .getWorkspaceName(); + } catch (NoSuchPackageException e) { + throw new LoadingFailedException("Failed to load //external package", e); + } + } } diff --git a/src/main/java/com/google/devtools/build/lib/pkgcache/LoadingResult.java b/src/main/java/com/google/devtools/build/lib/pkgcache/LoadingResult.java index 94f597649e..f78e0afb75 100644 --- a/src/main/java/com/google/devtools/build/lib/pkgcache/LoadingResult.java +++ b/src/main/java/com/google/devtools/build/lib/pkgcache/LoadingResult.java @@ -27,14 +27,16 @@ public final class LoadingResult { private final boolean hasLoadingError; private final ImmutableSet<Target> targetsToAnalyze; private final ImmutableSet<Target> testsToRun; + private final String workspaceName; public LoadingResult(boolean hasTargetPatternError, boolean hasLoadingError, - Collection<Target> targetsToAnalyze, Collection<Target> testsToRun) { + Collection<Target> targetsToAnalyze, Collection<Target> testsToRun, String workspaceName) { this.hasTargetPatternError = hasTargetPatternError; this.hasLoadingError = hasLoadingError; this.targetsToAnalyze = targetsToAnalyze == null ? null : ImmutableSet.copyOf(targetsToAnalyze); this.testsToRun = testsToRun == null ? null : ImmutableSet.copyOf(testsToRun); + this.workspaceName = workspaceName; } /** Whether there were errors during target pattern evaluation. */ @@ -56,4 +58,9 @@ public final class LoadingResult { public Collection<Target> getTestsToRun() { return testsToRun; } + + /** The name of the local workspace. */ + public String getWorkspaceName() { + return workspaceName; + } }
\ No newline at end of file diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternPhaseFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternPhaseFunction.java index 9608878f34..5215b7370a 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternPhaseFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternPhaseFunction.java @@ -20,6 +20,7 @@ import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.ResolvedTargets; import com.google.devtools.build.lib.cmdline.TargetParsingException; import com.google.devtools.build.lib.events.Event; +import com.google.devtools.build.lib.packages.NoSuchPackageException; import com.google.devtools.build.lib.packages.Target; import com.google.devtools.build.lib.packages.TargetUtils; import com.google.devtools.build.lib.pkgcache.CompileOneDependencyTransformer; @@ -37,14 +38,12 @@ import com.google.devtools.build.skyframe.SkyFunction; import com.google.devtools.build.skyframe.SkyKey; import com.google.devtools.build.skyframe.SkyValue; import com.google.devtools.build.skyframe.ValueOrException; - import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; - import javax.annotation.Nullable; /** @@ -56,6 +55,22 @@ final class TargetPatternPhaseFunction implements SkyFunction { @Override public TargetPatternPhaseValue compute(SkyKey key, Environment env) { TargetPatternList options = (TargetPatternList) key.argument(); + PackageValue packageValue = null; + boolean workspaceError = false; + try { + packageValue = (PackageValue) env.getValueOrThrow( + PackageValue.key(Label.EXTERNAL_PACKAGE_IDENTIFIER), NoSuchPackageException.class); + } catch (NoSuchPackageException e) { + env.getListener().handle(Event.error(e.getMessage())); + workspaceError = true; + } + if (env.valuesMissing()) { + return null; + } + String workspaceName = ""; + if (!workspaceError) { + workspaceName = packageValue.getPackage().getWorkspaceName(); + } // Determine targets to build: ResolvedTargets<Target> targets = getTargetsToBuild(env, @@ -163,8 +178,8 @@ final class TargetPatternPhaseFunction implements SkyFunction { Set<Target> testSuiteTargets = Sets.difference(targets.getTargets(), expandedTargets.getTargets()); return new TargetPatternPhaseValue(expandedTargets.getTargets(), testsToRun, preExpansionError, - expandedTargets.hasError(), filteredTargets, testFilteredTargets, - targets.getTargets(), ImmutableSet.copyOf(testSuiteTargets)); + expandedTargets.hasError() || workspaceError, filteredTargets, testFilteredTargets, + targets.getTargets(), ImmutableSet.copyOf(testSuiteTargets), workspaceName); } /** diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternPhaseValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternPhaseValue.java index 0e43191dbc..ca8881386f 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternPhaseValue.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternPhaseValue.java @@ -53,11 +53,12 @@ public final class TargetPatternPhaseValue implements SkyValue { // TODO(ulfjack): Support EventBus event posting in Skyframe, and remove this code again. private final ImmutableSet<Target> originalTargets; private final ImmutableSet<Target> testSuiteTargets; + private final String workspaceName; TargetPatternPhaseValue(ImmutableSet<Target> targets, @Nullable ImmutableSet<Target> testsToRun, boolean hasError, boolean hasPostExpansionError, ImmutableSet<Target> filteredTargets, ImmutableSet<Target> testFilteredTargets, ImmutableSet<Target> originalTargets, - ImmutableSet<Target> testSuiteTargets) { + ImmutableSet<Target> testSuiteTargets, String workspaceName) { this.targets = Preconditions.checkNotNull(targets); this.testsToRun = testsToRun; this.hasError = hasError; @@ -66,6 +67,7 @@ public final class TargetPatternPhaseValue implements SkyValue { this.testFilteredTargets = Preconditions.checkNotNull(testFilteredTargets); this.originalTargets = Preconditions.checkNotNull(originalTargets); this.testSuiteTargets = Preconditions.checkNotNull(testSuiteTargets); + this.workspaceName = workspaceName; } public ImmutableSet<Target> getTargets() { @@ -101,8 +103,13 @@ public final class TargetPatternPhaseValue implements SkyValue { return testSuiteTargets; } + public String getWorkspaceName() { + return workspaceName; + } + public LoadingResult toLoadingResult() { - return new LoadingResult(hasError(), hasPostExpansionError(), getTargets(), getTestsToRun()); + return new LoadingResult( + hasError(), hasPostExpansionError(), getTargets(), getTestsToRun(), getWorkspaceName()); } @SuppressWarnings("unused") diff --git a/src/test/java/com/google/devtools/build/lib/buildtool/SymlinkForestTest.java b/src/test/java/com/google/devtools/build/lib/buildtool/SymlinkForestTest.java index fec327e8e8..d86d2be261 100644 --- a/src/test/java/com/google/devtools/build/lib/buildtool/SymlinkForestTest.java +++ b/src/test/java/com/google/devtools/build/lib/buildtool/SymlinkForestTest.java @@ -27,20 +27,19 @@ import com.google.devtools.build.lib.cmdline.LabelSyntaxException; import com.google.devtools.build.lib.cmdline.PackageIdentifier; import com.google.devtools.build.lib.cmdline.RepositoryName; import com.google.devtools.build.lib.testutil.ManualClock; +import com.google.devtools.build.lib.testutil.TestConstants; import com.google.devtools.build.lib.vfs.FileSystem; import com.google.devtools.build.lib.vfs.FileSystemUtils; import com.google.devtools.build.lib.vfs.Path; import com.google.devtools.build.lib.vfs.PathFragment; import com.google.devtools.build.lib.vfs.Symlinks; import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem; - +import java.io.IOException; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import java.io.IOException; - /** * Tests {@link SymlinkForest}. */ @@ -188,7 +187,8 @@ public class SymlinkForestTest { Path linkRoot = fileSystem.getPath("/linkRoot"); createDirectoryAndParents(linkRoot); - new SymlinkForest(packageRootMap, linkRoot, "mock-product-name").plantSymlinkForest(); + new SymlinkForest(packageRootMap, linkRoot, TestConstants.PRODUCT_NAME, "wsname") + .plantSymlinkForest(); assertLinksTo(linkRoot, rootA, "pkgA"); assertIsDir(linkRoot, "dir1"); @@ -215,7 +215,8 @@ public class SymlinkForestTest { .put(createPkg(rootX, rootY, "foo"), rootX) .build(); - new SymlinkForest(packageRootMap, linkRoot, "mock-product-name").plantSymlinkForest(); + new SymlinkForest(packageRootMap, linkRoot, TestConstants.PRODUCT_NAME, "wsname") + .plantSymlinkForest(); assertLinksTo(linkRoot, rootX, "file"); } @@ -239,7 +240,8 @@ public class SymlinkForestTest { .put(createPkg(outputBase, "w", ""), outputBase) .build(); - new SymlinkForest(packageRootMap, linkRoot, "mock-product-name").plantSymlinkForest(); + new SymlinkForest(packageRootMap, linkRoot, TestConstants.PRODUCT_NAME, "wsname") + .plantSymlinkForest(); assertFalse(linkRoot.getRelative(Label.EXTERNAL_PATH_PREFIX + "/y/file").exists()); assertLinksTo( linkRoot.getRelative(Label.EXTERNAL_PATH_PREFIX + "/y/w"), rootY.getRelative("w")); @@ -261,7 +263,22 @@ public class SymlinkForestTest { .put(Label.EXTERNAL_PACKAGE_IDENTIFIER, root) .build(); - new SymlinkForest(packageRootMap, linkRoot, "mock-product-name").plantSymlinkForest(); + new SymlinkForest(packageRootMap, linkRoot, TestConstants.PRODUCT_NAME, "wsname") + .plantSymlinkForest(); assertThat(linkRoot.getRelative(Label.EXTERNAL_PATH_PREFIX).exists()).isFalse(); } + + @Test + public void testWorkspaceName() throws Exception { + Path root = fileSystem.getPath("/src"); + ImmutableMap<PackageIdentifier, Path> packageRootMap = + ImmutableMap.<PackageIdentifier, Path>builder() + // Remote repo without top-level package. + .put(createPkg(root, "y", "w"), root) + .build(); + + new SymlinkForest(packageRootMap, linkRoot, TestConstants.PRODUCT_NAME, "wsname") + .plantSymlinkForest(); + assertThat(linkRoot.getRelative("../wsname").exists()).isTrue(); + } } diff --git a/src/test/shell/bazel/BUILD b/src/test/shell/bazel/BUILD index a3d9751b3a..5ed4d00481 100644 --- a/src/test/shell/bazel/BUILD +++ b/src/test/shell/bazel/BUILD @@ -355,6 +355,13 @@ sh_test( data = [":test-deps"], ) +sh_test( + name = "execroot_test", + size = "small", + srcs = ["execroot_test.sh"], + data = [":test-deps"], +) + test_suite( name = "all_tests", visibility = ["//visibility:public"], diff --git a/src/test/shell/bazel/execroot_test.sh b/src/test/shell/bazel/execroot_test.sh new file mode 100755 index 0000000000..0a97fa6cb0 --- /dev/null +++ b/src/test/shell/bazel/execroot_test.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# +# Copyright 2016 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -eu + +# Load test environment +source $(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/test-setup.sh \ + || { echo "test-setup.sh not found!" >&2; exit 1; } + +function test_execroot_structure() { + ws_name="dooby_dooby_doo" + cat > WORKSPACE <<EOF +workspace(name = "$ws_name") +EOF + + mkdir dir + cat > dir/BUILD <<'EOF' +genrule( + name = "use-srcs", + srcs = ["BUILD"], + cmd = "cp $< $@", + outs = ["used-srcs"], +) +EOF + + bazel build -s //dir:use-srcs &> $TEST_log || fail "expected success" + test -e "$(bazel info execution_root)/../${ws_name}" +} + +run_suite "execution root tests" |