Unverified Commit 81c7af34 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Add fuchsia specific entrypoint (#23916)

parent cf2fba7b
......@@ -236,3 +236,19 @@ dart_tool("fuchsia_tester") {
"$flutter_root/shell",
]
}
dart_tool("fuchsia_tools") {
package_name = "fuchsia_tools"
main_dart = "bin/fuchsia_tools.dart"
# Can be left empty as analysis is disabled.
sources = []
disable_analysis = true
deps = [
":flutter_tools",
]
# TODO(jonahwilliams): add a frontend_server as a non dart dep.
}
// 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.
import 'package:flutter_tools/fuchsia_executable.dart' as executable;
void main(List<String> args) {
executable.main(args);
}
......@@ -18,7 +18,6 @@ import 'src/commands/doctor.dart';
import 'src/commands/drive.dart';
import 'src/commands/emulators.dart';
import 'src/commands/format.dart';
import 'src/commands/fuchsia_reload.dart';
import 'src/commands/ide_config.dart';
import 'src/commands/inject_plugins.dart';
import 'src/commands/install.dart';
......@@ -63,7 +62,6 @@ Future<void> main(List<String> args) async {
DriveCommand(),
EmulatorsCommand(),
FormatCommand(),
FuchsiaReloadCommand(),
IdeConfigCommand(hidden: !verboseHelp),
InjectPluginsCommand(hidden: !verboseHelp),
InstallCommand(),
......
// 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.
import 'dart:async';
import 'package:args/args.dart';
import 'runner.dart' as runner;
import 'src/artifacts.dart';
import 'src/base/common.dart';
import 'src/base/context.dart';
import 'src/base/file_system.dart';
import 'src/commands/attach.dart';
import 'src/commands/devices.dart';
import 'src/commands/shell_completion.dart';
import 'src/fuchsia/fuchsia_sdk.dart';
import 'src/runner/flutter_command.dart';
final ArgParser parser = ArgParser.allowAnything()
..addOption('verbose', abbr: 'v')
..addOption('help', abbr: 'h')
..addOption(
'frontend-server',
help: 'The path to the frontend server snapshot.',
)
..addOption(
'dart-sdk',
help: 'The path to the patched dart-sdk binary.',
)
..addOption(
'ssh-config',
help: 'The path to the ssh configuration file.',
);
/// Main entry point for fuchsia commands.
///
/// This function is intended to be used within the fuchsia source tree.
Future<void> main(List<String> args) async {
final ArgResults results = parser.parse(args);
final bool verbose = results['verbose'];
final bool help = results['help'];
final bool verboseHelp = help && verbose;
final File dartSdk = fs.file(results['dart-sdk']);
final File frontendServer = fs.file(results['frontend-server']);
final File sshConfig = fs.file(results['ssh-config']);
if (!dartSdk.existsSync()) {
throwToolExit('--dart-sdk is required: ${dartSdk.path} does not exist.');
}
if (!frontendServer.existsSync()) {
throwToolExit('--frontend-server is required: ${frontendServer.path} does not exist.');
}
if (!sshConfig.existsSync()) {
throwToolExit('--ssh-config is required: ${sshConfig.path} does not exist.');
}
await runner.run(args, <FlutterCommand>[
AttachCommand(verboseHelp: verboseHelp),
DevicesCommand(),
ShellCompletionCommand(),
], verbose: verbose,
muteCommandLogging: help,
verboseHelp: verboseHelp,
overrides: <Type, Generator>{
FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig),
Artifacts: () => OverrideArtifacts(
parent: CachedArtifacts(),
frontendServer: frontendServer,
engineDartBinary: dartSdk,
)
});
}
......@@ -34,6 +34,7 @@ Future<int> run(
bool verboseHelp = false,
bool reportCrashes,
String flutterVersion,
Map<Type, Generator> overrides,
}) {
reportCrashes ??= !isRunningOnBot;
......@@ -63,7 +64,7 @@ Future<int> run(
return await _handleToolError(error, stackTrace, verbose, args, reportCrashes, getVersion);
}
return 0;
});
}, overrides: overrides);
}
Future<int> _handleToolError(
......
......@@ -303,7 +303,6 @@ class LocalEngineArtifacts extends Artifacts {
/// An implementation of [Artifacts] that provides individual overrides.
///
/// If an artifact is not provided, the lookup delegates to the parent.
/// Currently only allows overriding the location of the [frontendServer].
class OverrideArtifacts implements Artifacts {
/// Creates a new [OverrideArtifacts].
///
......@@ -311,16 +310,21 @@ class OverrideArtifacts implements Artifacts {
OverrideArtifacts({
@required this.parent,
this.frontendServer,
this.engineDartBinary,
}) : assert(parent != null);
final Artifacts parent;
final File frontendServer;
final File engineDartBinary;
@override
String getArtifactPath(Artifact artifact, [TargetPlatform platform, BuildMode mode]) {
if (artifact == Artifact.frontendServerSnapshotForEngineDartSdk && frontendServer != null) {
return frontendServer.path;
}
if (artifact == Artifact.engineDartBinary && engineDartBinary != null) {
return engineDartBinary.path;
}
return parent.getArtifactPath(artifact, platform, mode);
}
......
......@@ -11,6 +11,7 @@ import '../base/logger.dart';
import '../base/utils.dart';
import '../cache.dart';
import '../commands/daemon.dart';
import '../compile.dart';
import '../device.dart';
import '../fuchsia/fuchsia_device.dart';
import '../globals.dart';
......@@ -48,6 +49,7 @@ class AttachCommand extends FlutterCommand {
usesIsolateFilterOption(hide: !verboseHelp);
usesTargetOption();
usesFilesystemOptions(hide: !verboseHelp);
usesFuchsiaOptions(hide: !verboseHelp);
argParser
..addOption(
'debug-port',
......@@ -60,12 +62,6 @@ class AttachCommand extends FlutterCommand {
'project-root',
hide: !verboseHelp,
help: 'Normally used only in run target',
)..addOption(
'module',
abbr: 'm',
hide: !verboseHelp,
help: 'The name of the module (required if attaching to a fuchsia device)',
valueHelp: 'module-name',
)..addFlag('machine',
hide: !verboseHelp,
negatable: false,
......@@ -180,6 +176,7 @@ class AttachCommand extends FlutterCommand {
fileSystemRoots: argResults['filesystem-root'],
fileSystemScheme: argResults['filesystem-scheme'],
viewFilter: argResults['isolate-filter'],
targetModel: TargetModel(argResults['target-model']),
);
flutterDevice.observatoryUris = <Uri>[ observatoryUri ];
final HotRunner hotRunner = hotRunnerFactory.build(
......
......@@ -24,6 +24,38 @@ KernelCompiler get kernelCompiler => context[KernelCompiler];
typedef CompilerMessageConsumer = void Function(String message, {bool emphasis, TerminalColor color});
/// The target model describes the set of core libraries that are availible within
/// the SDK.
class TargetModel {
/// Parse a [TargetModel] from a raw string.
///
/// Throws an [AssertionError] if passed a value other than 'flutter' or
/// 'flutter_runner'.
factory TargetModel(String rawValue) {
switch (rawValue) {
case 'flutter':
return flutter;
case 'flutter_runner':
return flutterRunner;
}
assert(false);
return null;
}
const TargetModel._(this._value);
/// The flutter patched dart SDK
static const TargetModel flutter = TargetModel._('flutter');
/// The fuchsia patched SDK.
static const TargetModel flutterRunner = TargetModel._('flutter_runner');
final String _value;
@override
String toString() => _value;
}
class CompilerOutput {
const CompilerOutput(this.outputFilename, this.errorCount);
......@@ -122,6 +154,7 @@ class KernelCompiler {
String mainPath,
String outputFilePath,
String depFilePath,
TargetModel targetModel = TargetModel.flutter,
bool linkPlatformKernelIn = false,
bool aot = false,
@required bool trackWidgetCreation,
......@@ -172,7 +205,7 @@ class KernelCompiler {
'--sdk-root',
sdkRoot,
'--strong',
'--target=flutter',
'--target=$targetModel',
];
if (trackWidgetCreation)
command.add('--track-widget-creation');
......@@ -301,12 +334,14 @@ class ResidentCompiler {
String fileSystemScheme,
CompilerMessageConsumer compilerMessageConsumer = printError,
String initializeFromDill,
TargetModel targetModel = TargetModel.flutter,
bool unsafePackageSerialization
}) : assert(_sdkRoot != null),
_trackWidgetCreation = trackWidgetCreation,
_packagesPath = packagesPath,
_fileSystemRoots = fileSystemRoots,
_fileSystemScheme = fileSystemScheme,
_targetModel = targetModel,
_stdoutHandler = _StdoutHandler(consumer: compilerMessageConsumer),
_controller = StreamController<_CompilationRequest>(),
_initializeFromDill = initializeFromDill,
......@@ -318,6 +353,7 @@ class ResidentCompiler {
final bool _trackWidgetCreation;
final String _packagesPath;
final TargetModel _targetModel;
final List<String> _fileSystemRoots;
final String _fileSystemScheme;
String _sdkRoot;
......@@ -409,7 +445,7 @@ class ResidentCompiler {
_sdkRoot,
'--incremental',
'--strong',
'--target=flutter',
'--target=$_targetModel',
];
if (outputPath != null) {
command.addAll(<String>['--output-dill', outputPath]);
......
......@@ -65,6 +65,7 @@ Future<T> runInContext<T>(
DoctorValidatorsProvider: () => DoctorValidatorsProvider.defaultInstance,
EmulatorManager: () => EmulatorManager(),
FuchsiaSdk: () => FuchsiaSdk(),
FuchsiaArtifacts: () => FuchsiaArtifacts(),
FuchsiaWorkflow: () => FuchsiaWorkflow(),
Flags: () => const EmptyFlags(),
FlutterVersion: () => FlutterVersion(const Clock()),
......
......@@ -172,7 +172,7 @@ class FuchsiaDevice extends Device {
/// Run `command` on the Fuchsia device shell.
Future<String> shell(String command) async {
final RunResult result = await runAsync(<String>[
'ssh', '-F', fuchsiaSdk.sshConfig.absolute.path, id, command]);
'ssh', '-F', fuchsiaArtifacts.sshConfig.absolute.path, id, command]);
if (result.exitCode != 0) {
throwToolExit('Command failed: $command\nstdout: ${result.stdout}\nstderr: ${result.stderr}');
return null;
......@@ -228,7 +228,7 @@ class _FuchsiaPortForwarder extends DevicePortForwarder {
// Note: the provided command works around a bug in -N, see US-515
// for more explanation.
final List<String> command = <String>[
'ssh', '-6', '-F', fuchsiaSdk.sshConfig.absolute.path, '-nNT', '-vvv', '-f',
'ssh', '-6', '-F', fuchsiaArtifacts.sshConfig.absolute.path, '-nNT', '-vvv', '-f',
'-L', '$hostPort:$_ipv4Loopback:$devicePort', device.id, 'true'
];
final Process process = await processManager.start(command);
......@@ -252,7 +252,7 @@ class _FuchsiaPortForwarder extends DevicePortForwarder {
final Process process = _processes.remove(forwardedPort.hostPort);
process?.kill();
final List<String> command = <String>[
'ssh', '-F', fuchsiaSdk.sshConfig.absolute.path, '-O', 'cancel', '-vvv',
'ssh', '-F', fuchsiaArtifacts.sshConfig.absolute.path, '-O', 'cancel', '-vvv',
'-L', '${forwardedPort.hostPort}:$_ipv4Loopback:${forwardedPort.devicePort}', device.id];
final ProcessResult result = await processManager.run(command);
if (result.exitCode != 0) {
......
......@@ -17,6 +17,9 @@ import '../globals.dart';
/// The [FuchsiaSdk] instance.
FuchsiaSdk get fuchsiaSdk => context[FuchsiaSdk];
/// The [FuchsiaArtifacts] instance.
FuchsiaArtifacts get fuchsiaArtifacts => context[FuchsiaArtifacts];
/// The Fuchsia SDK shell commands.
///
/// This workflow assumes development within the fuchsia source tree,
......@@ -26,19 +29,6 @@ class FuchsiaSdk {
static const List<String> _netlsCommand = <String>['fx', 'netls', '--nowait'];
static const List<String> _syslogCommand = <String>['fx', 'syslog'];
/// The location of the SSH configuration file used to interact with a
/// fuchsia device.
///
/// Requires the env variable `BUILD_DIR` to be set.
File get sshConfig {
if (_sshConfig == null) {
final String buildDirectory = platform.environment['BUILD_DIR'];
_sshConfig = fs.file('$buildDirectory/ssh-keys/ssh_config');
}
return _sshConfig;
}
File _sshConfig;
/// Invokes the `netaddr` command.
///
/// This returns the network address of an attached fuchsia device. Does
......@@ -100,3 +90,26 @@ class FuchsiaSdk {
return null;
}
}
/// Fuchsia-specific artifacts used to interact with a device.
class FuchsiaArtifacts {
/// Creates a new [FuchsiaArtifacts].
///
/// May optionally provide a file `sshConfig` file.
FuchsiaArtifacts({File sshConfig})
: _sshConfig = sshConfig;
/// The location of the SSH configuration file used to interact with a
/// fuchsia device.
///
/// Requires the env variable `BUILD_DIR` to be set if not provided by
/// the constructor.
File get sshConfig {
if (_sshConfig == null) {
final String buildDirectory = platform.environment['BUILD_DIR'];
_sshConfig = fs.file('$buildDirectory/ssh-keys/ssh_config');
}
return _sshConfig;
}
File _sshConfig;
}
......@@ -35,6 +35,7 @@ class FlutterDevice {
this.fileSystemRoots,
this.fileSystemScheme,
this.viewFilter,
TargetModel targetModel = TargetModel.flutter,
ResidentCompiler generator,
}) : assert(trackWidgetCreation != null),
generator = generator ?? ResidentCompiler(
......@@ -42,6 +43,7 @@ class FlutterDevice {
trackWidgetCreation: trackWidgetCreation,
fileSystemRoots: fileSystemRoots,
fileSystemScheme: fileSystemScheme,
targetModel: targetModel,
);
final Device device;
......
......@@ -193,6 +193,23 @@ abstract class FlutterCommand extends Command<void> {
'--release or --profile; --debug always has this enabled.');
}
void usesFuchsiaOptions({bool hide = false}) {
argParser.addOption(
'target-model',
help: 'Target model that determines what core libraries are available',
defaultsTo: 'flutter',
hide: hide,
allowed: const <String>['flutter', 'flutter_runner'],
);
argParser.addOption(
'module',
abbr: 'm',
hide: hide,
help: 'The name of the module (required if attaching to a fuchsia device)',
valueHelp: 'module-name',
);
}
set defaultBuildMode(BuildMode value) {
_defaultBuildMode = value;
}
......
// Copyright 2017 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.
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter_tools/src/commands/fuchsia_reload.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
import '../src/common.dart';
import '../src/context.dart';
void main() {
group('FuchsiaDeviceCommandRunner', () {
testUsingContext('a test', () async {
final FuchsiaDeviceCommandRunner commandRunner =
FuchsiaDeviceCommandRunner('8.8.9.9',
'~/fuchsia/out/release-x86-64');
final List<String> ports = await commandRunner.run('ls /tmp');
expect(ports, hasLength(3));
expect(ports[0], equals('1234'));
expect(ports[1], equals('5678'));
expect(ports[2], equals('5'));
}, overrides: <Type, Generator>{
ProcessManager: () => MockProcessManager(),
});
});
}
class MockProcessManager extends Mock implements ProcessManager {
@override
Future<ProcessResult> run(
List<dynamic> command, {
String workingDirectory,
Map<String, String> environment,
bool includeParentEnvironment = true,
bool runInShell = false,
Encoding stdoutEncoding = systemEncoding,
Encoding stderrEncoding = systemEncoding,
}) async {
return ProcessResult(0, 0, '1234\n5678\n5', '');
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment