blob: 1b79f50353892028a3976584c911f32cde55c362 [file] [log] [blame]
// Copyright 2013 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 'dart:io';
import 'package:meta/meta.dart';
import 'package:uuid/uuid.dart';
import '../fuchsia_ctl.dart';
const SshClient _kSsh = SshClient();
/// Wrapper for amberctl utility for commands executed on the target device.
@immutable
class AmberCtl {
/// Creates a new [AmberCtl] with the specified [targetIp] and [identityFile].
const AmberCtl(
this._targetIp,
this._identityFile,
);
final String _identityFile;
final String _targetIp;
/// Adds a new package update source for the target device.
///
/// * [port] is what "pm serve" is bound to.
/// * Returns the name of the package update source that is randomly generated.
Future<String> addSrc(int port) async {
final String uuid = const Uuid().v4();
final String localIp = await _getLocalIp(_targetIp);
final List<String> addSource = <String>[
'amberctl',
'add_src',
'-f',
'http://[$localIp]:$port/config.json',
'-n',
uuid,
];
stdout.writeln('Adding amberctl source: ${addSource.join(' ')}');
final OperationResult result = await _kSsh.runCommand(
_targetIp,
identityFilePath: _identityFile,
command: addSource,
);
if (!result.success) {
throw AmberCtlException('"add_src" failed, aborting.', result);
} else {
stdout.writeln('Successfully added an update'
' source on port $port with name $uuid.');
return uuid;
}
}
/// Adds a package with the given [packageName] to the device.
Future<void> addPackage(String packageName) async {
stdout.writeln('Adding $packageName...');
final List<String> updateCommand = <String>[
'pkgctl',
'resolve',
'fuchsia-pkg://fuchsia.com/$packageName',
];
final OperationResult result = await _kSsh.runCommand(
_targetIp,
identityFilePath: _identityFile,
command: updateCommand,
);
if (!result.success) {
throw AmberCtlException(
'${updateCommand.join(' ')} failed, aborting.', result);
}
}
Future<String> _getLocalIp(String targetIp) async {
final OperationResult result = await _kSsh.runCommand(targetIp,
identityFilePath: _identityFile,
command: <String>[r'echo $SSH_CONNECTION']);
if (!result.success) {
throw AmberCtlException('Failed to get local address, aborting.', result);
} else {
return result.info.split(' ')[0].replaceAll('%', '%25');
}
}
}
/// Wraps exceptions thrown by amberctl utility.
@immutable
class AmberCtlException implements Exception {
/// Creates a new [AmberCtlException] using the specified [cause] and [result].
const AmberCtlException(this.cause, this.result);
/// Represents the human-readable cause for the amberctl error.
final String cause;
/// Contains the result of the executed target command.
final OperationResult result;
@override
String toString() =>
'$runtimeType, cause: "$cause", underlying exception: $result.';
}