Add RULEDIR to genrule's cmd

###Description of the problem / feature request:
Add new Make variable to genrule's cmd which always points to the output directory containing output from running genrule. See #7248 for details.

Closes #7249.

RELNOTES[NEW]: genrules now support a $(RULEDIR) variable that resolves to the directory where the outputs of the rule are put.

PiperOrigin-RevId: 236612681
diff --git a/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBase.java b/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBase.java
index 7228f4b..2b2ab5c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBase.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBase.java
@@ -309,6 +309,15 @@
         return expandSingletonArtifact(filesToBuild, "$@", "output file");
       }
 
+      if (variableName.equals("RULEDIR")) {
+        // The output root directory. This variable expands to the package's root directory
+        // in the genfiles tree.
+        PathFragment dir = ruleContext.getBinOrGenfilesDirectory().getExecPath();
+        PathFragment relPath =
+            ruleContext.getRule().getLabel().getPackageIdentifier().getSourceRoot();
+        return dir.getRelative(relPath).getPathString();
+      }
+
       if (variableName.equals("@D")) {
         // The output directory. If there is only one filename in outs,
         // this expands to the directory containing that file. If there are
diff --git a/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBaseRule.java b/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBaseRule.java
index c0287c3..3534938 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBaseRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBaseRule.java
@@ -131,9 +131,10 @@
           list, not in <code>srcs</code>, to ensure they are built in the correct configuration.
         </p>
         <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
-        .add(attr("tools", LABEL_LIST)
-            .cfg(HostTransition.INSTANCE)
-            .allowedFileTypes(FileTypeSet.ANY_FILE))
+        .add(
+            attr("tools", LABEL_LIST)
+                .cfg(HostTransition.INSTANCE)
+                .allowedFileTypes(FileTypeSet.ANY_FILE))
         /* <!-- #BLAZE_RULE(genrule).ATTRIBUTE(outs) -->
         A list of files generated by this rule.
         <p>
@@ -161,8 +162,8 @@
             <p>
               Note that <code>outs</code> are <i>not</i> included in this substitution. Output files
               are always generated into a predictable location (available via <code>$(@D)</code>,
-              <code>$@</code>, <code>$(OUTS)</code> or <code>$(location <i>output_name</i>)</code>;
-              see below).
+              <code>$@</code>, <code>$(OUTS)</code> or <code>$(RULEDIR)</code> or
+              <code>$(location <i>output_name</i>)</code>; see below).
             </p>
           </li>
           <li>
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/PathFragment.java b/src/main/java/com/google/devtools/build/lib/vfs/PathFragment.java
index 0fc6a89..4c7e219 100644
--- a/src/main/java/com/google/devtools/build/lib/vfs/PathFragment.java
+++ b/src/main/java/com/google/devtools/build/lib/vfs/PathFragment.java
@@ -241,8 +241,9 @@
   /**
    * Returns the {@link PathFragment} relative to the base {@link PathFragment}.
    *
-   * <p>For example, <code>FilePath.create("foo/bar/wiz").relativeTo(FilePath.create("foo"))</code>
-   * returns <code>"bar/wiz"</code>.
+   * <p>For example, <code>
+   * {@link PathFragment}.create("foo/bar/wiz").relativeTo({@link PathFragment}.create("foo"))
+   * </code> returns <code>"bar/wiz"</code>.
    *
    * <p>If the {@link PathFragment} is not a child of the passed {@link PathFragment} an {@link
    * IllegalArgumentException} is thrown. In particular, this will happen whenever the two {@link
diff --git a/src/test/java/com/google/devtools/build/lib/bazel/rules/genrule/GenRuleConfiguredTargetTest.java b/src/test/java/com/google/devtools/build/lib/bazel/rules/genrule/GenRuleConfiguredTargetTest.java
index ece88bd..a8e9bbb 100644
--- a/src/test/java/com/google/devtools/build/lib/bazel/rules/genrule/GenRuleConfiguredTargetTest.java
+++ b/src/test/java/com/google/devtools/build/lib/bazel/rules/genrule/GenRuleConfiguredTargetTest.java
@@ -283,6 +283,26 @@
     assertThat(bazExpected.equals(barExpected)).isFalse();
   }
 
+  /** Ensure that variable $(RULE_DIR) gets expanded correctly in the genrule cmd. */
+  @Test
+  public void testRuleDirExpansion() throws Exception {
+    scratch.file(
+        "foo/BUILD",
+        "genrule(name = 'bar',",
+        "        srcs = ['bar_in.txt'],",
+        "        cmd = 'touch $(RULEDIR)',",
+        "        outs = ['bar/bar_out.txt'])",
+        "genrule(name = 'baz',",
+        "        srcs = ['bar/bar_out.txt'],",
+        "        cmd = 'touch $(RULEDIR)',",
+        "        outs = ['baz/baz_out.txt', 'logs/baz.log'])");
+
+    // Make sure the expansion for $(RULE_DIR) results in the directory of the BUILD file ("foo")
+    String expectedRegex = "touch b.{4}-out.*foo";
+    assertThat(getCommand("//foo:bar")).containsMatch(expectedRegex);
+    assertThat(getCommand("//foo:baz")).containsMatch(expectedRegex);
+  }
+
   /** Ensure that variable $(CC) gets expanded correctly in the genrule cmd. */
   @Test
   public void testMakeVarExpansion() throws Exception {