Make intra-package wildcards work for remote repositories and clean up target pattern parsing just a tiny little bit.

This wounds #389 dealing 4d6 fire damage (recursive wildcards, e.g. /... and friends still don't work)

--
MOS_MIGRATED_REVID=103822319
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 6dc2385..d456059 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
@@ -22,6 +22,8 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.cmdline.LabelValidator.BadLabelException;
 import com.google.devtools.build.lib.cmdline.LabelValidator.PackageAndTarget;
+import com.google.devtools.build.lib.cmdline.PackageIdentifier.RepositoryName;
+import com.google.devtools.build.lib.util.StringUtilities;
 
 import java.io.Serializable;
 import java.util.ArrayList;
@@ -197,7 +199,7 @@
       Preconditions.checkArgument(excludedSubdirectories.isEmpty(),
           "Target pattern \"%s\" of type %s cannot be evaluated with excluded subdirectories: %s.",
           getOriginalPattern(), getType(), excludedSubdirectories);
-      return resolver.getExplicitTarget(targetName);
+      return resolver.getExplicitTarget(label(targetName));
     }
 
     @Override
@@ -251,7 +253,7 @@
           getOriginalPattern(), getType(), excludedSubdirectories);
       if (resolver.isPackage(PackageIdentifier.createInDefaultRepo(path))) {
         // User has specified a package name. lookout for default target.
-        return resolver.getExplicitTarget("//" + path);
+        return resolver.getExplicitTarget(label("//" + path));
       }
 
       List<String> pieces = SLASH_SPLITTER.splitToList(path);
@@ -262,7 +264,7 @@
         String packageName = SLASH_JOINER.join(pieces.subList(0, i));
         if (resolver.isPackage(PackageIdentifier.createInDefaultRepo(packageName))) {
           String targetName = SLASH_JOINER.join(pieces.subList(i, pieces.size()));
-          return resolver.getExplicitTarget("//" + packageName + ":" + targetName);
+          return resolver.getExplicitTarget(label("//" + packageName + ":" + targetName));
         }
       }
 
@@ -305,16 +307,16 @@
 
   private static final class TargetsInPackage extends TargetPattern {
 
-    private final String pattern;
+    private final PackageIdentifier packageIdentifier;
     private final String suffix;
     private final boolean isAbsolute;
     private final boolean rulesOnly;
     private final boolean checkWildcardConflict;
 
-    private TargetsInPackage(String originalPattern, String pattern, String suffix,
-        boolean isAbsolute, boolean rulesOnly, boolean checkWildcardConflict) {
+    private TargetsInPackage(String originalPattern, PackageIdentifier packageIdentifier,
+        String suffix, boolean isAbsolute, boolean rulesOnly, boolean checkWildcardConflict) {
       super(Type.TARGETS_IN_PACKAGE, originalPattern);
-      this.pattern = Preconditions.checkNotNull(pattern);
+      this.packageIdentifier = packageIdentifier;
       this.suffix = Preconditions.checkNotNull(suffix);
       this.isAbsolute = isAbsolute;
       this.rulesOnly = rulesOnly;
@@ -335,17 +337,7 @@
         }
       }
 
-      String packageName = removeSuffix(pattern, suffix);
-
-      try {
-        PackageIdentifier.parse(packageName);
-      } catch (LabelSyntaxException e) {
-        throw new TargetParsingException(
-            "Invalid package name '" + packageName + "': " + e.getMessage());
-      }
-
-      return resolver.getTargetsInPackage(getOriginalPattern(),
-          PackageIdentifier.createInDefaultRepo(packageName), rulesOnly);
+      return resolver.getTargetsInPackage(getOriginalPattern(), packageIdentifier, rulesOnly);
     }
 
     @Override
@@ -355,7 +347,7 @@
 
     @Override
     public String getDirectory() {
-      return removeSuffix(pattern, suffix);
+      return packageIdentifier.getPackageFragment().getPathString();
     }
 
     @Override
@@ -375,13 +367,13 @@
       return isAbsolute == that.isAbsolute && rulesOnly == that.rulesOnly
           && checkWildcardConflict == that.checkWildcardConflict
           && getOriginalPattern().equals(that.getOriginalPattern())
-          && pattern.equals(that.pattern) && suffix.equals(that.suffix);
+          && packageIdentifier.equals(that.packageIdentifier) && suffix.equals(that.suffix);
     }
 
     @Override
     public int hashCode() {
-      return Objects.hash(getType(), getOriginalPattern(), pattern, suffix, isAbsolute, rulesOnly,
-          checkWildcardConflict);
+      return Objects.hash(getType(), getOriginalPattern(), packageIdentifier, suffix, isAbsolute,
+          rulesOnly, checkWildcardConflict);
     }
 
     /**
@@ -397,18 +389,23 @@
         return null;
       }
 
-      T target = resolver.getTargetOrNull("//" + pattern);
+      T target;
+      Label label;
+      try {
+        label = Label.create(packageIdentifier, suffix);
+        target = resolver.getTargetOrNull(label);
+      } catch (LabelSyntaxException e) {
+        return null;
+      }
+
       if (target != null) {
-        String name = pattern.lastIndexOf(':') != -1
-            ? pattern.substring(pattern.lastIndexOf(':') + 1)
-            : pattern.substring(pattern.lastIndexOf('/') + 1);
-        resolver.warn(String.format("The Blaze target pattern '%s' is ambiguous: '%s' is " +
+        resolver.warn(String.format("The target pattern '%s' is ambiguous: '%s' is " +
                                     "both a wildcard, and the name of an existing %s; " +
                                     "using the latter interpretation",
-                                    "//" + pattern, ":" + name,
+                                    getOriginalPattern(), ":" + suffix,
                                     resolver.getTargetKind(target)));
         try {
-          return resolver.getExplicitTarget("//" + pattern);
+          return resolver.getExplicitTarget(label);
         } catch (TargetParsingException e) {
           throw new IllegalStateException(
               "getTargetOrNull() returned non-null, so target should exist", e);
@@ -548,13 +545,18 @@
 
       String originalPattern = pattern;
       final boolean includesRepo = pattern.startsWith("@");
-      String repoName = "";
+      RepositoryName repository = PackageIdentifier.DEFAULT_REPOSITORY_NAME;
       if (includesRepo) {
         int pkgStart = pattern.indexOf("//");
         if (pkgStart < 0) {
           throw new TargetParsingException("Couldn't find package in target " + pattern);
         }
-        repoName = pattern.substring(0, pkgStart);
+        try {
+          repository = RepositoryName.create(pattern.substring(0, pkgStart));
+        } catch (LabelSyntaxException e) {
+          throw new TargetParsingException(e.getMessage());
+        }
+
         pattern = pattern.substring(pkgStart);
       }
       final boolean isAbsolute = pattern.startsWith("//");
@@ -598,19 +600,32 @@
       }
 
       if (ALL_RULES_IN_SUFFIXES.contains(targetPart)) {
+        PackageIdentifier packageIdentifier;
+        try {
+          packageIdentifier = PackageIdentifier.parse(repository.getName() + "//" + packagePart);
+        } catch (LabelSyntaxException e) {
+          throw new TargetParsingException(
+              "Invalid package name '" + packagePart + "': " + e.getMessage());
+        }
         return new TargetsInPackage(
-            originalPattern, pattern, ":" + targetPart, isAbsolute, true, true);
+            originalPattern, packageIdentifier, targetPart, isAbsolute, true, true);
       }
 
       if (ALL_TARGETS_IN_SUFFIXES.contains(targetPart)) {
+        PackageIdentifier packageIdentifier;
+        try {
+          packageIdentifier = PackageIdentifier.parse(repository.getName() + "//" + packagePart);
+        } catch (LabelSyntaxException e) {
+          throw new TargetParsingException(
+              "Invalid package name '" + packagePart + "': " + e.getMessage());
+        }
         return new TargetsInPackage(
-            originalPattern, pattern, ":" + targetPart, isAbsolute, false, true);
+            originalPattern, packageIdentifier, targetPart, isAbsolute, false, true);
       }
 
-
       if (includesRepo || isAbsolute || pattern.contains(":")) {
         PackageAndTarget packageAndTarget;
-        String fullLabel = repoName + "//" + pattern;
+        String fullLabel = repository.getName() + "//" + pattern;
         try {
           packageAndTarget = LabelValidator.validateAbsoluteLabel(fullLabel);
         } catch (BadLabelException e) {
@@ -666,6 +681,18 @@
     }
   }
 
+  // Parse 'label' as a Label, mapping LabelSyntaxException into
+  // TargetParsingException.
+  private static Label label(String label) throws TargetParsingException {
+    try {
+      return Label.parseAbsolute(label);
+    } catch (LabelSyntaxException e) {
+      throw new TargetParsingException("invalid target format: '"
+          + StringUtilities.sanitizeControlChars(label) + "'; "
+          + StringUtilities.sanitizeControlChars(e.getMessage()));
+    }
+  }
+
   /**
    * The target pattern type (targets below package, in package, explicit target, etc.)
    */