Switch to using ../repo-name syntax for runfiles

--
MOS_MIGRATED_REVID=121475668
diff --git a/src/main/java/com/google/devtools/build/lib/actions/Artifact.java b/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
index 95faf51..3c71f88 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
@@ -498,6 +498,21 @@
   }
 
   /**
+   * For targets in external repositories, this returns the path the artifact live at in the
+   * runfiles tree. For local targets, it returns the rootRelativePath.
+   */
+  public final PathFragment getRunfilesPath() {
+    PathFragment relativePath = rootRelativePath;
+    if (relativePath.segmentCount() > 1
+        && relativePath.getSegment(0).equals(Label.EXTERNAL_PATH_PREFIX)) {
+      // Turn external/repo/foo into ../repo/foo.
+      relativePath = relativePath.relativeTo(Label.EXTERNAL_PATH_PREFIX);
+      relativePath = new PathFragment("..").getRelative(relativePath);
+    }
+    return relativePath;
+  }
+
+  /**
    * Returns this.getExecPath().getPathString().
    */
   @Override
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java
index d147bdd..15ff6f2 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java
@@ -208,7 +208,7 @@
         buffer.append(delimiter);
       }
       buffer.append("${RUNPATH}");
-      buffer.append(artifact.getRootRelativePath().getPathString());
+      buffer.append(artifact.getRunfilesPath().getPathString());
     }
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPythonSemantics.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPythonSemantics.java
index 5b72cbd..f82c9fe 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPythonSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPythonSemantics.java
@@ -72,7 +72,11 @@
   @Override
   public List<PathFragment> getImports(RuleContext ruleContext) {
     List<PathFragment> result = new ArrayList<>();
-    PathFragment packageFragment = ruleContext.getLabel().getPackageIdentifier().getPathFragment();
+    PathFragment packageFragment = ruleContext.getLabel().getPackageIdentifier().getRunfilesPath();
+    // Python scripts start with x.runfiles/ as the module space, so everything must be manually
+    // adjusted to be relative to the workspace name.
+    packageFragment = new PathFragment(ruleContext.getWorkspaceName())
+        .getRelative(packageFragment);
     for (String importsAttr : ruleContext.attributes().get("imports", Type.STRING_LIST)) {
       importsAttr = ruleContext.expandMakeVariables("includes", importsAttr);
       if (importsAttr.startsWith("/")) {
@@ -83,7 +87,7 @@
       PathFragment importsPath = packageFragment.getRelative(importsAttr).normalize();
       if (!importsPath.isNormalized()) {
         ruleContext.attributeError("imports",
-            "Path references a path above the execution root.");
+            "Path " + importsAttr + " references a path above the execution root");
       }
       result.add(importsPath);
     }
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/stub_template.txt b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/stub_template.txt
index 594e534..f3fcc8c 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/stub_template.txt
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/stub_template.txt
@@ -75,18 +75,11 @@
                          sys.argv[0])
 
   python_imports = '%imports%'
-  module_space_with_workspace_name = module_space
-  if '%workspace_name%' != '':
-    module_space_with_workspace_name = os.path.join(module_space, '%workspace_name%')
+  python_path_entries = CreatePythonPathEntries(python_imports, module_space)
 
-  python_path_entries = CreatePythonPathEntries(
-    python_imports, module_space_with_workspace_name)
-
-  external_dir = os.path.join(module_space_with_workspace_name, 'external')
-  if os.path.isdir(external_dir):
-    external_entries = [os.path.join(external_dir, d) for d in os.listdir(external_dir)]
-    repositories = [d for d in external_entries if os.path.isdir(d)]
-    python_path_entries += repositories
+  repo_dirs = [os.path.join(module_space, d) for d in os.listdir(module_space)]
+  repositories = [d for d in repo_dirs if os.path.isdir(d)]
+  python_path_entries += repositories
 
   old_python_path = os.environ.get('PYTHONPATH')
   separator = ':'
diff --git a/src/main/java/com/google/devtools/build/lib/cmdline/PackageIdentifier.java b/src/main/java/com/google/devtools/build/lib/cmdline/PackageIdentifier.java
index 021845c..2fa4494 100644
--- a/src/main/java/com/google/devtools/build/lib/cmdline/PackageIdentifier.java
+++ b/src/main/java/com/google/devtools/build/lib/cmdline/PackageIdentifier.java
@@ -129,6 +129,14 @@
     return repository.getPathFragment().getRelative(pkgName);
   }
 
+  /**
+   * Returns the runfiles path for this repository (relative to the x.runfiles/main-repo/
+   * directory).
+   */
+  public PathFragment getRunfilesPath() {
+    return getRepository().getRunfilesPath().getRelative(getPackageFragment());
+  }
+
   public PackageIdentifier makeAbsolute() {
     if (!repository.isDefault()) {
       return this;
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 9a4e5a7..6b89a6e 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
@@ -202,6 +202,16 @@
   }
 
   /**
+   * Returns the runfiles path for this repository (relative to the x.runfiles/main-repo/
+   * directory). If we don't know the name of this repo (i.e., it is in the main repository),
+   * return an empty path fragment.
+   */
+  public PathFragment getRunfilesPath() {
+    return isDefault() || isMain()
+        ? PathFragment.EMPTY_FRAGMENT : new PathFragment("..").getRelative(strippedName());
+  }
+
+  /**
    * Returns the repository name, with leading "{@literal @}" (or "" for the default repository).
    */
   @Override
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java
index b4650d2..1a564ab 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java
@@ -459,7 +459,7 @@
     if (launcher != null) {
       javaExecutable = launcher.getRootRelativePath();
     } else {
-      javaExecutable = ruleContext.getFragment(Jvm.class).getJavaExecutable();
+      javaExecutable = ruleContext.getFragment(Jvm.class).getRunfilesJavaExecutable();
     }
 
     String pathPrefix = javaExecutable.isAbsolute() ? "" : "${JAVA_RUNFILES}/"
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/Jvm.java b/src/main/java/com/google/devtools/build/lib/rules/java/Jvm.java
index e24266d..edecece 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/Jvm.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/Jvm.java
@@ -39,6 +39,10 @@
   private final PathFragment jar;
   private final PathFragment java;
 
+  private static final String BIN_JAVAC = "bin/javac" + OsUtils.executableExtension();
+  private static final String BIN_JAR = "bin/jar" + OsUtils.executableExtension();
+  private static final String BIN_JAVA = "bin/java" + OsUtils.executableExtension();
+
   /**
    * Creates a Jvm instance. Either the {@code javaHome} parameter is absolute,
    * or the {@code jvmLabel} parameter must be non-null. This restriction might
@@ -48,9 +52,9 @@
     Preconditions.checkArgument(javaHome.isAbsolute() ^ (jvmLabel != null));
     this.javaHome = javaHome;
     this.jvmLabel = jvmLabel;
-    this.javac = getJavaHome().getRelative("bin/javac" + OsUtils.executableExtension());
-    this.jar = getJavaHome().getRelative("bin/jar" + OsUtils.executableExtension());
-    this.java = getJavaHome().getRelative("bin/java" + OsUtils.executableExtension());
+    this.javac = getJavaHome().getRelative(BIN_JAVAC);
+    this.jar = getJavaHome().getRelative(BIN_JAR);
+    this.java = getJavaHome().getRelative(BIN_JAVA);
   }
 
   /**
@@ -95,6 +99,17 @@
     return jvmLabel;
   }
 
+  /**
+   * If possible, resolves java relative to the jvmLabel's repository. Otherwise, returns the
+   * same thing as getJavaExecutable().
+   */
+  public PathFragment getRunfilesJavaExecutable() {
+    if (jvmLabel == null || jvmLabel.getPackageIdentifier().getRepository().isMain()) {
+      return getJavaExecutable();
+    }
+    return jvmLabel.getPackageIdentifier().getRepository().getRunfilesPath().getRelative(BIN_JAVA);
+  }
+
   @Override
   public void addGlobalMakeVariables(Builder<String, String> globalMakeEnvBuilder) {
     globalMakeEnvBuilder.put("JAVABASE", getJavaHome().getPathString());
diff --git a/src/main/java/com/google/devtools/build/lib/rules/python/PyCommon.java b/src/main/java/com/google/devtools/build/lib/rules/python/PyCommon.java
index 60fa5a6..045c06c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/python/PyCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/python/PyCommon.java
@@ -406,8 +406,8 @@
         } else {
           ruleContext.attributeError("srcs",
               buildMultipleMainMatchesErrorText(explicitMain, mainSourceName,
-                  mainArtifact.getRootRelativePath().toString(),
-                  outItem.getRootRelativePath().toString()));
+                  mainArtifact.getRunfilesPath().toString(),
+                  outItem.getRunfilesPath().toString()));
         }
       }
     }
@@ -418,7 +418,7 @@
     }
 
     PathFragment workspaceName = new PathFragment(ruleContext.getRule().getWorkspaceName());
-    return workspaceName.getRelative(mainArtifact.getRootRelativePath()).getPathString();
+    return workspaceName.getRelative(mainArtifact.getRunfilesPath()).getPathString();
   }
 
   public Artifact getExecutable() {
diff --git a/src/test/java/com/google/devtools/build/lib/cmdline/PackageIdentifierTest.java b/src/test/java/com/google/devtools/build/lib/cmdline/PackageIdentifierTest.java
index a2a133c..5d32df7 100644
--- a/src/test/java/com/google/devtools/build/lib/cmdline/PackageIdentifierTest.java
+++ b/src/test/java/com/google/devtools/build/lib/cmdline/PackageIdentifierTest.java
@@ -99,4 +99,12 @@
     PackageIdentifier p2 = PackageIdentifier.create("@whatever", new PathFragment("foo/bar"));
     assertSame(p2.getPackageFragment(), p1.getPackageFragment());
   }
+
+  @Test
+  public void testRunfilesDir() throws Exception {
+    assertThat(PackageIdentifier.create("@foo", new PathFragment("bar/baz")).getRunfilesPath())
+        .isEqualTo(new PathFragment("../foo/bar/baz"));
+    assertThat(PackageIdentifier.create("@", new PathFragment("bar/baz")).getRunfilesPath())
+        .isEqualTo(new PathFragment("bar/baz"));
+  }
 }
diff --git a/src/test/java/com/google/devtools/build/lib/cmdline/RepositoryNameTest.java b/src/test/java/com/google/devtools/build/lib/cmdline/RepositoryNameTest.java
index b84af2f..9a39bbf 100644
--- a/src/test/java/com/google/devtools/build/lib/cmdline/RepositoryNameTest.java
+++ b/src/test/java/com/google/devtools/build/lib/cmdline/RepositoryNameTest.java
@@ -18,6 +18,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
+import com.google.devtools.build.lib.vfs.PathFragment;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -56,4 +57,14 @@
     assertNotValid("@foo\0", "workspace names may contain only A-Z, a-z, 0-9, '-', '_' and '.'");
   }
 
+  @Test
+  public void testRunfilesDir() throws Exception {
+    assertThat(RepositoryName.create("@foo").getRunfilesPath())
+        .isEqualTo(new PathFragment("../foo"));
+    assertThat(RepositoryName.create("@").getRunfilesPath())
+        .isEqualTo(PathFragment.EMPTY_FRAGMENT);
+    assertThat(RepositoryName.create("").getRunfilesPath())
+        .isEqualTo(PathFragment.EMPTY_FRAGMENT);
+  }
+
 }
diff --git a/src/test/shell/bazel/bazel_rules_test.sh b/src/test/shell/bazel/bazel_rules_test.sh
index 73893ac..c82b9cd 100755
--- a/src/test/shell/bazel/bazel_rules_test.sh
+++ b/src/test/shell/bazel/bazel_rules_test.sh
@@ -357,8 +357,8 @@
 EOF
 
  cat > module2/bez.py <<EOF
-from external.remote.module_a import foo
-from external.remote.module_b import bar
+from remote.module_a import foo
+from remote.module_b import bar
 from module1 import fib
 
 print "The number is %d" % foo.GetNumber()
diff --git a/src/test/shell/bazel/external_integration_test.sh b/src/test/shell/bazel/external_integration_test.sh
index 6f3a6b0..e9c1bc6 100755
--- a/src/test/shell/bazel/external_integration_test.sh
+++ b/src/test/shell/bazel/external_integration_test.sh
@@ -139,7 +139,7 @@
 
     cat > zoo/female.sh <<EOF
 #!/bin/bash
-./external/endangered/fox/male
+../endangered/fox/male
 EOF
     chmod +x zoo/female.sh
 fi
@@ -422,10 +422,10 @@
   cat > test/test.sh <<EOF
 #!/bin/bash
 echo "symlink:"
-ls -l external/toto/file
+ls -l ../toto/file
 echo "dest:"
-ls -l \$(readlink -f external/toto/file/toto)
-external/toto/file/toto
+ls -l \$(readlink -f ../toto/file/toto)
+../toto/file/toto
 EOF
 
   chmod +x test/test.sh
@@ -459,7 +459,7 @@
 
   cat > test/test.sh <<EOF
 #!/bin/bash
-cat external/toto/file/toto
+cat ../toto/file/toto
 EOF
 
   chmod +x test/test.sh
@@ -581,7 +581,7 @@
 
   cat > zoo/female.sh <<EOF
 #!/bin/bash
-cat external/endangered/fox/male
+cat ../endangered/fox/male
 EOF
   chmod +x zoo/female.sh
 
diff --git a/src/test/shell/bazel/git_repository_test.sh b/src/test/shell/bazel/git_repository_test.sh
index 67a630d..2c862b7 100755
--- a/src/test/shell/bazel/git_repository_test.sh
+++ b/src/test/shell/bazel/git_repository_test.sh
@@ -85,7 +85,7 @@
 
   cat > planets/planet_info.sh <<EOF
 #!/bin/bash
-cat external/pluto/info
+cat ../pluto/info
 EOF
   chmod +x planets/planet_info.sh
 
@@ -171,7 +171,7 @@
 
   cat > planets/planet_info.sh <<EOF
 #!/bin/bash
-cat external/pluto/info
+cat ../pluto/info
 EOF
   chmod +x planets/planet_info.sh
 
@@ -246,8 +246,8 @@
 
   cat > planets/planet_info.sh <<EOF
 #!/bin/bash
-cat external/outer_planets/neptune/info
-cat external/outer_planets/pluto/info
+cat ../outer_planets/neptune/info
+cat ../outer_planets/pluto/info
 EOF
   chmod +x planets/planet_info.sh
 
diff --git a/src/test/shell/bazel/local_repository_test.sh b/src/test/shell/bazel/local_repository_test.sh
index d2ba764..d078cad 100755
--- a/src/test/shell/bazel/local_repository_test.sh
+++ b/src/test/shell/bazel/local_repository_test.sh
@@ -95,7 +95,7 @@
 
   cat > zoo/dumper.sh <<EOF
 #!/bin/bash
-cat external/pandas/red/baby-panda
+cat ../pandas/red/baby-panda
 cat red/day-keeper
 EOF
   chmod +x zoo/dumper.sh
diff --git a/src/test/shell/bazel/testenv.sh b/src/test/shell/bazel/testenv.sh
index 30ee820..8733ead 100755
--- a/src/test/shell/bazel/testenv.sh
+++ b/src/test/shell/bazel/testenv.sh
@@ -33,7 +33,7 @@
 bazel_data="${BAZEL_RUNFILES}"
 
 # Java
-jdk_dir="${BAZEL_RUNFILES}/external/local_jdk"
+jdk_dir="${TEST_SRCDIR}/local_jdk"
 langtools="${BAZEL_RUNFILES}/src/test/shell/bazel/langtools.jar"
 
 # Tools directory location
diff --git a/third_party/ijar/test/BUILD b/third_party/ijar/test/BUILD
index 507256c..da06173 100644
--- a/third_party/ijar/test/BUILD
+++ b/third_party/ijar/test/BUILD
@@ -9,10 +9,10 @@
     size = "enormous",
     srcs = ["ijar_test.sh"],
     args = [
-        "$(JAVABASE)/bin/javac",
-        "$(JAVA)",
-        "$(JAVABASE)/bin/jar",
-        "$(JAVABASE)/bin/javap",
+        "../local_jdk/bin/javac",
+        "../local_jdk/bin/java",
+        "../local_jdk/bin/jar",
+        "../local_jdk/bin/javap",
         "io_bazel/$(location //third_party/ijar)",
         "io_bazel/$(location //tools/jdk:langtools)",
         # We assume unzip and zip to be on the path