Untangle resolvers (#1458)

Until now the `maven` and `gradle` resolvers have been linked into the
same binary. While this is convenient, it means that people need to
download dependencies they won't otherwise use.

This change breaks the resolvers into their own `java_binary` targets
so that they can be referenced individually, thus reducing the amount
of dependencies that need to be downloaded before resolution can
begin.

After this change:

```
bazel query 'somepath(@regression_testing_maven//:pin, @gradle//...:*)'
```

returns an empty set.
diff --git a/private/rules/coursier.bzl b/private/rules/coursier.bzl
index fba9020..ad30f1b 100644
--- a/private/rules/coursier.bzl
+++ b/private/rules/coursier.bzl
@@ -721,6 +721,13 @@
         else:
             lock_file_location = "/".join([package_path, file_name])  # e.g. path/to/some.json
 
+        if repository_ctx.attr.resolver == "maven":
+            resolver_target = Label("//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/maven:MavenMain")
+        elif repository_ctx.attr.resolver == "gradle":
+            resolver_target = Label("//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle:GradleMain")
+        else:
+            fail("Unknown resolver")
+
         return _IN_REPO_PIN.format(
             boms = repr(repository_ctx.attr.boms),
             artifacts = repr(repository_ctx.attr.artifacts),
@@ -730,7 +737,7 @@
             fetch_sources = repr(repository_ctx.attr.fetch_sources),
             fetch_javadocs = repr(repository_ctx.attr.fetch_javadoc),
             lock_file = repr(lock_file_location),
-            resolver = repr(repository_ctx.attr.resolver),
+            resolver = repr(str(resolver_target)),
         )
 
 def infer_artifact_path_from_primary_and_repos(primary_url, repository_urls):
diff --git a/private/rules/pin_dependencies.bzl b/private/rules/pin_dependencies.bzl
index cf554d0..e500359 100644
--- a/private/rules/pin_dependencies.bzl
+++ b/private/rules/pin_dependencies.bzl
@@ -15,7 +15,7 @@
 
 _TEMPLATE = """#!/usr/bin/env bash
 
-{resolver_cmd} --jvm_flags={jvm_flags} --argsfile {config} --resolver {resolver} --input_hash '{input_hash}' --output {output}
+{resolver_cmd} --jvm_flags={jvm_flags} --argsfile {config} --input_hash '{input_hash}' --output {output}
 """
 
 def _stringify_exclusions(exclusions):
@@ -76,8 +76,7 @@
         _TEMPLATE.format(
             config = config_file.short_path,
             input_hash = input_hash[0],
-            resolver_cmd = ctx.executable._resolver.short_path,
-            resolver = ctx.attr.resolver,
+            resolver_cmd = ctx.executable.resolver.short_path,
             output = "$BUILD_WORKSPACE_DIRECTORY/" + ctx.attr.lock_file,
             jvm_flags = ctx.attr.jvm_flags,
         ),
@@ -88,7 +87,7 @@
         DefaultInfo(
             executable = script,
             files = depset([script, config_file]),
-            runfiles = ctx.runfiles(files = [script, config_file]).merge(ctx.attr._resolver[DefaultInfo].default_runfiles),
+            runfiles = ctx.runfiles(files = [script, config_file]).merge(ctx.attr.resolver[DefaultInfo].default_runfiles),
         ),
     ]
 
@@ -96,11 +95,6 @@
     _pin_dependencies_impl,
     executable = True,
     attrs = {
-        "resolver": attr.string(
-            doc = "The resolver to use",
-            values = ["gradle", "maven"],
-            default = "maven",
-        ),
         "artifacts": attr.string_list(
             doc = "List of JSON blobs generated by parse_artifact_spec_list",
         ),
@@ -122,7 +116,7 @@
         "jvm_flags": attr.string(
             doc = "JVM flags to pass to resolver",
         ),
-        "_resolver": attr.label(
+        "resolver": attr.label(
             executable = True,
             cfg = "exec",
             default = "//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/cmd:Resolver",
diff --git a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/cmd/Main.java b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/cmd/AbstractMain.java
similarity index 94%
rename from private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/cmd/Main.java
rename to private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/cmd/AbstractMain.java
index 176244e..26559a6 100644
--- a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/cmd/Main.java
+++ b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/cmd/AbstractMain.java
@@ -28,6 +28,7 @@
 import com.github.bazelbuild.rules_jvm_external.resolver.events.EventListener;
 import com.github.bazelbuild.rules_jvm_external.resolver.events.PhaseEvent;
 import com.github.bazelbuild.rules_jvm_external.resolver.lockfile.V2LockFile;
+import com.github.bazelbuild.rules_jvm_external.resolver.netrc.Netrc;
 import com.github.bazelbuild.rules_jvm_external.resolver.remote.DownloadResult;
 import com.github.bazelbuild.rules_jvm_external.resolver.remote.Downloader;
 import com.github.bazelbuild.rules_jvm_external.resolver.remote.HttpDownloader;
@@ -56,20 +57,20 @@
 import java.util.concurrent.Executors;
 import java.util.function.Supplier;
 
-public class Main {
+public abstract class AbstractMain {
 
-  public static void main(String[] args) throws IOException {
+  public void doMain(String[] args) {
     Set<DependencyInfo> infos;
     try (EventListener listener = HttpDownloader.defaultEventListener()) {
       ResolverConfig config = new ResolverConfig(listener, args);
 
       ResolutionRequest request = config.getResolutionRequest();
 
-      Resolver resolver = config.getResolver();
+      Resolver resolver = getResolver(config.getNetrc(), config.getMaxThreads(), listener);
 
       ResolutionResult resolutionResult = resolver.resolve(request);
 
-      infos = fulfillDependencyInfos(listener, config, resolutionResult.getResolution());
+      infos = fulfillDependencyInfos(resolver, listener, config, resolutionResult.getResolution());
 
       writeLockFile(listener, config, request, infos, resolutionResult.getConflicts());
 
@@ -80,8 +81,13 @@
     }
   }
 
+  public abstract Resolver getResolver(Netrc netrc, int maxThreads, EventListener listener);
+
   private static Set<DependencyInfo> fulfillDependencyInfos(
-      EventListener listener, ResolverConfig config, Graph<Coordinates> resolved) {
+      Resolver resolver,
+      EventListener listener,
+      ResolverConfig config,
+      Graph<Coordinates> resolved) {
     listener.onEvent(new PhaseEvent("Downloading dependencies"));
 
     ResolutionRequest request = config.getResolutionRequest();
@@ -94,7 +100,7 @@
     Downloader downloader =
         new Downloader(
             config.getNetrc(),
-            request.getLocalCache(config.getResolver().getName()),
+            request.getLocalCache(resolver.getName()),
             request.getRepositories(),
             listener,
             cacheResults);
diff --git a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/cmd/BUILD b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/cmd/BUILD
index d223d01..a73f513 100644
--- a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/cmd/BUILD
+++ b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/cmd/BUILD
@@ -1,4 +1,4 @@
-load("@rules_java//java:defs.bzl", "java_binary", "java_library")
+load("@rules_java//java:defs.bzl", "java_library")
 load("@rules_jvm_external//:defs.bzl", "artifact")
 
 java_library(
@@ -12,9 +12,7 @@
         "//private/tools/java/com/github/bazelbuild/rules_jvm_external/jar:IndexJar-lib",
         "//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver",
         "//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/events",
-        "//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle",
         "//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/lockfile",
-        "//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/maven",
         "//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/netrc",
         "//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/remote",
         "//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/ui",
@@ -28,14 +26,3 @@
         ),
     ],
 )
-
-java_binary(
-    name = "Resolver",
-    main_class = "com.github.bazelbuild.rules_jvm_external.resolver.cmd.Main",
-    visibility = [
-        "//visibility:public",
-    ],
-    runtime_deps = [
-        ":cmd",
-    ],
-)
diff --git a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/cmd/ResolverConfig.java b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/cmd/ResolverConfig.java
index 2f81d35..a4dba95 100644
--- a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/cmd/ResolverConfig.java
+++ b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/cmd/ResolverConfig.java
@@ -16,11 +16,8 @@
 
 import com.github.bazelbuild.rules_jvm_external.Coordinates;
 import com.github.bazelbuild.rules_jvm_external.resolver.ResolutionRequest;
-import com.github.bazelbuild.rules_jvm_external.resolver.Resolver;
 import com.github.bazelbuild.rules_jvm_external.resolver.events.EventListener;
 import com.github.bazelbuild.rules_jvm_external.resolver.events.PhaseEvent;
-import com.github.bazelbuild.rules_jvm_external.resolver.gradle.GradleResolver;
-import com.github.bazelbuild.rules_jvm_external.resolver.maven.MavenResolver;
 import com.github.bazelbuild.rules_jvm_external.resolver.netrc.Netrc;
 import com.google.gson.Gson;
 import com.google.gson.reflect.TypeToken;
@@ -37,7 +34,6 @@
   public static final int DEFAULT_MAX_THREADS =
       Math.min(5, Runtime.getRuntime().availableProcessors());
   private final ResolutionRequest request;
-  private final Resolver resolver;
   private final boolean fetchSources;
   private final boolean fetchJavadoc;
   private final Netrc netrc;
@@ -50,7 +46,6 @@
     this.netrc = Netrc.fromUserHome();
 
     ResolutionRequest request = new ResolutionRequest();
-    String chosenResolver = "maven";
     boolean fetchSources = false;
     boolean fetchJavadoc = false;
     int maxThreads = DEFAULT_MAX_THREADS;
@@ -99,22 +94,6 @@
           }
           break;
 
-        case "--resolver":
-          i++;
-          switch (args[i]) {
-            case "gradle":
-              chosenResolver = "gradle";
-              break;
-
-            case "maven":
-              chosenResolver = "maven";
-              break;
-
-            default:
-              throw new IllegalArgumentException("Resolver must be one of `maven` or `gradle`");
-          }
-          break;
-
         case "--sources":
           fetchSources = true;
           break;
@@ -153,10 +132,6 @@
 
       config.getRepositories().forEach(request::addRepository);
 
-      if (config.getResolver() != null) {
-        chosenResolver = config.getResolver();
-      }
-
       config.getGlobalExclusions().forEach(request::exclude);
 
       config
@@ -208,24 +183,12 @@
     this.inputHash = inputHash;
     this.maxThreads = maxThreads;
     this.output = output;
-
-    if (chosenResolver.equals("maven")) {
-      this.resolver = new MavenResolver(netrc, maxThreads, listener);
-    } else if (chosenResolver.equals("gradle")) {
-      this.resolver = new GradleResolver(netrc, maxThreads, listener);
-    } else {
-      throw new RuntimeException("Unknown resolver: " + chosenResolver);
-    }
   }
 
   public ResolutionRequest getResolutionRequest() {
     return request;
   }
 
-  public Resolver getResolver() {
-    return resolver;
-  }
-
   public boolean isFetchSources() {
     return fetchSources;
   }
diff --git a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/BUILD.bazel b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/BUILD.bazel
index 8f8b590..0974c0e 100644
--- a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/BUILD.bazel
+++ b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/BUILD.bazel
@@ -3,7 +3,10 @@
 
 java_library(
     name = "gradle",
-    srcs = glob(["*.java"]),
+    srcs = glob(
+        ["*.java"],
+        exclude = ["GradleMain.java"],
+    ),
     data = [
         "//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/data:gradle_build_templates",
         "//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/plugin:plugin-single-jar",
@@ -41,3 +44,19 @@
         "@gradle",
     ],
 )
+
+java_binary(
+    name = "GradleMain",
+    srcs = [
+        "GradleMain.java",
+    ],
+    main_class = "com.github.bazelbuild.rules_jvm_external.resolver.gradle.GradleMain",
+    visibility = ["//visibility:public"],
+    deps = [
+        ":gradle",
+        "//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver",
+        "//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/cmd",
+        "//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/events",
+        "//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/netrc",
+    ],
+)
diff --git a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/GradleMain.java b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/GradleMain.java
new file mode 100644
index 0000000..d68dae7
--- /dev/null
+++ b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/GradleMain.java
@@ -0,0 +1,18 @@
+package com.github.bazelbuild.rules_jvm_external.resolver.gradle;
+
+import com.github.bazelbuild.rules_jvm_external.resolver.Resolver;
+import com.github.bazelbuild.rules_jvm_external.resolver.cmd.AbstractMain;
+import com.github.bazelbuild.rules_jvm_external.resolver.events.EventListener;
+import com.github.bazelbuild.rules_jvm_external.resolver.netrc.Netrc;
+
+public class GradleMain extends AbstractMain {
+
+  public static void main(String[] args) {
+    new GradleMain().doMain(args);
+  }
+
+  @Override
+  public Resolver getResolver(Netrc netrc, int maxThreads, EventListener listener) {
+    return new GradleResolver(netrc, maxThreads, listener);
+  }
+}
diff --git a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/maven/BUILD b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/maven/BUILD
index d0f502c..d23974a 100644
--- a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/maven/BUILD
+++ b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/maven/BUILD
@@ -3,7 +3,10 @@
 
 java_library(
     name = "maven",
-    srcs = glob(["*.java"]),
+    srcs = glob(
+        ["*.java"],
+        exclude = ["MavenMain.java"],
+    ),
     visibility = [
         "//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver:__subpackages__",
         "//tests/com/github/bazelbuild/rules_jvm_external:__subpackages__",
@@ -91,3 +94,19 @@
         ),
     ],
 )
+
+java_binary(
+    name = "MavenMain",
+    srcs = [
+        "MavenMain.java",
+    ],
+    main_class = "com.github.bazelbuild.rules_jvm_external.resolver.maven.MavenMain",
+    visibility = ["//visibility:public"],
+    deps = [
+        ":maven",
+        "//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver",
+        "//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/cmd",
+        "//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/events",
+        "//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/netrc",
+    ],
+)
diff --git a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/maven/MavenMain.java b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/maven/MavenMain.java
new file mode 100644
index 0000000..8ec6901
--- /dev/null
+++ b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/maven/MavenMain.java
@@ -0,0 +1,18 @@
+package com.github.bazelbuild.rules_jvm_external.resolver.maven;
+
+import com.github.bazelbuild.rules_jvm_external.resolver.Resolver;
+import com.github.bazelbuild.rules_jvm_external.resolver.cmd.AbstractMain;
+import com.github.bazelbuild.rules_jvm_external.resolver.events.EventListener;
+import com.github.bazelbuild.rules_jvm_external.resolver.netrc.Netrc;
+
+public class MavenMain extends AbstractMain {
+
+  public static void main(String[] args) {
+    new MavenMain().doMain(args);
+  }
+
+  @Override
+  public Resolver getResolver(Netrc netrc, int maxThreads, EventListener listener) {
+    return new MavenResolver(netrc, maxThreads, listener);
+  }
+}