Unverified Commit 53be552a authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Be more verbose when pub fails (#42187)

parent 6d18d31b
......@@ -114,13 +114,13 @@ abstract class Pub {
/// 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 @@ abstract class Pub {
/// 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 @@ class _DefaultPub implements Pub {
@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 @@ class _DefaultPub implements Pub {
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 @@ class _DefaultPub implements Pub {
).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(
......
......@@ -44,46 +44,46 @@ void main() {
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 @@ void main() {
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 @@ typedef StartCallback = void Function(List<dynamic> command);
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 @@ class MockProcessManager implements ProcessManager {
lastPubCache = environment['PUB_CACHE'];
return Future<Process>.value(mocks.createMockProcess(
exitCode: fakeExitCode,
stdout: stdout,
stderr: stderr,
));
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment