Add support for @foo//:bar-format labels on the command line

It's annoying how split up the Label parsing code is, but it seems like too much
work to bother fixing. Maybe next fixit.

--
MOS_MIGRATED_REVID=94758275
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 0458469..7d56f52 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
@@ -206,6 +206,13 @@
   }
 
   /**
+   * Returns if the label starts with a repository (@whatever) or a package (//whatever).
+   */
+  public static boolean isAbsolute(String label) {
+    return label.startsWith("//") || label.startsWith("@");
+  }
+
+  /**
    * Parses the given absolute label by verifying that it starts with "//". If it contains a ':',
    * then the part after that is the target name within the package, and the part before that (but
    * without the leading "//") is the package name. However, it performs no validation on these two
@@ -217,9 +224,16 @@
    * @throws BadLabelException if {@code absName} starts with "//"
    */
   public static PackageAndTarget parseAbsoluteLabel(String absName) throws BadLabelException {
-    if (!absName.startsWith("//")) {
+    if (!isAbsolute(absName)) {
       throw new BadLabelException("invalid label: " + absName);
     }
+    if (absName.startsWith("@")) {
+      int endOfRepo = absName.indexOf("//");
+      if (endOfRepo < 0) {
+        throw new BadLabelException("invalid fully-qualified label: " + absName);
+      }
+      absName = absName.substring(endOfRepo);
+    }
     // Find the package/suffix separation:
     int colonIndex = absName.indexOf(':');
     int splitAt = colonIndex >= 0 ? colonIndex : absName.length();
diff --git a/src/main/java/com/google/devtools/build/lib/cmdline/TargetPattern.java b/src/main/java/com/google/devtools/build/lib/cmdline/TargetPattern.java
index dee9659..c10b252 100644
--- a/src/main/java/com/google/devtools/build/lib/cmdline/TargetPattern.java
+++ b/src/main/java/com/google/devtools/build/lib/cmdline/TargetPattern.java
@@ -81,6 +81,7 @@
   @VisibleForTesting
   static String normalize(String path) {
     Preconditions.checkArgument(!path.startsWith("/"));
+    Preconditions.checkArgument(!path.startsWith("@"));
     Iterator<String> it = SLASH_SPLITTER.split(path).iterator();
     List<String> pieces = new ArrayList<>();
     while (it.hasNext()) {
@@ -502,6 +503,16 @@
       // constant (see lib/blaze/commands/target-syntax.txt).
 
       String originalPattern = pattern;
+      final boolean includesRepo = pattern.startsWith("@");
+      String repoName = "";
+      if (includesRepo) {
+        int pkgStart = pattern.indexOf("//");
+        if (pkgStart < 0) {
+          throw new TargetParsingException("Couldn't find package in target " + pattern);
+        }
+        repoName = pattern.substring(0, pkgStart);
+        pattern = pattern.substring(pkgStart);
+      }
       final boolean isAbsolute = pattern.startsWith("//");
 
       // We now absolutize non-absolute target patterns.
@@ -553,9 +564,9 @@
       }
 
 
-      if (isAbsolute || pattern.contains(":")) {
+      if (includesRepo || isAbsolute || pattern.contains(":")) {
         PackageAndTarget packageAndTarget;
-        String fullLabel = "//" + pattern;
+        String fullLabel = repoName + "//" + pattern;
         try {
           packageAndTarget = LabelValidator.validateAbsoluteLabel(fullLabel);
         } catch (BadLabelException e) {
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Label.java b/src/main/java/com/google/devtools/build/lib/syntax/Label.java
index e1c28aa..5a744c0f 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/Label.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Label.java
@@ -135,7 +135,7 @@
   public static Label parseCommandLineLabel(String label, PathFragment workspaceRelativePath)
       throws SyntaxException {
     Preconditions.checkArgument(!workspaceRelativePath.isAbsolute());
-    if (isAbsolute(label)) {
+    if (LabelValidator.isAbsolute(label)) {
       return parseAbsolute(label);
     }
     int index = label.indexOf(':');
@@ -150,13 +150,6 @@
   }
 
   /**
-   * Returns if the label starts with a repository (@whatever) or a package (//whatever).
-   */
-  private static boolean isAbsolute(String label) {
-    return label.startsWith("//") || label.startsWith("@");
-  }
-
-  /**
    * Validates the given target name and returns a canonical String instance if it is valid.
    * Otherwise it throws a SyntaxException.
    */
@@ -351,7 +344,7 @@
     if (relName.length() == 0) {
       throw new SyntaxException("empty package-relative label");
     }
-    if (isAbsolute(relName)) {
+    if (LabelValidator.isAbsolute(relName)) {
       return parseAbsolute(relName);
     } else if (relName.equals(":")) {
       throw new SyntaxException("':' is not a valid package-relative label");
diff --git a/src/test/shell/bazel/local_repository_test.sh b/src/test/shell/bazel/local_repository_test.sh
index 3aa6363..7b6f993 100755
--- a/src/test/shell/bazel/local_repository_test.sh
+++ b/src/test/shell/bazel/local_repository_test.sh
@@ -138,7 +138,8 @@
 }
 EOF
 
-  bazel fetch //zoo:ball-pit || fail "Fetch failed"
+  bazel build @endangered//carnivore:mongoose >& $TEST_log || \
+    fail "Expected build to succeed"
   bazel run //zoo:ball-pit >& $TEST_log
   expect_log "Tra-la!"
 }