Only depend on the WORKSPACE file for external files that are under the external/ directory, i.e. were created by Bazel.

This avoids a cycle that arose when a file is load()ed from the WORKSPACE file that is reached through a symlink to an external directory:

* The WORKSPACE file depends on the package lookup node of the .bzl file
* The package lookup node (transitively) depends on wherever the symlink points
* The target of the symlink is an external file and as such, it depends on the WORKSPACE file

This will probably be, erm, interesting to solve when we get as far as to load stuff from external repositories in the WORKSPACE file, but we are just not there yet.

--
MOS_MIGRATED_REVID=110344658
diff --git a/src/test/java/com/google/devtools/build/lib/pkgcache/IncrementalLoadingTest.java b/src/test/java/com/google/devtools/build/lib/pkgcache/IncrementalLoadingTest.java
index 4fe5227..2cebe83 100644
--- a/src/test/java/com/google/devtools/build/lib/pkgcache/IncrementalLoadingTest.java
+++ b/src/test/java/com/google/devtools/build/lib/pkgcache/IncrementalLoadingTest.java
@@ -383,7 +383,69 @@
     tester.getTarget("//a:a");
   }
 
+  @Test
+  public void testChangedExternalFile() throws Exception {
+    tester.addFile("a/BUILD",
+        "load('/a/b', 'b')",
+        "b()");
+
+    tester.addFile("/b.bzl",
+        "def b():",
+        "  pass");
+    tester.addSymlink("a/b.bzl", "/b.bzl");
+    tester.sync();
+    tester.getTarget("//a:BUILD");
+    tester.modifyFile("/b.bzl", "ERROR ERROR");
+    tester.sync();
+
+    try {
+      tester.getTarget("//a:BUILD");
+      fail();
+    } catch (NoSuchThingException e) {
+      // expected
+    }
+  }
+
+
   static class PackageCacheTester {
+    private class ManualDiffAwareness implements DiffAwareness {
+      private View lastView;
+      private View currentView;
+
+      @Override
+      public View getCurrentView() {
+        lastView = currentView;
+        currentView = new View() {};
+        return currentView;
+      }
+
+      @Override
+      public ModifiedFileSet getDiff(View oldView, View newView) {
+        if (oldView == lastView && newView == currentView) {
+          return Preconditions.checkNotNull(modifiedFileSet);
+        } else {
+          return ModifiedFileSet.EVERYTHING_MODIFIED;
+        }
+      }
+
+      @Override
+      public String name() {
+        return "PackageCacheTester.DiffAwareness";
+      }
+
+      @Override
+      public void close() {
+      }
+    }
+
+    private class ManualDiffAwarenessFactory implements DiffAwareness.Factory {
+      @Nullable
+      @Override
+      public DiffAwareness maybeCreate(Path pathEntry) {
+        return pathEntry == workspace ? new ManualDiffAwareness() : null;
+      }
+    }
+
     private final ManualClock clock;
     private final Path workspace;
     private final Path outputBase;
@@ -391,6 +453,7 @@
     private final SkyframeExecutor skyframeExecutor;
     private final List<Path> changes = new ArrayList<>();
     private boolean everythingModified = false;
+    private ModifiedFileSet modifiedFileSet;
 
     public PackageCacheTester(
         FileSystem fs, ManualClock clock, Preprocessor.Factory.Supplier supplier)
@@ -410,7 +473,7 @@
               null, /* BinTools */
               null, /* workspaceStatusActionFactory */
               TestRuleClassProvider.getRuleClassProvider().getBuildInfoFactories(),
-              ImmutableList.<DiffAwareness.Factory>of(),
+              ImmutableList.of(new ManualDiffAwarenessFactory()),
               Predicates.<PathFragment>alwaysFalse(),
               supplier,
               ImmutableMap.<SkyFunctionName, SkyFunction>of(),
@@ -494,12 +557,13 @@
     void sync() throws InterruptedException {
       clock.advanceMillis(1);
 
+      modifiedFileSet = getModifiedFileSet();
       skyframeExecutor.preparePackageLoading(
           new PathPackageLocator(outputBase, ImmutableList.of(workspace)),
           ConstantRuleVisibility.PUBLIC, true, 7, "",
           UUID.randomUUID());
       skyframeExecutor.invalidateFilesUnderPathForTesting(
-          new Reporter(), getModifiedFileSet(), workspace);
+          new Reporter(), modifiedFileSet, workspace);
       ((SequencedSkyframeExecutor) skyframeExecutor).handleDiffs(new Reporter());
 
       changes.clear();