fuchsia_ffx.dart 4.82 KB
Newer Older
1 2 3 4
// 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.

5
import 'package:file/file.dart';
6 7 8 9 10
import 'package:process/process.dart';

import '../base/common.dart';
import '../base/logger.dart';
import '../base/process.dart';
11
import '../globals.dart' as globals;
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
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
30 31 32
//   session           Control the current session. See
//                     https://fuchsia.dev/fuchsia-src/concepts/session/introduction
//                     for details.
33 34 35 36

/// A simple wrapper for the Fuchsia SDK's 'ffx' tool.
class FuchsiaFfx {
  FuchsiaFfx({
37 38 39 40 41 42 43 44
    FuchsiaArtifacts? fuchsiaArtifacts,
    Logger? logger,
    ProcessManager? processManager,
  })  : _fuchsiaArtifacts = fuchsiaArtifacts ?? globals.fuchsiaArtifacts,
        _logger = logger ?? globals.logger,
        _processUtils = ProcessUtils(
            logger: logger ?? globals.logger,
            processManager: processManager ?? globals.processManager);
45

46
  final FuchsiaArtifacts? _fuchsiaArtifacts;
47 48 49 50 51 52 53
  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
54 55 56
  Future<List<String>?> list({Duration? timeout}) async {
    final File? ffx = _fuchsiaArtifacts?.ffx;
    if (ffx == null || !ffx.existsSync()) {
57 58 59
      throwToolExit('Fuchsia ffx tool not found.');
    }
    final List<String> command = <String>[
60
      ffx.path,
61
      if (timeout != null) ...<String>['-T', '${timeout.inSeconds}'],
62 63
      'target',
      'list',
64 65 66
      // TODO(akbiggs): Revert -f back to --format once we've verified that
      // analytics spam is coming from here.
      '-f',
67
      's',
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
    ];
    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'.
84 85 86
  Future<String?> resolve(String deviceName) async {
    final File? ffx = _fuchsiaArtifacts?.ffx;
    if (ffx == null || !ffx.existsSync()) {
87 88 89
      throwToolExit('Fuchsia ffx tool not found.');
    }
    final List<String> command = <String>[
90
      ffx.path,
91 92
      'target',
      'list',
93
      '-f',
94 95 96 97 98 99 100 101 102 103
      '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();
  }
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149

  /// 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;
  }
150
}