mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
139 lines
4.5 KiB
Dart
139 lines
4.5 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'dart:io' as io;
|
|
|
|
import 'package:meta/meta.dart';
|
|
|
|
import 'utils.dart' show forwardStandardStreams;
|
|
|
|
/// Options passed to Chrome when launching it.
|
|
class ChromeOptions {
|
|
ChromeOptions({
|
|
this.userDataDirectory,
|
|
this.url,
|
|
this.windowWidth = 1024,
|
|
this.windowHeight = 1024,
|
|
this.headless,
|
|
this.debugPort,
|
|
});
|
|
|
|
/// If not null passed as `--user-data-dir`.
|
|
final String userDataDirectory;
|
|
|
|
/// If not null launches a Chrome tab at this URL.
|
|
final String url;
|
|
|
|
/// The width of the Chrome window.
|
|
///
|
|
/// This is important for screenshots and benchmarks.
|
|
final int windowWidth;
|
|
|
|
/// The height of the Chrome window.
|
|
///
|
|
/// This is important for screenshots and benchmarks.
|
|
final int windowHeight;
|
|
|
|
/// Launches code in "headless" mode, which allows running Chrome in
|
|
/// environments without a display, such as LUCI and Cirrus.
|
|
final bool headless;
|
|
|
|
/// The port Chrome will use for its debugging protocol.
|
|
///
|
|
/// If null, Chrome is launched without debugging. When running in headless
|
|
/// mode without a debug port, Chrome quits immediately. For most tests it is
|
|
/// typical to set [headless] to true and set a non-null debug port.
|
|
final int debugPort;
|
|
}
|
|
|
|
/// A function called when the Chrome process encounters an error.
|
|
typedef ChromeErrorCallback = void Function(String);
|
|
|
|
/// Manages a single Chrome process.
|
|
class Chrome {
|
|
Chrome._(this._chromeProcess, this._onError) {
|
|
// If the Chrome process quits before it was asked to quit, notify the
|
|
// error listener.
|
|
_chromeProcess.exitCode.then((int exitCode) {
|
|
if (!_isStopped) {
|
|
_onError('Chrome process exited prematurely with exit code $exitCode');
|
|
}
|
|
});
|
|
}
|
|
|
|
/// Launches Chrome with the give [options].
|
|
///
|
|
/// The [onError] callback is called with an error message when the Chrome
|
|
/// process encounters an error. In particular, [onError] is called when the
|
|
/// Chrome process exits prematurely, i.e. before [stop] is called.
|
|
static Future<Chrome> launch(ChromeOptions options, { String workingDirectory, @required ChromeErrorCallback onError }) async {
|
|
final io.ProcessResult versionResult = io.Process.runSync(_findSystemChromeExecutable(), const <String>['--version']);
|
|
print('Launching ${versionResult.stdout}');
|
|
|
|
final List<String> args = <String>[
|
|
if (options.userDataDirectory != null)
|
|
'--user-data-dir=${options.userDataDirectory}',
|
|
if (options.url != null)
|
|
options.url,
|
|
if (io.Platform.environment['CHROME_NO_SANDBOX'] == 'true')
|
|
'--no-sandbox',
|
|
if (options.headless)
|
|
'--headless',
|
|
if (options.debugPort != null)
|
|
'--remote-debugging-port=${options.debugPort}',
|
|
'--window-size=${options.windowWidth},${options.windowHeight}',
|
|
'--disable-extensions',
|
|
'--disable-popup-blocking',
|
|
// Indicates that the browser is in "browse without sign-in" (Guest session) mode.
|
|
'--bwsi',
|
|
'--no-first-run',
|
|
'--no-default-browser-check',
|
|
'--disable-default-apps',
|
|
'--disable-translate',
|
|
];
|
|
final io.Process chromeProcess = await io.Process.start(
|
|
_findSystemChromeExecutable(),
|
|
args,
|
|
workingDirectory: workingDirectory,
|
|
);
|
|
forwardStandardStreams(chromeProcess);
|
|
return Chrome._(chromeProcess, onError);
|
|
}
|
|
|
|
final io.Process _chromeProcess;
|
|
final ChromeErrorCallback _onError;
|
|
bool _isStopped = false;
|
|
|
|
/// Stops the Chrome process.
|
|
void stop() {
|
|
_isStopped = true;
|
|
_chromeProcess.kill();
|
|
}
|
|
}
|
|
|
|
String _findSystemChromeExecutable() {
|
|
// On some environments, such as the Dart HHH tester, Chrome resides in a
|
|
// non-standard location and is provided via the following environment
|
|
// variable.
|
|
final String envExecutable = io.Platform.environment['CHROME_EXECUTABLE'];
|
|
if (envExecutable != null) {
|
|
return envExecutable;
|
|
}
|
|
|
|
if (io.Platform.isLinux) {
|
|
final io.ProcessResult which =
|
|
io.Process.runSync('which', <String>['google-chrome']);
|
|
|
|
if (which.exitCode != 0) {
|
|
throw Exception('Failed to locate system Chrome installation.');
|
|
}
|
|
|
|
return (which.stdout as String).trim();
|
|
} else if (io.Platform.isMacOS) {
|
|
return '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
|
|
} else {
|
|
throw Exception('Web benchmarks cannot run on ${io.Platform.operatingSystem} yet.');
|
|
}
|
|
}
|