fuchsia_sdk.dart 5.08 KB
Newer Older
1 2 3 4
// Copyright 2018 The Chromium 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 6
import 'dart:async';

7
import '../base/context.dart';
8 9
import '../base/file_system.dart';
import '../base/io.dart';
10
import '../base/platform.dart';
11
import '../base/process_manager.dart';
12
import '../cache.dart';
13
import '../convert.dart';
14
import '../globals.dart';
15

16 17 18 19
import 'fuchsia_dev_finder.dart';
import 'fuchsia_kernel_compiler.dart';
import 'fuchsia_pm.dart';

20
/// The [FuchsiaSdk] instance.
21
FuchsiaSdk get fuchsiaSdk => context.get<FuchsiaSdk>();
22

23
/// The [FuchsiaArtifacts] instance.
24
FuchsiaArtifacts get fuchsiaArtifacts => context.get<FuchsiaArtifacts>();
25

26 27 28 29 30
/// The Fuchsia SDK shell commands.
///
/// This workflow assumes development within the fuchsia source tree,
/// including a working fx command-line tool in the user's PATH.
class FuchsiaSdk {
31 32 33 34 35 36 37 38 39 40 41 42 43 44
  /// Interface to the 'pm' tool.
  FuchsiaPM get fuchsiaPM => _fuchsiaPM ??= FuchsiaPM();
  FuchsiaPM _fuchsiaPM;

  /// Interface to the 'dev_finder' tool.
  FuchsiaDevFinder _fuchsiaDevFinder;
  FuchsiaDevFinder get fuchsiaDevFinder =>
      _fuchsiaDevFinder ??= FuchsiaDevFinder();

  /// Interface to the 'kernel_compiler' tool.
  FuchsiaKernelCompiler _fuchsiaKernelCompiler;
  FuchsiaKernelCompiler get fuchsiaKernelCompiler =>
      _fuchsiaKernelCompiler ??= FuchsiaKernelCompiler();

45
  /// Example output:
46 47 48
  ///    $ dev_finder list -full
  ///    > 192.168.42.56 paper-pulp-bush-angel
  Future<String> listDevices() async {
49 50
    if (fuchsiaArtifacts.devFinder == null ||
        !fuchsiaArtifacts.devFinder.existsSync()) {
51
      return null;
52
    }
53
    final List<String> devices = await fuchsiaDevFinder.list();
54 55 56
    if (devices == null) {
      return null;
    }
57
    return devices.isNotEmpty ? devices[0] : null;
58 59 60
  }

  /// Returns the fuchsia system logs for an attached device.
61
  Stream<String> syslogs(String id) {
62 63
    Process process;
    try {
64
      final StreamController<String> controller = StreamController<String>(onCancel: () {
65 66
        process.kill();
      });
67 68
      if (fuchsiaArtifacts.sshConfig == null ||
          !fuchsiaArtifacts.sshConfig.existsSync()) {
69 70
        printError('Cannot read device logs: No ssh config.');
        printError('Have you set FUCHSIA_SSH_CONFIG or FUCHSIA_BUILD_DIR?');
71 72 73 74 75 76 77 78
        return null;
      }
      const String remoteCommand = 'log_listener --clock Local';
      final List<String> cmd = <String>[
        'ssh',
        '-F',
        fuchsiaArtifacts.sshConfig.absolute.path,
        id,
79
        remoteCommand,
80 81
      ];
      processManager.start(cmd).then((Process newProcess) {
82 83 84 85
        if (controller.isClosed) {
          return;
        }
        process = newProcess;
86
        process.exitCode.whenComplete(controller.close);
87 88 89
        controller.addStream(process.stdout
            .transform(utf8.decoder)
            .transform(const LineSplitter()));
90 91
      });
      return controller.stream;
92 93
    } catch (exception) {
      printTrace('$exception');
94
    }
95
    return const Stream<String>.empty();
96 97
  }
}
98 99 100 101

/// Fuchsia-specific artifacts used to interact with a device.
class FuchsiaArtifacts {
  /// Creates a new [FuchsiaArtifacts].
102 103 104
  FuchsiaArtifacts({
    this.sshConfig,
    this.devFinder,
105
    this.pm,
106
  });
107

108 109 110 111 112 113 114
  /// Creates a new [FuchsiaArtifacts] using the cached Fuchsia SDK.
  ///
  /// Finds tools under bin/cache/artifacts/fuchsia/tools.
  /// Queries environment variables (first FUCHSIA_BUILD_DIR, then
  /// FUCHSIA_SSH_CONFIG) to find the ssh configuration needed to talk to
  /// a device.
  factory FuchsiaArtifacts.find() {
115 116 117 118
    if (!platform.isLinux && !platform.isMacOS) {
      // Don't try to find the artifacts on platforms that are not supported.
      return FuchsiaArtifacts();
    }
119 120 121 122 123 124
    // If FUCHSIA_BUILD_DIR is defined, then look for the ssh_config dir
    // relative to it. Next, if FUCHSIA_SSH_CONFIG is defined, then use it.
    // TODO(zra): Consider passing the ssh config path in with a flag.
    File sshConfig;
    if (platform.environment.containsKey(_kFuchsiaBuildDir)) {
      sshConfig = fs.file(fs.path.join(
125
          platform.environment[_kFuchsiaBuildDir], 'ssh-keys', 'ssh_config'));
126 127 128
    } else if (platform.environment.containsKey(_kFuchsiaSshConfig)) {
      sshConfig = fs.file(platform.environment[_kFuchsiaSshConfig]);
    }
129 130 131 132 133 134

    final String fuchsia = Cache.instance.getArtifactDirectory('fuchsia').path;
    final String tools = fs.path.join(fuchsia, 'tools');
    final File devFinder = fs.file(fs.path.join(tools, 'dev_finder'));
    final File pm = fs.file(fs.path.join(tools, 'pm'));

135 136
    return FuchsiaArtifacts(
      sshConfig: sshConfig,
137 138
      devFinder: devFinder.existsSync() ? devFinder : null,
      pm: pm.existsSync() ? pm : null,
139 140 141 142 143 144
    );
  }

  static const String _kFuchsiaSshConfig = 'FUCHSIA_SSH_CONFIG';
  static const String _kFuchsiaBuildDir = 'FUCHSIA_BUILD_DIR';

145
  /// The location of the SSH configuration file used to interact with a
146 147 148 149 150 151
  /// Fuchsia device.
  final File sshConfig;

  /// The location of the dev finder tool used to locate connected
  /// Fuchsia devices.
  final File devFinder;
152

153 154
  /// The pm tool.
  final File pm;
155
}