Unverified Commit 32041c0c authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Reland: Switch to dev_finder (#26250)

parent 6f1d10b7
...@@ -41,6 +41,7 @@ Future<void> main(List<String> args) async { ...@@ -41,6 +41,7 @@ Future<void> main(List<String> args) async {
final String buildDirectory = argResults['build-dir']; final String buildDirectory = argResults['build-dir'];
final File frontendServer = fs.file('$buildDirectory/host_x64/gen/third_party/flutter/frontend_server/frontend_server_tool.snapshot'); final File frontendServer = fs.file('$buildDirectory/host_x64/gen/third_party/flutter/frontend_server/frontend_server_tool.snapshot');
final File sshConfig = fs.file('$buildDirectory/ssh-keys/ssh_config'); final File sshConfig = fs.file('$buildDirectory/ssh-keys/ssh_config');
final File devFinder = fs.file('$buildDirectory/host_x64/dev_finder');
final File platformKernelDill = fs.file('$buildDirectory/flutter_runner_patched_sdk/platform_strong.dill'); final File platformKernelDill = fs.file('$buildDirectory/flutter_runner_patched_sdk/platform_strong.dill');
final File flutterPatchedSdk = fs.file('$buildDirectory/flutter_runner_patched_sdk'); final File flutterPatchedSdk = fs.file('$buildDirectory/flutter_runner_patched_sdk');
final String packages = '$buildDirectory/dartlang/gen/$path/${name}_dart_library.packages'; final String packages = '$buildDirectory/dartlang/gen/$path/${name}_dart_library.packages';
...@@ -91,7 +92,7 @@ Future<void> main(List<String> args) async { ...@@ -91,7 +92,7 @@ Future<void> main(List<String> args) async {
muteCommandLogging: false, muteCommandLogging: false,
verboseHelp: false, verboseHelp: false,
overrides: <Type, Generator>{ overrides: <Type, Generator>{
FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig), FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig, devFinder: devFinder),
Artifacts: () => OverrideArtifacts( Artifacts: () => OverrideArtifacts(
parent: CachedArtifacts(), parent: CachedArtifacts(),
frontendServer: frontendServer, frontendServer: frontendServer,
......
...@@ -108,12 +108,8 @@ class FuchsiaDevices extends PollingDeviceDiscovery { ...@@ -108,12 +108,8 @@ class FuchsiaDevices extends PollingDeviceDiscovery {
if (!fuchsiaWorkflow.canListDevices) { if (!fuchsiaWorkflow.canListDevices) {
return <Device>[]; return <Device>[];
} }
final String text = await fuchsiaSdk.netls(); final String text = await fuchsiaSdk.listDevices();
final List<FuchsiaDevice> devices = <FuchsiaDevice>[]; final List<FuchsiaDevice> devices = parseListDevices(text);
for (String name in parseFuchsiaDeviceOutput(text)) {
final String id = await fuchsiaSdk.netaddr();
devices.add(FuchsiaDevice(id, name: name));
}
return devices; return devices;
} }
...@@ -121,24 +117,18 @@ class FuchsiaDevices extends PollingDeviceDiscovery { ...@@ -121,24 +117,18 @@ class FuchsiaDevices extends PollingDeviceDiscovery {
Future<List<String>> getDiagnostics() async => const <String>[]; Future<List<String>> getDiagnostics() async => const <String>[];
} }
/// Parses output from the netls tool into fuchsia devices names.
///
/// Example output:
/// $ ./netls
/// > device liliac-shore-only-last (fe80::82e4:da4d:fe81:227d/3)
@visibleForTesting @visibleForTesting
List<String> parseFuchsiaDeviceOutput(String text) { List<FuchsiaDevice> parseListDevices(String text) {
final List<String> names = <String>[]; final List<FuchsiaDevice> devices = <FuchsiaDevice>[];
for (String rawLine in text.trim().split('\n')) { for (String rawLine in text.trim().split('\n')) {
final String line = rawLine.trim(); final String line = rawLine.trim();
if (!line.startsWith('device')) // ['ip', 'device name']
continue;
// ['device', 'device name', '(id)']
final List<String> words = line.split(' '); final List<String> words = line.split(' ');
final String name = words[1]; final String name = words[1];
names.add(name); final String id = words[0];
devices.add(FuchsiaDevice(id, name: name));
} }
return names; return devices;
} }
class FuchsiaDevice extends Device { class FuchsiaDevice extends Device {
......
...@@ -9,7 +9,6 @@ import '../base/common.dart'; ...@@ -9,7 +9,6 @@ import '../base/common.dart';
import '../base/context.dart'; import '../base/context.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/io.dart'; import '../base/io.dart';
import '../base/platform.dart';
import '../base/process.dart'; import '../base/process.dart';
import '../base/process_manager.dart'; import '../base/process_manager.dart';
...@@ -24,21 +23,15 @@ FuchsiaArtifacts get fuchsiaArtifacts => context[FuchsiaArtifacts]; ...@@ -24,21 +23,15 @@ FuchsiaArtifacts get fuchsiaArtifacts => context[FuchsiaArtifacts];
/// This workflow assumes development within the fuchsia source tree, /// This workflow assumes development within the fuchsia source tree,
/// including a working fx command-line tool in the user's PATH. /// including a working fx command-line tool in the user's PATH.
class FuchsiaSdk { class FuchsiaSdk {
static const List<String> _netaddrCommand = <String>['fx', 'netaddr', '--fuchsia', '--nowait'];
static const List<String> _netlsCommand = <String>['fx', 'netls', '--nowait'];
static const List<String> _syslogCommand = <String>['fx', 'syslog', '--clock', 'Local']; static const List<String> _syslogCommand = <String>['fx', 'syslog', '--clock', 'Local'];
/// Invokes the `netaddr` command.
///
/// This returns the network address of an attached fuchsia device. Does
/// not currently support multiple attached devices.
///
/// Example output: /// Example output:
/// $ fx netaddr --fuchsia --nowait /// $ dev_finder list -full
/// > fe80::9aaa:fcff:fe60:d3af%eth1 /// > 192.168.42.56 paper-pulp-bush-angel
Future<String> netaddr() async { Future<String> listDevices() async {
try { try {
final RunResult process = await runAsync(_netaddrCommand); final String path = fuchsiaArtifacts.devFinder.absolute.path;
final RunResult process = await runAsync(<String>[path, 'list', '-full']);
return process.stdout.trim(); return process.stdout.trim();
} on ArgumentError catch (exception) { } on ArgumentError catch (exception) {
throwToolExit('$exception'); throwToolExit('$exception');
...@@ -69,49 +62,18 @@ class FuchsiaSdk { ...@@ -69,49 +62,18 @@ class FuchsiaSdk {
} }
return null; return null;
} }
/// Invokes the `netls` command.
///
/// This lists attached fuchsia devices with their name and address. Does
/// not currently support multiple attached devices.
///
/// Example output:
/// $ fx netls --nowait
/// > device liliac-shore-only-last (fe80::82e4:da4d:fe81:227d/3)
Future<String> netls() async {
try {
final RunResult process = await runAsync(_netlsCommand);
return process.stdout;
} on ArgumentError catch (exception) {
throwToolExit('$exception');
}
return null;
}
} }
/// Fuchsia-specific artifacts used to interact with a device. /// Fuchsia-specific artifacts used to interact with a device.
class FuchsiaArtifacts { class FuchsiaArtifacts {
/// Creates a new [FuchsiaArtifacts]. /// Creates a new [FuchsiaArtifacts].
/// FuchsiaArtifacts({this.sshConfig, this.devFinder});
/// May optionally provide a file `sshConfig` file.
FuchsiaArtifacts({File sshConfig})
: _sshConfig = sshConfig;
/// The location of the SSH configuration file used to interact with a /// The location of the SSH configuration file used to interact with a
/// fuchsia device. /// Fuchsia device.
/// final File sshConfig;
/// Requires the env variable `BUILD_DIR` to be set if not provided by
/// the constructor. /// The location of the dev finder tool used to locate connected
File get sshConfig { /// Fuchsia devices.
if (_sshConfig == null) { final File devFinder;
final String buildDirectory = platform.environment['BUILD_DIR'];
if (buildDirectory == null) {
throwToolExit('BUILD_DIR must be supplied to locate SSH keys. For example:\n'
' export BUILD_DIR=path/to/fuchsia/out/x64\n');
}
_sshConfig = fs.file('$buildDirectory/ssh-keys/ssh_config');
}
return _sshConfig;
}
File _sshConfig;
} }
...@@ -3,9 +3,9 @@ ...@@ -3,9 +3,9 @@
// found in the LICENSE file. // found in the LICENSE file.
import '../base/context.dart'; import '../base/context.dart';
import '../base/os.dart';
import '../base/platform.dart'; import '../base/platform.dart';
import '../doctor.dart'; import '../doctor.dart';
import 'fuchsia_sdk.dart';
/// The [FuchsiaWorkflow] instance. /// The [FuchsiaWorkflow] instance.
FuchsiaWorkflow get fuchsiaWorkflow => context[FuchsiaWorkflow]; FuchsiaWorkflow get fuchsiaWorkflow => context[FuchsiaWorkflow];
...@@ -21,12 +21,12 @@ class FuchsiaWorkflow implements Workflow { ...@@ -21,12 +21,12 @@ class FuchsiaWorkflow implements Workflow {
@override @override
bool get canListDevices { bool get canListDevices {
return os.which('fx') != null; return fuchsiaArtifacts.devFinder != null;
} }
@override @override
bool get canLaunchDevices { bool get canLaunchDevices {
return os.which('fx') != null; return fuchsiaArtifacts.devFinder != null && fuchsiaArtifacts.sshConfig != null;
} }
@override @override
......
...@@ -29,12 +29,13 @@ void main() { ...@@ -29,12 +29,13 @@ void main() {
expect(device.name, name); expect(device.name, name);
}); });
test('parse netls log output', () { test('parse dev_finder output', () {
const String example = 'device lilia-shore-only-last (fe80::0000:a00a:f00f:2002/3)'; const String example = '192.168.42.56 paper-pulp-bush-angel';
final List<String> names = parseFuchsiaDeviceOutput(example); final List<FuchsiaDevice> names = parseListDevices(example);
expect(names.length, 1); expect(names.length, 1);
expect(names.first, 'lilia-shore-only-last'); expect(names.first.name, 'paper-pulp-bush-angel');
expect(names.first.id, '192.168.42.56');
}); });
test('default capabilities', () async { test('default capabilities', () async {
...@@ -50,7 +51,6 @@ void main() { ...@@ -50,7 +51,6 @@ void main() {
group('displays friendly error when', () { group('displays friendly error when', () {
final MockProcessManager mockProcessManager = MockProcessManager(); final MockProcessManager mockProcessManager = MockProcessManager();
final MockProcessResult mockProcessResult = MockProcessResult(); final MockProcessResult mockProcessResult = MockProcessResult();
final MockFuchsiaArtifacts mockFuchsiaArtifacts = MockFuchsiaArtifacts();
final MockFile mockFile = MockFile(); final MockFile mockFile = MockFile();
when(mockProcessManager.run( when(mockProcessManager.run(
any, any,
...@@ -60,23 +60,9 @@ void main() { ...@@ -60,23 +60,9 @@ void main() {
when(mockProcessResult.exitCode).thenReturn(1); when(mockProcessResult.exitCode).thenReturn(1);
when<String>(mockProcessResult.stdout).thenReturn(''); when<String>(mockProcessResult.stdout).thenReturn('');
when<String>(mockProcessResult.stderr).thenReturn(''); when<String>(mockProcessResult.stderr).thenReturn('');
when(mockFuchsiaArtifacts.sshConfig).thenReturn(mockFile);
when(mockFile.absolute).thenReturn(mockFile); when(mockFile.absolute).thenReturn(mockFile);
when(mockFile.path).thenReturn(''); when(mockFile.path).thenReturn('');
testUsingContext('No BUILD_DIR set', () async {
final FuchsiaDevice device = FuchsiaDevice('id');
ToolExit toolExit;
try {
await device.servicePorts();
} on ToolExit catch (err) {
toolExit = err;
}
expect(toolExit.message, contains('BUILD_DIR must be supplied to locate SSH keys'));
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
});
final MockProcessManager emptyStdoutProcessManager = MockProcessManager(); final MockProcessManager emptyStdoutProcessManager = MockProcessManager();
final MockProcessResult emptyStdoutProcessResult = MockProcessResult(); final MockProcessResult emptyStdoutProcessResult = MockProcessResult();
when(emptyStdoutProcessManager.run( when(emptyStdoutProcessManager.run(
...@@ -99,7 +85,10 @@ void main() { ...@@ -99,7 +85,10 @@ void main() {
expect(toolExit.message, contains('No Dart Observatories found. Are you running a debug build?')); expect(toolExit.message, contains('No Dart Observatories found. Are you running a debug build?'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
ProcessManager: () => emptyStdoutProcessManager, ProcessManager: () => emptyStdoutProcessManager,
FuchsiaArtifacts: () => mockFuchsiaArtifacts, FuchsiaArtifacts: () => FuchsiaArtifacts(
sshConfig: mockFile,
devFinder: mockFile,
),
}); });
group('device logs', () { group('device logs', () {
...@@ -211,8 +200,6 @@ void main() { ...@@ -211,8 +200,6 @@ void main() {
}); });
} }
class MockFuchsiaArtifacts extends Mock implements FuchsiaArtifacts {}
class MockProcessManager extends Mock implements ProcessManager {} class MockProcessManager extends Mock implements ProcessManager {}
class MockProcessResult extends Mock implements ProcessResult {} class MockProcessResult extends Mock implements ProcessResult {}
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/os.dart'; import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/fuchsia/fuchsia_sdk.dart';
import 'package:flutter_tools/src/fuchsia/fuchsia_workflow.dart'; import 'package:flutter_tools/src/fuchsia/fuchsia_workflow.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
...@@ -14,28 +15,34 @@ class MockOperatingSystemUtils extends Mock implements OperatingSystemUtils {} ...@@ -14,28 +15,34 @@ class MockOperatingSystemUtils extends Mock implements OperatingSystemUtils {}
class MockFile extends Mock implements File {} class MockFile extends Mock implements File {}
void main() { void main() {
bool fxPresent = false;
final MockOperatingSystemUtils utils = MockOperatingSystemUtils();
final MockFile file = MockFile();
when(utils.which('fx')).thenAnswer((Invocation _) => fxPresent ? file : null);
group('android workflow', () { group('android workflow', () {
testUsingContext('can not list and launch devices if there is no `fx` command', () { final MockFile devFinder = MockFile();
fxPresent = false; final MockFile sshConfig = MockFile();
when(devFinder.absolute).thenReturn(devFinder);
when(sshConfig.absolute).thenReturn(sshConfig);
testUsingContext('can not list and launch devices if there is not ssh config and dev finder', () {
expect(fuchsiaWorkflow.canLaunchDevices, false); expect(fuchsiaWorkflow.canLaunchDevices, false);
expect(fuchsiaWorkflow.canListDevices, false); expect(fuchsiaWorkflow.canListDevices, false);
expect(fuchsiaWorkflow.canListEmulators, false); expect(fuchsiaWorkflow.canListEmulators, false);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
OperatingSystemUtils: () => utils, FuchsiaArtifacts: () => FuchsiaArtifacts(devFinder: null, sshConfig: null),
});
testUsingContext('can not list and launch devices if there is not ssh config and dev finder', () {
expect(fuchsiaWorkflow.canLaunchDevices, false);
expect(fuchsiaWorkflow.canListDevices, true);
expect(fuchsiaWorkflow.canListEmulators, false);
}, overrides: <Type, Generator>{
FuchsiaArtifacts: () => FuchsiaArtifacts(devFinder: devFinder, sshConfig: null),
}); });
testUsingContext('can list and launch devices supported if there is a `fx` command', () { testUsingContext('can list and launch devices supported if there is a `fx` command', () {
fxPresent = true;
expect(fuchsiaWorkflow.canLaunchDevices, true); expect(fuchsiaWorkflow.canLaunchDevices, true);
expect(fuchsiaWorkflow.canListDevices, true); expect(fuchsiaWorkflow.canListDevices, true);
expect(fuchsiaWorkflow.canListEmulators, false); expect(fuchsiaWorkflow.canListEmulators, false);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
OperatingSystemUtils: () => utils, FuchsiaArtifacts: () => FuchsiaArtifacts(devFinder: devFinder, sshConfig: sshConfig),
}); });
}); });
} }
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