Be more verbose when pub fails (#42187)
diff --git a/packages/flutter_tools/lib/src/dart/pub.dart b/packages/flutter_tools/lib/src/dart/pub.dart
index 6ffdbc0..a01367f 100644
--- a/packages/flutter_tools/lib/src/dart/pub.dart
+++ b/packages/flutter_tools/lib/src/dart/pub.dart
@@ -114,13 +114,13 @@
/// understand usage.
Future<void> batch(
List<String> arguments, {
- @required PubContext context,
- String directory,
- MessageFilter filter,
- String failureMessage = 'pub failed',
- @required bool retry,
- bool showTraceForErrors,
- });
+ @required PubContext context,
+ String directory,
+ MessageFilter filter,
+ String failureMessage = 'pub failed',
+ @required bool retry,
+ bool showTraceForErrors,
+ });
/// Runs pub in 'interactive' mode.
@@ -129,8 +129,8 @@
/// stdout/stderr stream of pub to the corresponding streams of this process.
Future<void> interactively(
List<String> arguments, {
- String directory,
- });
+ String directory,
+ });
}
class _DefaultPub implements Pub {
@@ -201,17 +201,19 @@
@override
Future<void> batch(
List<String> arguments, {
- @required PubContext context,
- String directory,
- MessageFilter filter,
- String failureMessage = 'pub failed',
- @required bool retry,
- bool showTraceForErrors,
- }) async {
+ @required PubContext context,
+ String directory,
+ MessageFilter filter,
+ String failureMessage = 'pub failed',
+ @required bool retry,
+ bool showTraceForErrors,
+ }) async {
showTraceForErrors ??= isRunningOnBot;
+ String lastPubMessage = 'no message';
bool versionSolvingFailed = false;
String filterWrapper(String line) {
+ lastPubMessage = line;
if (line.contains('version solving failed')) {
versionSolvingFailed = true;
}
@@ -227,19 +229,25 @@
int attempts = 0;
int duration = 1;
int code;
- while (true) {
+ loop: while (true) {
attempts += 1;
code = await processUtils.stream(
_pubCommand(arguments),
workingDirectory: directory,
- mapFunction: filterWrapper,
+ mapFunction: filterWrapper, // may set versionSolvingFailed, lastPubMessage
environment: _createPubEnvironment(context),
);
- if (code != 69) { // UNAVAILABLE in https://github.com/dart-lang/pub/blob/master/lib/src/exit_codes.dart
- break;
+ String message;
+ switch (code) {
+ case 69: // UNAVAILABLE in https://github.com/dart-lang/pub/blob/master/lib/src/exit_codes.dart
+ message = 'server unavailable';
+ break;
+ default:
+ break loop;
}
+ assert(message != null);
versionSolvingFailed = false;
- printStatus('$failureMessage ($code) -- attempting retry $attempts in $duration second${ duration == 1 ? "" : "s"}...');
+ printStatus('$failureMessage ($message) -- attempting retry $attempts in $duration second${ duration == 1 ? "" : "s"}...');
await Future<void>.delayed(Duration(seconds: duration));
if (duration < 64) {
duration *= 2;
@@ -259,14 +267,14 @@
).send();
if (code != 0) {
- throwToolExit('$failureMessage ($code)', exitCode: code);
+ throwToolExit('$failureMessage ($code; $lastPubMessage)', exitCode: code);
}
}
@override
Future<void> interactively(
List<String> arguments, {
- String directory,
+ String directory,
}) async {
Cache.releaseLockEarly();
final io.Process process = await processUtils.start(
diff --git a/packages/flutter_tools/test/general.shard/dart/pub_get_test.dart b/packages/flutter_tools/test/general.shard/dart/pub_get_test.dart
index ecd7f34..41970b4 100644
--- a/packages/flutter_tools/test/general.shard/dart/pub_get_test.dart
+++ b/packages/flutter_tools/test/general.shard/dart/pub_get_test.dart
@@ -44,46 +44,46 @@
time.elapse(const Duration(milliseconds: 500));
expect(testLogger.statusText,
'Running "flutter pub get" in /...\n'
- 'pub get failed (69) -- attempting retry 1 in 1 second...\n',
+ 'pub get failed (server unavailable) -- attempting retry 1 in 1 second...\n',
);
expect(processMock.lastPubEnvironment, contains('flutter_cli:flutter_tests'));
expect(processMock.lastPubCache, isNull);
time.elapse(const Duration(milliseconds: 500));
expect(testLogger.statusText,
'Running "flutter pub get" in /...\n'
- 'pub get failed (69) -- attempting retry 1 in 1 second...\n'
- 'pub get failed (69) -- attempting retry 2 in 2 seconds...\n',
+ 'pub get failed (server unavailable) -- attempting retry 1 in 1 second...\n'
+ 'pub get failed (server unavailable) -- attempting retry 2 in 2 seconds...\n',
);
time.elapse(const Duration(seconds: 1));
expect(testLogger.statusText,
'Running "flutter pub get" in /...\n'
- 'pub get failed (69) -- attempting retry 1 in 1 second...\n'
- 'pub get failed (69) -- attempting retry 2 in 2 seconds...\n',
+ 'pub get failed (server unavailable) -- attempting retry 1 in 1 second...\n'
+ 'pub get failed (server unavailable) -- attempting retry 2 in 2 seconds...\n',
);
time.elapse(const Duration(seconds: 100)); // from t=0 to t=100
expect(testLogger.statusText,
'Running "flutter pub get" in /...\n'
- 'pub get failed (69) -- attempting retry 1 in 1 second...\n'
- 'pub get failed (69) -- attempting retry 2 in 2 seconds...\n'
- 'pub get failed (69) -- attempting retry 3 in 4 seconds...\n' // at t=1
- 'pub get failed (69) -- attempting retry 4 in 8 seconds...\n' // at t=5
- 'pub get failed (69) -- attempting retry 5 in 16 seconds...\n' // at t=13
- 'pub get failed (69) -- attempting retry 6 in 32 seconds...\n' // at t=29
- 'pub get failed (69) -- attempting retry 7 in 64 seconds...\n', // at t=61
+ 'pub get failed (server unavailable) -- attempting retry 1 in 1 second...\n'
+ 'pub get failed (server unavailable) -- attempting retry 2 in 2 seconds...\n'
+ 'pub get failed (server unavailable) -- attempting retry 3 in 4 seconds...\n' // at t=1
+ 'pub get failed (server unavailable) -- attempting retry 4 in 8 seconds...\n' // at t=5
+ 'pub get failed (server unavailable) -- attempting retry 5 in 16 seconds...\n' // at t=13
+ 'pub get failed (server unavailable) -- attempting retry 6 in 32 seconds...\n' // at t=29
+ 'pub get failed (server unavailable) -- attempting retry 7 in 64 seconds...\n', // at t=61
);
time.elapse(const Duration(seconds: 200)); // from t=0 to t=200
expect(testLogger.statusText,
'Running "flutter pub get" in /...\n'
- 'pub get failed (69) -- attempting retry 1 in 1 second...\n'
- 'pub get failed (69) -- attempting retry 2 in 2 seconds...\n'
- 'pub get failed (69) -- attempting retry 3 in 4 seconds...\n'
- 'pub get failed (69) -- attempting retry 4 in 8 seconds...\n'
- 'pub get failed (69) -- attempting retry 5 in 16 seconds...\n'
- 'pub get failed (69) -- attempting retry 6 in 32 seconds...\n'
- 'pub get failed (69) -- attempting retry 7 in 64 seconds...\n'
- 'pub get failed (69) -- attempting retry 8 in 64 seconds...\n' // at t=39
- 'pub get failed (69) -- attempting retry 9 in 64 seconds...\n' // at t=103
- 'pub get failed (69) -- attempting retry 10 in 64 seconds...\n', // at t=167
+ 'pub get failed (server unavailable) -- attempting retry 1 in 1 second...\n'
+ 'pub get failed (server unavailable) -- attempting retry 2 in 2 seconds...\n'
+ 'pub get failed (server unavailable) -- attempting retry 3 in 4 seconds...\n'
+ 'pub get failed (server unavailable) -- attempting retry 4 in 8 seconds...\n'
+ 'pub get failed (server unavailable) -- attempting retry 5 in 16 seconds...\n'
+ 'pub get failed (server unavailable) -- attempting retry 6 in 32 seconds...\n'
+ 'pub get failed (server unavailable) -- attempting retry 7 in 64 seconds...\n'
+ 'pub get failed (server unavailable) -- attempting retry 8 in 64 seconds...\n' // at t=39
+ 'pub get failed (server unavailable) -- attempting retry 9 in 64 seconds...\n' // at t=103
+ 'pub get failed (server unavailable) -- attempting retry 10 in 64 seconds...\n', // at t=167
);
});
expect(testLogger.errorText, isEmpty);
@@ -97,6 +97,33 @@
Pub: () => const Pub(),
});
+ testUsingContext('pub get 66 shows message from pub', () async {
+ try {
+ await pub.get(context: PubContext.flutterTests, checkLastModified: false);
+ throw AssertionError('pubGet did not fail');
+ } on ToolExit catch (error) {
+ expect(error.message, 'pub get failed (66; err3)');
+ }
+ expect(testLogger.statusText,
+ 'Running "flutter pub get" in /...\n'
+ 'out1\n'
+ 'out2\n'
+ 'out3\n'
+ );
+ expect(testLogger.errorText,
+ 'err1\n'
+ 'err2\n'
+ 'err3\n'
+ );
+ }, overrides: <Type, Generator>{
+ ProcessManager: () => MockProcessManager(66, stderr: 'err1\nerr2\nerr3\n', stdout: 'out1\nout2\nout3\n'),
+ FileSystem: () => MockFileSystem(),
+ Platform: () => FakePlatform(
+ environment: UnmodifiableMapView<String, String>(<String, String>{}),
+ ),
+ Pub: () => const Pub(),
+ });
+
testUsingContext('pub cache in root is used', () async {
String error;
@@ -218,10 +245,12 @@
class MockProcessManager implements ProcessManager {
MockProcessManager(this.fakeExitCode, {
+ this.stdout = '',
this.stderr = '',
});
final int fakeExitCode;
+ final String stdout;
final String stderr;
String lastPubEnvironment;
@@ -240,6 +269,7 @@
lastPubCache = environment['PUB_CACHE'];
return Future<Process>.value(mocks.createMockProcess(
exitCode: fakeExitCode,
+ stdout: stdout,
stderr: stderr,
));
}