Skip to content

Commit e4b7bdb

Browse files
authored
[ Widget Preview ] Improve --machine output (flutter#175003)
This change adds the following events: - `widget_preview.initializing`: sent immediately after the widget previewer starts. This event includes the PID of the process starting the widget previewer for use by tooling to explicitly kill the tool process. - `widget_preview.logMessage`: sent for calls to `Logger` methods when in machine mode. This follows the same format as `daemon.logMessage`. This change also fixes and improves testing of `WidgetPreviewMachineAwareLogger` in `widget_preview_machine_test.dart` as the existing test validator did not cause tests to fail correctly. Fixes flutter#175002
1 parent 6ae2795 commit e4b7bdb

File tree

6 files changed

+91
-17
lines changed

6 files changed

+91
-17
lines changed

packages/flutter_tools/lib/executable.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ Future<void> main(List<String> args) async {
8888
final bool muteCommandLogging = (help || doctor) && !veryVerbose;
8989
final bool verboseHelp = help && verbose;
9090
final bool daemon = args.contains('daemon');
91+
final bool widgetPreviews = args.contains(WidgetPreviewCommand.kWidgetPreview);
9192
final bool runMachine = args.contains('--machine');
9293

9394
// Cache.flutterRoot must be set early because other features use it (e.g.
@@ -133,6 +134,7 @@ Future<void> main(List<String> args) async {
133134
verbose: verbose && !muteCommandLogging,
134135
prefixedErrors: prefixedErrors,
135136
windows: globals.platform.isWindows,
137+
widgetPreviews: widgetPreviews,
136138
);
137139
},
138140
AnsiTerminal: () {
@@ -294,6 +296,7 @@ class LoggerFactory {
294296
required bool machine,
295297
required bool daemon,
296298
required bool windows,
299+
required bool widgetPreviews,
297300
}) {
298301
Logger logger;
299302
if (windows) {
@@ -317,6 +320,9 @@ class LoggerFactory {
317320
if (prefixedErrors) {
318321
logger = PrefixedErrorLogger(logger);
319322
}
323+
if (widgetPreviews) {
324+
return WidgetPreviewMachineAwareLogger(logger, machine: machine, verbose: verbose);
325+
}
320326
if (daemon) {
321327
return NotifyingLogger(verbose: verbose, parent: logger);
322328
}

packages/flutter_tools/lib/src/commands/widget_preview.dart

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import 'package:process/process.dart';
1313
import '../artifacts.dart';
1414
import '../base/common.dart';
1515
import '../base/file_system.dart';
16+
import '../base/io.dart';
1617
import '../base/logger.dart';
1718
import '../base/os.dart';
1819
import '../base/platform.dart';
@@ -28,7 +29,6 @@ import '../isolated/resident_web_runner.dart';
2829
import '../project.dart';
2930
import '../resident_runner.dart';
3031
import '../runner/flutter_command.dart';
31-
import '../runner/flutter_command_runner.dart';
3232
import '../web/web_device.dart';
3333
import '../widget_preview/analytics.dart';
3434
import '../widget_preview/dependency_graph.dart';
@@ -77,7 +77,8 @@ class WidgetPreviewCommand extends FlutterCommand {
7777
String get description => 'Manage the widget preview environment.';
7878

7979
@override
80-
String get name => 'widget-preview';
80+
String get name => kWidgetPreview;
81+
static const kWidgetPreview = 'widget-preview';
8182

8283
@override
8384
String get category => FlutterCommandCategory.tools;
@@ -130,7 +131,7 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C
130131
required this.processManager,
131132
required this.artifacts,
132133
@visibleForTesting WidgetPreviewDtdServices? dtdServicesOverride,
133-
}) : logger = WidgetPreviewMachineAwareLogger(logger) {
134+
}) : _logger = logger {
134135
if (dtdServicesOverride != null) {
135136
_dtdService = dtdServicesOverride;
136137
}
@@ -200,7 +201,8 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C
200201
final FileSystem fs;
201202

202203
@override
203-
final WidgetPreviewMachineAwareLogger logger;
204+
WidgetPreviewMachineAwareLogger get logger => _logger as WidgetPreviewMachineAwareLogger;
205+
final Logger _logger;
204206

205207
@override
206208
final FlutterProjectFactory projectFactory;
@@ -259,17 +261,17 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C
259261

260262
@override
261263
Future<FlutterCommandResult> runCommand() async {
264+
assert(_logger is WidgetPreviewMachineAwareLogger);
265+
262266
// Start the timer tracking how long it takes to launch the preview environment.
263267
previewAnalytics.initializeLaunchStopwatch();
268+
logger.sendInitializingEvent();
264269

265270
final String? customPreviewScaffoldOutput = stringArg(kWidgetPreviewScaffoldOutputDir);
266271
final Directory widgetPreviewScaffold = customPreviewScaffoldOutput != null
267272
? fs.directory(customPreviewScaffoldOutput)
268273
: rootProject.widgetPreviewScaffold;
269274

270-
final bool machine = boolArg(FlutterGlobalOptions.kMachineFlag);
271-
logger.machine = machine;
272-
273275
// Check to see if a preview scaffold has already been generated. If not,
274276
// generate one.
275277
final bool generateScaffoldProject =
@@ -479,7 +481,7 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C
479481
);
480482
unawaited(_widgetPreviewApp!.run(appStartedCompleter: appStarted));
481483
await appStarted.future;
482-
logger.sendEvent('started', {'url': flutterDevice.devFS!.baseUri.toString()});
484+
logger.sendStartedEvent(applicationUrl: flutterDevice.devFS!.baseUri!);
483485
}
484486
} on Exception catch (error) {
485487
throwToolExit(error.toString());
@@ -531,9 +533,10 @@ final class WidgetPreviewCleanCommand extends WidgetPreviewSubCommandBase {
531533
/// A custom logger for the widget-preview commands that disables non-event output to stdio when
532534
/// machine mode is enabled.
533535
final class WidgetPreviewMachineAwareLogger extends DelegatingLogger {
534-
WidgetPreviewMachineAwareLogger(super.delegate);
536+
WidgetPreviewMachineAwareLogger(super.delegate, {required this.machine, required this.verbose});
535537

536-
var machine = false;
538+
final bool machine;
539+
final bool verbose;
537540

538541
@override
539542
void printError(
@@ -546,6 +549,11 @@ final class WidgetPreviewMachineAwareLogger extends DelegatingLogger {
546549
bool? wrap,
547550
}) {
548551
if (machine) {
552+
sendEvent('logMessage', <String, Object?>{
553+
'level': 'error',
554+
'message': message,
555+
'stackTrace': ?stackTrace?.toString(),
556+
});
549557
return;
550558
}
551559
super.printError(
@@ -570,6 +578,7 @@ final class WidgetPreviewMachineAwareLogger extends DelegatingLogger {
570578
bool fatal = true,
571579
}) {
572580
if (machine) {
581+
sendEvent('logMessage', <String, Object?>{'level': 'warning', 'message': message});
573582
return;
574583
}
575584
super.printWarning(
@@ -594,6 +603,7 @@ final class WidgetPreviewMachineAwareLogger extends DelegatingLogger {
594603
bool? wrap,
595604
}) {
596605
if (machine) {
606+
sendEvent('logMessage', <String, Object?>{'level': 'status', 'message': message});
597607
return;
598608
}
599609
super.printStatus(
@@ -617,12 +627,27 @@ final class WidgetPreviewMachineAwareLogger extends DelegatingLogger {
617627

618628
@override
619629
void printTrace(String message) {
630+
if (!verbose) {
631+
return;
632+
}
620633
if (machine) {
634+
sendEvent('logMessage', <String, Object?>{'level': 'trace', 'message': message});
621635
return;
622636
}
623637
super.printTrace(message);
624638
}
625639

640+
/// Notifies tooling that the widget previewer is initializing.
641+
void sendInitializingEvent() {
642+
sendEvent('initializing', {'pid': pid});
643+
}
644+
645+
/// Notifies tooling that the widget previewer has started and is being
646+
/// served at [applicationUrl].
647+
void sendStartedEvent({required Uri applicationUrl}) {
648+
sendEvent('started', {'url': applicationUrl.toString()});
649+
}
650+
626651
@override
627652
void sendEvent(String name, [Map<String, dynamic>? args]) {
628653
if (!machine) {
@@ -642,6 +667,7 @@ final class WidgetPreviewMachineAwareLogger extends DelegatingLogger {
642667
int progressIndicatorPadding = kDefaultStatusPadding,
643668
}) {
644669
if (machine) {
670+
printStatus(message);
645671
return SilentStatus(stopwatch: Stopwatch());
646672
}
647673
return super.startProgress(

packages/flutter_tools/test/commands.shard/permeable/widget_preview/widget_preview_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ void main() {
109109
await ensureFlutterToolsSnapshot();
110110
loggingProcessManager = LoggingProcessManager();
111111
shutdownHooks = ShutdownHooks();
112-
logger = BufferLogger.test();
112+
logger = WidgetPreviewMachineAwareLogger(BufferLogger.test(), machine: false, verbose: false);
113113
fs = LocalFileSystem.test(signals: Signals.test());
114114
botDetector = const FakeBotDetector(false);
115115
tempDir = fs.systemTempDirectory.createTempSync('flutter_tools_create_test.');
@@ -190,7 +190,7 @@ void main() {
190190
void expectSinglePreviewLaunchTimingEvent() => expectNPreviewLaunchTimingEvents(1);
191191

192192
void expectDeviceSelected(Device device) {
193-
final bufferLogger = logger as BufferLogger;
193+
final BufferLogger bufferLogger = asLogger<BufferLogger>(logger);
194194
expect(
195195
bufferLogger.statusText,
196196
contains('Launching the Widget Preview Scaffold on ${device.displayName}...'),

packages/flutter_tools/test/general.shard/base/logger_test.dart

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import 'package:flutter_tools/src/base/logger.dart';
1212
import 'package:flutter_tools/src/base/platform.dart';
1313
import 'package:flutter_tools/src/base/terminal.dart';
1414
import 'package:flutter_tools/src/commands/daemon.dart';
15+
import 'package:flutter_tools/src/commands/widget_preview.dart';
1516
import 'package:test/fake.dart';
1617

1718
import '../../src/common.dart';
@@ -37,6 +38,7 @@ void main() {
3738
prefixedErrors: false,
3839
machine: false,
3940
daemon: false,
41+
widgetPreviews: false,
4042
windows: false,
4143
),
4244
isA<StdoutLogger>(),
@@ -47,6 +49,7 @@ void main() {
4749
prefixedErrors: false,
4850
machine: false,
4951
daemon: false,
52+
widgetPreviews: false,
5053
windows: true,
5154
),
5255
isA<WindowsStdoutLogger>(),
@@ -57,6 +60,7 @@ void main() {
5760
prefixedErrors: false,
5861
machine: false,
5962
daemon: false,
63+
widgetPreviews: false,
6064
windows: true,
6165
),
6266
isA<VerboseLogger>(),
@@ -67,6 +71,7 @@ void main() {
6771
prefixedErrors: false,
6872
machine: false,
6973
daemon: false,
74+
widgetPreviews: false,
7075
windows: false,
7176
),
7277
isA<VerboseLogger>(),
@@ -77,6 +82,7 @@ void main() {
7782
prefixedErrors: true,
7883
machine: false,
7984
daemon: false,
85+
widgetPreviews: false,
8086
windows: false,
8187
),
8288
isA<PrefixedErrorLogger>(),
@@ -87,6 +93,7 @@ void main() {
8793
prefixedErrors: false,
8894
machine: false,
8995
daemon: true,
96+
widgetPreviews: false,
9097
windows: false,
9198
),
9299
isA<NotifyingLogger>(),
@@ -97,10 +104,32 @@ void main() {
97104
prefixedErrors: false,
98105
machine: true,
99106
daemon: false,
107+
widgetPreviews: false,
100108
windows: false,
101109
),
102110
isA<MachineOutputLogger>(),
103111
);
112+
113+
for (final verbose in [false, true]) {
114+
for (final machine in [false, true]) {
115+
for (final windows in [false, true]) {
116+
expect(
117+
loggerFactory.createLogger(
118+
verbose: verbose,
119+
prefixedErrors: false,
120+
machine: machine,
121+
daemon: false,
122+
widgetPreviews: true,
123+
windows: windows,
124+
),
125+
isA<WidgetPreviewMachineAwareLogger>(),
126+
reason:
127+
'Did not produce WidgetPreviewMachineAwareLogger for '
128+
'verbose: $verbose machine: $machine windows: $windows.',
129+
);
130+
}
131+
}
132+
}
104133
});
105134

106135
testWithoutContext(

packages/flutter_tools/test/general.shard/runner/runner_test.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,7 @@ void main() {
604604
machine: true,
605605
verbose: false,
606606
prefixedErrors: false,
607+
widgetPreviews: false,
607608
windows: globals.platform.isWindows,
608609
);
609610
},

packages/flutter_tools/test/integration.shard/widget_preview_machine_test.dart

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,28 @@ import '../src/common.dart';
1616
import 'test_data/basic_project.dart';
1717
import 'test_utils.dart';
1818

19-
typedef ExpectedEvent = ({String event, FutureOr<void> Function(Map<String, Object?>)? validator});
19+
typedef ExpectedEvent = ({String event, FutureOr<bool> Function(Map<String, Object?>)? validator});
2020

2121
final launchEvents = <ExpectedEvent>[
22+
(
23+
event: 'widget_preview.initializing',
24+
validator: (Map<String, Object?> params) {
25+
return params.containsKey('pid');
26+
},
27+
),
2228
(
2329
event: 'widget_preview.started',
2430
validator: (Map<String, Object?> params) async {
25-
if (params case {'uri': final String uri}) {
31+
if (params case {'url': final String uri}) {
2632
try {
2733
final Response response = await get(Uri.parse(uri));
28-
expect(response.statusCode, HttpStatus.ok, reason: 'Failed to retrieve widget previewer');
34+
return response.statusCode == HttpStatus.ok;
35+
// ignore: avoid_catches_without_on_clauses
2936
} catch (e) {
30-
fail('Failed to access widget previewer: $e');
37+
printOnFailure('Failed to access widget previewer: $e');
3138
}
3239
}
40+
return false;
3341
},
3442
),
3543
];
@@ -82,7 +90,11 @@ void main() {
8290
if (event case [final Map<String, Object?> eventObject]) {
8391
final ExpectedEvent expectation = expectedEvents[nextExpectationIndex];
8492
if (expectation.event == eventObject['event']) {
85-
await expectation.validator?.call(eventObject);
93+
expect(
94+
await expectation.validator?.call(eventObject['params']! as Map<String, Object?>),
95+
true,
96+
reason: 'Validator[$nextExpectationIndex] failed.',
97+
);
8698
++nextExpectationIndex;
8799
}
88100
}

0 commit comments

Comments
 (0)