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") { ...@@ -236,3 +236,19 @@ dart_tool("fuchsia_tester") {
"$flutter_root/shell", "$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'; ...@@ -18,7 +18,6 @@ import 'src/commands/doctor.dart';
import 'src/commands/drive.dart'; import 'src/commands/drive.dart';
import 'src/commands/emulators.dart'; import 'src/commands/emulators.dart';
import 'src/commands/format.dart'; import 'src/commands/format.dart';
import 'src/commands/fuchsia_reload.dart';
import 'src/commands/ide_config.dart'; import 'src/commands/ide_config.dart';
import 'src/commands/inject_plugins.dart'; import 'src/commands/inject_plugins.dart';
import 'src/commands/install.dart'; import 'src/commands/install.dart';
...@@ -63,7 +62,6 @@ Future<void> main(List<String> args) async { ...@@ -63,7 +62,6 @@ Future<void> main(List<String> args) async {
DriveCommand(), DriveCommand(),
EmulatorsCommand(), EmulatorsCommand(),
FormatCommand(), FormatCommand(),
FuchsiaReloadCommand(),
IdeConfigCommand(hidden: !verboseHelp), IdeConfigCommand(hidden: !verboseHelp),
InjectPluginsCommand(hidden: !verboseHelp), InjectPluginsCommand(hidden: !verboseHelp),
InstallCommand(), 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( ...@@ -34,6 +34,7 @@ Future<int> run(
bool verboseHelp = false, bool verboseHelp = false,
bool reportCrashes, bool reportCrashes,
String flutterVersion, String flutterVersion,
Map<Type, Generator> overrides,
}) { }) {
reportCrashes ??= !isRunningOnBot; reportCrashes ??= !isRunningOnBot;
...@@ -63,7 +64,7 @@ Future<int> run( ...@@ -63,7 +64,7 @@ Future<int> run(
return await _handleToolError(error, stackTrace, verbose, args, reportCrashes, getVersion); return await _handleToolError(error, stackTrace, verbose, args, reportCrashes, getVersion);
} }
return 0; return 0;
}); }, overrides: overrides);
} }
Future<int> _handleToolError( Future<int> _handleToolError(
......
...@@ -303,7 +303,6 @@ class LocalEngineArtifacts extends Artifacts { ...@@ -303,7 +303,6 @@ class LocalEngineArtifacts extends Artifacts {
/// An implementation of [Artifacts] that provides individual overrides. /// An implementation of [Artifacts] that provides individual overrides.
/// ///
/// If an artifact is not provided, the lookup delegates to the parent. /// 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 { class OverrideArtifacts implements Artifacts {
/// Creates a new [OverrideArtifacts]. /// Creates a new [OverrideArtifacts].
/// ///
...@@ -311,16 +310,21 @@ class OverrideArtifacts implements Artifacts { ...@@ -311,16 +310,21 @@ class OverrideArtifacts implements Artifacts {
OverrideArtifacts({ OverrideArtifacts({
@required this.parent, @required this.parent,
this.frontendServer, this.frontendServer,
this.engineDartBinary,
}) : assert(parent != null); }) : assert(parent != null);
final Artifacts parent; final Artifacts parent;
final File frontendServer; final File frontendServer;
final File engineDartBinary;
@override @override
String getArtifactPath(Artifact artifact, [TargetPlatform platform, BuildMode mode]) { String getArtifactPath(Artifact artifact, [TargetPlatform platform, BuildMode mode]) {
if (artifact == Artifact.frontendServerSnapshotForEngineDartSdk && frontendServer != null) { if (artifact == Artifact.frontendServerSnapshotForEngineDartSdk && frontendServer != null) {
return frontendServer.path; return frontendServer.path;
} }
if (artifact == Artifact.engineDartBinary && engineDartBinary != null) {
return engineDartBinary.path;
}
return parent.getArtifactPath(artifact, platform, mode); return parent.getArtifactPath(artifact, platform, mode);
} }
......
...@@ -11,6 +11,7 @@ import '../base/logger.dart'; ...@@ -11,6 +11,7 @@ import '../base/logger.dart';
import '../base/utils.dart'; import '../base/utils.dart';
import '../cache.dart'; import '../cache.dart';
import '../commands/daemon.dart'; import '../commands/daemon.dart';
import '../compile.dart';
import '../device.dart'; import '../device.dart';
import '../fuchsia/fuchsia_device.dart'; import '../fuchsia/fuchsia_device.dart';
import '../globals.dart'; import '../globals.dart';
...@@ -48,6 +49,7 @@ class AttachCommand extends FlutterCommand { ...@@ -48,6 +49,7 @@ class AttachCommand extends FlutterCommand {
usesIsolateFilterOption(hide: !verboseHelp); usesIsolateFilterOption(hide: !verboseHelp);
usesTargetOption(); usesTargetOption();
usesFilesystemOptions(hide: !verboseHelp); usesFilesystemOptions(hide: !verboseHelp);
usesFuchsiaOptions(hide: !verboseHelp);
argParser argParser
..addOption( ..addOption(
'debug-port', 'debug-port',
...@@ -60,12 +62,6 @@ class AttachCommand extends FlutterCommand { ...@@ -60,12 +62,6 @@ class AttachCommand extends FlutterCommand {
'project-root', 'project-root',
hide: !verboseHelp, hide: !verboseHelp,
help: 'Normally used only in run target', 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', )..addFlag('machine',
hide: !verboseHelp, hide: !verboseHelp,
negatable: false, negatable: false,
...@@ -180,6 +176,7 @@ class AttachCommand extends FlutterCommand { ...@@ -180,6 +176,7 @@ class AttachCommand extends FlutterCommand {
fileSystemRoots: argResults['filesystem-root'], fileSystemRoots: argResults['filesystem-root'],
fileSystemScheme: argResults['filesystem-scheme'], fileSystemScheme: argResults['filesystem-scheme'],
viewFilter: argResults['isolate-filter'], viewFilter: argResults['isolate-filter'],
targetModel: TargetModel(argResults['target-model']),
); );
flutterDevice.observatoryUris = <Uri>[ observatoryUri ]; flutterDevice.observatoryUris = <Uri>[ observatoryUri ];
final HotRunner hotRunner = hotRunnerFactory.build( final HotRunner hotRunner = hotRunnerFactory.build(
......
...@@ -24,6 +24,38 @@ KernelCompiler get kernelCompiler => context[KernelCompiler]; ...@@ -24,6 +24,38 @@ KernelCompiler get kernelCompiler => context[KernelCompiler];
typedef CompilerMessageConsumer = void Function(String message, {bool emphasis, TerminalColor color}); 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 { class CompilerOutput {
const CompilerOutput(this.outputFilename, this.errorCount); const CompilerOutput(this.outputFilename, this.errorCount);
...@@ -122,6 +154,7 @@ class KernelCompiler { ...@@ -122,6 +154,7 @@ class KernelCompiler {
String mainPath, String mainPath,
String outputFilePath, String outputFilePath,
String depFilePath, String depFilePath,
TargetModel targetModel = TargetModel.flutter,
bool linkPlatformKernelIn = false, bool linkPlatformKernelIn = false,
bool aot = false, bool aot = false,
@required bool trackWidgetCreation, @required bool trackWidgetCreation,
...@@ -172,7 +205,7 @@ class KernelCompiler { ...@@ -172,7 +205,7 @@ class KernelCompiler {
'--sdk-root', '--sdk-root',
sdkRoot, sdkRoot,
'--strong', '--strong',
'--target=flutter', '--target=$targetModel',
]; ];
if (trackWidgetCreation) if (trackWidgetCreation)
command.add('--track-widget-creation'); command.add('--track-widget-creation');
...@@ -301,12 +334,14 @@ class ResidentCompiler { ...@@ -301,12 +334,14 @@ class ResidentCompiler {
String fileSystemScheme, String fileSystemScheme,
CompilerMessageConsumer compilerMessageConsumer = printError, CompilerMessageConsumer compilerMessageConsumer = printError,
String initializeFromDill, String initializeFromDill,
TargetModel targetModel = TargetModel.flutter,
bool unsafePackageSerialization bool unsafePackageSerialization
}) : assert(_sdkRoot != null), }) : assert(_sdkRoot != null),
_trackWidgetCreation = trackWidgetCreation, _trackWidgetCreation = trackWidgetCreation,
_packagesPath = packagesPath, _packagesPath = packagesPath,
_fileSystemRoots = fileSystemRoots, _fileSystemRoots = fileSystemRoots,
_fileSystemScheme = fileSystemScheme, _fileSystemScheme = fileSystemScheme,
_targetModel = targetModel,
_stdoutHandler = _StdoutHandler(consumer: compilerMessageConsumer), _stdoutHandler = _StdoutHandler(consumer: compilerMessageConsumer),
_controller = StreamController<_CompilationRequest>(), _controller = StreamController<_CompilationRequest>(),
_initializeFromDill = initializeFromDill, _initializeFromDill = initializeFromDill,
...@@ -318,6 +353,7 @@ class ResidentCompiler { ...@@ -318,6 +353,7 @@ class ResidentCompiler {
final bool _trackWidgetCreation; final bool _trackWidgetCreation;
final String _packagesPath; final String _packagesPath;
final TargetModel _targetModel;
final List<String> _fileSystemRoots; final List<String> _fileSystemRoots;
final String _fileSystemScheme; final String _fileSystemScheme;
String _sdkRoot; String _sdkRoot;
...@@ -409,7 +445,7 @@ class ResidentCompiler { ...@@ -409,7 +445,7 @@ class ResidentCompiler {
_sdkRoot, _sdkRoot,
'--incremental', '--incremental',
'--strong', '--strong',
'--target=flutter', '--target=$_targetModel',
]; ];
if (outputPath != null) { if (outputPath != null) {
command.addAll(<String>['--output-dill', outputPath]); command.addAll(<String>['--output-dill', outputPath]);
......
...@@ -65,6 +65,7 @@ Future<T> runInContext<T>( ...@@ -65,6 +65,7 @@ Future<T> runInContext<T>(
DoctorValidatorsProvider: () => DoctorValidatorsProvider.defaultInstance, DoctorValidatorsProvider: () => DoctorValidatorsProvider.defaultInstance,
EmulatorManager: () => EmulatorManager(), EmulatorManager: () => EmulatorManager(),
FuchsiaSdk: () => FuchsiaSdk(), FuchsiaSdk: () => FuchsiaSdk(),
FuchsiaArtifacts: () => FuchsiaArtifacts(),
FuchsiaWorkflow: () => FuchsiaWorkflow(), FuchsiaWorkflow: () => FuchsiaWorkflow(),
Flags: () => const EmptyFlags(), Flags: () => const EmptyFlags(),
FlutterVersion: () => FlutterVersion(const Clock()), FlutterVersion: () => FlutterVersion(const Clock()),
......
...@@ -172,7 +172,7 @@ class FuchsiaDevice extends Device { ...@@ -172,7 +172,7 @@ class FuchsiaDevice extends Device {
/// Run `command` on the Fuchsia device shell. /// Run `command` on the Fuchsia device shell.
Future<String> shell(String command) async { Future<String> shell(String command) async {
final RunResult result = await runAsync(<String>[ 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) { if (result.exitCode != 0) {
throwToolExit('Command failed: $command\nstdout: ${result.stdout}\nstderr: ${result.stderr}'); throwToolExit('Command failed: $command\nstdout: ${result.stdout}\nstderr: ${result.stderr}');
return null; return null;
...@@ -228,7 +228,7 @@ class _FuchsiaPortForwarder extends DevicePortForwarder { ...@@ -228,7 +228,7 @@ class _FuchsiaPortForwarder extends DevicePortForwarder {
// Note: the provided command works around a bug in -N, see US-515 // Note: the provided command works around a bug in -N, see US-515
// for more explanation. // for more explanation.
final List<String> command = <String>[ 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' '-L', '$hostPort:$_ipv4Loopback:$devicePort', device.id, 'true'
]; ];
final Process process = await processManager.start(command); final Process process = await processManager.start(command);
...@@ -252,7 +252,7 @@ class _FuchsiaPortForwarder extends DevicePortForwarder { ...@@ -252,7 +252,7 @@ class _FuchsiaPortForwarder extends DevicePortForwarder {
final Process process = _processes.remove(forwardedPort.hostPort); final Process process = _processes.remove(forwardedPort.hostPort);
process?.kill(); process?.kill();
final List<String> command = <String>[ 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]; '-L', '${forwardedPort.hostPort}:$_ipv4Loopback:${forwardedPort.devicePort}', device.id];
final ProcessResult result = await processManager.run(command); final ProcessResult result = await processManager.run(command);
if (result.exitCode != 0) { if (result.exitCode != 0) {
......
...@@ -17,6 +17,9 @@ import '../globals.dart'; ...@@ -17,6 +17,9 @@ import '../globals.dart';
/// The [FuchsiaSdk] instance. /// The [FuchsiaSdk] instance.
FuchsiaSdk get fuchsiaSdk => context[FuchsiaSdk]; FuchsiaSdk get fuchsiaSdk => context[FuchsiaSdk];
/// The [FuchsiaArtifacts] instance.
FuchsiaArtifacts get fuchsiaArtifacts => context[FuchsiaArtifacts];
/// The Fuchsia SDK shell commands. /// The Fuchsia SDK shell commands.
/// ///
/// This workflow assumes development within the fuchsia source tree, /// This workflow assumes development within the fuchsia source tree,
...@@ -26,19 +29,6 @@ class FuchsiaSdk { ...@@ -26,19 +29,6 @@ class FuchsiaSdk {
static const List<String> _netlsCommand = <String>['fx', 'netls', '--nowait']; static const List<String> _netlsCommand = <String>['fx', 'netls', '--nowait'];
static const List<String> _syslogCommand = <String>['fx', 'syslog']; 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. /// Invokes the `netaddr` command.
/// ///
/// This returns the network address of an attached fuchsia device. Does /// This returns the network address of an attached fuchsia device. Does
...@@ -100,3 +90,26 @@ class FuchsiaSdk { ...@@ -100,3 +90,26 @@ class FuchsiaSdk {
return null; 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 { ...@@ -35,6 +35,7 @@ class FlutterDevice {
this.fileSystemRoots, this.fileSystemRoots,
this.fileSystemScheme, this.fileSystemScheme,
this.viewFilter, this.viewFilter,
TargetModel targetModel = TargetModel.flutter,
ResidentCompiler generator, ResidentCompiler generator,
}) : assert(trackWidgetCreation != null), }) : assert(trackWidgetCreation != null),
generator = generator ?? ResidentCompiler( generator = generator ?? ResidentCompiler(
...@@ -42,6 +43,7 @@ class FlutterDevice { ...@@ -42,6 +43,7 @@ class FlutterDevice {
trackWidgetCreation: trackWidgetCreation, trackWidgetCreation: trackWidgetCreation,
fileSystemRoots: fileSystemRoots, fileSystemRoots: fileSystemRoots,
fileSystemScheme: fileSystemScheme, fileSystemScheme: fileSystemScheme,
targetModel: targetModel,
); );
final Device device; final Device device;
......
...@@ -193,6 +193,23 @@ abstract class FlutterCommand extends Command<void> { ...@@ -193,6 +193,23 @@ abstract class FlutterCommand extends Command<void> {
'--release or --profile; --debug always has this enabled.'); '--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) { set defaultBuildMode(BuildMode value) {
_defaultBuildMode = 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