| // 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 'package:file/file.dart'; | |
| import 'package:process/process.dart'; | |
| import '../base/common.dart'; | |
| import '../base/logger.dart'; | |
| import '../base/process.dart'; | |
| import '../globals.dart' as globals; | |
| import 'fuchsia_sdk.dart'; | |
| // Usage: ffx [-c <config>] [-e <env>] [-t <target>] [-T <timeout>] [-v] [<command>] [<args>] | |
| // Fuchsia's developer tool | |
| // Options: | |
| // -c, --config override default configuration | |
| // -e, --env override default environment settings | |
| // -t, --target apply operations across single or multiple targets | |
| // -T, --timeout override default proxy timeout | |
| // -v, --verbose use verbose output | |
| // --help display usage information | |
| // Commands: | |
| // config View and switch default and user configurations | |
| // daemon Interact with/control the ffx daemon | |
| // target Interact with a target device or emulator | |
| // session Control the current session. See | |
| // https://fuchsia.dev/fuchsia-src/concepts/session/introduction | |
| // for details. | |
| /// A simple wrapper for the Fuchsia SDK's 'ffx' tool. | |
| class FuchsiaFfx { | |
| FuchsiaFfx({ | |
| FuchsiaArtifacts? fuchsiaArtifacts, | |
| Logger? logger, | |
| ProcessManager? processManager, | |
| }) : _fuchsiaArtifacts = fuchsiaArtifacts ?? globals.fuchsiaArtifacts, | |
| _logger = logger ?? globals.logger, | |
| _processUtils = ProcessUtils( | |
| logger: logger ?? globals.logger, | |
| processManager: processManager ?? globals.processManager); | |
| final FuchsiaArtifacts? _fuchsiaArtifacts; | |
| final Logger _logger; | |
| final ProcessUtils _processUtils; | |
| /// Returns a list of attached devices as a list of strings with entries | |
| /// formatted as follows: | |
| /// | |
| /// abcd::abcd:abc:abcd:abcd%qemu scare-cable-skip-joy | |
| Future<List<String>?> list({Duration? timeout}) async { | |
| final File? ffx = _fuchsiaArtifacts?.ffx; | |
| if (ffx == null || !ffx.existsSync()) { | |
| throwToolExit('Fuchsia ffx tool not found.'); | |
| } | |
| final List<String> command = <String>[ | |
| ffx.path, | |
| if (timeout != null) ...<String>['-T', '${timeout.inSeconds}'], | |
| 'target', | |
| 'list', | |
| // TODO(akbiggs): Revert -f back to --format once we've verified that | |
| // analytics spam is coming from here. | |
| '-f', | |
| 's', | |
| ]; | |
| final RunResult result = await _processUtils.run(command); | |
| if (result.exitCode != 0) { | |
| _logger.printError('ffx failed: ${result.stderr}'); | |
| return null; | |
| } | |
| if (result.stderr.contains('No devices found')) { | |
| return null; | |
| } | |
| return result.stdout.split('\n'); | |
| } | |
| /// Returns the address of the named device. | |
| /// | |
| /// The string [deviceName] should be the name of the device from the | |
| /// 'list' command, e.g. 'scare-cable-skip-joy'. | |
| Future<String?> resolve(String deviceName) async { | |
| final File? ffx = _fuchsiaArtifacts?.ffx; | |
| if (ffx == null || !ffx.existsSync()) { | |
| throwToolExit('Fuchsia ffx tool not found.'); | |
| } | |
| final List<String> command = <String>[ | |
| ffx.path, | |
| 'target', | |
| 'list', | |
| '-f', | |
| 'a', | |
| deviceName, | |
| ]; | |
| final RunResult result = await _processUtils.run(command); | |
| if (result.exitCode != 0) { | |
| _logger.printError('ffx failed: ${result.stderr}'); | |
| return null; | |
| } | |
| return result.stdout.trim(); | |
| } | |
| /// Show information about the current session | |
| /// | |
| /// Returns `null` if the command failed, which can be interpreted as there is | |
| /// no usable session. | |
| Future<String?> sessionShow() async { | |
| final File? ffx = _fuchsiaArtifacts?.ffx; | |
| if (ffx == null || !ffx.existsSync()) { | |
| throwToolExit('Fuchsia ffx tool not found.'); | |
| } | |
| final List<String> command = <String>[ | |
| ffx.path, | |
| 'session', | |
| 'show', | |
| ]; | |
| final RunResult result = await _processUtils.run(command); | |
| if (result.exitCode != 0) { | |
| _logger.printError('ffx failed: ${result.stderr}'); | |
| return null; | |
| } | |
| return result.stdout; | |
| } | |
| /// Add an element to the current session | |
| /// | |
| /// [url] should be formatted as a Fuchsia-style package URL, e.g.: | |
| /// fuchsia-pkg://fuchsia.com/flutter_gallery#meta/flutter_gallery.cmx | |
| /// Returns true on success and false on failure. | |
| Future<bool> sessionAdd(String url) async { | |
| final File? ffx = _fuchsiaArtifacts?.ffx; | |
| if (ffx == null || !ffx.existsSync()) { | |
| throwToolExit('Fuchsia ffx tool not found.'); | |
| } | |
| final List<String> command = <String>[ | |
| ffx.path, | |
| 'session', | |
| 'add', | |
| url, | |
| ]; | |
| final RunResult result = await _processUtils.run(command); | |
| if (result.exitCode != 0) { | |
| _logger.printError('ffx failed: ${result.stderr}'); | |
| return false; | |
| } | |
| return true; | |
| } | |
| } |