Throw catchable exception from ensurePubspecResolved (#3852)

diff --git a/lib/pub.dart b/lib/pub.dart
index 0dd0e90..1751672 100644
--- a/lib/pub.dart
+++ b/lib/pub.dart
@@ -3,9 +3,12 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:args/command_runner.dart';
+
 import 'src/entrypoint.dart';
+import 'src/exceptions.dart';
 import 'src/pub_embeddable_command.dart';
 import 'src/system_cache.dart';
+
 export 'src/executable.dart'
     show
         getExecutableForCommand,
@@ -39,6 +42,8 @@
 ///
 /// If [onlyOutputWhenTerminal] is `true` (the default) there will be no
 /// output if no terminal is attached.
+///
+/// Throws a [ResolutionFailedException] if resolution fails.
 Future<void> ensurePubspecResolved(
   String dir, {
   PubAnalytics? analytics,
@@ -47,10 +52,19 @@
   bool summaryOnly = true,
   bool onlyOutputWhenTerminal = true,
 }) async {
-  await Entrypoint(dir, SystemCache(isOffline: isOffline)).ensureUpToDate(
-    analytics: analytics,
-    checkForSdkUpdate: checkForSdkUpdate,
-    summaryOnly: summaryOnly,
-    onlyOutputWhenTerminal: onlyOutputWhenTerminal,
-  );
+  try {
+    await Entrypoint(dir, SystemCache(isOffline: isOffline)).ensureUpToDate(
+      analytics: analytics,
+      checkForSdkUpdate: checkForSdkUpdate,
+      summaryOnly: summaryOnly,
+      onlyOutputWhenTerminal: onlyOutputWhenTerminal,
+    );
+  } on ApplicationException catch (e) {
+    throw ResolutionFailedException._(e.toString());
+  }
+}
+
+class ResolutionFailedException implements Exception {
+  String message;
+  ResolutionFailedException._(this.message);
 }