Validate package name in `pub global activate` (#3735)

diff --git a/lib/src/command/global_activate.dart b/lib/src/command/global_activate.dart
index 1cb8438..8fdbc46 100644
--- a/lib/src/command/global_activate.dart
+++ b/lib/src/command/global_activate.dart
@@ -7,7 +7,10 @@
 import 'package:pub_semver/pub_semver.dart';
 
 import '../command.dart';
+import '../command_runner.dart';
+import '../io.dart';
 import '../package_name.dart';
+import '../pubspec.dart';
 import '../utils.dart';
 
 /// Handles the `global activate` pub command.
@@ -148,6 +151,14 @@
         }
 
         validateNoExtraArgs();
+
+        if (!packageNameRegExp.hasMatch(package)) {
+          final suggestion = dirExists(package)
+              ? '\n\nDid you mean `$topLevelProgram pub global activate --source path ${escapeShellArgument(package)}`?'
+              : '';
+
+          usageException('Not a valid package name: "$package"$suggestion');
+        }
         return globals.activateHosted(
           ref.withConstraint(constraint),
           executables,
diff --git a/test/global/activate/activate_hosted_test.dart b/test/global/activate/activate_hosted_test.dart
new file mode 100644
index 0000000..c7d3ba9
--- /dev/null
+++ b/test/global/activate/activate_hosted_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2014, 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:pub/src/exit_codes.dart';
+import 'package:test/test.dart';
+
+import '../../descriptor.dart';
+import '../../test_pub.dart';
+
+void main() {
+  test('activating an invalid package name fails nicely', () async {
+    await appDir().create();
+    await runPub(
+      args: ['global', 'activate', '.'],
+      error: allOf(
+        contains('Not a valid package name: "."'),
+        contains('Did you mean `dart pub global activate --source path .'),
+      ),
+      exitCode: USAGE,
+    );
+  });
+}