Add the repository name as a parameter to the output path functions

This doesn't do anything yet, it's in preparation for the execroot rearranging
change.  The execroot will have one bazel-out per repo, so it'll look like:

execroot/
  repo1/
    bazel-out/
      local-fastbuild/
        bin/
  repo2/
    bazel-out/
      local-fastbuild/
        bin/
        genfiles/
  repo3/
    bazel-out/
      local-fastbuild/
        testlogs/

and so on. Thus, any output path (getBinDirectory() & friends) needs to know
what the repo name is. This changes so many places in the code I thought it
would be good to do separately, then just flip the functionality in the
execroot-rearranging commit.

While I was poking around, I changed all of the refs I could from getPackageRelativeArtifact() to getBin/GenfilesArtifact(), so that 1) rule implementation don't have to know as much about roots and 2) they'll be more isolated from other output dir changes.

`bazel info` and similar just return roots for the main repository.

The only "change" is passing around a target label in the Java rules.

Continues work on #1262.

--
MOS_MIGRATED_REVID=129985336
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/CompilationHelper.java b/src/main/java/com/google/devtools/build/lib/analysis/CompilationHelper.java
index dbf9a57..8a1fddc 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/CompilationHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/CompilationHelper.java
@@ -55,7 +55,8 @@
     MiddlemanFactory factory = env.getMiddlemanFactory();
     return ImmutableList.of(factory.createMiddlemanAllowMultiple(
         env, actionOwner, ruleContext.getPackageDirectory(), purpose, filesToBuild,
-        ruleContext.getConfiguration().getMiddlemanDirectory()));
+        ruleContext.getConfiguration().getMiddlemanDirectory(
+            ruleContext.getRule().getRepository())));
   }
 
   // TODO(bazel-team): remove this duplicated code after the ConfiguredTarget migration
@@ -87,6 +88,7 @@
     Iterable<Artifact> artifacts = dep.getProvider(FileProvider.class).getFilesToBuild();
     return ImmutableList.of(
         factory.createMiddlemanAllowMultiple(env, actionOwner, ruleContext.getPackageDirectory(),
-            purpose, artifacts, ruleContext.getConfiguration().getMiddlemanDirectory()));
+            purpose, artifacts, ruleContext.getConfiguration().getMiddlemanDirectory(
+                ruleContext.getRule().getRepository())));
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java
index dc91ecb..ac47679 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java
@@ -139,8 +139,8 @@
       boolean isFileset, ArtifactFactory artifactFactory) {
     Rule rule = outputFile.getAssociatedRule();
     Root root = rule.hasBinaryOutput()
-        ? configuration.getBinDirectory()
-        : configuration.getGenfilesDirectory();
+        ? configuration.getBinDirectory(rule.getRepository())
+        : configuration.getGenfilesDirectory(rule.getRepository());
     ArtifactOwner owner =
         new ConfiguredTargetKey(rule.getLabel(), configuration.getArtifactOwnerConfiguration());
     PathFragment rootRelativePath =
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/PseudoAction.java b/src/main/java/com/google/devtools/build/lib/analysis/PseudoAction.java
index e0eb712..eb2115a 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/PseudoAction.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/PseudoAction.java
@@ -84,6 +84,7 @@
   public static Artifact getDummyOutput(RuleContext ruleContext) {
     return ruleContext.getPackageRelativeArtifact(
         ruleContext.getLabel().getName() + ".extra_action_dummy",
-        ruleContext.getConfiguration().getGenfilesDirectory());
+        ruleContext.getConfiguration().getGenfilesDirectory(
+            ruleContext.getRule().getRepository()));
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
index 1bd77b5..d4cea81 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
@@ -103,7 +103,6 @@
  */
 public final class RuleContext extends TargetContext
     implements ActionConstructionContext, ActionRegistry, RuleErrorConsumer {
-
   /**
    * The configured version of FilesetEntry.
    */
@@ -520,8 +519,8 @@
    */
   public Root getBinOrGenfilesDirectory() {
     return rule.hasBinaryOutput()
-        ? getConfiguration().getBinDirectory()
-        : getConfiguration().getGenfilesDirectory();
+        ? getConfiguration().getBinDirectory(rule.getRepository())
+        : getConfiguration().getGenfilesDirectory(rule.getRepository());
   }
 
   /**
@@ -537,8 +536,12 @@
    * guaranteeing that it never clashes with artifacts created by rules in other packages.
    */
   public Artifact getBinArtifact(String relative) {
+    return getBinArtifact(new PathFragment(relative));
+  }
+
+  public Artifact getBinArtifact(PathFragment relative) {
     return getPackageRelativeArtifact(
-        new PathFragment(relative), getConfiguration().getBinDirectory());
+        relative, getConfiguration().getBinDirectory(rule.getRepository()));
   }
 
   /**
@@ -546,8 +549,12 @@
    * guaranteeing that it never clashes with artifacts created by rules in other packages.
    */
   public Artifact getGenfilesArtifact(String relative) {
+    return getGenfilesArtifact(new PathFragment(relative));
+  }
+
+  public Artifact getGenfilesArtifact(PathFragment relative) {
     return getPackageRelativeArtifact(
-        new PathFragment(relative), getConfiguration().getGenfilesDirectory());
+        relative, getConfiguration().getGenfilesDirectory(rule.getRepository()));
   }
 
   /**
@@ -1311,7 +1318,7 @@
    */
   public final Artifact getRelatedArtifact(PathFragment pathFragment, String extension) {
     PathFragment file = FileSystemUtils.replaceExtension(pathFragment, extension);
-    return getDerivedArtifact(file, getConfiguration().getBinDirectory());
+    return getDerivedArtifact(file, getConfiguration().getBinDirectory(rule.getRepository()));
   }
 
   /**
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RunfilesSupport.java b/src/main/java/com/google/devtools/build/lib/analysis/RunfilesSupport.java
index fe06afb..c6b6e04 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RunfilesSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RunfilesSupport.java
@@ -175,7 +175,7 @@
     String basename = relativePath.getBaseName();
     PathFragment inputManifestPath = relativePath.replaceName(basename + ".runfiles_manifest");
     return context.getDerivedArtifact(inputManifestPath,
-        context.getConfiguration().getBinDirectory());
+        context.getConfiguration().getBinDirectory(context.getRule().getRepository()));
   }
 
   /**
@@ -261,7 +261,8 @@
       Iterable<Artifact> allRunfilesArtifacts) {
     return context.getAnalysisEnvironment().getMiddlemanFactory().createRunfilesMiddleman(
         context.getActionOwner(), owningExecutable, allRunfilesArtifacts,
-        context.getConfiguration().getMiddlemanDirectory(), "runfiles_artifacts");
+        context.getConfiguration().getMiddlemanDirectory(context.getRule().getRepository()),
+        "runfiles_artifacts");
   }
 
   private Artifact createRunfilesMiddleman(ActionConstructionContext context,
@@ -269,7 +270,8 @@
     return context.getAnalysisEnvironment().getMiddlemanFactory().createRunfilesMiddleman(
         context.getActionOwner(), owningExecutable,
         ImmutableList.of(artifactsMiddleman, outputManifest),
-        context.getConfiguration().getMiddlemanDirectory(), "runfiles");
+        context.getConfiguration().getMiddlemanDirectory(context.getRule().getRepository()),
+        "runfiles");
   }
 
   /**
@@ -300,7 +302,7 @@
 
     BuildConfiguration config = context.getConfiguration();
     Artifact outputManifest = context.getDerivedArtifact(
-        outputManifestPath, config.getBinDirectory());
+        outputManifestPath, config.getBinDirectory(context.getRule().getRepository()));
     context
         .getAnalysisEnvironment()
         .registerAction(
@@ -328,7 +330,8 @@
     PathFragment sourcesManifestPath = executablePath.getParentDirectory().getChild(
         executablePath.getBaseName() + ".runfiles.SOURCES");
     Artifact sourceOnlyManifest = context.getDerivedArtifact(
-        sourcesManifestPath, context.getConfiguration().getBinDirectory());
+        sourcesManifestPath,
+        context.getConfiguration().getBinDirectory(context.getRule().getRepository()));
     context.getAnalysisEnvironment().registerAction(SourceManifestAction.forRunfiles(
         ManifestType.SOURCES_ONLY, context.getActionOwner(), sourceOnlyManifest, runfiles));
     return sourceOnlyManifest;
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/FileWriteAction.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/FileWriteAction.java
index 23c1484..1c7043a 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/actions/FileWriteAction.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/FileWriteAction.java
@@ -136,7 +136,8 @@
   public static Artifact createFile(RuleContext ruleContext,
       String fileName, CharSequence contents, boolean executable) {
     Artifact scriptFileArtifact = ruleContext.getPackageRelativeArtifact(
-        fileName, ruleContext.getConfiguration().getGenfilesDirectory());
+        fileName, ruleContext.getConfiguration().getGenfilesDirectory(
+            ruleContext.getRule().getRepository()));
     ruleContext.registerAction(new FileWriteAction(
         ruleContext.getActionOwner(), scriptFileArtifact, contents, executable));
     return scriptFileArtifact;
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/ParamFileHelper.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/ParamFileHelper.java
index 6d4b767..20834f9 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/actions/ParamFileHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/ParamFileHelper.java
@@ -22,6 +22,7 @@
 import com.google.devtools.build.lib.actions.ParameterFile;
 import com.google.devtools.build.lib.analysis.AnalysisEnvironment;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.util.Preconditions;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import java.util.List;
 import javax.annotation.Nullable;
@@ -55,7 +56,7 @@
    * @param analysisEnvironment the analysis environment
    * @param outputs outputs of the action (used to construct a filename for the params file)
    */
-  public static Artifact getParamsFileMaybe(
+  static Artifact getParamsFileMaybe(
       List<String> executableArgs,
       @Nullable Iterable<String> arguments,
       @Nullable CommandLine commandLine,
@@ -72,10 +73,10 @@
       return null;
     }
 
-    PathFragment paramFilePath =
-        ParameterFile.derivePath(Iterables.getFirst(outputs, null).getRootRelativePath());
-
-    return analysisEnvironment.getDerivedArtifact(paramFilePath, configuration.getBinDirectory());
+    Artifact output = Iterables.getFirst(outputs, null);
+    Preconditions.checkNotNull(output);
+    PathFragment paramFilePath = ParameterFile.derivePath(output.getRootRelativePath());
+    return analysisEnvironment.getDerivedArtifact(paramFilePath, output.getRoot());
   }
 
   /**
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 f97ea94..fe2f807 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
@@ -39,6 +39,7 @@
 import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection.Transitions;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
+import com.google.devtools.build.lib.cmdline.RepositoryName;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.packages.Attribute;
@@ -444,12 +445,12 @@
     }
 
     @Option(
-      name = "define",
-      converter = Converters.AssignmentConverter.class,
-      defaultValue = "",
-      category = "semantics",
-      allowMultiple = true,
-      help = "Each --define option specifies an assignment for a build variable."
+        name = "define",
+        converter = Converters.AssignmentConverter.class,
+        defaultValue = "",
+        category = "semantics",
+        allowMultiple = true,
+        help = "Each --define option specifies an assignment for a build variable."
     )
     public List<Map.Entry<String, String>> commandLineBuildVariables;
 
@@ -557,7 +558,7 @@
         defaultValue = "fastbuild",
         category = "semantics", // Should this be "flags"?
         help = "Specify the mode the binary will be built in. "
-               + "Values: 'fastbuild', 'dbg', 'opt'.")
+            + "Values: 'fastbuild', 'dbg', 'opt'.")
     public CompilationMode compilationMode;
 
     /**
@@ -590,7 +591,7 @@
             + "will be read from the Bazel client environment, or by the name=value pair. "
             + "This option can be used multiple times to specify several variables. "
             + "Used only by the 'bazel test' command."
-        )
+    )
     public List<Map.Entry<String, String>> testEnvironment;
 
     @Option(name = "collect_code_coverage",
@@ -600,7 +601,7 @@
             + "possible) and will collect coverage information during tests. Only targets that "
             + " match --instrumentation_filter will be affected. Usually this option should "
             + " not be specified directly - 'bazel coverage' command should be used instead."
-        )
+    )
     public boolean collectCodeCoverage;
 
     @Option(name = "microcoverage",
@@ -611,7 +612,7 @@
             + "--instrumentation_filter will be affected. Usually this option should not be "
             + "specified directly - 'blaze coverage --microcoverage' command should be used "
             + "instead."
-        )
+    )
     public boolean collectMicroCoverage;
 
     @Option(name = "coverage_support",
@@ -704,7 +705,7 @@
             + "executable. Can be used multiple times to specify several arguments. "
             + "If multiple tests are executed, each of them will receive identical arguments. "
             + "Used only by the 'bazel test' command."
-        )
+    )
     public List<String> testArguments;
 
     @Option(name = "test_filter",
@@ -727,31 +728,31 @@
     public boolean checkFilesetDependenciesRecursively;
 
     @Option(
-      name = "experimental_skyframe_native_filesets",
-      defaultValue = "false",
-      category = "experimental",
-      help =
-          "If true, Blaze will use the skyframe-native implementation of the Fileset rule."
-              + " This offers improved performance in incremental builds of Filesets as well as"
-              + " correct incremental behavior, but is not yet stable. The default is false,"
-              + " meaning Blaze uses the legacy impelementation of Fileset."
+        name = "experimental_skyframe_native_filesets",
+        defaultValue = "false",
+        category = "experimental",
+        help =
+            "If true, Blaze will use the skyframe-native implementation of the Fileset rule."
+                + " This offers improved performance in incremental builds of Filesets as well as"
+                + " correct incremental behavior, but is not yet stable. The default is false,"
+                + " meaning Blaze uses the legacy impelementation of Fileset."
     )
     public boolean skyframeNativeFileset;
 
     @Option(
-      name = "run_under",
-      category = "run",
-      defaultValue = "null",
-      converter = RunUnderConverter.class,
-      help =
-          "Prefix to insert in front of command before running. "
-              + "Examples:\n"
-              + "\t--run_under=valgrind\n"
-              + "\t--run_under=strace\n"
-              + "\t--run_under='strace -c'\n"
-              + "\t--run_under='valgrind --quiet --num-callers=20'\n"
-              + "\t--run_under=//package:target\n"
-              + "\t--run_under='//package:target --options'\n"
+        name = "run_under",
+        category = "run",
+        defaultValue = "null",
+        converter = RunUnderConverter.class,
+        help =
+            "Prefix to insert in front of command before running. "
+                + "Examples:\n"
+                + "\t--run_under=valgrind\n"
+                + "\t--run_under=strace\n"
+                + "\t--run_under='strace -c'\n"
+                + "\t--run_under='valgrind --quiet --num-callers=20'\n"
+                + "\t--run_under=//package:target\n"
+                + "\t--run_under='//package:target --options'\n"
     )
     public RunUnder runUnder;
 
@@ -789,13 +790,13 @@
     public boolean checkLicenses;
 
     @Option(
-      name = "enforce_constraints",
-      defaultValue = "true",
-      category = "undocumented",
-      help =
-          "Checks the environments each target is compatible with and reports errors if any "
-              + "target has dependencies that don't support the same environments",
-      oldName = "experimental_enforce_constraints"
+        name = "enforce_constraints",
+        defaultValue = "true",
+        category = "undocumented",
+        help =
+            "Checks the environments each target is compatible with and reports errors if any "
+                + "target has dependencies that don't support the same environments",
+        oldName = "experimental_enforce_constraints"
     )
     public boolean enforceConstraints;
 
@@ -849,18 +850,18 @@
     public boolean useDynamicConfigurations;
 
     @Option(
-      name = "experimental_enable_runfiles",
-      defaultValue = "auto",
-      category = "undocumented",
-      help = "Enable runfiles; off on Windows, on on other platforms"
+        name = "experimental_enable_runfiles",
+        defaultValue = "auto",
+        category = "undocumented",
+        help = "Enable runfiles; off on Windows, on on other platforms"
     )
     public TriState enableRunfiles;
 
     @Option(
-      name = "build_python_zip",
-      defaultValue = "auto",
-      category = "undocumented",
-      help = "Build python executable zip; on on Windows, off on other platforms"
+        name = "build_python_zip",
+        defaultValue = "auto",
+        category = "undocumented",
+        help = "Build python executable zip; on on Windows, off on other platforms"
     )
     public TriState buildPythonZip;
 
@@ -1153,8 +1154,8 @@
         == TestActionBuilder.TestShardingStrategy.EXPERIMENTAL_HEURISTIC) {
       reporter.handle(Event.warn(
           "Heuristic sharding is intended as a one-off experimentation tool for determing the "
-          + "benefit from sharding certain tests. Please don't keep this option in your "
-          + ".blazerc or continuous build"));
+              + "benefit from sharding certain tests. Please don't keep this option in your "
+              + ".blazerc or continuous build"));
     }
 
     if (options.useDynamicConfigurations && !options.useDistinctHostConfiguration) {
@@ -1256,8 +1257,8 @@
     globalMakeEnvBuilder.put("COMPILATION_MODE", options.compilationMode.toString());
     globalMakeEnvBuilder.put("BINMODE", "-"
         + ((options.compilationMode == CompilationMode.FASTBUILD)
-            ? "dbg"
-            : options.compilationMode.toString()));
+        ? "dbg"
+        : options.compilationMode.toString()));
     /*
      * Attention! Document these in the build-encyclopedia
      */
@@ -1351,7 +1352,7 @@
               if (lateBoundDefaults.containsKey(option.name())) {
                 value = lateBoundDefaults.get(option.name());
               } else if (!option.defaultValue().equals("null")) {
-                 // See {@link Option#defaultValue} for an explanation of default "null" strings.
+                // See {@link Option#defaultValue} for an explanation of default "null" strings.
                 value = option.defaultValue();
               }
             }
@@ -1469,10 +1470,10 @@
    */
   public interface TransitionApplier {
     /**
-      * Creates a new instance of this transition applier bound to the specified source
-      * configuration.
-      */
-     TransitionApplier create(BuildConfiguration config);
+     * Creates a new instance of this transition applier bound to the specified source
+     * configuration.
+     */
+    TransitionApplier create(BuildConfiguration config);
 
     /**
      * Accepts the given configuration transition. The implementation decides how to turn
@@ -1810,7 +1811,7 @@
    */
   @VisibleForTesting
   static Map<String, String> getMapping(List<String> variables,
-                                        Map<String, String> environment) {
+      Map<String, String> environment) {
     Map<String, String> result = new HashMap<>();
     for (String var : variables) {
       if (environment.containsKey(var)) {
@@ -1868,7 +1869,7 @@
   /**
    * Returns the output directory for this build configuration.
    */
-  public Root getOutputDirectory() {
+  public Root getOutputDirectory(RepositoryName repositoryName) {
     return outputRoots.outputDirectory;
   }
 
@@ -1882,6 +1883,18 @@
   }
 
   /**
+   * TODO(kchodorow): This (and the other get*Directory functions) won't work with external
+   * repositories without changes to how ArtifactFactory resolves derived roots. This is not an
+   * issue right now because it only effects Blaze's include scanning (internal) and Bazel's
+   * repositories (external) but will need to be fixed.
+   * TODO(kchodorow): Use the repository name to derive the bin directory.
+   */
+  @SuppressWarnings("unused")
+  public Root getBinDirectory(RepositoryName repositoryName) {
+    return getBinDirectory();
+  }
+
+  /**
    * Returns a relative path to the bin directory at execution time.
    */
   public PathFragment getBinFragment() {
@@ -1890,8 +1903,10 @@
 
   /**
    * Returns the include directory for this build configuration.
+   * TODO(kchodorow): Use the repository name to derive the include directory.
    */
-  public Root getIncludeDirectory() {
+  @SuppressWarnings("unused")
+  public Root getIncludeDirectory(RepositoryName repositoryName) {
     return outputRoots.includeDirectory;
   }
 
@@ -1904,19 +1919,29 @@
     return outputRoots.genfilesDirectory;
   }
 
+  // TODO(kchodorow): Use the repository name to derive the genfiles directory.
+  @SuppressWarnings("unused")
+  public Root getGenfilesDirectory(RepositoryName repositoryName) {
+    return getGenfilesDirectory();
+  }
+
   /**
    * Returns the directory where coverage-related artifacts and metadata files
    * should be stored. This includes for example uninstrumented class files
    * needed for Jacoco's coverage reporting tools.
+   * TODO(kchodorow): Use the repository name to derive the coverage directory.
    */
-  public Root getCoverageMetadataDirectory() {
+  @SuppressWarnings("unused")
+  public Root getCoverageMetadataDirectory(RepositoryName repositoryName) {
     return outputRoots.coverageMetadataDirectory;
   }
 
   /**
    * Returns the testlogs directory for this build configuration.
+   * TODO(kchodorow): Use the repository name to derive the test directory.
    */
-  public Root getTestLogsDirectory() {
+  @SuppressWarnings("unused")
+  public Root getTestLogsDirectory(RepositoryName repositoryName) {
     return outputRoots.testLogsDirectory;
   }
 
@@ -1942,8 +1967,10 @@
 
   /**
    * Returns the internal directory (used for middlemen) for this build configuration.
+   * TODO(kchodorow): Use the repository name to derive the middleman directory.
    */
-  public Root getMiddlemanDirectory() {
+  @SuppressWarnings("unused")
+  public Root getMiddlemanDirectory(RepositoryName repositoryName) {
     return outputRoots.middlemanDirectory;
   }
 
@@ -1977,12 +2004,11 @@
   }
 
   @SkylarkCallable(
-    name = "default_shell_env",
-    structField = true,
-    doc =
-        "A dictionary representing the local shell environment. It maps variables "
-            + "to their values (strings).  The local shell environment contains settings that are "
-            + "machine specific, therefore its use should be avoided in rules meant to be hermetic."
+      name = "default_shell_env",
+      structField = true,
+      doc = "A dictionary representing the local shell environment. It maps variables "
+          + "to their values (strings).  The local shell environment contains settings that are "
+          + "machine specific, therefore its use should be avoided in rules meant to be hermetic."
   )
   public ImmutableMap<String, String> getLocalShellEnvironment() {
     return localShellEnvironment;
@@ -2263,9 +2289,9 @@
     // Configuration-specific roots.
     roots.add(getBinDirectory());
     roots.add(getGenfilesDirectory());
-    roots.add(getIncludeDirectory());
-    roots.add(getMiddlemanDirectory());
-    roots.add(getTestLogsDirectory());
+    roots.add(getIncludeDirectory(RepositoryName.MAIN));
+    roots.add(getMiddlemanDirectory(RepositoryName.MAIN));
+    roots.add(getTestLogsDirectory(RepositoryName.MAIN));
 
     return ImmutableList.copyOf(roots);
   }
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 562391a..ffbca76 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
@@ -27,11 +27,13 @@
 import com.google.devtools.build.lib.analysis.RunfilesProvider;
 import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
 import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
+import com.google.devtools.build.lib.analysis.actions.CustomCommandLine.Builder;
 import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction;
 import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction.ComputedSubstitution;
 import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction.Substitution;
 import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction.Template;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.packages.BuildType;
 import com.google.devtools.build.lib.rules.java.DeployArchiveBuilder;
@@ -145,7 +147,7 @@
 
   @Override
   public void buildJavaCommandLine(Collection<Artifact> outputs, BuildConfiguration configuration,
-      CustomCommandLine.Builder result) {
+      Builder result, Label targetLabel) {
   }
 
   @Override
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/OutputDirectoryLinksUtils.java b/src/main/java/com/google/devtools/build/lib/buildtool/OutputDirectoryLinksUtils.java
index 2698861..63f533c 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/OutputDirectoryLinksUtils.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/OutputDirectoryLinksUtils.java
@@ -15,6 +15,7 @@
 
 import com.google.common.base.Joiner;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.cmdline.RepositoryName;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
@@ -69,11 +70,11 @@
 
     if (targetConfig != null) {
       createLink(workspace, symlinkPrefix + "bin",
-          targetConfig.getBinDirectory().getPath(), failures);
+          targetConfig.getBinDirectory(RepositoryName.MAIN).getPath(), failures);
       createLink(workspace, symlinkPrefix + "testlogs",
-          targetConfig.getTestLogsDirectory().getPath(), failures);
+          targetConfig.getTestLogsDirectory(RepositoryName.MAIN).getPath(), failures);
       createLink(workspace, symlinkPrefix + "genfiles",
-          targetConfig.getGenfilesDirectory().getPath(), failures);
+          targetConfig.getGenfilesDirectory(RepositoryName.MAIN).getPath(), failures);
     }
 
     if (!failures.isEmpty()) {
diff --git a/src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoAspect.java b/src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoAspect.java
index 2d88b4b..bbd9624 100644
--- a/src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoAspect.java
+++ b/src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoAspect.java
@@ -485,7 +485,8 @@
       String suffix) {
     BuildConfiguration configuration = ruleContext.getConfiguration();
     assert configuration != null;
-    Root genfilesDirectory = configuration.getGenfilesDirectory();
+    Root genfilesDirectory = configuration.getGenfilesDirectory(
+        ruleContext.getRule().getRepository());
 
     PathFragment derivedFilePath =
         getOutputFilePath(base, ruleContext, suffix);
diff --git a/src/main/java/com/google/devtools/build/lib/packages/Rule.java b/src/main/java/com/google/devtools/build/lib/packages/Rule.java
index b99e55e..dd5df33 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/Rule.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/Rule.java
@@ -28,6 +28,7 @@
 import com.google.common.collect.Multimap;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
+import com.google.devtools.build.lib.cmdline.RepositoryName;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.events.Location;
@@ -694,4 +695,11 @@
     }
     return labels.values();
   }
+
+  /**
+   * @return The repository name.
+   */
+  public RepositoryName getRepository() {
+    return getLabel().getPackageIdentifier().getRepository();
+  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
index 994a1cd..8afd384 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
@@ -568,7 +568,7 @@
 
   private Root newFileRoot() {
     return isForAspect()
-        ? getConfiguration().getBinDirectory()
+        ? getConfiguration().getBinDirectory(ruleContext.getRule().getRepository())
         : ruleContext.getBinOrGenfilesDirectory();
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdlHelper.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdlHelper.java
index b963947..40d3495 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdlHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdlHelper.java
@@ -30,7 +30,6 @@
 import com.google.devtools.build.lib.syntax.Type;
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
 import com.google.devtools.build.lib.vfs.PathFragment;
-
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
@@ -38,7 +37,6 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
-
 import javax.annotation.Nullable;
 
 /**
@@ -213,8 +211,7 @@
       PathFragment javaOutputPath = FileSystemUtils.replaceExtension(
           new PathFragment(ruleName + "_aidl").getRelative(idl.getRootRelativePath()),
           ".java");
-      Artifact output = ruleContext.getPackageRelativeArtifact(
-          javaOutputPath, ruleContext.getConfiguration().getGenfilesDirectory());
+      Artifact output = ruleContext.getGenfilesArtifact(javaOutputPath.getPathString());
       outputJavaSources.put(idl, output);
     }
     return outputJavaSources.build();
@@ -268,7 +265,9 @@
       Artifact idlClassJar,
       Artifact idlSourceJar) {
     String basename = FileSystemUtils.removeExtension(classJar.getExecPath().getBaseName());
-    PathFragment idlTempDir = ruleContext.getConfiguration().getBinDirectory().getExecPath()
+    PathFragment idlTempDir = ruleContext.getConfiguration()
+        .getBinDirectory(ruleContext.getRule().getRepository())
+        .getExecPath()
         .getRelative(ruleContext.getUniqueDirectory("_idl"))
         .getRelative(basename + "_temp");
     ruleContext.registerAction(new SpawnAction.Builder()
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/NativeLibs.java b/src/main/java/com/google/devtools/build/lib/rules/android/NativeLibs.java
index 421e8f2..4e582aa 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/NativeLibs.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/NativeLibs.java
@@ -160,7 +160,8 @@
     Artifact nativeLibsMiddleman =
         ruleContext.getAnalysisEnvironment().getMiddlemanFactory().createRunfilesMiddleman(
             ruleContext.getActionOwner(), null, symlinks.values(),
-            ruleContext.getConfiguration().getMiddlemanDirectory(), "android_native_libs");
+            ruleContext.getConfiguration().getMiddlemanDirectory(
+                ruleContext.getRule().getRepository()), "android_native_libs");
 
     ruleContext.registerAction(
         new SymlinkTreeAction(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java
index a4ceda4..0e12de1 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java
@@ -190,8 +190,7 @@
     if (!isLinkShared(ruleContext)) {
       binaryPath = new PathFragment(binaryPath.getPathString() + OsUtils.executableExtension());
     }
-    Artifact binary = ruleContext.getPackageRelativeArtifact(
-        binaryPath, ruleContext.getConfiguration().getBinDirectory());
+    Artifact binary = ruleContext.getBinArtifact(binaryPath);
     CppLinkActionBuilder linkActionBuilder =
         determineLinkerArguments(
             ruleContext,
@@ -229,9 +228,8 @@
     linkActionBuilder.setFeatureConfiguration(featureConfiguration);
 
     if (CppLinkAction.enableSymbolsCounts(cppConfiguration, fake, linkType)) {
-      linkActionBuilder.setSymbolCountsOutput(ruleContext.getPackageRelativeArtifact(
-          CppLinkAction.symbolCountsFileName(binaryPath),
-          ruleContext.getConfiguration().getBinDirectory()));
+      linkActionBuilder.setSymbolCountsOutput(ruleContext.getBinArtifact(
+          CppLinkAction.symbolCountsFileName(binaryPath)));
     }
 
     // Store immutable context for use in other *_binary rules that are implemented by
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcIncLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcIncLibrary.java
index 923bc71..8e2a5aa 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcIncLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcIncLibrary.java
@@ -81,7 +81,8 @@
     // is actually a symlink into the source tree.
     PathFragment includeDirectory = new PathFragment("_")
         .getRelative(ruleContext.getTarget().getName());
-    PathFragment includePath = ruleContext.getConfiguration().getIncludeDirectory().getExecPath()
+    PathFragment includePath = ruleContext.getConfiguration()
+        .getIncludeDirectory(ruleContext.getRule().getRepository()).getExecPath()
         .getRelative(packageFragment)
         .getRelative(includeDirectory);
 
@@ -112,7 +113,8 @@
 
       // These virtual artifacts have the symlink action as generating action.
       Artifact virtualArtifact = ruleContext.getPackageRelativeArtifact(
-          virtualPath, ruleContext.getConfiguration().getIncludeDirectory());
+          virtualPath, ruleContext.getConfiguration()
+              .getIncludeDirectory(ruleContext.getRule().getRepository()));
       virtualArtifactMapBuilder.put(virtualArtifact, src);
     }
     ImmutableSortedMap<Artifact, Artifact> virtualArtifactMap = virtualArtifactMapBuilder.build();
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
index 0785b36..80de4c0 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
@@ -161,8 +161,7 @@
         }
 
         if (createDynamicLibrary) {
-          soImplArtifact = ruleContext.getPackageRelativeArtifact(
-              soImplFilename, ruleContext.getConfiguration().getBinDirectory());
+          soImplArtifact = ruleContext.getBinArtifact(soImplFilename);
         }
       }
     }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppBuildInfo.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppBuildInfo.java
index 726fad2..71be346 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppBuildInfo.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppBuildInfo.java
@@ -20,6 +20,7 @@
 import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoCollection;
 import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoFactory;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.cmdline.RepositoryName;
 import com.google.devtools.build.lib.vfs.PathFragment;
 
 import java.util.ArrayList;
@@ -68,7 +69,7 @@
       BuildConfiguration config, PathFragment headerName,
       Collection<Artifact> inputs,
       boolean writeVolatileInfo, boolean writeNonVolatileInfo) {
-    Root outputPath = config.getIncludeDirectory();
+    Root outputPath = config.getIncludeDirectory(RepositoryName.MAIN);
     final Artifact header =
         buildInfoContext.getBuildInfoArtifact(headerName, outputPath,
             writeVolatileInfo && !inputs.isEmpty()
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompilationContext.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompilationContext.java
index c53b049..67f0897 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompilationContext.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompilationContext.java
@@ -927,7 +927,8 @@
       return middlemanFactory.createErrorPropagatingMiddleman(
           owner, ruleContext.getLabel().toString(), purpose,
           ImmutableList.copyOf(compilationPrerequisites),
-          ruleContext.getConfiguration().getMiddlemanDirectory());
+          ruleContext.getConfiguration().getMiddlemanDirectory(
+              ruleContext.getRule().getRepository()));
     }
 
     /**
@@ -939,8 +940,11 @@
         return null;
       }
 
-      return middlemanFactory.getErrorPropagatingMiddlemanArtifact(ruleContext.getLabel()
-          .toString(), purpose, ruleContext.getConfiguration().getMiddlemanDirectory());
+      return middlemanFactory.getErrorPropagatingMiddlemanArtifact(
+          ruleContext.getLabel().toString(),
+          purpose,
+          ruleContext.getConfiguration().getMiddlemanDirectory(
+              ruleContext.getRule().getRepository()));
     }
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionBuilder.java
index 8360791..c751955 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionBuilder.java
@@ -387,7 +387,7 @@
       if (configuration.getFragment(CppConfiguration.class).getInmemoryDotdFiles()) {
         // Just set the path, no artifact is constructed
         dotdFile = new DotdFile(
-            configuration.getBinDirectory().getExecPath()
+            configuration.getBinDirectory(ruleContext.getRule().getRepository()).getExecPath()
                 .getRelative(CppHelper.getObjDirectory(ruleContext.getLabel()))
                 .getRelative(dotdFileName));
       } else {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java
index c70e8db..fe0b605 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java
@@ -342,8 +342,7 @@
       name = name.replaceName("lib" + name.getBaseName() + linkType.getExtension());
     }
 
-    return ruleContext.getPackageRelativeArtifact(
-        name, ruleContext.getConfiguration().getBinDirectory());
+    return ruleContext.getBinArtifact(name);
   }
 
   /**
@@ -445,7 +444,8 @@
     Artifact mapFile = ruleContext.getPackageRelativeArtifact(
         ruleContext.getLabel().getName()
             + Iterables.getOnlyElement(CppFileTypes.CPP_MODULE_MAP.getExtensions()),
-        ruleContext.getConfiguration().getGenfilesDirectory());
+        ruleContext.getConfiguration().getGenfilesDirectory(
+            ruleContext.getRule().getRepository()));
     return new CppModuleMap(mapFile, ruleContext.getLabel().toString());
   }
 
@@ -497,7 +497,8 @@
     }
     return ImmutableList.of(
         factory.createMiddlemanAllowMultiple(env, actionOwner, ruleContext.getPackageDirectory(),
-            purpose, artifacts, configuration.getMiddlemanDirectory()));
+            purpose, artifacts, configuration.getMiddlemanDirectory(
+                ruleContext.getRule().getRepository())));
   }
 
   /**
@@ -606,7 +607,7 @@
   static Artifact getCompileOutputArtifact(RuleContext ruleContext, String outputName) {
     PathFragment objectDir = getObjDirectory(ruleContext.getLabel());
     return ruleContext.getDerivedArtifact(objectDir.getRelative(outputName),
-        ruleContext.getConfiguration().getBinDirectory());
+        ruleContext.getConfiguration().getBinDirectory(ruleContext.getRule().getRepository()));
   }
 
   static String getCompileArtifactName(RuleContext ruleContext, ArtifactCategory category,
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkAction.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkAction.java
index 32782a7..ef5e4e4 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkAction.java
@@ -85,7 +85,8 @@
     @Override
     public Artifact create(RuleContext ruleContext, BuildConfiguration configuration,
                            PathFragment rootRelativePath) {
-      return ruleContext.getDerivedArtifact(rootRelativePath, configuration.getBinDirectory());
+      return ruleContext.getDerivedArtifact(
+          rootRelativePath, configuration.getBinDirectory(ruleContext.getRule().getRepository()));
     }
   };
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java
index 21425b2..81cdd26 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java
@@ -588,10 +588,11 @@
       opts.add("-Wl,-plugin-opt,thinlto-emit-imports-files");
       opts.add(
           "-Wl,-plugin-opt,thinlto-prefix-replace="
-              + configuration.getBinDirectory().getExecPathString()
+              + configuration.getBinDirectory(ruleContext.getRule().getRepository())
+                  .getExecPathString()
               + ";"
               + configuration
-                  .getBinDirectory()
+                  .getBinDirectory(ruleContext.getRule().getRepository())
                   .getExecPath()
                   .getRelative(ltoOutputRootPrefix)
                   .toString());
@@ -1262,7 +1263,7 @@
 
       PathFragment solibDir =
           configuration
-              .getBinDirectory()
+              .getBinDirectory(ruleContext.getRule().getRepository())
               .getExecPath()
               .getRelative(cppConfiguration.getSolibDirectory());
       String runtimeSolibName = runtimeSolibDir != null ? runtimeSolibDir.getBaseName() : null;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java
index 67cf452..77b7e13 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java
@@ -784,8 +784,7 @@
           linkTargetType.getLinkerOutput(), ruleContext, ImmutableMap.<String, String>of());
       PathFragment artifactFragment = new PathFragment(ruleContext.getLabel().getName())
           .getParentDirectory().getRelative(templatedName);
-      result = ruleContext.getPackageRelativeArtifact(
-          artifactFragment, ruleContext.getConfiguration().getBinDirectory());
+      result = ruleContext.getBinArtifact(artifactFragment);
     } catch (ExpansionException e) {
       ruleContext.throwWithRuleError(e.getMessage());
     }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/SolibSymlinkAction.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/SolibSymlinkAction.java
index f967590..98db892 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/SolibSymlinkAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/SolibSymlinkAction.java
@@ -163,7 +163,7 @@
     Preconditions.checkArgument(!library.getRootRelativePath().getSegment(0).startsWith("_solib_"));
 
     // Ignore libraries that are already represented by the symlinks.
-    Root root = configuration.getBinDirectory();
+    Root root = configuration.getBinDirectory(ruleContext.getRule().getRepository());
     Artifact symlink = ruleContext.getShareableArtifact(symlinkName, root);
     ruleContext.registerAction(
         new SolibSymlinkAction(ruleContext.getActionOwner(), library, symlink));
diff --git a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionSpec.java b/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionSpec.java
index e8115e8..cf7f1ac 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionSpec.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionSpec.java
@@ -204,7 +204,7 @@
     // We need to use getDerivedArtifact here because extra actions are at
     // <EXTRA ACTION LABEL> / <RULE LABEL> instead of <RULE LABEL> / <EXTRA ACTION LABEL>. Bummer.
     return ruleContext.getAnalysisEnvironment().getDerivedArtifact(rootRelativePath,
-        ruleContext.getConfiguration().getOutputDirectory());
+        ruleContext.getConfiguration().getOutputDirectory(ruleContext.getRule().getRepository()));
   }
 
   /**
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/BaseJavaCompilationHelper.java b/src/main/java/com/google/devtools/build/lib/rules/java/BaseJavaCompilationHelper.java
index 78b1c84..510d9a0 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/BaseJavaCompilationHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/BaseJavaCompilationHelper.java
@@ -104,7 +104,8 @@
       String ijarBasename = FileSystemUtils.removeExtension(jar.getFilename()) + "-ijar.jar";
       return ruleContext.getDerivedArtifact(
           ruleBase.getRelative(artifactDirFragment).getRelative(ijarBasename),
-          ruleContext.getConfiguration().getGenfilesDirectory());
+          ruleContext.getConfiguration().getGenfilesDirectory(
+              ruleContext.getRule().getRepository()));
     } else {
       return derivedArtifact(jar, "", "-ijar.jar");
     }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaBuildInfoFactory.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaBuildInfoFactory.java
index 9d05cba..3ab7bde 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaBuildInfoFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaBuildInfoFactory.java
@@ -21,17 +21,16 @@
 import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoCollection;
 import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoFactory;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.cmdline.RepositoryName;
 import com.google.devtools.build.lib.rules.java.WriteBuildInfoPropertiesAction.TimestampFormatter;
 import com.google.devtools.build.lib.vfs.PathFragment;
-
+import java.util.ArrayList;
+import java.util.List;
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.joda.time.format.DateTimeFormat;
 import org.joda.time.format.DateTimeFormatter;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * Java build info creation - generates properties file that contain the corresponding build-info
  * data.
@@ -121,7 +120,7 @@
       BuildInfoPropertiesTranslator translator,
       boolean includeVolatile,
       boolean includeNonVolatile) {
-    Root outputPath = config.getIncludeDirectory();
+    Root outputPath = config.getIncludeDirectory(RepositoryName.MAIN);
     final Artifact output = context.getBuildInfoArtifact(propertyFileName, outputPath,
         includeVolatile && !inputs.isEmpty() ? BuildInfoType.NO_REBUILD
             : BuildInfoType.FORCE_REBUILD_IF_CHANGED);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java
index 97a05f2..4c97fe3 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java
@@ -155,7 +155,9 @@
     builder.setDirectJars(attributes.getDirectJars());
     builder.addCompileTimeDependencyArtifacts(attributes.getCompileTimeDependencyArtifacts());
     builder.setRuleKind(attributes.getRuleKind());
-    builder.setTargetLabel(attributes.getTargetLabel());
+    builder.setTargetLabel(
+        attributes.getTargetLabel() == null
+            ? ruleContext.getLabel() : attributes.getTargetLabel());
     getAnalysisEnvironment().registerAction(builder.build());
   }
 
@@ -442,6 +444,7 @@
     builder.setJavaBuilderJar(javaToolchain.getJavaBuilder());
     builder.setJavacOpts(getDefaultJavacOptsFromRule(getRuleContext()));
     builder.setJavacJvmOpts(javaToolchain.getJvmOptions());
+    builder.setTargetLabel(ruleContext.getLabel());
     getAnalysisEnvironment().registerAction(builder.build());
     return resourceJar;
   }
@@ -452,6 +455,7 @@
     builder.setJavaExecutable(
         ruleContext.getHostConfiguration().getFragment(Jvm.class).getJavaExecutable());
     builder.setJavaBaseInputs(getHostJavabaseInputsNonStatic(ruleContext));
+    builder.setTargetLabel(ruleContext.getLabel());
     return builder;
   }
 
@@ -479,7 +483,7 @@
    */
   private PathFragment workDir(Artifact outputJar, String suffix) {
     String basename = FileSystemUtils.removeExtension(outputJar.getExecPath().getBaseName());
-    return getConfiguration().getBinDirectory().getExecPath()
+    return getConfiguration().getBinDirectory(ruleContext.getRule().getRepository()).getExecPath()
         .getRelative(ruleContext.getUniqueDirectory("_javac"))
         .getRelative(basename + suffix);
   }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java
index 2f25f7b..c168642 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java
@@ -893,7 +893,7 @@
       if (paramFile == null) {
         paramFile = artifactFactory.create(
             ParameterFile.derivePath(outputJar.getRootRelativePath()),
-            configuration.getBinDirectory());
+            configuration.getBinDirectory(targetLabel.getPackageIdentifier().getRepository()));
       }
 
       // ImmutableIterable is safe to use here because we know that none of the components of
@@ -953,7 +953,8 @@
           strictJavaDeps,
           compileTimeDependencyArtifacts
       );
-      semantics.buildJavaCommandLine(outputs, configuration, paramFileContentsBuilder);
+      semantics.buildJavaCommandLine(
+          outputs, configuration, paramFileContentsBuilder, targetLabel);
       CommandLine paramFileContents = paramFileContentsBuilder.build();
       Action parameterFileWriteAction = new ParameterFileWriteAction(owner, paramFile,
           paramFileContents, ParameterFile.ParameterFileType.UNQUOTED, ISO_8859_1);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java
index c2b5875..4424789 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java
@@ -217,7 +217,7 @@
    * May add extra command line options to the Java compile command line.
    */
   void buildJavaCommandLine(Collection<Artifact> outputs, BuildConfiguration configuration,
-      CustomCommandLine.Builder result);
+      CustomCommandLine.Builder result, Label targetLabel);
 
 
   /**
diff --git a/src/main/java/com/google/devtools/build/lib/rules/nativedeps/NativeDepsHelper.java b/src/main/java/com/google/devtools/build/lib/rules/nativedeps/NativeDepsHelper.java
index 72633de..a7a53d5 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/nativedeps/NativeDepsHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/nativedeps/NativeDepsHelper.java
@@ -64,7 +64,7 @@
         public Artifact create(RuleContext ruleContext, BuildConfiguration configuration,
             PathFragment rootRelativePath) {
           return ruleContext.getShareableArtifact(rootRelativePath,
-              configuration.getBinDirectory());
+              configuration.getBinDirectory(ruleContext.getRule().getRepository()));
         }
       };
 
@@ -103,7 +103,7 @@
         .getPathString();
     Artifact nativeDeps = ruleContext.getUniqueDirectoryArtifact(ANDROID_UNIQUE_DIR,
         labelName.replaceName("lib" + labelName.getBaseName() + ".so"),
-        configuration.getBinDirectory());
+        configuration.getBinDirectory(ruleContext.getRule().getRepository()));
 
     return createNativeDepsAction(
             ruleContext,
@@ -113,7 +113,7 @@
             toolchain,
             nativeDeps,
             libraryIdentifier,
-            configuration.getBinDirectory(),
+            configuration.getBinDirectory(ruleContext.getRule().getRepository()),
             /*useDynamicRuntime*/ false)
         .getLibrary();
   }
@@ -153,7 +153,7 @@
       libraryIdentifier = sharedPath.getPathString();
       sharedLibrary = ruleContext.getShareableArtifact(
           sharedPath.replaceName(sharedPath.getBaseName() + ".so"),
-          configuration.getBinDirectory());
+          configuration.getBinDirectory(ruleContext.getRule().getRepository()));
     } else {
       sharedLibrary = nativeDeps;
     }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AbstractJ2ObjcProtoAspect.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AbstractJ2ObjcProtoAspect.java
index 6bacad5..bcc4ba0 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/AbstractJ2ObjcProtoAspect.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AbstractJ2ObjcProtoAspect.java
@@ -193,7 +193,8 @@
     Iterable<Artifact> generatedSourceFiles = checkShouldCreateSources(ruleContext)
         ? ProtoCommon.getGeneratedOutputs(ruleContext, protoSources, ".j2objc.pb.m")
         : ImmutableList.<Artifact>of();
-    PathFragment objcFileRootExecPath = ruleContext.getConfiguration().getGenfilesDirectory()
+    PathFragment objcFileRootExecPath = ruleContext.getConfiguration()
+        .getGenfilesDirectory(ruleContext.getRule().getRepository())
         .getExecPath();
     Iterable<PathFragment> headerSearchPaths = J2ObjcLibrary.j2objcSourceHeaderSearchPaths(
         ruleContext, objcFileRootExecPath, protoSources);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/BazelJ2ObjcProtoAspect.java b/src/main/java/com/google/devtools/build/lib/rules/objc/BazelJ2ObjcProtoAspect.java
index f5fb477..98e0501 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/BazelJ2ObjcProtoAspect.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/BazelJ2ObjcProtoAspect.java
@@ -69,7 +69,8 @@
       Iterable<Artifact> headerMappingFiles,
       Iterable<Artifact> classMappingFiles,
       J2ObjcSource j2ObjcSource) {
-    String genDir = ruleContext.getConfiguration().getGenfilesDirectory().getExecPathString();
+    String genDir = ruleContext.getConfiguration().getGenfilesDirectory(
+        ruleContext.getRule().getRepository()).getExecPathString();
     Artifact compiler = ruleContext.getPrerequisiteArtifact("$protoc", Mode.HOST);
     Artifact j2objcPlugin = ruleContext.getPrerequisiteArtifact("$j2objc_plugin", Mode.HOST);
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/IntermediateArtifacts.java b/src/main/java/com/google/devtools/build/lib/rules/objc/IntermediateArtifacts.java
index 455526a..9b8ced2 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/IntermediateArtifacts.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/IntermediateArtifacts.java
@@ -74,7 +74,7 @@
         ruleContext.getDerivedArtifact(
             entitlementsDirectory.replaceName(
                 addOutputPrefix(entitlementsDirectory.getBaseName(), extension)),
-            buildConfiguration.getBinDirectory());
+            buildConfiguration.getBinDirectory(ruleContext.getRule().getRepository()));
     return artifact;
   }
 
@@ -204,8 +204,8 @@
   private Artifact scopedArtifact(PathFragment scopeRelative, boolean inGenfiles) {
     Root root =
         inGenfiles
-            ? buildConfiguration.getGenfilesDirectory()
-            : buildConfiguration.getBinDirectory();
+            ? buildConfiguration.getGenfilesDirectory(ruleContext.getRule().getRepository())
+            : buildConfiguration.getBinDirectory(ruleContext.getRule().getRepository());
 
     // The path of this artifact will be RULE_PACKAGE/SCOPERELATIVE
     return ruleContext.getPackageRelativeArtifact(scopeRelative, root);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ProtoSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ProtoSupport.java
index bcfc5e3..5cfe31f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ProtoSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ProtoSupport.java
@@ -318,7 +318,8 @@
 
   private Artifact getProtoInputListFile() {
     return ruleContext.getUniqueDirectoryArtifact(
-        "_protos", "_proto_input_files", ruleContext.getConfiguration().getGenfilesDirectory());
+        "_protos", "_proto_input_files", ruleContext.getConfiguration().getGenfilesDirectory(
+            ruleContext.getRule().getRepository()));
   }
 
   private String getProtoInputListFileContents() {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCommon.java b/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCommon.java
index aa7a3e1..fdabf5f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCommon.java
@@ -132,7 +132,8 @@
   public static ImmutableList<Artifact> getGeneratedOutputs(RuleContext ruleContext,
       ImmutableList<Artifact> protoSources, String extension, boolean pythonNames) {
     ImmutableList.Builder<Artifact> outputsBuilder = new ImmutableList.Builder<>();
-    Root genfiles = ruleContext.getConfiguration().getGenfilesDirectory();
+    Root genfiles = ruleContext.getConfiguration().getGenfilesDirectory(
+        ruleContext.getRule().getRepository());
     for (Artifact src : protoSources) {
       PathFragment srcPath = src.getRootRelativePath();
       if (pythonNames) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/python/PythonUtils.java b/src/main/java/com/google/devtools/build/lib/rules/python/PythonUtils.java
index b110280..c2508c2 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/python/PythonUtils.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/python/PythonUtils.java
@@ -84,7 +84,8 @@
    * subdirectory to avoid conflicts (eg. when the input file is generated).
    */
   private static Artifact get2to3OutputArtifact(RuleContext ruleContext, Artifact input) {
-    Root root = ruleContext.getConfiguration().getGenfilesDirectory();
+    Root root = ruleContext.getConfiguration().getGenfilesDirectory(
+        ruleContext.getRule().getRepository());
     PathFragment path = new PathFragment("python3").getRelative(input.getRootRelativePath());
     return ruleContext.getShareableArtifact(path, root);
   }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/test/BaselineCoverageAction.java b/src/main/java/com/google/devtools/build/lib/rules/test/BaselineCoverageAction.java
index 99626d2..8b7dea8 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/test/BaselineCoverageAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/test/BaselineCoverageAction.java
@@ -117,7 +117,8 @@
     // Baseline coverage artifacts will still go into "testlogs" directory.
     Artifact coverageData = ruleContext.getPackageRelativeArtifact(
         new PathFragment(ruleContext.getTarget().getName()).getChild("baseline_coverage.dat"),
-        ruleContext.getConfiguration().getTestLogsDirectory());
+        ruleContext.getConfiguration().getTestLogsDirectory(
+            ruleContext.getRule().getRepository()));
     ruleContext.registerAction(new BaselineCoverageAction(
         ruleContext.getActionOwner(), instrumentedFiles, coverageData));
     return NestedSetBuilder.create(Order.STABLE_ORDER, coverageData);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/test/InstrumentedFileManifestAction.java b/src/main/java/com/google/devtools/build/lib/rules/test/InstrumentedFileManifestAction.java
index 1327547..a2c5432 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/test/InstrumentedFileManifestAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/test/InstrumentedFileManifestAction.java
@@ -99,9 +99,8 @@
       NestedSet<Artifact> additionalSourceFiles, NestedSet<Artifact> metadataFiles) {
     // Instrumented manifest makes sense only for rules with binary output.
     Preconditions.checkState(ruleContext.getRule().hasBinaryOutput());
-    Artifact instrumentedFileManifest = ruleContext.getPackageRelativeArtifact(
-        ruleContext.getTarget().getName()  + ".instrumented_files",
-        ruleContext.getConfiguration().getBinDirectory());
+    Artifact instrumentedFileManifest = ruleContext.getBinArtifact(
+        ruleContext.getTarget().getName()  + ".instrumented_files");
 
     NestedSet<Artifact> inputs = NestedSetBuilder.<Artifact>stableOrder()
         .addTransitive(additionalSourceFiles)
diff --git a/src/main/java/com/google/devtools/build/lib/rules/test/TestActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/test/TestActionBuilder.java
index 29be94d..f0a2733 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/test/TestActionBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/test/TestActionBuilder.java
@@ -182,7 +182,7 @@
     PathFragment targetName = new PathFragment(ruleContext.getLabel().getName());
     BuildConfiguration config = ruleContext.getConfiguration();
     AnalysisEnvironment env = ruleContext.getAnalysisEnvironment();
-    Root root = config.getTestLogsDirectory();
+    Root root = config.getTestLogsDirectory(ruleContext.getRule().getRepository());
 
     NestedSetBuilder<Artifact> inputsBuilder = NestedSetBuilder.stableOrder();
     inputsBuilder.addTransitive(
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/InfoItem.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/InfoItem.java
index 8237317..4677b4a 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/commands/InfoItem.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/InfoItem.java
@@ -22,6 +22,7 @@
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.analysis.BlazeVersionInfo;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.cmdline.RepositoryName;
 import com.google.devtools.build.lib.packages.Attribute;
 import com.google.devtools.build.lib.packages.BuildType;
 import com.google.devtools.build.lib.packages.ProtoUtils;
@@ -216,7 +217,7 @@
     public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
         throws AbruptExitException {
       checkNotNull(configurationSupplier);
-      return print(configurationSupplier.get().getBinDirectory().getPath());
+      return print(configurationSupplier.get().getBinDirectory(RepositoryName.MAIN).getPath());
     }
   }
 
@@ -237,7 +238,8 @@
     public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
         throws AbruptExitException {
       checkNotNull(configurationSupplier);
-      return print(configurationSupplier.get().getGenfilesDirectory().getPath());
+      return print(
+          configurationSupplier.get().getGenfilesDirectory(RepositoryName.MAIN).getPath());
     }
   }
 
@@ -258,7 +260,8 @@
     public byte[] get(Supplier<BuildConfiguration> configurationSupplier, CommandEnvironment env)
         throws AbruptExitException {
       checkNotNull(configurationSupplier);
-      return print(configurationSupplier.get().getTestLogsDirectory().getPath());
+      return print(
+          configurationSupplier.get().getTestLogsDirectory(RepositoryName.MAIN).getPath());
     }
   }