Parse the workspace name when a repository is loaded

Moved RepositoryValue to RepositoryDirectoryValue so that it could be cached
(and not re-downloaded) even if the WorkspaceAST caused a Skyframe restart
(as mentioned in https://github.com/bazelbuild/bazel/blob/master/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorFunction.java#L130-L133).

--
MOS_MIGRATED_REVID=113358489
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java b/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java
index 9c83d70..0befcba 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java
@@ -48,10 +48,11 @@
 import com.google.devtools.build.lib.rules.repository.NewLocalRepositoryFunction;
 import com.google.devtools.build.lib.rules.repository.NewLocalRepositoryRule;
 import com.google.devtools.build.lib.rules.repository.RepositoryDelegatorFunction;
+import com.google.devtools.build.lib.rules.repository.RepositoryDirectoryValue;
 import com.google.devtools.build.lib.rules.repository.RepositoryFunction;
+import com.google.devtools.build.lib.rules.repository.RepositoryLoaderFunction;
 import com.google.devtools.build.lib.runtime.BlazeCommand;
 import com.google.devtools.build.lib.runtime.BlazeModule;
-import com.google.devtools.build.lib.skyframe.RepositoryValue;
 import com.google.devtools.build.lib.skyframe.SkyFunctions;
 import com.google.devtools.build.lib.skyframe.SkyValueDirtinessChecker;
 import com.google.devtools.build.lib.util.Clock;
@@ -105,8 +106,9 @@
   }
 
   /**
-   * A dirtiness checker that always dirties {@link RepositoryValue}s so that if they were produced
-   * in a {@code --nofetch} build, they are re-created no subsequent {@code --fetch} builds.
+   * A dirtiness checker that always dirties {@link RepositoryDirectoryValue}s so that if they were
+   * produced in a {@code --nofetch} build, they are re-created no subsequent {@code --fetch}
+   * builds.
    *
    * <p>The alternative solution would be to reify the value of the flag as a Skyframe value.
    */
@@ -114,7 +116,7 @@
       new SkyValueDirtinessChecker() {
         @Override
         public boolean applies(SkyKey skyKey) {
-          return skyKey.functionName().equals(SkyFunctions.REPOSITORY);
+          return skyKey.functionName().equals(SkyFunctions.REPOSITORY_DIRECTORY);
         }
 
         @Override
@@ -125,7 +127,7 @@
         @Override
         public DirtyResult check(
             SkyKey skyKey, SkyValue skyValue, @Nullable TimestampGranularityMonitor tsgm) {
-          RepositoryValue repositoryValue = (RepositoryValue) skyValue;
+          RepositoryDirectoryValue repositoryValue = (RepositoryDirectoryValue) skyValue;
           return repositoryValue.isFetchingDelayed()
               ? DirtyResult.dirty(skyValue)
               : DirtyResult.notDirty(skyValue);
@@ -166,11 +168,12 @@
   public ImmutableMap<SkyFunctionName, SkyFunction> getSkyFunctions(BlazeDirectories directories) {
     ImmutableMap.Builder<SkyFunctionName, SkyFunction> builder = ImmutableMap.builder();
 
-    // Create the delegator everything flows through.
-    builder.put(SkyFunctions.REPOSITORY,
-        new RepositoryDelegatorFunction(directories, repositoryHandlers, isFetch));
+    // Create the repository function everything flows through.
+    builder.put(SkyFunctions.REPOSITORY, new RepositoryLoaderFunction());
 
     // Helper SkyFunctions.
+    builder.put(SkyFunctions.REPOSITORY_DIRECTORY,
+        new RepositoryDelegatorFunction(directories, repositoryHandlers, isFetch));
     builder.put(MavenServerFunction.NAME, new MavenServerFunction(directories));
     return builder.build();
   }
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/GitRepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/GitRepositoryFunction.java
index 66ef6bc..7ba85c6 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/repository/GitRepositoryFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/GitRepositoryFunction.java
@@ -17,8 +17,8 @@
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.bazel.rules.workspace.GitRepositoryRule;
 import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.rules.repository.RepositoryDirectoryValue;
 import com.google.devtools.build.lib.rules.repository.RepositoryFunction;
-import com.google.devtools.build.lib.skyframe.RepositoryValue;
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.skyframe.SkyFunction.Environment;
@@ -42,7 +42,7 @@
       throws SkyFunctionException {
     createDirectory(outputDirectory, rule);
     GitCloner.clone(rule, outputDirectory, env.getListener());
-    return RepositoryValue.create(outputDirectory);
+    return RepositoryDirectoryValue.create(outputDirectory);
   }
 
   protected void createDirectory(Path path, Rule rule)
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/HttpArchiveFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/HttpArchiveFunction.java
index 5f5628a..5158bc6 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/repository/HttpArchiveFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/HttpArchiveFunction.java
@@ -18,8 +18,8 @@
 import com.google.devtools.build.lib.bazel.rules.workspace.HttpArchiveRule;
 import com.google.devtools.build.lib.packages.AggregatingAttributeMapper;
 import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.rules.repository.RepositoryDirectoryValue;
 import com.google.devtools.build.lib.rules.repository.RepositoryFunction;
-import com.google.devtools.build.lib.skyframe.RepositoryValue;
 import com.google.devtools.build.lib.syntax.Type;
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
 import com.google.devtools.build.lib.vfs.Path;
@@ -61,7 +61,7 @@
     Path downloadedPath = HttpDownloader.download(rule, outputDirectory, env.getListener());
 
     DecompressorValue.decompress(getDescriptor(rule, downloadedPath, outputDirectory));
-    return RepositoryValue.create(outputDirectory);
+    return RepositoryDirectoryValue.create(outputDirectory);
   }
 
   protected DecompressorDescriptor getDescriptor(Rule rule, Path downloadPath, Path outputDirectory)
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/MavenJarFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/MavenJarFunction.java
index 83a7ed1..1bbe61ff 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/repository/MavenJarFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/MavenJarFunction.java
@@ -26,8 +26,8 @@
 import com.google.devtools.build.lib.packages.AggregatingAttributeMapper;
 import com.google.devtools.build.lib.packages.AttributeMap;
 import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.rules.repository.RepositoryDirectoryValue;
 import com.google.devtools.build.lib.rules.repository.RepositoryFunction;
-import com.google.devtools.build.lib.skyframe.RepositoryValue;
 import com.google.devtools.build.lib.syntax.EvalException;
 import com.google.devtools.build.lib.syntax.Type;
 import com.google.devtools.build.lib.util.Fingerprint;
@@ -142,7 +142,7 @@
         .setTargetName(downloader.getName())
         .setArchivePath(repositoryJar)
         .setRepositoryPath(outputDirectory).build());
-    return RepositoryValue.create(result);
+    return RepositoryDirectoryValue.create(result);
   }
 
   /**
diff --git a/src/main/java/com/google/devtools/build/lib/packages/Package.java b/src/main/java/com/google/devtools/build/lib/packages/Package.java
index 1cfb443..c861bfe 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/Package.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/Package.java
@@ -484,7 +484,7 @@
    * <p>Package-private to encourage callers to get their workspace name from a rule, not a
    * package.</p>
    */
-  String getWorkspaceName() {
+  public String getWorkspaceName() {
     return workspaceName;
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/pkgcache/PathPackageLocator.java b/src/main/java/com/google/devtools/build/lib/pkgcache/PathPackageLocator.java
index f14b954..93a5e01 100644
--- a/src/main/java/com/google/devtools/build/lib/pkgcache/PathPackageLocator.java
+++ b/src/main/java/com/google/devtools/build/lib/pkgcache/PathPackageLocator.java
@@ -105,8 +105,8 @@
           "External package '%s' needs to be loaded but this PathPackageLocator instance does not "
               + "support external packages", packageIdentifier));
       // This works only to some degree, because it relies on the presence of the repository under
-      // $OUTPUT_BASE/external, which is created by the appropriate RepositoryValue. This is true
-      // for the invocation in GlobCache, but not for the locator.getBuildFileForPackage()
+      // $OUTPUT_BASE/external, which is created by the appropriate RepositoryDirectoryValue. This
+      // is true for the invocation in GlobCache, but not for the locator.getBuildFileForPackage()
       // invocation in Parser#include().
       Path buildFile = outputBase.getRelative(
           packageIdentifier.getPathFragment()).getRelative("BUILD");
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/LocalRepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/rules/repository/LocalRepositoryFunction.java
index 400783e..d372043 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/repository/LocalRepositoryFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/LocalRepositoryFunction.java
@@ -18,7 +18,6 @@
 import com.google.devtools.build.lib.packages.AggregatingAttributeMapper;
 import com.google.devtools.build.lib.packages.Rule;
 import com.google.devtools.build.lib.skyframe.FileValue;
-import com.google.devtools.build.lib.skyframe.RepositoryValue;
 import com.google.devtools.build.lib.syntax.Type;
 import com.google.devtools.build.lib.vfs.FileSystem;
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
@@ -71,7 +70,7 @@
           new IOException(rule + " must specify an existing directory"), Transience.TRANSIENT);
     }
 
-    return RepositoryValue.create(outputDirectory);
+    return RepositoryDirectoryValue.create(outputDirectory);
   }
 
   @Override
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorFunction.java b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorFunction.java
index 903fc63..e83433b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorFunction.java
@@ -22,7 +22,6 @@
 import com.google.devtools.build.lib.packages.Rule;
 import com.google.devtools.build.lib.rules.repository.RepositoryFunction.RepositoryFunctionException;
 import com.google.devtools.build.lib.skyframe.FileValue;
-import com.google.devtools.build.lib.skyframe.RepositoryValue;
 import com.google.devtools.build.lib.syntax.EvalException;
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
 import com.google.devtools.build.lib.vfs.Path;
@@ -116,7 +115,7 @@
       // NB: This returns the wrong repository value for non-local new_* repository functions.
       // This should sort itself out automatically once the ExternalFilesHelper refactoring is
       // finally submitted.
-      return RepositoryValue.create(repoRootValue.realRootedPath().asPath());
+      return RepositoryDirectoryValue.create(repoRootValue.realRootedPath().asPath());
     }
 
     if (isFetch.get()) {
@@ -156,7 +155,7 @@
         + "run the build without the '--nofetch' command line option.",
         rule.getName())));
 
-    return RepositoryValue.fetchingDelayed(repoRootValue.realRootedPath().asPath());
+    return RepositoryDirectoryValue.fetchingDelayed(repoRootValue.realRootedPath().asPath());
   }
 
   @Override
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDirectoryValue.java b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDirectoryValue.java
new file mode 100644
index 0000000..6b43297
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDirectoryValue.java
@@ -0,0 +1,94 @@
+// Copyright 2014 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.rules.repository;
+
+import com.google.common.base.Objects;
+import com.google.devtools.build.lib.cmdline.RepositoryName;
+import com.google.devtools.build.lib.skyframe.SkyFunctions;
+import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.SkyValue;
+
+/**
+ * A local view of an external repository.
+ */
+public class RepositoryDirectoryValue implements SkyValue {
+  private final Path path;
+  private final boolean fetchingDelayed;
+
+  private RepositoryDirectoryValue(Path path, boolean fetchingDelayed) {
+    this.path = path;
+    this.fetchingDelayed = fetchingDelayed;
+  }
+
+  /**
+   * Creates an immutable external repository.
+   */
+  public static RepositoryDirectoryValue create(Path repositoryDirectory) {
+    return new RepositoryDirectoryValue(repositoryDirectory, false);
+  }
+
+  /**
+   * Creates a value that represents a repository whose fetching has been delayed by a
+   * {@code --nofetch} command line option.
+   */
+  public static RepositoryDirectoryValue fetchingDelayed(Path repositoryDirectory) {
+    return new RepositoryDirectoryValue(repositoryDirectory, true);
+  }
+
+  /**
+   * Returns the path to the directory containing the repository's contents. This directory is
+   * guaranteed to exist.  It may contain a full Bazel repository (with a WORKSPACE file,
+   * directories, and BUILD files) or simply contain a file (or set of files) for, say, a jar from
+   * Maven.
+   */
+  public Path getPath() {
+    return path;
+  }
+
+  public boolean isFetchingDelayed() {
+    return fetchingDelayed;
+  }
+
+  @Override
+  public boolean equals(Object other) {
+    if (this == other) {
+      return true;
+    }
+
+    if (other instanceof RepositoryDirectoryValue) {
+      RepositoryDirectoryValue otherValue = (RepositoryDirectoryValue) other;
+      return path.equals(otherValue.path);
+    }
+    return false;
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hashCode(path);
+  }
+
+  @Override
+  public String toString() {
+    return path.getPathString();
+  }
+
+  /**
+   * Creates a key from the given repository name.
+   */
+  public static SkyKey key(RepositoryName repository) {
+    return new SkyKey(SkyFunctions.REPOSITORY_DIRECTORY, repository);
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java
index f5fdd79..fbf079c8 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java
@@ -32,7 +32,6 @@
 import com.google.devtools.build.lib.skyframe.FileValue;
 import com.google.devtools.build.lib.skyframe.InconsistentFilesystemException;
 import com.google.devtools.build.lib.skyframe.PackageValue;
-import com.google.devtools.build.lib.skyframe.RepositoryValue;
 import com.google.devtools.build.lib.syntax.EvalException;
 import com.google.devtools.build.lib.syntax.Type;
 import com.google.devtools.build.lib.util.Fingerprint;
@@ -77,11 +76,11 @@
  * repository has never been fetched, Bazel errors out for lack of a better option. This is
  * implemented using
  * {@link com.google.devtools.build.lib.bazel.BazelRepositoryModule#REPOSITORY_VALUE_CHECKER} and
- * a flag in {@link RepositoryValue} that tells Bazel whether the value in Skyframe is stale
- * according to the value of {@code --nofetch} or not.
+ * a flag in {@link RepositoryDirectoryValue} that tells Bazel whether the value in Skyframe is
+ * stale according to the value of {@code --nofetch} or not.
  *
- * <p>When a rule in the WORKSPACE file is changed, the corresponding {@link RepositoryValue} is
- * invalidated using the usual Skyframe route.
+ * <p>When a rule in the WORKSPACE file is changed, the corresponding
+ * {@link RepositoryDirectoryValue} is invalidated using the usual Skyframe route.
  */
 public abstract class RepositoryFunction {
   /**
@@ -244,7 +243,7 @@
     }
   }
 
-  protected RepositoryValue writeBuildFile(Path repositoryDirectory, String contents)
+  protected RepositoryDirectoryValue writeBuildFile(Path repositoryDirectory, String contents)
       throws RepositoryFunctionException {
     Path buildFilePath = repositoryDirectory.getRelative("BUILD");
     try {
@@ -253,7 +252,7 @@
       throw new RepositoryFunctionException(e, Transience.TRANSIENT);
     }
 
-    return RepositoryValue.create(repositoryDirectory);
+    return RepositoryDirectoryValue.create(repositoryDirectory);
   }
 
   protected FileValue getBuildFileValue(Rule rule, Environment env)
@@ -307,11 +306,11 @@
    * @throws RepositoryFunctionException if the BUILD file specified does not exist or cannot be
    *         linked.
    */
-  protected RepositoryValue symlinkBuildFile(FileValue buildFileValue, Path outputDirectory)
-      throws RepositoryFunctionException {
+  protected RepositoryDirectoryValue symlinkBuildFile(
+      FileValue buildFileValue, Path outputDirectory) throws RepositoryFunctionException {
     Path buildFilePath = outputDirectory.getRelative("BUILD");
     createSymbolicLink(buildFilePath, buildFileValue.realRootedPath().asPath());
-    return RepositoryValue.create(outputDirectory);
+    return RepositoryDirectoryValue.create(outputDirectory);
   }
 
   @VisibleForTesting
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryLoaderFunction.java b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryLoaderFunction.java
new file mode 100644
index 0000000..2753346
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryLoaderFunction.java
@@ -0,0 +1,83 @@
+// Copyright 2016 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.rules.repository;
+
+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.Location;
+import com.google.devtools.build.lib.skyframe.PackageValue;
+import com.google.devtools.build.lib.skyframe.RepositoryValue;
+import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import com.google.devtools.build.lib.vfs.RootedPath;
+import com.google.devtools.build.skyframe.SkyFunction;
+import com.google.devtools.build.skyframe.SkyFunctionException;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.SkyValue;
+
+import javax.annotation.Nullable;
+
+/**
+ * Creates a local or remote repository and checks its WORKSPACE file.
+ */
+public class RepositoryLoaderFunction implements SkyFunction {
+  @Nullable
+  @Override
+  public SkyValue compute(SkyKey skyKey, Environment env)
+      throws SkyFunctionException, InterruptedException {
+    // This cannot be combined with {@link RepositoryDelegatorFunction}. RDF fetches the
+    // repository and must not have a Skyframe restart after writing it (otherwise the repository
+    // would be re-downloaded).
+    RepositoryName nameFromRule = (RepositoryName) skyKey.argument();
+    SkyKey repositoryKey = RepositoryDirectoryValue.key(nameFromRule);
+    RepositoryDirectoryValue repository = (RepositoryDirectoryValue) env.getValue(repositoryKey);
+    if (repository == null) {
+      return null;
+    }
+
+    SkyKey workspaceKey = PackageValue.workspaceKey(
+        RootedPath.toRootedPath(repository.getPath(), new PathFragment("WORKSPACE")));
+    PackageValue workspacePackage = (PackageValue) env.getValue(workspaceKey);
+    if (workspacePackage == null) {
+      return null;
+    }
+
+    RepositoryName workspaceName;
+    try {
+      String workspaceNameStr = workspacePackage.getPackage().getWorkspaceName();
+      workspaceName = workspaceNameStr.isEmpty()
+          ? RepositoryName.create("") : RepositoryName.create("@" + workspaceNameStr);
+    } catch (LabelSyntaxException e) {
+      throw new IllegalStateException(e);
+    }
+
+    if (!workspaceName.isDefault() && !nameFromRule.equals(workspaceName)) {
+      Path workspacePath = repository.getPath().getRelative("WORKSPACE");
+      env.getListener().handle(Event.warn(Location.fromFile(workspacePath),
+          "Workspace name in " + workspacePath + " (" + workspaceName + ") does not match name "
+              + " given in the repository's definition (" + nameFromRule + "), this will cause "
+              + " a build error in future versions."));
+    }
+
+    return new RepositoryValue(nameFromRule, repository);
+  }
+
+  @Nullable
+  @Override
+  public String extractTag(SkyKey skyKey) {
+    return null;
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/EnvironmentBackedRecursivePackageProvider.java b/src/main/java/com/google/devtools/build/lib/skyframe/EnvironmentBackedRecursivePackageProvider.java
index a388389..8045c59 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/EnvironmentBackedRecursivePackageProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/EnvironmentBackedRecursivePackageProvider.java
@@ -29,6 +29,7 @@
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
 import com.google.devtools.build.lib.pkgcache.RecursivePackageProvider;
+import com.google.devtools.build.lib.rules.repository.RepositoryDirectoryValue;
 import com.google.devtools.build.lib.util.Preconditions;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.vfs.PathFragment;
@@ -122,8 +123,8 @@
     if (repository.isDefault()) {
       roots.addAll(packageLocator.getPathEntries());
     } else {
-      RepositoryValue repositoryValue =
-          (RepositoryValue) env.getValue(RepositoryValue.key(repository));
+      RepositoryDirectoryValue repositoryValue =
+          (RepositoryDirectoryValue) env.getValue(RepositoryDirectoryValue.key(repository));
       if (repositoryValue == null) {
         throw new MissingDepException();
       }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/GraphBackedRecursivePackageProvider.java b/src/main/java/com/google/devtools/build/lib/skyframe/GraphBackedRecursivePackageProvider.java
index 60221ad..8c0e56c 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/GraphBackedRecursivePackageProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/GraphBackedRecursivePackageProvider.java
@@ -37,6 +37,7 @@
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
 import com.google.devtools.build.lib.pkgcache.RecursivePackageProvider;
+import com.google.devtools.build.lib.rules.repository.RepositoryDirectoryValue;
 import com.google.devtools.build.lib.skyframe.TargetPatternValue.TargetPatternKey;
 import com.google.devtools.build.lib.util.Preconditions;
 import com.google.devtools.build.lib.vfs.Path;
@@ -172,8 +173,8 @@
     if (repository.isDefault()) {
       roots.addAll(pkgPath.getPathEntries());
     } else {
-      RepositoryValue repositoryValue =
-            (RepositoryValue) graph.getValue(RepositoryValue.key(repository));
+      RepositoryDirectoryValue repositoryValue =
+            (RepositoryDirectoryValue) graph.getValue(RepositoryDirectoryValue.key(repository));
       if (repositoryValue == null) {
         // If this key doesn't exist, the repository is outside the universe, so we return
         // "nothing".
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternFunction.java
index 781c001..2261b77 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternFunction.java
@@ -32,6 +32,7 @@
 import com.google.devtools.build.lib.pkgcache.FilteringPolicy;
 import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
 import com.google.devtools.build.lib.pkgcache.TargetPatternResolverUtil;
+import com.google.devtools.build.lib.rules.repository.RepositoryDirectoryValue;
 import com.google.devtools.build.lib.skyframe.EnvironmentBackedRecursivePackageProvider.MissingDepException;
 import com.google.devtools.build.lib.util.BatchCallback;
 import com.google.devtools.build.lib.util.BatchCallback.NullCallback;
@@ -225,8 +226,8 @@
       if (repository.isDefault()) {
         roots.addAll(pkgPath.getPathEntries());
       } else {
-        RepositoryValue repositoryValue =
-            (RepositoryValue) env.getValue(RepositoryValue.key(repository));
+        RepositoryDirectoryValue repositoryValue =
+            (RepositoryDirectoryValue) env.getValue(RepositoryDirectoryValue.key(repository));
         if (repositoryValue == null) {
           throw new MissingDepException();
         }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RepositoryValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/RepositoryValue.java
index e647b81..2f8da11 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/RepositoryValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/RepositoryValue.java
@@ -1,4 +1,4 @@
-// Copyright 2014 The Bazel Authors. All rights reserved.
+// Copyright 2016 The Bazel Authors. All rights reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -16,49 +16,31 @@
 
 import com.google.common.base.Objects;
 import com.google.devtools.build.lib.cmdline.RepositoryName;
+import com.google.devtools.build.lib.rules.repository.RepositoryDirectoryValue;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.skyframe.SkyKey;
 import com.google.devtools.build.skyframe.SkyValue;
 
 /**
- * A local view of an external repository.
+ * A repository's name and directory.
  */
 public class RepositoryValue implements SkyValue {
-  private final Path path;
-  private final boolean fetchingDelayed;
-
-  private RepositoryValue(Path path, boolean fetchingDelayed) {
-    this.path = path;
-    this.fetchingDelayed = fetchingDelayed;
-  }
+  private final RepositoryName repositoryName;
+  private final RepositoryDirectoryValue repositoryDirectory;
 
   /**
-   * Creates an immutable external repository.
+   * Creates a repository with a given name in a certain directory.
    */
-  public static RepositoryValue create(Path repositoryDirectory) {
-    return new RepositoryValue(repositoryDirectory, false);
+  public RepositoryValue(RepositoryName repositoryName, RepositoryDirectoryValue repository) {
+    this.repositoryName = repositoryName;
+    this.repositoryDirectory = repository;
   }
 
   /**
-   * Creates a value that represents a repository whose fetching has been delayed by a
-   * {@code --nofetch} command line option.
-   */
-  public static RepositoryValue fetchingDelayed(Path repositoryDirectory) {
-    return new RepositoryValue(repositoryDirectory, true);
-  }
-
-  /**
-   * Returns the path to the directory containing the repository's contents. This directory is
-   * guaranteed to exist.  It may contain a full Bazel repository (with a WORKSPACE file,
-   * directories, and BUILD files) or simply contain a file (or set of files) for, say, a jar from
-   * Maven.
+   * Returns the path to the repository.
    */
   public Path getPath() {
-    return path;
-  }
-
-  public boolean isFetchingDelayed() {
-    return fetchingDelayed;
+    return repositoryDirectory.getPath();
   }
 
   @Override
@@ -66,28 +48,21 @@
     if (this == other) {
       return true;
     }
-
-    if (other instanceof RepositoryValue) {
-      RepositoryValue otherValue = (RepositoryValue) other;
-      return path.equals(otherValue.path);
+    if (other == null || getClass() != other.getClass()) {
+      return false;
     }
-    return false;
+
+    RepositoryValue that = (RepositoryValue) other;
+    return Objects.equal(repositoryName, that.repositoryName)
+        && Objects.equal(repositoryDirectory, that.repositoryDirectory);
   }
 
   @Override
   public int hashCode() {
-    return Objects.hashCode(path);
+    return Objects.hashCode(repositoryName, repositoryDirectory);
   }
 
-  @Override
-  public String toString() {
-    return path.getPathString();
-  }
-
-  /**
-   * Creates a key from the given repository name.
-   */
-  public static SkyKey key(RepositoryName repository) {
-    return new SkyKey(SkyFunctions.REPOSITORY, repository);
+  static SkyKey key(RepositoryName repositoryName) {
+    return new SkyKey(SkyFunctions.REPOSITORY, repositoryName);
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java
index 277b627..ed3508f 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java
@@ -96,6 +96,8 @@
   public static final SkyFunctionName WORKSPACE_FILE = SkyFunctionName.create("WORKSPACE_FILE");
   public static final SkyFunctionName COVERAGE_REPORT = SkyFunctionName.create("COVERAGE_REPORT");
   public static final SkyFunctionName REPOSITORY = SkyFunctionName.create("REPOSITORY");
+  public static final SkyFunctionName REPOSITORY_DIRECTORY =
+      SkyFunctionName.create("REPOSITORY_DIRECTORY");
   public static final SkyFunctionName WORKSPACE_AST = SkyFunctionName.create("WORKSPACE_AST");
 
   public static Predicate<SkyKey> isSkyFunction(final SkyFunctionName functionName) {
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceASTValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceASTValue.java
index 022541d..96f42df 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceASTValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceASTValue.java
@@ -35,7 +35,7 @@
     return ast;
   }
 
-  public SkyKey key(RootedPath path) {
+  public static SkyKey key(RootedPath path) {
     return new SkyKey(SkyFunctions.WORKSPACE_AST, path);
   }
 }