add host and port to run configuration for web devices (#40191)

This commit is contained in:
Jonah Williams 2019-09-12 08:58:49 -07:00 committed by GitHub
parent f174c0e2ba
commit 925a52fa6b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 66 additions and 10 deletions

View file

@ -168,9 +168,11 @@ class ResidentWebRunner extends ResidentRunner {
target: target, target: target,
flutterProject: flutterProject, flutterProject: flutterProject,
buildInfo: debuggingOptions.buildInfo, buildInfo: debuggingOptions.buildInfo,
skipDwds: device is WebDevices, hostname: debuggingOptions.hostname,
port: debuggingOptions.port,
skipDwds: device is WebServerDevice,
); );
await device.startApp(package, mainPath: target, platformArgs: <String, Object>{ await device.startApp(package, mainPath: target, debuggingOptions: debuggingOptions, platformArgs: <String, Object>{
'uri': _webFs.uri 'uri': _webFs.uri
}); });
if (supportsServiceProtocol) { if (supportsServiceProtocol) {

View file

@ -75,6 +75,8 @@ typedef WebFsFactory = Future<WebFs> Function({
@required FlutterProject flutterProject, @required FlutterProject flutterProject,
@required BuildInfo buildInfo, @required BuildInfo buildInfo,
@required bool skipDwds, @required bool skipDwds,
@required String hostname,
@required String port,
}); });
/// The dev filesystem responsible for building and serving web applications. /// The dev filesystem responsible for building and serving web applications.
@ -104,10 +106,10 @@ class WebFs {
await _connectedApps?.cancel(); await _connectedApps?.cancel();
} }
/// Retrieve the [DebugConnection] for the current application. /// Retrieve the [DebugConnection] for the current application
Future<DebugConnection> runAndDebug() { Future<DebugConnection> runAndDebug() {
final Completer<DebugConnection> firstConnection = Completer<DebugConnection>(); final Completer<DebugConnection> firstConnection = Completer<DebugConnection>();
_connectedApps = _dwds.connectedApps.listen((AppConnection appConnection) async { _connectedApps = _dwds.connectedApps.listen((AppConnection appConnection) async {
appConnection.runMain(); appConnection.runMain();
final DebugConnection debugConnection = await _dwds.debugConnection(appConnection); final DebugConnection debugConnection = await _dwds.debugConnection(appConnection);
if (!firstConnection.isCompleted) { if (!firstConnection.isCompleted) {
@ -140,6 +142,8 @@ class WebFs {
@required FlutterProject flutterProject, @required FlutterProject flutterProject,
@required BuildInfo buildInfo, @required BuildInfo buildInfo,
@required bool skipDwds, @required bool skipDwds,
@required String hostname,
@required String port,
}) async { }) async {
// workaround for https://github.com/flutter/flutter/issues/38290 // workaround for https://github.com/flutter/flutter/issues/38290
if (!flutterProject.dartTool.existsSync()) { if (!flutterProject.dartTool.existsSync()) {
@ -165,7 +169,7 @@ class WebFs {
await writeBundle(fs.directory(getAssetBuildDirectory()), assetBundle.entries); await writeBundle(fs.directory(getAssetBuildDirectory()), assetBundle.entries);
// Initialize the dwds server. // Initialize the dwds server.
final int port = await os.findFreePort(); final int hostPort = port == null ? await os.findFreePort() : int.tryParse(port);
// Map the bootstrap files to the correct package directory. // Map the bootstrap files to the correct package directory.
final String targetBaseName = fs.path final String targetBaseName = fs.path
.withoutExtension(target).replaceFirst('lib${fs.path.separator}', ''); .withoutExtension(target).replaceFirst('lib${fs.path.separator}', '');
@ -203,8 +207,8 @@ class WebFs {
Dwds dwds; Dwds dwds;
if (!skipDwds) { if (!skipDwds) {
dwds = await dwdsFactory( dwds = await dwdsFactory(
hostname: _kHostName, hostname: hostname ?? _kHostName,
applicationPort: port, applicationPort: hostPort,
applicationTarget: kBuildTargetName, applicationTarget: kBuildTargetName,
assetServerPort: daemonAssetPort, assetServerPort: daemonAssetPort,
buildResults: filteredBuildResults, buildResults: filteredBuildResults,
@ -224,13 +228,13 @@ class WebFs {
Cascade cascade = Cascade(); Cascade cascade = Cascade();
cascade = cascade.add(handler); cascade = cascade.add(handler);
cascade = cascade.add(_assetHandler(flutterProject)); cascade = cascade.add(_assetHandler(flutterProject));
final HttpServer server = await httpMultiServerFactory(_kHostName, port); final HttpServer server = await httpMultiServerFactory(hostname ?? _kHostName, hostPort);
shelf_io.serveRequests(server, cascade.handler); shelf_io.serveRequests(server, cascade.handler);
return WebFs( return WebFs(
client, client,
server, server,
dwds, dwds,
'http://$_kHostName:$port/', 'http://$_kHostName:$hostPort/',
); );
} }

View file

@ -44,6 +44,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
..addOption('route', ..addOption('route',
help: 'Which route to load when running the app.', help: 'Which route to load when running the app.',
); );
usesWebOptions(hide: !verboseHelp);
usesTargetOption(); usesTargetOption();
usesPortOptions(); usesPortOptions();
usesIpv6Flag(); usesIpv6Flag();
@ -288,6 +289,8 @@ class RunCommand extends RunCommandBase {
dumpSkpOnShaderCompilation: argResults['dump-skp-on-shader-compilation'], dumpSkpOnShaderCompilation: argResults['dump-skp-on-shader-compilation'],
observatoryPort: observatoryPort, observatoryPort: observatoryPort,
verboseSystemLogs: argResults['verbose-system-logs'], verboseSystemLogs: argResults['verbose-system-logs'],
hostname: featureFlags.isWebEnabled ? argResults['hostname'] : '',
port: featureFlags.isWebEnabled ? argResults['port'] : '',
); );
} }
} }

View file

@ -484,6 +484,8 @@ class DebuggingOptions {
this.useTestFonts = false, this.useTestFonts = false,
this.verboseSystemLogs = false, this.verboseSystemLogs = false,
this.observatoryPort, this.observatoryPort,
this.hostname,
this.port,
}) : debuggingEnabled = true; }) : debuggingEnabled = true;
DebuggingOptions.disabled(this.buildInfo) DebuggingOptions.disabled(this.buildInfo)
@ -498,6 +500,8 @@ class DebuggingOptions {
traceSystrace = false, traceSystrace = false,
dumpSkpOnShaderCompilation = false, dumpSkpOnShaderCompilation = false,
verboseSystemLogs = false, verboseSystemLogs = false,
hostname = null,
port = null,
observatoryPort = null; observatoryPort = null;
final bool debuggingEnabled; final bool debuggingEnabled;
@ -514,6 +518,8 @@ class DebuggingOptions {
final bool useTestFonts; final bool useTestFonts;
final bool verboseSystemLogs; final bool verboseSystemLogs;
final int observatoryPort; final int observatoryPort;
final String port;
final String hostname;
bool get hasObservatoryPort => observatoryPort != null; bool get hasObservatoryPort => observatoryPort != null;
} }

View file

@ -132,6 +132,20 @@ abstract class FlutterCommand extends Command<void> {
_requiresPubspecYaml = true; _requiresPubspecYaml = true;
} }
void usesWebOptions({ bool hide = true }) {
argParser.addOption('hostname',
defaultsTo: 'localhost',
help: 'The hostname to serve web application on.',
hide: hide,
);
argParser.addOption('port',
defaultsTo: null,
help: 'The host port to serve the web application from. If not provided, the tool '
'will select a random open port on the host.',
hide: hide,
);
}
void usesTargetOption() { void usesTargetOption() {
argParser.addOption('target', argParser.addOption('target',
abbr: 't', abbr: 't',

View file

@ -137,7 +137,7 @@ class ChromeDevice extends Device {
@override @override
Future<bool> stopApp(ApplicationPackage app) async { Future<bool> stopApp(ApplicationPackage app) async {
await _chrome.close(); await _chrome?.close();
return true; return true;
} }

View file

@ -43,6 +43,8 @@ void main() {
@required FlutterProject flutterProject, @required FlutterProject flutterProject,
@required BuildInfo buildInfo, @required BuildInfo buildInfo,
@required bool skipDwds, @required bool skipDwds,
@required String hostname,
@required String port,
}) async { }) async {
return mockWebFs; return mockWebFs;
}, },

View file

@ -52,6 +52,8 @@ void main() {
@required FlutterProject flutterProject, @required FlutterProject flutterProject,
@required BuildInfo buildInfo, @required BuildInfo buildInfo,
@required bool skipDwds, @required bool skipDwds,
@required String hostname,
@required String port,
}) async { }) async {
return mockWebFs; return mockWebFs;
}, },

View file

@ -26,8 +26,12 @@ void main() {
MockHttpMultiServer mockHttpMultiServer; MockHttpMultiServer mockHttpMultiServer;
MockBuildDaemonClient mockBuildDaemonClient; MockBuildDaemonClient mockBuildDaemonClient;
MockOperatingSystemUtils mockOperatingSystemUtils; MockOperatingSystemUtils mockOperatingSystemUtils;
dynamic lastAddress;
int lastPort;
setUp(() { setUp(() {
lastAddress = null;
lastPort = null;
mockBuildDaemonCreator = MockBuildDaemonCreator(); mockBuildDaemonCreator = MockBuildDaemonCreator();
mockChromeLauncher = MockChromeLauncher(); mockChromeLauncher = MockChromeLauncher();
mockHttpMultiServer = MockHttpMultiServer(); mockHttpMultiServer = MockHttpMultiServer();
@ -56,6 +60,8 @@ void main() {
BuildDaemonCreator: () => mockBuildDaemonCreator, BuildDaemonCreator: () => mockBuildDaemonCreator,
ChromeLauncher: () => mockChromeLauncher, ChromeLauncher: () => mockChromeLauncher,
HttpMultiServerFactory: () => (dynamic address, int port) async { HttpMultiServerFactory: () => (dynamic address, int port) async {
lastAddress = address;
lastPort = port;
return mockHttpMultiServer; return mockHttpMultiServer;
}, },
DwdsFactory: () => ({ DwdsFactory: () => ({
@ -83,6 +89,8 @@ void main() {
target: fs.path.join('lib', 'main.dart'), target: fs.path.join('lib', 'main.dart'),
buildInfo: BuildInfo.debug, buildInfo: BuildInfo.debug,
flutterProject: flutterProject, flutterProject: flutterProject,
hostname: null,
port: null,
); );
// The build daemon is told to build once. // The build daemon is told to build once.
@ -91,6 +99,21 @@ void main() {
// .dart_tool directory is created. // .dart_tool directory is created.
expect(flutterProject.dartTool.existsSync(), true); expect(flutterProject.dartTool.existsSync(), true);
})); }));
test('Uses provided port number and hostname.', () => testbed.run(() async {
final FlutterProject flutterProject = FlutterProject.current();
await WebFs.start(
skipDwds: false,
target: fs.path.join('lib', 'main.dart'),
buildInfo: BuildInfo.debug,
flutterProject: flutterProject,
hostname: 'foo',
port: '1234',
);
expect(lastPort, 1234);
expect(lastAddress, contains('foo'));
}));
} }
class MockBuildDaemonCreator extends Mock implements BuildDaemonCreator {} class MockBuildDaemonCreator extends Mock implements BuildDaemonCreator {}