Break up and show more progression during an Xcode build (#14715)
* Created plumbing but has stream problem
* testing with makePipe
* Trying pipe but not really getting anywhere
* works by repeatedly reading line
* Minor cleanup
* works
* Clean up pipe after use.
* Move the last status forward
* Make sure failed script commands bubble up
diff --git a/packages/flutter_tools/lib/src/base/logger.dart b/packages/flutter_tools/lib/src/base/logger.dart
index 0c13133..0493edb 100644
--- a/packages/flutter_tools/lib/src/base/logger.dart
+++ b/packages/flutter_tools/lib/src/base/logger.dart
@@ -40,7 +40,15 @@
///
/// [message] is the message to display to the user; [progressId] provides an ID which can be
/// used to identify this type of progress (`hot.reload`, `hot.restart`, ...).
- Status startProgress(String message, { String progressId, bool expectSlowOperation: false });
+ ///
+ /// [progressIndicatorPadding] can optionally be used to specify spacing
+ /// between the [message] and the progress indicator.
+ Status startProgress(
+ String message, {
+ String progressId,
+ bool expectSlowOperation: false,
+ int progressIndicatorPadding: 52,
+ });
}
class Status {
@@ -96,13 +104,23 @@
void printTrace(String message) { }
@override
- Status startProgress(String message, { String progressId, bool expectSlowOperation: false }) {
+ Status startProgress(
+ String message, {
+ String progressId,
+ bool expectSlowOperation: false,
+ int progressIndicatorPadding: 52,
+ }) {
if (_status != null) {
// Ignore nested progresses; return a no-op status object.
return new Status();
} else {
if (supportsColor) {
- _status = new _AnsiStatus(message, expectSlowOperation, () { _status = null; });
+ _status = new _AnsiStatus(
+ message,
+ expectSlowOperation,
+ () { _status = null; },
+ progressIndicatorPadding,
+ );
return _status;
} else {
printStatus(message);
@@ -163,7 +181,12 @@
void printTrace(String message) => _trace.writeln(message);
@override
- Status startProgress(String message, { String progressId, bool expectSlowOperation: false }) {
+ Status startProgress(
+ String message, {
+ String progressId,
+ bool expectSlowOperation: false,
+ int progressIndicatorPadding: 52,
+ }) {
printStatus(message);
return new Status();
}
@@ -208,7 +231,12 @@
}
@override
- Status startProgress(String message, { String progressId, bool expectSlowOperation: false }) {
+ Status startProgress(
+ String message, {
+ String progressId,
+ bool expectSlowOperation: false,
+ int progressIndicatorPadding: 52,
+ }) {
printStatus(message);
return new Status();
}
@@ -253,10 +281,10 @@
}
class _AnsiStatus extends Status {
- _AnsiStatus(this.message, this.expectSlowOperation, this.onFinish) {
+ _AnsiStatus(this.message, this.expectSlowOperation, this.onFinish, int padding) {
stopwatch = new Stopwatch()..start();
- stdout.write('${message.padRight(52)} ');
+ stdout.write('${message.padRight(padding)} ');
stdout.write('${_progress[0]}');
timer = new Timer.periodic(const Duration(milliseconds: 100), _callback);
diff --git a/packages/flutter_tools/lib/src/commands/daemon.dart b/packages/flutter_tools/lib/src/commands/daemon.dart
index 9d16715..7c9dbba 100644
--- a/packages/flutter_tools/lib/src/commands/daemon.dart
+++ b/packages/flutter_tools/lib/src/commands/daemon.dart
@@ -763,7 +763,12 @@
}
@override
- Status startProgress(String message, { String progressId, bool expectSlowOperation: false }) {
+ Status startProgress(
+ String message, {
+ String progressId,
+ bool expectSlowOperation: false,
+ int progressIndicatorPadding: 52,
+ }) {
printStatus(message);
return new Status();
}
@@ -863,7 +868,12 @@
Status _status;
@override
- Status startProgress(String message, { String progressId, bool expectSlowOperation: false }) {
+ Status startProgress(
+ String message, {
+ String progressId,
+ bool expectSlowOperation: false,
+ int progressIndicatorPadding: 52,
+ }) {
// Ignore nested progresses; return a no-op status object.
if (_status != null)
return new Status();
diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart
index 970def0..5a24e31 100644
--- a/packages/flutter_tools/lib/src/ios/devices.dart
+++ b/packages/flutter_tools/lib/src/ios/devices.dart
@@ -8,6 +8,7 @@
import '../application_package.dart';
import '../base/file_system.dart';
import '../base/io.dart';
+import '../base/logger.dart';
import '../base/platform.dart';
import '../base/port_scanner.dart';
import '../base/process.dart';
@@ -239,6 +240,8 @@
int installationResult = -1;
Uri localObservatoryUri;
+ final Status installStatus =
+ logger.startProgress('Installing and launching...', expectSlowOperation: true);
if (!debuggingOptions.debuggingEnabled) {
// If debugging is not enabled, just launch the application and continue.
printTrace('Debugging is not enabled');
@@ -247,6 +250,7 @@
mapFunction: monitorInstallationFailure,
trace: true,
);
+ installStatus.stop();
} else {
// Debugging is enabled, look for the observatory server port post launch.
printTrace('Debugging is enabled, connecting to observatory');
@@ -282,6 +286,7 @@
observatoryDiscovery.cancel();
});
}
+ installStatus.stop();
if (installationResult != 0) {
printError('Could not install ${bundle.path} on $id.');
diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart
index 621186d..7044ef3 100644
--- a/packages/flutter_tools/lib/src/ios/mac.dart
+++ b/packages/flutter_tools/lib/src/ios/mac.dart
@@ -13,9 +13,11 @@
import '../base/file_system.dart';
import '../base/io.dart';
import '../base/logger.dart';
+import '../base/os.dart';
import '../base/platform.dart';
import '../base/process.dart';
import '../base/process_manager.dart';
+import '../base/utils.dart';
import '../build_info.dart';
import '../flx.dart' as flx;
import '../globals.dart';
@@ -346,14 +348,58 @@
);
}
- final Status buildStatus =
- logger.startProgress('Running Xcode build...', expectSlowOperation: true);
+ Status buildSubStatus;
+ Status initialBuildStatus;
+ Directory scriptOutputPipeTempDirectory;
+
+ if (logger.supportsColor) {
+ scriptOutputPipeTempDirectory = fs.systemTempDirectory
+ .createTempSync('flutter_build_log_pipe');
+ final File scriptOutputPipeFile =
+ scriptOutputPipeTempDirectory.childFile('pipe_to_stdout');
+ os.makePipe(scriptOutputPipeFile.path);
+
+ Future<void> listenToScriptOutputLine() async {
+ final List<String> lines = await scriptOutputPipeFile.readAsLines();
+ for (String line in lines) {
+ if (line == 'done') {
+ buildSubStatus?.stop();
+ buildSubStatus = null;
+ } else {
+ initialBuildStatus.cancel();
+ buildSubStatus = logger.startProgress(
+ line,
+ expectSlowOperation: true,
+ progressIndicatorPadding: 45,
+ );
+ }
+ }
+ return listenToScriptOutputLine();
+ }
+
+ // Trigger the start of the pipe -> stdout loop. Ignore exceptions.
+ listenToScriptOutputLine(); // ignore: unawaited_futures
+
+ buildCommands.add('SCRIPT_OUTPUT_STREAM_FILE=${scriptOutputPipeFile.absolute.path}');
+ }
+
+ final Stopwatch buildStopwatch = new Stopwatch()..start();
+ initialBuildStatus = logger.startProgress('Starting Xcode build...');
final RunResult buildResult = await runAsync(
buildCommands,
workingDirectory: app.appDirectory,
allowReentrantFlutter: true
);
- buildStatus.stop();
+ buildSubStatus?.stop();
+ initialBuildStatus?.cancel();
+ buildStopwatch.stop();
+ // Free pipe file.
+ scriptOutputPipeTempDirectory?.deleteSync(recursive: true);
+ printStatus(
+ 'Xcode build done',
+ ansiAlternative: 'Xcode build done'.padRight(53)
+ + '${getElapsedAsSeconds(buildStopwatch.elapsed).padLeft(5)}',
+ );
// Run -showBuildSettings again but with the exact same parameters as the build.
final Map<String, String> buildSettings = parseXcodeBuildSettings(runCheckedSync(