From d9121976fa7b39372027c70edddf9eb3c0bba7a6 Mon Sep 17 00:00:00 2001 From: Kristina Chodorow Date: Mon, 25 Apr 2016 17:45:55 +0000 Subject: Create runfiles at both .runfiles/ws/external/repo and .runfiles/repo The major piece of #848. RELNOTES[INC]: All repositories are now directly under the x.runfiles directory in the runfiles tree (previously, external repositories were at x.runfiles/main-repo/external/other-repo. This simplifies handling remote repository runfiles considerably, but will break existing references to external repository runfiles. -- MOS_MIGRATED_REVID=120722312 --- .../devtools/build/lib/analysis/Runfiles.java | 95 ++++++++++++++++++++-- .../build/lib/analysis/SourceManifestAction.java | 1 + .../lib/analysis/config/BuildConfiguration.java | 2 +- 3 files changed, 88 insertions(+), 10 deletions(-) (limited to 'src/main/java/com/google/devtools/build') diff --git a/src/main/java/com/google/devtools/build/lib/analysis/Runfiles.java b/src/main/java/com/google/devtools/build/lib/analysis/Runfiles.java index c18bf60997..d1f1434a39 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/Runfiles.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/Runfiles.java @@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; +import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.collect.nestedset.Order; @@ -458,23 +459,99 @@ public final class Runfiles { // Copy manifest map to another manifest map, prepending the workspace name to every path. // E.g. for workspace "myworkspace", the runfile entry "mylib.so"->"/path/to/mylib.so" becomes // "myworkspace/mylib.so"->"/path/to/mylib.so". - Map rootManifest = new HashMap<>(); - for (Map.Entry entry : manifest.entrySet()) { - checker.put(rootManifest, suffix.getRelative(entry.getKey()), entry.getValue()); - } + ManifestBuilder builder = new ManifestBuilder(suffix, legacyExternalRunfiles); + builder.addUnderWorkspace(manifest, checker); // Finally add symlinks relative to the root of the runfiles tree, on top of everything else. // This operation is always checked for conflicts, to match historical behavior. if (conflictPolicy == ConflictPolicy.IGNORE) { checker = new ConflictChecker(ConflictPolicy.WARN, eventHandler, location); } - for (Map.Entry entry : getRootSymlinksAsMap(checker).entrySet()) { - PathFragment mappedPath = entry.getKey(); - Artifact mappedArtifact = entry.getValue(); - checker.put(rootManifest, mappedPath, mappedArtifact); + builder.add(getRootSymlinksAsMap(checker), checker); + return builder.build(); + } + + /** + * Helper class to handle munging the paths of external artifacts. + */ + @VisibleForTesting + static final class ManifestBuilder { + // Manifest of paths to artifacts. Path fragments are relative to the .runfiles directory. + private final Map manifest; + private final PathFragment workspaceName; + private final boolean legacyExternalRunfiles; + // Whether we saw the local workspace name in the runfiles. If legacyExternalRunfiles is true, + // then this is true, as anything under external/ will also have a runfile under the local + // workspace. + private boolean sawWorkspaceName; + + public ManifestBuilder( + PathFragment workspaceName, boolean legacyExternalRunfiles) { + this.manifest = new HashMap<>(); + this.workspaceName = workspaceName; + this.legacyExternalRunfiles = legacyExternalRunfiles; + this.sawWorkspaceName = legacyExternalRunfiles; } - return rootManifest; + /** + * Adds a map under the workspaceName. + */ + public void addUnderWorkspace( + Map inputManifest, ConflictChecker checker) { + for (Map.Entry entry : inputManifest.entrySet()) { + PathFragment path = entry.getKey(); + if (isUnderWorkspace(path)) { + sawWorkspaceName = true; + checker.put(manifest, workspaceName.getRelative(path), entry.getValue()); + } else { + if (legacyExternalRunfiles) { + checker.put(manifest, workspaceName.getRelative(path), entry.getValue()); + } + // Always add the non-legacy .runfiles/repo/whatever path. + checker.put(manifest, getExternalPath(path), entry.getValue()); + } + } + } + + /** + * Adds a map to the root directory. + */ + public void add(Map inputManifest, ConflictChecker checker) { + for (Map.Entry entry : inputManifest.entrySet()) { + checker.put(manifest, checkForWorkspace(entry.getKey()), entry.getValue()); + } + } + + /** + * Returns the manifest, adding the workspaceName directory if it is not already present. + */ + public Map build() { + if (!sawWorkspaceName) { + // If we haven't seen it and we have seen other files, add the workspace name directory. + // It might not be there if all of the runfiles are from other repos (and then running from + // x.runfiles/ws will fail, because ws won't exist). We can't tell Runfiles to create a + // directory, so instead this creates a hidden file inside the desired directory. + manifest.put(workspaceName.getRelative(".runfile"), null); + } + return manifest; + } + + private PathFragment getExternalPath(PathFragment path) { + return checkForWorkspace(path.relativeTo(Label.EXTERNAL_PACKAGE_NAME)); + } + + private PathFragment checkForWorkspace(PathFragment path) { + sawWorkspaceName = sawWorkspaceName || path.getSegment(0).equals(workspaceName); + return path; + } + + private static boolean isUnderWorkspace(PathFragment path) { + return !path.startsWith(Label.EXTERNAL_PACKAGE_NAME); + } + } + + boolean getLegacyExternalRunfiles() { + return legacyExternalRunfiles; } /** diff --git a/src/main/java/com/google/devtools/build/lib/analysis/SourceManifestAction.java b/src/main/java/com/google/devtools/build/lib/analysis/SourceManifestAction.java index 6d726e760d..73e8c40b7f 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/SourceManifestAction.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/SourceManifestAction.java @@ -192,6 +192,7 @@ public final class SourceManifestAction extends AbstractFileWriteAction { protected String computeKey() { Fingerprint f = new Fingerprint(); f.addString(GUID); + f.addBoolean(runfiles.getLegacyExternalRunfiles()); Map symlinks = runfiles.getSymlinksAsMap(null); f.addInt(symlinks.size()); for (Map.Entry symlink : symlinks.entrySet()) { diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java index b62824708c..3f8c6be31f 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java @@ -710,7 +710,7 @@ public final class BuildConfiguration { @Option(name = "legacy_external_runfiles", defaultValue = "true", - category = "undocumented", + category = "strategy", help = "If true, build runfiles symlink forests for external repositories under " + ".runfiles/wsname/external/repo (in addition to .runfiles/repo).") public boolean legacyExternalRunfiles; -- cgit v1.2.3