Add support for global activating package from a custom pub URL (#2041)

* Add support for global activating package from custom pub URL

* Rename CL option to `--hosted-url`.

* dartfmt
diff --git a/lib/src/command/global_activate.dart b/lib/src/command/global_activate.dart
index c15d0b9..4aca1b0 100644
--- a/lib/src/command/global_activate.dart
+++ b/lib/src/command/global_activate.dart
@@ -38,6 +38,11 @@
     argParser.addFlag("overwrite",
         negatable: false,
         help: "Overwrite executables from other packages with the same name.");
+
+    argParser.addOption("hosted-url",
+        abbr: "u",
+        help:
+            "A custom pub server URL for the package. Only applies when using the `hosted` source.");
   }
 
   Future run() {
@@ -67,6 +72,7 @@
     }
 
     var overwrite = argResults["overwrite"];
+    var hostedUrl = argResults["hosted-url"];
     Iterable<String> args = argResults.rest;
 
     readArg([String error]) {
@@ -106,7 +112,7 @@
 
         validateNoExtraArgs();
         return globals.activateHosted(package, constraint, executables,
-            features: features, overwriteBinStubs: overwrite);
+            features: features, overwriteBinStubs: overwrite, url: hostedUrl);
 
       case "path":
         if (features.isNotEmpty) {
diff --git a/lib/src/global_packages.dart b/lib/src/global_packages.dart
index 03e2960..796a4b2 100644
--- a/lib/src/global_packages.dart
+++ b/lib/src/global_packages.dart
@@ -113,13 +113,18 @@
   /// if [overwriteBinStubs] is `true`, any binstubs that collide with
   /// existing binstubs in other packages will be overwritten by this one's.
   /// Otherwise, the previous ones will be preserved.
+  ///
+  /// [url] is an optional custom pub server URL. If not null, the package to be
+  /// activated will be fetched from this URL instead of the default pub URL.
   Future activateHosted(
       String name, VersionConstraint constraint, List<String> executables,
-      {Map<String, FeatureDependency> features, bool overwriteBinStubs}) async {
+      {Map<String, FeatureDependency> features,
+      bool overwriteBinStubs,
+      String url}) async {
     _describeActive(name);
     await _installInCache(
         cache.hosted.source
-            .refFor(name)
+            .refFor(name, url: url)
             .withConstraint(constraint)
             .withFeatures(features ?? const {}),
         executables,
diff --git a/test/global/activate/custom_hosted_url_test.dart b/test/global/activate/custom_hosted_url_test.dart
new file mode 100644
index 0000000..f5fb0c8
--- /dev/null
+++ b/test/global/activate/custom_hosted_url_test.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:test/test.dart';
+
+import '../../test_pub.dart';
+
+main() {
+  test('activating a package from a custom pub server', () async {
+    // The default pub server (i.e. pub.dartlang.org).
+    await servePackages((builder) {
+      builder.serve("baz", "1.0.0");
+    });
+
+    // The custom pub server.
+    final customServer = await PackageServer.start((builder) {
+      Map<String, dynamic> hostedDep(String name, String constraint) => {
+            "hosted": {
+              "url": builder.serverUrl,
+              "name": name,
+            },
+            "version": constraint,
+          };
+      builder.serve("foo", "1.0.0", deps: {"bar": hostedDep("bar", "any")});
+      builder.serve("bar", "1.0.0", deps: {"baz": "any"});
+    });
+
+    await runPub(
+        args: ["global", "activate", "foo", "-u", customServer.url],
+        output: allOf([
+          contains("Downloading bar 1.0.0..."),
+          contains("Downloading baz 1.0.0..."),
+          contains("Downloading foo 1.0.0..."),
+          contains("Activated foo 1.0.0")
+        ]));
+  });
+}
diff --git a/test/package_server.dart b/test/package_server.dart
index 107ff9d..5626745 100644
--- a/test/package_server.dart
+++ b/test/package_server.dart
@@ -58,12 +58,12 @@
   /// package to serve.
   ///
   /// This is preserved so that additional packages can be added.
-  final _builder = PackageServerBuilder._();
+  PackageServerBuilder _builder;
 
-  /// A future that will complete to the port used for the server.
+  /// The port used for the server.
   int get port => _inner.port;
 
-  /// A future that will complete to the URL for the server.
+  /// The URL for the server.
   String get url => 'http://localhost:$port';
 
   /// Creates an HTTP server that replicates the structure of pub.dartlang.org.
@@ -81,7 +81,9 @@
     return server;
   }
 
-  PackageServer._(this._inner);
+  PackageServer._(this._inner) {
+    _builder = PackageServerBuilder._(this);
+  }
 
   /// Add to the current set of packages that are being served.
   void add(void callback(PackageServerBuilder builder)) {
@@ -135,7 +137,13 @@
   /// A map from package names to a list of concrete packages to serve.
   final _packages = <String, List<_ServedPackage>>{};
 
-  PackageServerBuilder._();
+  /// The package server that this builder is associated with.
+  final PackageServer _server;
+
+  /// The URL for the server that this builder is associated with.
+  String get serverUrl => _server.url;
+
+  PackageServerBuilder._(this._server);
 
   /// Specifies that a package named [name] with [version] should be served.
   ///