Unverified Commit 9c138f9c authored by Christopher Fujino's avatar Christopher Fujino Committed by GitHub

[flutter_tools] warn when doctor takes long (#100805)

* warn when doctor takes long
parent 4ece0772
...@@ -186,11 +186,13 @@ class AndroidValidator extends DoctorValidator { ...@@ -186,11 +186,13 @@ class AndroidValidator extends DoctorValidator {
messages.add(ValidationMessage(_userMessages.androidSdkLocation(androidSdk.directory.path))); messages.add(ValidationMessage(_userMessages.androidSdkLocation(androidSdk.directory.path)));
_task = 'Validating Android SDK command line tools are available';
if (!androidSdk.cmdlineToolsAvailable) { if (!androidSdk.cmdlineToolsAvailable) {
messages.add(ValidationMessage.error(_userMessages.androidMissingCmdTools)); messages.add(ValidationMessage.error(_userMessages.androidMissingCmdTools));
return ValidationResult(ValidationType.missing, messages); return ValidationResult(ValidationType.missing, messages);
} }
_task = 'Validating Android SDK licenses';
if (androidSdk.licensesAvailable && !androidSdk.platformToolsAvailable) { if (androidSdk.licensesAvailable && !androidSdk.platformToolsAvailable) {
messages.add(ValidationMessage.hint(_userMessages.androidSdkLicenseOnly(kAndroidHome))); messages.add(ValidationMessage.hint(_userMessages.androidSdkLicenseOnly(kAndroidHome)));
return ValidationResult(ValidationType.partial, messages); return ValidationResult(ValidationType.partial, messages);
...@@ -227,6 +229,7 @@ class AndroidValidator extends DoctorValidator { ...@@ -227,6 +229,7 @@ class AndroidValidator extends DoctorValidator {
messages.add(ValidationMessage('$kAndroidSdkRoot = $androidSdkRoot')); messages.add(ValidationMessage('$kAndroidSdkRoot = $androidSdkRoot'));
} }
_task = 'Validating Android SDK';
final List<String> validationResult = androidSdk.validateSdkWellFormed(); final List<String> validationResult = androidSdk.validateSdkWellFormed();
if (validationResult.isNotEmpty) { if (validationResult.isNotEmpty) {
...@@ -238,6 +241,7 @@ class AndroidValidator extends DoctorValidator { ...@@ -238,6 +241,7 @@ class AndroidValidator extends DoctorValidator {
return ValidationResult(ValidationType.partial, messages, statusInfo: sdkVersionText); return ValidationResult(ValidationType.partial, messages, statusInfo: sdkVersionText);
} }
_task = 'Finding Java binary';
// Now check for the JDK. // Now check for the JDK.
final String? javaBinary = AndroidSdk.findJavaBinary( final String? javaBinary = AndroidSdk.findJavaBinary(
androidStudio: _androidStudio, androidStudio: _androidStudio,
......
...@@ -212,7 +212,11 @@ abstract class Logger { ...@@ -212,7 +212,11 @@ abstract class Logger {
/// A [SilentStatus] or an [AnonymousSpinnerStatus] (depending on whether the /// A [SilentStatus] or an [AnonymousSpinnerStatus] (depending on whether the
/// terminal is fancy enough), already started. /// terminal is fancy enough), already started.
Status startSpinner({ VoidCallback? onFinish }); Status startSpinner({
VoidCallback? onFinish,
Duration? timeout,
SlowWarningCallback? slowWarningCallback,
});
/// Send an event to be emitted. /// Send an event to be emitted.
/// ///
...@@ -368,8 +372,16 @@ class DelegatingLogger implements Logger { ...@@ -368,8 +372,16 @@ class DelegatingLogger implements Logger {
} }
@override @override
Status startSpinner({VoidCallback? onFinish}) { Status startSpinner({
return _delegate.startSpinner(onFinish: onFinish); VoidCallback? onFinish,
Duration? timeout,
SlowWarningCallback? slowWarningCallback,
}) {
return _delegate.startSpinner(
onFinish: onFinish,
timeout: timeout,
slowWarningCallback: slowWarningCallback,
);
} }
@override @override
...@@ -571,7 +583,11 @@ class StdoutLogger extends Logger { ...@@ -571,7 +583,11 @@ class StdoutLogger extends Logger {
} }
@override @override
Status startSpinner({ VoidCallback? onFinish }) { Status startSpinner({
VoidCallback? onFinish,
Duration? timeout,
SlowWarningCallback? slowWarningCallback,
}) {
if (_status != null || !supportsColor) { if (_status != null || !supportsColor) {
return SilentStatus( return SilentStatus(
onFinish: onFinish, onFinish: onFinish,
...@@ -588,6 +604,8 @@ class StdoutLogger extends Logger { ...@@ -588,6 +604,8 @@ class StdoutLogger extends Logger {
stdio: _stdio, stdio: _stdio,
stopwatch: _stopwatchFactory.createStopwatch(), stopwatch: _stopwatchFactory.createStopwatch(),
terminal: terminal, terminal: terminal,
timeout: timeout,
slowWarningCallback: slowWarningCallback,
)..start(); )..start();
return _status!; return _status!;
} }
...@@ -859,7 +877,11 @@ class BufferLogger extends Logger { ...@@ -859,7 +877,11 @@ class BufferLogger extends Logger {
} }
@override @override
Status startSpinner({VoidCallback? onFinish}) { Status startSpinner({
VoidCallback? onFinish,
Duration? timeout,
SlowWarningCallback? slowWarningCallback,
}) {
return SilentStatus( return SilentStatus(
stopwatch: _stopwatchFactory.createStopwatch(), stopwatch: _stopwatchFactory.createStopwatch(),
onFinish: onFinish, onFinish: onFinish,
...@@ -1111,9 +1133,11 @@ abstract class Status { ...@@ -1111,9 +1133,11 @@ abstract class Status {
Status({ Status({
this.onFinish, this.onFinish,
required Stopwatch stopwatch, required Stopwatch stopwatch,
this.timeout,
}) : _stopwatch = stopwatch; }) : _stopwatch = stopwatch;
final VoidCallback? onFinish; final VoidCallback? onFinish;
final Duration? timeout;
@protected @protected
final Stopwatch _stopwatch; final Stopwatch _stopwatch;
...@@ -1126,6 +1150,9 @@ abstract class Status { ...@@ -1126,6 +1150,9 @@ abstract class Status {
return getElapsedAsMilliseconds(_stopwatch.elapsed); return getElapsedAsMilliseconds(_stopwatch.elapsed);
} }
@visibleForTesting
bool get seemsSlow => timeout != null && _stopwatch.elapsed > timeout!;
/// Call to start spinning. /// Call to start spinning.
void start() { void start() {
assert(!_stopwatch.isRunning); assert(!_stopwatch.isRunning);
...@@ -1247,16 +1274,21 @@ class AnonymousSpinnerStatus extends Status { ...@@ -1247,16 +1274,21 @@ class AnonymousSpinnerStatus extends Status {
required Stopwatch stopwatch, required Stopwatch stopwatch,
required Stdio stdio, required Stdio stdio,
required Terminal terminal, required Terminal terminal,
this.slowWarningCallback,
Duration? timeout,
}) : _stdio = stdio, }) : _stdio = stdio,
_terminal = terminal, _terminal = terminal,
_animation = _selectAnimation(terminal), _animation = _selectAnimation(terminal),
super( super(
onFinish: onFinish, onFinish: onFinish,
stopwatch: stopwatch, stopwatch: stopwatch,
); timeout: timeout,
);
final Stdio _stdio; final Stdio _stdio;
final Terminal _terminal; final Terminal _terminal;
String _slowWarning = '';
final SlowWarningCallback? slowWarningCallback;
static const String _backspaceChar = '\b'; static const String _backspaceChar = '\b';
static const String _clearChar = ' '; static const String _clearChar = ' ';
...@@ -1300,9 +1332,10 @@ class AnonymousSpinnerStatus extends Status { ...@@ -1300,9 +1332,10 @@ class AnonymousSpinnerStatus extends Status {
Timer? timer; Timer? timer;
int ticks = 0; int ticks = 0;
int _lastAnimationFrameLength = 0; int _lastAnimationFrameLength = 0;
bool timedOut = false;
String get _currentAnimationFrame => _animation[ticks % _animation.length]; String get _currentAnimationFrame => _animation[ticks % _animation.length];
int get _currentLineLength => _lastAnimationFrameLength; int get _currentLineLength => _lastAnimationFrameLength + _slowWarning.length;
void _writeToStdOut(String message) => _stdio.stdoutWrite(message); void _writeToStdOut(String message) => _stdio.stdoutWrite(message);
...@@ -1332,6 +1365,16 @@ class AnonymousSpinnerStatus extends Status { ...@@ -1332,6 +1365,16 @@ class AnonymousSpinnerStatus extends Status {
assert(timer.isActive); assert(timer.isActive);
_writeToStdOut(_backspaceChar * _lastAnimationFrameLength); _writeToStdOut(_backspaceChar * _lastAnimationFrameLength);
ticks += 1; ticks += 1;
if (seemsSlow) {
if (!timedOut) {
timedOut = true;
_clear(_currentLineLength);
}
if (_slowWarning == '' && slowWarningCallback != null) {
_slowWarning = slowWarningCallback!();
_writeToStdOut(_slowWarning);
}
}
final String newFrame = _currentAnimationFrame; final String newFrame = _currentAnimationFrame;
_lastAnimationFrameLength = newFrame.runes.length; _lastAnimationFrameLength = newFrame.runes.length;
_writeToStdOut(newFrame); _writeToStdOut(newFrame);
......
...@@ -315,7 +315,10 @@ class Doctor { ...@@ -315,7 +315,10 @@ class Doctor {
for (final ValidatorTask validatorTask in startedValidatorTasks ?? startValidatorTasks()) { for (final ValidatorTask validatorTask in startedValidatorTasks ?? startValidatorTasks()) {
final DoctorValidator validator = validatorTask.validator; final DoctorValidator validator = validatorTask.validator;
final Status status = _logger.startSpinner(); final Status status = _logger.startSpinner(
timeout: const Duration(seconds: 2),
slowWarningCallback: () => validator.slowWarning,
);
ValidationResult result; ValidationResult result;
try { try {
result = await validatorTask.result; result = await validatorTask.result;
......
...@@ -631,7 +631,11 @@ class StreamLogger extends Logger { ...@@ -631,7 +631,11 @@ class StreamLogger extends Logger {
} }
@override @override
Status startSpinner({ VoidCallback onFinish }) { Status startSpinner({
VoidCallback onFinish,
Duration timeout,
SlowWarningCallback slowWarningCallback,
}) {
return SilentStatus( return SilentStatus(
stopwatch: Stopwatch(), stopwatch: Stopwatch(),
onFinish: onFinish, onFinish: onFinish,
......
...@@ -451,7 +451,7 @@ void main() { ...@@ -451,7 +451,7 @@ void main() {
FakeAsync().run((FakeAsync time) { FakeAsync().run((FakeAsync time) {
final AnonymousSpinnerStatus spinner = AnonymousSpinnerStatus( final AnonymousSpinnerStatus spinner = AnonymousSpinnerStatus(
stdio: mockStdio, stdio: mockStdio,
stopwatch: stopwatchFactory.createStopwatch(), stopwatch: mockStopwatch,
terminal: terminal, terminal: terminal,
)..start(); )..start();
doWhileAsync(time, () => spinner.ticks < 10); doWhileAsync(time, () => spinner.ticks < 10);
...@@ -479,6 +479,35 @@ void main() { ...@@ -479,6 +479,35 @@ void main() {
expect(done, isTrue); expect(done, isTrue);
}); });
testWithoutContext('AnonymousSpinnerStatus logs warning after timeout', () async {
mockStopwatch = FakeStopwatch();
const String warningMessage = 'a warning message.';
final bool done = FakeAsync().run<bool>((FakeAsync time) {
final AnonymousSpinnerStatus spinner = AnonymousSpinnerStatus(
stdio: mockStdio,
stopwatch: mockStopwatch,
terminal: terminal,
slowWarningCallback: () => warningMessage,
timeout: const Duration(milliseconds: 100),
)..start();
// must be greater than the spinner timer duration
const Duration timeLapse = Duration(milliseconds: 101);
mockStopwatch.elapsed += timeLapse;
time.elapse(timeLapse);
List<String> lines = outputStdout();
expect(
lines.join(),
contains(warningMessage),
);
spinner.stop();
lines = outputStdout();
return true;
});
expect(done, isTrue);
});
testWithoutContext('Stdout startProgress on colored terminal', () async { testWithoutContext('Stdout startProgress on colored terminal', () async {
final Logger logger = StdoutLogger( final Logger logger = StdoutLogger(
terminal: coloredTerminal, terminal: coloredTerminal,
......
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