diff options
author | Googler <noreply@google.com> | 2016-03-10 17:55:17 +0000 |
---|---|---|
committer | David Chen <dzc@google.com> | 2016-03-11 21:29:24 +0000 |
commit | c85af31c5b0938a24cf454f437d766c65cb4c921 (patch) | |
tree | 5b9102dd2d611290ae61ba95a2fb6b57eb85b222 /src/main/java/com/google/devtools/build/lib/analysis/Runfiles.java | |
parent | 443f78fcdff99e313001a7dc06026c70f71e8792 (diff) |
Expose runfiles symlink functionality in Skylark
The Skylark rule context object has a runfiles method. This adds two
optional parameters to that method, "symlinks" and "root_symlinks",
that expose functionality from the underlying Runfiles java class.
With this functionality, one can construct links in the runfiles tree
where the source and destination of the link have different names
and/or relative directories. This might be useful for things like
AppEngine rules where a file in a subdirectory of the source tree
needs to appear in the root directory of the runfiles tree.
If either new parameter is used, the runfiles is subject to stricter
validity checking. This checking propagates to other runfiles that
depend on it.
RELNOTES: Added "root_symlinks" and "symlinks" parameters to Skylark
runfiles() method.
--
MOS_MIGRATED_REVID=116879064
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/analysis/Runfiles.java')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/analysis/Runfiles.java | 41 |
1 files changed, 37 insertions, 4 deletions
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 c2dfa756e7..95efeb3f29 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 @@ -79,6 +79,13 @@ public final class Runfiles { /** * An entry in the runfiles map. + * + * <p>build-runfiles.cc enforces the following constraints: The PathFragment must not be an + * absolute path, nor contain "..". Overlapping runfiles links are also refused. This is the case + * where you ask to create a link to "foo" and also "foo/bar.txt". I.e. you're asking it to make + * "foo" both a file (symlink) and a directory. + * + * <p>Links to directories are heavily discouraged. */ // // O intrepid fixer or bugs and implementor of features, dare not to add a .equals() method @@ -171,7 +178,8 @@ public final class Runfiles { /** * Behavior upon finding a conflict between two runfile entries. A conflict means that two * different artifacts have the same runfiles path specified. For example, adding artifact - * "a.foo" at path "bar" when there is already an artifact "b.foo" at path "bar". + * "a.foo" at path "bar" when there is already an artifact "b.foo" at path "bar". The policies + * are ordered from least strict to most strict. * * <p>Note that conflicts are found relatively late, when the manifest file is created, not when * the symlinks are added to runfiles. @@ -242,13 +250,15 @@ public final class Runfiles { NestedSet<SymlinkEntry> symlinks, NestedSet<SymlinkEntry> rootSymlinks, NestedSet<PruningManifest> pruningManifests, - EmptyFilesSupplier emptyFilesSupplier) { + EmptyFilesSupplier emptyFilesSupplier, + ConflictPolicy conflictPolicy) { this.suffix = suffix; this.unconditionalArtifacts = Preconditions.checkNotNull(artifacts); this.symlinks = Preconditions.checkNotNull(symlinks); this.rootSymlinks = Preconditions.checkNotNull(rootSymlinks); this.pruningManifests = Preconditions.checkNotNull(pruningManifests); this.emptyFilesSupplier = Preconditions.checkNotNull(emptyFilesSupplier); + this.conflictPolicy = conflictPolicy; } /** @@ -519,9 +529,15 @@ public final class Runfiles { return map; } + /** Returns currently policy for conflicting symlink entries. */ + public ConflictPolicy getConflictPolicy() { + return this.conflictPolicy; + } + /** Set whether we should warn about conflicting symlink entries. */ - public void setConflictPolicy(ConflictPolicy conflictPolicy) { + public Runfiles setConflictPolicy(ConflictPolicy conflictPolicy) { this.conflictPolicy = conflictPolicy; + return this; } /** @@ -605,6 +621,9 @@ public final class Runfiles { NestedSetBuilder.stableOrder(); private EmptyFilesSupplier emptyFilesSupplier = DUMMY_EMPTY_FILES_SUPPLIER; + /** Build the Runfiles object with this policy */ + private ConflictPolicy conflictPolicy = ConflictPolicy.IGNORE; + /** * Only used for Runfiles.EMPTY. */ @@ -626,7 +645,7 @@ public final class Runfiles { public Runfiles build() { return new Runfiles(suffix, artifactsBuilder.build(), symlinksBuilder.build(), rootSymlinksBuilder.build(), pruningManifestsBuilder.build(), - emptyFilesSupplier); + emptyFilesSupplier, conflictPolicy); } /** @@ -698,6 +717,16 @@ public final class Runfiles { } /** + * Adds a root symlink. + */ + public Builder addRootSymlink(PathFragment link, Artifact target) { + Preconditions.checkNotNull(link); + Preconditions.checkNotNull(target); + rootSymlinksBuilder.add(new SymlinkEntry(link, target)); + return this; + } + + /** * Adds several root symlinks. */ public Builder addRootSymlinks(Map<PathFragment, Artifact> symlinks) { @@ -876,6 +905,10 @@ public final class Runfiles { * pruning manifests in the merge. */ private Builder merge(Runfiles runfiles, boolean includePruningManifests) { + // Propagate the most strict conflict checking from merged-in runfiles + if (runfiles.conflictPolicy.compareTo(conflictPolicy) > 0) { + conflictPolicy = runfiles.conflictPolicy; + } if (runfiles.isEmpty()) { return this; } |