• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2018 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import 'dart:async';
6
7import '../base/context.dart';
8import '../base/file_system.dart';
9import '../base/io.dart';
10import '../base/platform.dart';
11import '../base/process_manager.dart';
12import '../cache.dart';
13import '../convert.dart';
14import '../globals.dart';
15
16import 'fuchsia_dev_finder.dart';
17import 'fuchsia_kernel_compiler.dart';
18import 'fuchsia_pm.dart';
19
20/// The [FuchsiaSdk] instance.
21FuchsiaSdk get fuchsiaSdk => context.get<FuchsiaSdk>();
22
23/// The [FuchsiaArtifacts] instance.
24FuchsiaArtifacts get fuchsiaArtifacts => context.get<FuchsiaArtifacts>();
25
26/// The Fuchsia SDK shell commands.
27///
28/// This workflow assumes development within the fuchsia source tree,
29/// including a working fx command-line tool in the user's PATH.
30class FuchsiaSdk {
31  /// Interface to the 'pm' tool.
32  FuchsiaPM get fuchsiaPM => _fuchsiaPM ??= FuchsiaPM();
33  FuchsiaPM _fuchsiaPM;
34
35  /// Interface to the 'dev_finder' tool.
36  FuchsiaDevFinder _fuchsiaDevFinder;
37  FuchsiaDevFinder get fuchsiaDevFinder =>
38      _fuchsiaDevFinder ??= FuchsiaDevFinder();
39
40  /// Interface to the 'kernel_compiler' tool.
41  FuchsiaKernelCompiler _fuchsiaKernelCompiler;
42  FuchsiaKernelCompiler get fuchsiaKernelCompiler =>
43      _fuchsiaKernelCompiler ??= FuchsiaKernelCompiler();
44
45  /// Example output:
46  ///    $ dev_finder list -full
47  ///    > 192.168.42.56 paper-pulp-bush-angel
48  Future<String> listDevices() async {
49    if (fuchsiaArtifacts.devFinder == null ||
50        !fuchsiaArtifacts.devFinder.existsSync()) {
51      return null;
52    }
53    final List<String> devices = await fuchsiaDevFinder.list();
54    if (devices == null) {
55      return null;
56    }
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    Process process;
63    try {
64      final StreamController<String> controller =
65          StreamController<String>(onCancel: () {
66        process.kill();
67      });
68      if (fuchsiaArtifacts.sshConfig == null ||
69          !fuchsiaArtifacts.sshConfig.existsSync()) {
70        printError('Cannot read device logs: No ssh config.');
71        printError('Have you set FUCHSIA_SSH_CONFIG or FUCHSIA_BUILD_DIR?');
72        return null;
73      }
74      const String remoteCommand = 'log_listener --clock Local';
75      final List<String> cmd = <String>[
76        'ssh',
77        '-F',
78        fuchsiaArtifacts.sshConfig.absolute.path,
79        id,
80        remoteCommand
81      ];
82      processManager.start(cmd).then((Process newProcess) {
83        if (controller.isClosed) {
84          return;
85        }
86        process = newProcess;
87        process.exitCode.whenComplete(controller.close);
88        controller.addStream(process.stdout
89            .transform(utf8.decoder)
90            .transform(const LineSplitter()));
91      });
92      return controller.stream;
93    } catch (exception) {
94      printTrace('$exception');
95    }
96    return const Stream<String>.empty();
97  }
98}
99
100/// Fuchsia-specific artifacts used to interact with a device.
101class FuchsiaArtifacts {
102  /// Creates a new [FuchsiaArtifacts].
103  FuchsiaArtifacts({
104    this.sshConfig,
105    this.devFinder,
106    this.platformKernelDill,
107    this.flutterPatchedSdk,
108    this.kernelCompiler,
109    this.pm,
110  });
111
112  /// Creates a new [FuchsiaArtifacts] using the cached Fuchsia SDK.
113  ///
114  /// Finds tools under bin/cache/artifacts/fuchsia/tools.
115  /// Queries environment variables (first FUCHSIA_BUILD_DIR, then
116  /// FUCHSIA_SSH_CONFIG) to find the ssh configuration needed to talk to
117  /// a device.
118  factory FuchsiaArtifacts.find() {
119    if (!platform.isLinux && !platform.isMacOS) {
120      // Don't try to find the artifacts on platforms that are not supported.
121      return FuchsiaArtifacts();
122    }
123    final String fuchsia = Cache.instance.getArtifactDirectory('fuchsia').path;
124    final String tools = fs.path.join(fuchsia, 'tools');
125    final String dartPrebuilts = fs.path.join(tools, 'dart_prebuilts');
126
127    final File devFinder = fs.file(fs.path.join(tools, 'dev_finder'));
128    final File platformDill = fs.file(fs.path.join(
129          dartPrebuilts, 'flutter_runner', 'platform_strong.dill'));
130    final File patchedSdk = fs.file(fs.path.join(
131          dartPrebuilts, 'flutter_runner'));
132    final File kernelCompiler = fs.file(fs.path.join(
133          dartPrebuilts, 'kernel_compiler.snapshot'));
134    final File pm = fs.file(fs.path.join(tools, 'pm'));
135
136    // If FUCHSIA_BUILD_DIR is defined, then look for the ssh_config dir
137    // relative to it. Next, if FUCHSIA_SSH_CONFIG is defined, then use it.
138    // TODO(zra): Consider passing the ssh config path in with a flag.
139    File sshConfig;
140    if (platform.environment.containsKey(_kFuchsiaBuildDir)) {
141      sshConfig = fs.file(fs.path.join(
142          platform.environment[_kFuchsiaBuildDir], 'ssh-keys', 'ssh_config'));
143    } else if (platform.environment.containsKey(_kFuchsiaSshConfig)) {
144      sshConfig = fs.file(platform.environment[_kFuchsiaSshConfig]);
145    }
146    return FuchsiaArtifacts(
147      sshConfig: sshConfig,
148      devFinder: devFinder.existsSync() ? devFinder : null,
149      platformKernelDill: platformDill.existsSync() ? platformDill : null,
150      flutterPatchedSdk: patchedSdk.existsSync() ? patchedSdk : null,
151      kernelCompiler: kernelCompiler.existsSync() ? kernelCompiler : null,
152      pm: pm.existsSync() ? pm : null,
153    );
154  }
155
156  static const String _kFuchsiaSshConfig = 'FUCHSIA_SSH_CONFIG';
157  static const String _kFuchsiaBuildDir = 'FUCHSIA_BUILD_DIR';
158
159  /// The location of the SSH configuration file used to interact with a
160  /// Fuchsia device.
161  final File sshConfig;
162
163  /// The location of the dev finder tool used to locate connected
164  /// Fuchsia devices.
165  final File devFinder;
166
167  /// The location of the Fuchsia-specific platform dill.
168  final File platformKernelDill;
169
170  /// The directory containing [platformKernelDill].
171  final File flutterPatchedSdk;
172
173  /// The snapshot of the Fuchsia kernel compiler.
174  final File kernelCompiler;
175
176  /// The pm tool.
177  final File pm;
178}
179