Allow BUILD files directly under the build root

This makes the empty package name legal (//:foo). If the empty package is used,
this symlinks everything under the build root to the exec root.  This includes
directories.

--
MOS_MIGRATED_REVID=87960882
diff --git a/docs/build-ref.html b/docs/build-ref.html
index fe808ac..315603f 100644
--- a/docs/build-ref.html
+++ b/docs/build-ref.html
@@ -546,6 +546,11 @@
   '<code>_</code>', and '<code>/</code>'.
 </p>
 
+<p>
+  The empty string is also a valid package name (e.g., //:foo). Generally
+  projects should attempt to use more descriptively named packages, though.
+</p>
+
 
 <p>
   Package names may not contain the substring <code>//</code>, nor
diff --git a/src/main/java/com/google/devtools/build/lib/cmdline/LabelValidator.java b/src/main/java/com/google/devtools/build/lib/cmdline/LabelValidator.java
index 0df134d..0458469 100644
--- a/src/main/java/com/google/devtools/build/lib/cmdline/LabelValidator.java
+++ b/src/main/java/com/google/devtools/build/lib/cmdline/LabelValidator.java
@@ -64,11 +64,12 @@
   public static String validatePackageName(String packageName) {
     int len = packageName.length();
     if (len == 0) {
-      return "empty package name";
+      // Empty package name (//:foo).
+      return null;
     }
 
     if (packageName.charAt(0) == '/') {
-      return "package names may not start with '/'";      
+      return "package names may not start with '/'";
     }
 
     // Fast path for packages with '.' in their name
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PackageLookupFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/PackageLookupFunction.java
index f800d36..9ba197b 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PackageLookupFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PackageLookupFunction.java
@@ -54,12 +54,6 @@
       return computeExternalPackageLookupValue(skyKey, env);
     }
     PathFragment pkg = packageKey.getPackageFragment();
-
-    // This represents a package lookup at the package root.
-    if (pkg.equals(PathFragment.EMPTY_FRAGMENT)) {
-      return PackageLookupValue.invalidPackageName("The empty package name is invalid");
-    }
-
     String pkgName = pkg.getPathString();
     String packageNameErrorMsg = LabelValidator.validatePackageName(pkgName);
     if (packageNameErrorMsg != null) {
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/FileSystemUtils.java b/src/main/java/com/google/devtools/build/lib/vfs/FileSystemUtils.java
index c3d7787..796d828 100644
--- a/src/main/java/com/google/devtools/build/lib/vfs/FileSystemUtils.java
+++ b/src/main/java/com/google/devtools/build/lib/vfs/FileSystemUtils.java
@@ -23,6 +23,7 @@
 import com.google.common.io.ByteSink;
 import com.google.common.io.ByteSource;
 import com.google.common.io.ByteStreams;
+import com.google.devtools.build.lib.Constants;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ConditionallyThreadSafe;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
 
@@ -679,6 +680,8 @@
    */
   public static void plantLinkForest(ImmutableMap<PathFragment, Path> packageRootMap, Path linkRoot)
       throws IOException {
+    Path emptyPackagePath = null;
+
     // Create a sorted map of all dirs (packages and their ancestors) to sets of their roots.
     // Packages come from exactly one root, but their shared ancestors may come from more.
     // The map is maintained sorted lexicographically, so parents are before their children.
@@ -686,6 +689,9 @@
     for (Map.Entry<PathFragment, Path> entry : packageRootMap.entrySet()) {
       PathFragment pkgDir = entry.getKey();
       Path pkgRoot = entry.getValue();
+      if (pkgDir.segmentCount() == 0) {
+        emptyPackagePath = entry.getValue();
+      }
       for (int i = 1; i <= pkgDir.segmentCount(); i++) {
         PathFragment dir = pkgDir.subFragment(0, i);
         Set<Path> roots = dirRootsMap.get(dir);
@@ -764,6 +770,19 @@
         }
       }
     }
+
+    if (emptyPackagePath != null) {
+      // For the top-level directory, generate symlinks to everything in the directory instead of
+      // the directory itself.
+      for (Path target : emptyPackagePath.getDirectoryEntries()) {
+        String baseName = target.getBaseName();
+        // Create any links that don't exist yet and don't start with bazel-.
+        if (!baseName.startsWith(Constants.PRODUCT_NAME + "-")
+            && !linkRoot.getRelative(baseName).exists()) {
+          linkRoot.getRelative(baseName).createSymbolicLink(target);
+        }
+      }
+    }
   }
 
   /****************************************************************************
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/LabelTest.java b/src/test/java/com/google/devtools/build/lib/syntax/LabelTest.java
index 4aac0de..cc4134f 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/LabelTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/LabelTest.java
@@ -53,6 +53,11 @@
       assertEquals("foo/bar", l.getPackageName());
       assertEquals("bar", l.getName());
     }
+    {
+      Label l = Label.parseAbsolute("//:bar");
+      assertEquals("", l.getPackageName());
+      assertEquals("bar", l.getName());
+    }
   }
 
   private static String parseCommandLine(String label, String prefix) throws SyntaxException {
@@ -234,8 +239,6 @@
                       "//foo/./baz:baz");
     assertSyntaxError(BAD_PACKAGE_CHARS,
                       "//./bar/baz:baz");
-    assertSyntaxError(BAD_PACKAGE_CHARS,
-                      "//.:foo");
     assertSyntaxError("target names may not contain '.' as a path segment",
                       "//foo:bar/./baz");
     assertSyntaxError("target names may not contain '.' as a path segment",
@@ -257,7 +260,6 @@
   public void testSomeOtherBadLabels() throws Exception {
     assertSyntaxError("package names may not end with '/'",
                       "//foo/:bar");
-    assertSyntaxError("empty package name", "//:foo");
     assertSyntaxError("package names may not start with '/'", "///p:foo");
     assertSyntaxError("package names may not contain '//' path separators",
                       "//a//b:foo");