Commit fcfb2a5c authored by Devon Carew's avatar Devon Carew Committed by GitHub

Better progress (#6677)

* make showElapsedTime default to true

* support nested progresses

* improve hot reload message

* rethrow
parent 1f1adcaa
...@@ -241,7 +241,7 @@ class AndroidDevice extends Device { ...@@ -241,7 +241,7 @@ class AndroidDevice extends Device {
Status status = logger.startProgress('Installing ${apk.apkPath}...'); Status status = logger.startProgress('Installing ${apk.apkPath}...');
String installOut = runCheckedSync(adbCommandForDevice(<String>['install', '-r', apk.apkPath])); String installOut = runCheckedSync(adbCommandForDevice(<String>['install', '-r', apk.apkPath]));
status.stop(showElapsedTime: true); status.stop();
RegExp failureExp = new RegExp(r'^Failure.*$', multiLine: true); RegExp failureExp = new RegExp(r'^Failure.*$', multiLine: true);
String failure = failureExp.stringMatch(installOut); String failure = failureExp.stringMatch(installOut);
if (failure != null) { if (failure != null) {
......
...@@ -137,7 +137,7 @@ Future<int> buildGradleProject(BuildMode buildMode) async { ...@@ -137,7 +137,7 @@ Future<int> buildGradleProject(BuildMode buildMode) async {
workingDirectory: 'android', workingDirectory: 'android',
allowReentrantFlutter: true allowReentrantFlutter: true
); );
status.stop(showElapsedTime: true); status.stop();
if (exitcode != 0) if (exitcode != 0)
return exitcode; return exitcode;
} catch (error) { } catch (error) {
...@@ -159,7 +159,7 @@ Future<int> buildGradleProject(BuildMode buildMode) async { ...@@ -159,7 +159,7 @@ Future<int> buildGradleProject(BuildMode buildMode) async {
workingDirectory: 'android', workingDirectory: 'android',
allowReentrantFlutter: true allowReentrantFlutter: true
); );
status.stop(showElapsedTime: true); status.stop();
if (exitcode == 0) { if (exitcode == 0) {
File apkFile = new File(gradleAppOut); File apkFile = new File(gradleAppOut);
......
...@@ -37,7 +37,7 @@ abstract class Logger { ...@@ -37,7 +37,7 @@ abstract class Logger {
} }
class Status { class Status {
void stop({ bool showElapsedTime: false }) { } void stop({ bool showElapsedTime: true }) { }
void cancel() { } void cancel() { }
} }
...@@ -73,15 +73,17 @@ class StdoutLogger extends Logger { ...@@ -73,15 +73,17 @@ class StdoutLogger extends Logger {
@override @override
Status startProgress(String message) { Status startProgress(String message) {
_status?.cancel(); if (_status != null) {
_status = null; // Ignore nested progresses; return a no-op status object.
if (supportsColor) {
_status = new _AnsiStatus(message);
return _status;
} else {
printStatus(message);
return new Status(); return new Status();
} else {
if (supportsColor) {
_status = new _AnsiStatus(message);
return _status;
} else {
printStatus(message);
return new Status();
}
} }
} }
} }
...@@ -244,13 +246,13 @@ class _AnsiStatus extends Status { ...@@ -244,13 +246,13 @@ class _AnsiStatus extends Status {
} }
@override @override
void stop({ bool showElapsedTime: false }) { void stop({ bool showElapsedTime: true }) {
if (!live) if (!live)
return; return;
live = false; live = false;
if (showElapsedTime) { if (showElapsedTime) {
print('\b\b\b\b${stopwatch.elapsedMilliseconds.toString()}ms'); print('\b\b\b\b\b${stopwatch.elapsedMilliseconds.toString().padLeft(3)}ms');
} else { } else {
print('\b '); print('\b ');
} }
......
...@@ -233,7 +233,7 @@ class MaterialFonts { ...@@ -233,7 +233,7 @@ class MaterialFonts {
Uri.parse(cache.getVersionFor(kName)), fontsDir, true Uri.parse(cache.getVersionFor(kName)), fontsDir, true
).then((_) { ).then((_) {
cache.setStampFor(kName, cache.getVersionFor(kName)); cache.setStampFor(kName, cache.getVersionFor(kName));
status.stop(showElapsedTime: true); status.stop();
}).whenComplete(() { }).whenComplete(() {
status.cancel(); status.cancel();
}); });
...@@ -346,7 +346,7 @@ class FlutterEngine { ...@@ -346,7 +346,7 @@ class FlutterEngine {
String skyEnginePath = path.join(pkgDir.path, kSkyEngine); String skyEnginePath = path.join(pkgDir.path, kSkyEngine);
buildSkyEngineSdkSummary(skyEnginePath, kSdkBundle); buildSkyEngineSdkSummary(skyEnginePath, kSdkBundle);
} finally { } finally {
summaryStatus.stop(showElapsedTime: true); summaryStatus.stop();
} }
Directory engineDir = cache.getArtifactDirectory(kName); Directory engineDir = cache.getArtifactDirectory(kName);
...@@ -389,7 +389,7 @@ class FlutterEngine { ...@@ -389,7 +389,7 @@ class FlutterEngine {
Future<Null> _downloadItem(String message, String url, Directory dest) { Future<Null> _downloadItem(String message, String url, Directory dest) {
Status status = logger.startProgress(message); Status status = logger.startProgress(message);
return Cache._downloadFileToCache(Uri.parse(url), dest, true).then((_) { return Cache._downloadFileToCache(Uri.parse(url), dest, true).then((_) {
status.stop(showElapsedTime: true); status.stop();
}).whenComplete(() { }).whenComplete(() {
status.cancel(); status.cancel();
}); });
......
...@@ -66,7 +66,7 @@ class AnalyzeContinuously extends AnalyzeBase { ...@@ -66,7 +66,7 @@ class AnalyzeContinuously extends AnalyzeBase {
analyzedPaths.clear(); analyzedPaths.clear();
analysisTimer = new Stopwatch()..start(); analysisTimer = new Stopwatch()..start();
} else { } else {
analysisStatus?.stop(showElapsedTime: true); analysisStatus?.stop();
analysisTimer.stop(); analysisTimer.stop();
logger.printStatus(terminal.clearScreen(), newline: false); logger.printStatus(terminal.clearScreen(), newline: false);
......
...@@ -60,7 +60,7 @@ class BuildAotCommand extends BuildSubCommand { ...@@ -60,7 +60,7 @@ class BuildAotCommand extends BuildSubCommand {
outputPath: argResults['output-dir'], outputPath: argResults['output-dir'],
interpreter: argResults['interpreter'] interpreter: argResults['interpreter']
); );
status.stop(showElapsedTime: true); status.stop();
if (outputPath == null) if (outputPath == null)
return 1; return 1;
......
...@@ -591,7 +591,7 @@ Future<int> buildAndroid( ...@@ -591,7 +591,7 @@ Future<int> buildAndroid(
} }
int result = _buildApk(platform, buildMode, components, flxPath, keystore, outputFile); int result = _buildApk(platform, buildMode, components, flxPath, keystore, outputFile);
status.stop(showElapsedTime: true); status.stop();
if (result == 0) { if (result == 0) {
File apkFile = new File(outputFile); File apkFile = new File(outputFile);
......
...@@ -78,7 +78,7 @@ class BuildIOSCommand extends BuildSubCommand { ...@@ -78,7 +78,7 @@ class BuildIOSCommand extends BuildSubCommand {
buildForDevice: !forSimulator, buildForDevice: !forSimulator,
codesign: shouldCodesign codesign: shouldCodesign
); );
status.stop(showElapsedTime: true); status.stop();
if (!result.success) { if (!result.success) {
printError('Encountered error while building for $logTarget.'); printError('Encountered error while building for $logTarget.');
......
...@@ -705,8 +705,14 @@ class _AppRunLogger extends Logger { ...@@ -705,8 +705,14 @@ class _AppRunLogger extends Logger {
@override @override
void printTrace(String message) { } void printTrace(String message) { }
Status _status;
@override @override
Status startProgress(String message) { Status startProgress(String message) {
// Ignore nested progresses; return a no-op status object.
if (_status != null)
return new Status();
int id = _nextProgressId++; int id = _nextProgressId++;
_sendLogEvent(<String, dynamic>{ _sendLogEvent(<String, dynamic>{
...@@ -715,7 +721,8 @@ class _AppRunLogger extends Logger { ...@@ -715,7 +721,8 @@ class _AppRunLogger extends Logger {
'id': id.toString() 'id': id.toString()
}); });
return new _AppLoggerStatus(this, id); _status = new _AppLoggerStatus(this, id);
return _status;
} }
void close() { void close() {
...@@ -737,12 +744,14 @@ class _AppLoggerStatus implements Status { ...@@ -737,12 +744,14 @@ class _AppLoggerStatus implements Status {
final int id; final int id;
@override @override
void stop({ bool showElapsedTime: false }) { void stop({ bool showElapsedTime: true }) {
logger._status = null;
_sendFinished(); _sendFinished();
} }
@override @override
void cancel() { void cancel() {
logger._status = null;
_sendFinished(); _sendFinished();
} }
......
...@@ -89,7 +89,7 @@ class TestCommand extends FlutterCommand { ...@@ -89,7 +89,7 @@ class TestCommand extends FlutterCommand {
Future<bool> _collectCoverageData(CoverageCollector collector, { bool mergeCoverageData: false }) async { Future<bool> _collectCoverageData(CoverageCollector collector, { bool mergeCoverageData: false }) async {
Status status = logger.startProgress('Collecting coverage information...'); Status status = logger.startProgress('Collecting coverage information...');
String coverageData = await collector.finalizeCoverage(); String coverageData = await collector.finalizeCoverage();
status.stop(showElapsedTime: true); status.stop();
if (coverageData == null) if (coverageData == null)
return false; return false;
......
...@@ -42,7 +42,7 @@ class UpdatePackagesCommand extends FlutterCommand { ...@@ -42,7 +42,7 @@ class UpdatePackagesCommand extends FlutterCommand {
new File(path.join(coverageDir, 'lcov.info')) new File(path.join(coverageDir, 'lcov.info'))
..createSync(recursive: true) ..createSync(recursive: true)
..writeAsBytesSync(data, flush: true); ..writeAsBytesSync(data, flush: true);
status.stop(showElapsedTime: true); status.stop();
} }
@override @override
......
...@@ -53,7 +53,7 @@ Future<int> pubGet({ ...@@ -53,7 +53,7 @@ Future<int> pubGet({
mapFunction: _filterOverrideWarnings, mapFunction: _filterOverrideWarnings,
environment: <String, String>{ 'FLUTTER_ROOT': Cache.flutterRoot } environment: <String, String>{ 'FLUTTER_ROOT': Cache.flutterRoot }
); );
status.stop(showElapsedTime: true); status.stop();
if (code != 0) if (code != 0)
return code; return code;
} }
......
...@@ -102,7 +102,7 @@ Future<Null> _buildUnlinkedForPackage( ...@@ -102,7 +102,7 @@ Future<Null> _buildUnlinkedForPackage(
try { try {
await manager.computeUnlinkedForFolder(name, libFolder); await manager.computeUnlinkedForFolder(name, libFolder);
} finally { } finally {
status.stop(showElapsedTime: true); status.stop();
} }
} }
} }
......
...@@ -339,15 +339,7 @@ class HotRunner extends ResidentRunner { ...@@ -339,15 +339,7 @@ class HotRunner extends ResidentRunner {
Future<Null> handleTerminalCommand(String code) async { Future<Null> handleTerminalCommand(String code) async {
final String lower = code.toLowerCase(); final String lower = code.toLowerCase();
if ((lower == 'r') || (code == AnsiTerminal.KEY_F5)) { if ((lower == 'r') || (code == AnsiTerminal.KEY_F5)) {
OperationResult result = OperationResult.ok; OperationResult result = await restart(fullRestart: code == 'R');
// F5, restart
if ((code == 'r') || (code == AnsiTerminal.KEY_F5)) {
// lower-case 'r'
result = await _reloadSources();
} else {
// upper-case 'R'.
result = await _restartFromSources();
}
if (!result.isOk) { if (!result.isOk) {
// TODO(johnmccutchan): Attempt to determine the number of errors that // TODO(johnmccutchan): Attempt to determine the number of errors that
// occurred and tighten this message. // occurred and tighten this message.
...@@ -396,7 +388,7 @@ class HotRunner extends ResidentRunner { ...@@ -396,7 +388,7 @@ class HotRunner extends ResidentRunner {
bundle: bundle, bundle: bundle,
bundleDirty: rebuildBundle, bundleDirty: rebuildBundle,
fileFilter: _dartDependencies); fileFilter: _dartDependencies);
devFSStatus.stop(showElapsedTime: true); devFSStatus.stop();
// Clear the set after the sync. // Clear the set after the sync.
_dartDependencies = null; _dartDependencies = null;
printTrace('Synced ${getSizeAsMB(_devFS.bytes)}.'); printTrace('Synced ${getSizeAsMB(_devFS.bytes)}.');
...@@ -461,10 +453,10 @@ class HotRunner extends ResidentRunner { ...@@ -461,10 +453,10 @@ class HotRunner extends ResidentRunner {
// Wait for the first frame to be rendered. // Wait for the first frame to be rendered.
await firstFrameTimer.firstFrame(); await firstFrameTimer.firstFrame();
} }
restartStatus.stop(showElapsedTime: true); restartStatus.stop();
if (waitForFrame) { if (waitForFrame) {
printStatus('Restart performed in ' printTrace('Restart performed in '
'${getElapsedAsMilliseconds(firstFrameTimer.elapsed)}.'); '${getElapsedAsMilliseconds(firstFrameTimer.elapsed)}.');
if (benchmarkMode) { if (benchmarkMode) {
benchmarkData['hotRestartMillisecondsToFrame'] = benchmarkData['hotRestartMillisecondsToFrame'] =
firstFrameTimer.elapsed.inMilliseconds; firstFrameTimer.elapsed.inMilliseconds;
...@@ -476,25 +468,41 @@ class HotRunner extends ResidentRunner { ...@@ -476,25 +468,41 @@ class HotRunner extends ResidentRunner {
} }
/// Returns [true] if the reload was successful. /// Returns [true] if the reload was successful.
bool _printReloadReport(Map<String, dynamic> reloadReport) { bool _validateReloadReport(Map<String, dynamic> reloadReport) {
if (!reloadReport['success']) { if (!reloadReport['success']) {
printError('Hot reload was rejected:'); printError('Hot reload was rejected:');
for (Map<String, dynamic> notice in reloadReport['details']['notices']) for (Map<String, dynamic> notice in reloadReport['details']['notices'])
printError('${notice['message']}'); printError('${notice['message']}');
return false; return false;
} }
int loadedLibraryCount = reloadReport['details']['loadedLibraryCount'];
int finalLibraryCount = reloadReport['details']['finalLibraryCount'];
printStatus('Reloaded $loadedLibraryCount of $finalLibraryCount libraries.');
return true; return true;
} }
@override @override
Future<OperationResult> restart({ bool fullRestart: false, bool pauseAfterRestart: false }) async { Future<OperationResult> restart({ bool fullRestart: false, bool pauseAfterRestart: false }) async {
if (fullRestart) { if (fullRestart) {
return _restartFromSources(); Status status = logger.startProgress('Performing full restart...');
try {
await _restartFromSources();
status.stop();
printStatus('Restart complete.');
return OperationResult.ok;
} catch (error) {
status.stop();
rethrow;
}
} else { } else {
return _reloadSources(pause: pauseAfterRestart); Status status = logger.startProgress('Performing hot reload...');
try {
OperationResult result = await _reloadSources(pause: pauseAfterRestart);
status.stop();
if (result.isOk)
printStatus("${result.message}.");
return result;
} catch (error) {
status.stop();
rethrow;
}
} }
} }
...@@ -508,24 +516,23 @@ class HotRunner extends ResidentRunner { ...@@ -508,24 +516,23 @@ class HotRunner extends ResidentRunner {
if (!updatedDevFS) if (!updatedDevFS)
return new OperationResult(1, 'Dart Source Error'); return new OperationResult(1, 'Dart Source Error');
} }
Status reloadStatus = logger.startProgress('Performing hot reload...'); String reloadMessage;
try { try {
Map<String, dynamic> reloadReport = Map<String, dynamic> reloadReport =
await currentView.uiIsolate.reloadSources(pause: pause); await currentView.uiIsolate.reloadSources(pause: pause);
reloadStatus.stop(showElapsedTime: true); if (!_validateReloadReport(reloadReport)) {
if (!_printReloadReport(reloadReport)) {
// Reload failed. // Reload failed.
flutterUsage.sendEvent('hot', 'reload-reject'); flutterUsage.sendEvent('hot', 'reload-reject');
return new OperationResult(1, 'reload rejected'); return new OperationResult(1, 'reload rejected');
} else { } else {
flutterUsage.sendEvent('hot', 'reload'); flutterUsage.sendEvent('hot', 'reload');
int loadedLibraryCount = reloadReport['details']['loadedLibraryCount'];
int finalLibraryCount = reloadReport['details']['finalLibraryCount'];
reloadMessage = 'Reloaded $loadedLibraryCount of $finalLibraryCount libraries';
} }
} catch (error, st) { } catch (error, st) {
int errorCode = error['code']; int errorCode = error['code'];
String errorMessage = error['message']; String errorMessage = error['message'];
reloadStatus.stop(showElapsedTime: true);
if (errorCode == Isolate.kIsolateReloadBarred) { if (errorCode == Isolate.kIsolateReloadBarred) {
printError('Unable to hot reload app due to an unrecoverable error in ' printError('Unable to hot reload app due to an unrecoverable error in '
'the source code. Please address the error and then use ' 'the source code. Please address the error and then use '
...@@ -565,15 +572,15 @@ class HotRunner extends ResidentRunner { ...@@ -565,15 +572,15 @@ class HotRunner extends ResidentRunner {
// When the framework is present, we can wait for the first frame // When the framework is present, we can wait for the first frame
// event and measure reload time. // event and measure reload time.
await firstFrameTimer.firstFrame(); await firstFrameTimer.firstFrame();
printStatus('Hot reload performed in ' printTrace('Hot reload performed in '
'${getElapsedAsMilliseconds(firstFrameTimer.elapsed)}.'); '${getElapsedAsMilliseconds(firstFrameTimer.elapsed)}.');
if (benchmarkMode) { if (benchmarkMode) {
benchmarkData['hotReloadMillisecondsToFrame'] = benchmarkData['hotReloadMillisecondsToFrame'] =
firstFrameTimer.elapsed.inMilliseconds; firstFrameTimer.elapsed.inMilliseconds;
} }
flutterUsage.sendTiming('hot', 'reload', firstFrameTimer.elapsed); flutterUsage.sendTiming('hot', 'reload', firstFrameTimer.elapsed);
} }
return OperationResult.ok; return new OperationResult(OperationResult.ok.code, reloadMessage);
} }
@override @override
......
...@@ -89,7 +89,7 @@ class RunAndStayResident extends ResidentRunner { ...@@ -89,7 +89,7 @@ class RunAndStayResident extends ResidentRunner {
prebuiltApplication: prebuiltMode prebuiltApplication: prebuiltMode
); );
status.stop(showElapsedTime: true); status.stop();
if (result && extensionAddedEvent != null) { if (result && extensionAddedEvent != null) {
await extensionAddedEvent; await extensionAddedEvent;
......
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