first commit

This commit is contained in:
Hidenori Matsubayashi
2021-07-16 13:03:30 +09:00
commit d10fcb6127
42 changed files with 4287 additions and 0 deletions
+24
View File
@@ -0,0 +1,24 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter_tools/src/commands/analyze.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import '../elinux_plugins.dart';
class ELinuxAnalyzeCommand extends AnalyzeCommand with ELinuxExtension {
ELinuxAnalyzeCommand({bool verboseHelp = false})
: super(
verboseHelp: verboseHelp,
fileSystem: globals.fs,
platform: globals.platform,
processManager: globals.processManager,
logger: globals.logger,
terminal: globals.terminal,
artifacts: globals.artifacts,
);
}
+15
View File
@@ -0,0 +1,15 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter_tools/src/commands/attach.dart';
import '../elinux_plugins.dart';
class ELinuxAttachCommand extends AttachCommand with ELinuxExtension {
ELinuxAttachCommand({bool verboseHelp = false})
: super(verboseHelp: verboseHelp);
}
+99
View File
@@ -0,0 +1,99 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter_tools/src/android/build_validation.dart' as android;
import 'package:flutter_tools/src/base/analyze_size.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/commands/build.dart';
import 'package:flutter_tools/src/commands/build_apk.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import '../elinux_builder.dart';
import '../elinux_cache.dart';
import '../elinux_plugins.dart';
class ELinuxBuildCommand extends BuildCommand {
ELinuxBuildCommand({bool verboseHelp = false})
: super(verboseHelp: verboseHelp) {
addSubcommand(BuildPackageCommand(verboseHelp: verboseHelp));
}
}
class BuildPackageCommand extends BuildSubCommand with ELinuxExtension {
/// See: [BuildApkCommand] in `build_apk.dart`
BuildPackageCommand({bool verboseHelp = false}) {
addCommonDesktopBuildOptions(verboseHelp: verboseHelp);
usesBuildNameOption();
argParser.addOption(
'target-arch',
defaultsTo: _getCurrentHostPlatformArchName(),
allowed: <String>['x64', 'arm64'],
help: 'Target architecture for which the the app is compiled',
);
argParser.addOption(
'target-backend-type',
defaultsTo: 'wayland',
allowed: <String>['wayland', 'gbm', 'eglstream', 'x11'],
help: 'Target backend type that the app will run on devices.',
);
}
@override
final String name = 'elinux';
@override
Future<Set<DevelopmentArtifact>> get requiredArtifacts async =>
<DevelopmentArtifact>{
DevelopmentArtifact.androidGenSnapshot,
ELinuxDevelopmentArtifact.elinux,
};
@override
final String description = 'Build an eLinux package from your app.';
/// See: [android.validateBuild] in `build_validation.dart`
void validateBuild(ELinuxBuildInfo eLinuxBuildInfo) {
if (eLinuxBuildInfo.buildInfo.mode.isPrecompiled &&
eLinuxBuildInfo.targetArch == 'x86') {
throwToolExit('x86 ABI does not support AOT compilation.');
}
}
/// See: [BuildApkCommand.runCommand] in `build_apk.dart`
@override
Future<FlutterCommandResult> runCommand() async {
final BuildInfo buildInfo = await getBuildInfo();
final ELinuxBuildInfo eLinuxBuildInfo = ELinuxBuildInfo(
buildInfo,
targetArch: stringArg('target-arch'),
targetBackendType: stringArg('target-backend-type'),
);
validateBuild(eLinuxBuildInfo);
displayNullSafetyMode(buildInfo);
await ELinuxBuilder.buildBundle(
project: FlutterProject.current(),
targetFile: targetFile,
eLinuxBuildInfo: eLinuxBuildInfo,
sizeAnalyzer: SizeAnalyzer(
fileSystem: globals.fs,
logger: globals.logger,
flutterUsage: globals.flutterUsage,
),
);
return FlutterCommandResult.success();
}
String _getCurrentHostPlatformArchName() {
final HostPlatform hostPlatform = getCurrentHostPlatform();
return getNameForHostPlatformArch(hostPlatform);
}
}
+54
View File
@@ -0,0 +1,54 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:file/file.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/commands/clean.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:path/path.dart';
import '../elinux_cmake_project.dart';
class ELinuxCleanCommand extends CleanCommand {
ELinuxCleanCommand({bool verbose = false}) : super(verbose: verbose);
/// See: [CleanCommand.runCommand] in `clean.dart`
@override
Future<FlutterCommandResult> runCommand() async {
final FlutterProject flutterProject = FlutterProject.current();
_cleanELinuxProject(ELinuxProject.fromFlutter(flutterProject));
return super.runCommand();
}
void _cleanELinuxProject(ELinuxProject project) {
if (!project.existsSync()) {
return;
}
_deleteFile(project.ephemeralDirectory);
}
/// Source: [CleanCommand.deleteFile] in `clean.dart` (simplified)
void _deleteFile(FileSystemEntity file) {
if (!file.existsSync()) {
return;
}
final String path = relative(file.path);
final Status status = globals.logger.startProgress(
'Deleting $path...',
);
try {
file.deleteSync(recursive: true);
} on FileSystemException catch (error) {
globals.printError('Failed to remove $path: $error');
} finally {
status?.stop();
}
}
}
+163
View File
@@ -0,0 +1,163 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Copyright 2014 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.
// @dart = 2.8
import 'package:file/file.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/create.dart';
import 'package:flutter_tools/src/flutter_project_metadata.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:flutter_tools/src/template.dart';
import '../elinux_plugins.dart';
class ELinuxCreateCommand extends CreateCommand {
ELinuxCreateCommand({bool verboseHelp = false})
: super(verboseHelp: verboseHelp) {
argParser.addOption(
'target-backend-type',
defaultsTo: 'wayland',
allowed: <String>['wayland', 'gbm', 'eglstream', 'x11'],
help: 'Target backend type that the app will run on devices.',
);
}
@override
void printUsage() {
super.printUsage();
// TODO(swift-kim): I couldn't find a proper way to override the --platforms
// option without copying the entire class. This message is a workaround.
print(
'You don\'t have to specify "elinux" as a target platform with '
'"--platforms" option. It is automatically added by default.',
);
}
/// See:
/// - [CreateCommand.runCommand] in `create.dart`
/// - [CreateCommand._getProjectType] in `create.dart` (generatePlugin)
Future<FlutterCommandResult> runInternal() async {
final FlutterCommandResult result = await super.runCommand();
if (result != FlutterCommandResult.success() || argResults.rest.isEmpty) {
return result;
}
final bool generatePlugin = argResults['template'] != null
? stringArg('template') ==
flutterProjectTypeToString(FlutterProjectType.plugin)
: determineTemplateType() == FlutterProjectType.plugin;
if (generatePlugin) {
// Assume that pubspec.yaml uses the multi-platforms plugin format if the
// file already exists.
// TODO(swift-kim): Skip this message if elinux already exists in pubspec.
globals.printStatus(
'The `pubspec.yaml` under the project directory must be updated to support ELinux.\n'
'Add below lines to under the `platforms:` key.',
emphasis: true,
color: TerminalColor.yellow,
);
final Map<String, dynamic> templateContext = createTemplateContext(
organization: '',
projectName: projectName,
flutterRoot: '',
);
globals.printStatus(
'\nelinux:\n'
' pluginClass: ${templateContext['pluginClass'] as String}\n'
' fileName: ${projectName}_plugin.h',
emphasis: true,
color: TerminalColor.blue,
);
globals.printStatus('');
}
if (boolArg('pub')) {
final FlutterProject project = FlutterProject.fromDirectory(projectDir);
await ensureReadyForELinuxTooling(project);
if (project.hasExampleApp) {
await ensureReadyForELinuxTooling(project.example);
}
}
return result;
}
/// See: [Template.render] in `template.dart`
@override
Future<FlutterCommandResult> runCommand() async {
// The template directory that the flutter tools search for available
// templates cannot be overriden because the implementation is private.
// So we have to copy eLinux templates into the directory manually.
final Directory eLinuxTemplates = globals.fs
.directory(Cache.flutterRoot)
.parent
.childDirectory('templates');
if (!eLinuxTemplates.existsSync()) {
throwToolExit('Could not locate eLinux templates.');
}
final File eLinuxTemplateManifest =
eLinuxTemplates.childFile('template_manifest.json');
final Directory templates = globals.fs
.directory(Cache.flutterRoot)
.childDirectory('packages')
.childDirectory('flutter_tools')
.childDirectory('templates');
final File templateManifest = templates.childFile('template_manifest.json');
// This is required due to: https://github.com/flutter/flutter/pull/59706
// TODO(swift-kim): Find any better workaround. One option is to override
// renderTemplate() but it may result in additional complexity.
eLinuxTemplateManifest.copySync(templateManifest.path);
final String backend = stringArg('target-backend-type');
final List<Directory> created = <Directory>[];
try {
for (final Directory projectType
in eLinuxTemplates.listSync().whereType<Directory>()) {
final Directory sourceRunnerCommon =
projectType.childDirectory('runner');
if (!sourceRunnerCommon.existsSync()) {
continue;
}
final Directory sourceFlutter = projectType.childDirectory('flutter');
if (!sourceFlutter.existsSync()) {
continue;
}
final Directory dest = templates
.childDirectory(projectType.basename)
.childDirectory('elinux.tmpl');
if (dest.existsSync()) {
dest.deleteSync(recursive: true);
}
copyDirectory(projectType, dest);
copyDirectory(sourceFlutter, dest.childDirectory('flutter'));
copyDirectory(sourceRunnerCommon, dest.childDirectory('runner'));
if (projectType.basename == 'app') {
final Directory sourceVariation =
projectType.childDirectory('runner_$backend');
if (!sourceVariation.existsSync()) {
continue;
}
copyDirectory(sourceVariation, dest.childDirectory('runner'));
}
created.add(dest);
}
return await runInternal();
} finally {
for (final Directory template in created) {
template.deleteSync(recursive: true);
}
}
}
}
+21
View File
@@ -0,0 +1,21 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter_tools/src/commands/drive.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import '../elinux_plugins.dart';
class ELinuxDriveCommand extends DriveCommand with ELinuxExtension {
ELinuxDriveCommand({bool verboseHelp = false})
: super(
verboseHelp: verboseHelp,
fileSystem: globals.fs,
logger: globals.logger,
platform: globals.platform,
);
}
+106
View File
@@ -0,0 +1,106 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Copyright 2014 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.
// @dart = 2.8
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/commands/packages.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import '../elinux_plugins.dart';
/// This class was copied from [PackagesCommand] to substitute its
/// [PackagesGetCommand] and [PackagesInteractiveGetCommand] subcommands with
/// their ELinux equivalents. We may find a better workaround in the future.
///
/// Source: [PackagesCommand] in `packages.dart`
class ELinuxPackagesCommand extends FlutterCommand {
ELinuxPackagesCommand() {
addSubcommand(ELinuxPackagesGetCommand('get', false));
addSubcommand(ELinuxPackagesInteractiveGetCommand('upgrade',
'Upgrade the current package\'s dependencies to latest versions.'));
addSubcommand(ELinuxPackagesInteractiveGetCommand(
'add', 'Add a dependency to pubspec.yaml.'));
addSubcommand(ELinuxPackagesInteractiveGetCommand(
'remove', 'Removes a dependency from the current package.'));
addSubcommand(PackagesTestCommand());
addSubcommand(PackagesForwardCommand(
'publish', 'Publish the current package to pub.dartlang.org',
requiresPubspec: true));
addSubcommand(PackagesForwardCommand(
'downgrade', 'Downgrade packages in a Flutter project',
requiresPubspec: true));
addSubcommand(PackagesForwardCommand('deps', 'Print package dependencies',
requiresPubspec: true));
addSubcommand(PackagesForwardCommand(
'run', 'Run an executable from a package',
requiresPubspec: true));
addSubcommand(
PackagesForwardCommand('cache', 'Work with the Pub system cache'));
addSubcommand(PackagesForwardCommand('version', 'Print Pub version'));
addSubcommand(PackagesForwardCommand(
'uploader', 'Manage uploaders for a package on pub.dev'));
addSubcommand(PackagesForwardCommand('login', 'Log into pub.dev.'));
addSubcommand(PackagesForwardCommand('logout', 'Log out of pub.dev.'));
addSubcommand(
PackagesForwardCommand('global', 'Work with Pub global packages'));
addSubcommand(PackagesForwardCommand(
'outdated', 'Analyze dependencies to find which ones can be upgraded',
requiresPubspec: true));
addSubcommand(PackagesPassthroughCommand());
}
@override
final String name = 'pub';
@override
List<String> get aliases => const <String>['packages'];
@override
final String description = 'Commands for managing Flutter packages.';
@override
Future<FlutterCommandResult> runCommand() async => null;
}
class ELinuxPackagesGetCommand extends PackagesGetCommand
with _PostRunPluginInjection {
ELinuxPackagesGetCommand(String name, bool upgrade) : super(name, upgrade);
}
class ELinuxPackagesInteractiveGetCommand extends PackagesInteractiveGetCommand
with _PostRunPluginInjection {
ELinuxPackagesInteractiveGetCommand(String commandName, String description)
: super(commandName, description);
}
mixin _PostRunPluginInjection on FlutterCommand {
/// See: [PackagesGetCommand.runCommand] in `packages.dart`
@override
Future<FlutterCommandResult> runCommand() async {
final FlutterCommandResult result = await super.runCommand();
if (result == FlutterCommandResult.success()) {
final String workingDirectory =
argResults.rest.isNotEmpty ? argResults.rest[0] : null;
final String target = findProjectRoot(globals.fs, workingDirectory);
if (target == null) {
return result;
}
final FlutterProject rootProject =
FlutterProject.fromDirectory(globals.fs.directory(target));
await ensureReadyForELinuxTooling(rootProject);
if (rootProject.hasExampleApp &&
rootProject.example.pubspecFile.existsSync()) {
await ensureReadyForELinuxTooling(rootProject.example);
}
}
return result;
}
}
+86
View File
@@ -0,0 +1,86 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2021 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/precache.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:meta/meta.dart';
import '../elinux_cache.dart';
class ELinuxPrecacheCommand extends PrecacheCommand {
ELinuxPrecacheCommand({
bool verboseHelp = false,
@required Cache cache,
@required Platform platform,
@required Logger logger,
@required FeatureFlags featureFlags,
}) : _cache = cache,
_platform = platform,
super(
verboseHelp: verboseHelp,
cache: cache,
platform: platform,
logger: logger,
featureFlags: featureFlags,
) {
argParser.addFlag(
'elinux',
negatable: true,
defaultsTo: false,
help: 'Precache artifacts for Embedded Linux development.',
);
}
final Cache _cache;
final Platform _platform;
bool get _includeOtherPlatforms =>
boolArg('android') ||
DevelopmentArtifact.values.any((DevelopmentArtifact artifact) =>
boolArg(artifact.name) && argResults.wasParsed(artifact.name));
@override
Future<FlutterCommandResult> runCommand() async {
final bool includeAllPlatforms = boolArg('all-platforms');
final bool includeELinux = boolArg('elinux');
final bool includeDefaults = !includeELinux && !_includeOtherPlatforms;
const String elinuxStampName = 'elinux-sdk';
// Re-lock the cache.
if (_platform.environment['FLUTTER_ALREADY_LOCKED'] != 'true') {
await _cache.lock();
}
if (includeAllPlatforms || includeDefaults || includeELinux) {
if (boolArg('force')) {
_cache.setStampFor(elinuxStampName, '');
}
await _cache.updateAll(<DevelopmentArtifact>{
ELinuxDevelopmentArtifact.elinux,
});
}
if (includeAllPlatforms || includeDefaults || _includeOtherPlatforms) {
// If the '--force' option is used, the super.runCommand() will delete
// the elinux's stamp file. It should be restored.
final String elinuxStamp = _cache.getStampFor(elinuxStampName);
final FlutterCommandResult result = await super.runCommand();
if (elinuxStamp != null) {
_cache.setStampFor(elinuxStampName, elinuxStamp);
}
return result;
}
return FlutterCommandResult.success();
}
}
+31
View File
@@ -0,0 +1,31 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/run.dart';
import '../elinux_cache.dart';
import '../elinux_plugins.dart';
class ELinuxRunCommand extends RunCommand with ELinuxExtension {
ELinuxRunCommand({bool verboseHelp = false})
: super(verboseHelp: verboseHelp) {
argParser.addOption(
'target-backend-type',
defaultsTo: 'wayland',
allowed: <String>['wayland', 'gbm', 'eglstream', 'x11'],
help: 'Target backend type that the app will run on devices.',
);
}
@override
Future<Set<DevelopmentArtifact>> get requiredArtifacts async =>
<DevelopmentArtifact>{
DevelopmentArtifact.androidGenSnapshot,
ELinuxDevelopmentArtifact.elinux,
};
}
+15
View File
@@ -0,0 +1,15 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2021 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter_tools/src/commands/test.dart';
import '../elinux_plugins.dart';
class ELinuxTestCommand extends TestCommand with ELinuxExtension {
ELinuxTestCommand({bool verboseHelp = false})
: super(verboseHelp: verboseHelp);
}
+436
View File
@@ -0,0 +1,436 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Copyright 2014 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.
// @dart = 2.8
import 'dart:io';
import 'package:file/file.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/process.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/build_system/depfile.dart';
import 'package:flutter_tools/src/build_system/exceptions.dart';
import 'package:flutter_tools/src/build_system/source.dart';
import 'package:flutter_tools/src/build_system/targets/android.dart';
import 'package:flutter_tools/src/build_system/targets/assets.dart';
import 'package:flutter_tools/src/build_system/targets/common.dart';
import 'package:flutter_tools/src/build_system/targets/icon_tree_shaker.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/cmake.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/project.dart';
import 'elinux_builder.dart';
import 'elinux_cmake_project.dart';
import 'elinux_plugins.dart';
/// Prepares the pre-built flutter bundle.
///
/// Source: [AndroidAssetBundle] in `android.dart`
abstract class ELinuxAssetBundle extends Target {
const ELinuxAssetBundle();
@override
String get name => 'elinux_asset_bundle';
@override
List<Source> get inputs => const <Source>[
Source.pattern('{BUILD_DIR}/app.dill'),
...IconTreeShaker.inputs,
];
@override
List<Source> get outputs => const <Source>[];
@override
List<String> get depfiles => <String>[
'flutter_assets.d',
];
@override
List<Target> get dependencies => const <Target>[
KernelSnapshot(),
];
@override
Future<void> build(Environment environment) async {
if (environment.defines[kBuildMode] == null) {
throw MissingDefineException(kBuildMode, name);
}
final BuildMode buildMode =
getBuildModeForName(environment.defines[kBuildMode]);
final Directory outputDirectory = environment.outputDir
.childDirectory('flutter_assets')
..createSync(recursive: true);
// Only copy the prebuilt runtimes and kernel blob in debug mode.
if (buildMode == BuildMode.debug) {
final String vmSnapshotData = environment.artifacts
.getArtifactPath(Artifact.vmSnapshotData, mode: BuildMode.debug);
final String isolateSnapshotData = environment.artifacts
.getArtifactPath(Artifact.isolateSnapshotData, mode: BuildMode.debug);
environment.buildDir
.childFile('app.dill')
.copySync(outputDirectory.childFile('kernel_blob.bin').path);
environment.fileSystem
.file(vmSnapshotData)
.copySync(outputDirectory.childFile('vm_snapshot_data').path);
environment.fileSystem
.file(isolateSnapshotData)
.copySync(outputDirectory.childFile('isolate_snapshot_data').path);
}
final Depfile assetDepfile = await copyAssets(
environment,
outputDirectory,
targetPlatform: null, // corresponds to flutter-tester
);
final DepfileService depfileService = DepfileService(
fileSystem: environment.fileSystem,
logger: environment.logger,
);
depfileService.writeToFile(
assetDepfile,
environment.buildDir.childFile('flutter_assets.d'),
);
}
}
/// Source: [DebugAndroidApplication] in `android.dart`
class DebugELinuxApplication extends ELinuxAssetBundle {
DebugELinuxApplication(this.buildInfo);
final ELinuxBuildInfo buildInfo;
@override
String get name => 'debug_elinux_application';
@override
List<Source> get inputs => <Source>[
...super.inputs,
const Source.artifact(Artifact.vmSnapshotData, mode: BuildMode.debug),
const Source.artifact(Artifact.isolateSnapshotData,
mode: BuildMode.debug),
];
@override
List<Source> get outputs => <Source>[
...super.outputs,
const Source.pattern('{OUTPUT_DIR}/flutter_assets/vm_snapshot_data'),
const Source.pattern(
'{OUTPUT_DIR}/flutter_assets/isolate_snapshot_data'),
const Source.pattern('{OUTPUT_DIR}/flutter_assets/kernel_blob.bin'),
];
@override
List<Target> get dependencies => <Target>[
...super.dependencies,
ELinuxPlugins(buildInfo),
];
}
/// See: [ReleaseAndroidApplication] in `android.dart`
class ReleaseELinuxApplication extends ELinuxAssetBundle {
ReleaseELinuxApplication(this.buildInfo);
final ELinuxBuildInfo buildInfo;
@override
String get name => 'release_elinux_application';
@override
List<Target> get dependencies => <Target>[
...super.dependencies,
ELinuxAotElf(),
ELinuxPlugins(buildInfo),
];
}
/// Compiles eLinux native plugins into a single shared object.
class ELinuxPlugins extends Target {
ELinuxPlugins(this.buildInfo);
final ELinuxBuildInfo buildInfo;
@override
String get name => 'elinux_plugins';
@override
List<Source> get inputs => const <Source>[
Source.pattern('{FLUTTER_ROOT}/../lib/elinux_build_target.dart'),
Source.pattern('{PROJECT_DIR}/.packages'),
];
@override
List<Source> get outputs => const <Source>[];
@override
List<String> get depfiles => <String>[
'elinux_plugins.d',
];
@override
List<Target> get dependencies => const <Target>[];
@override
Future<void> build(Environment environment) async {
// todo: add plugin build support.
}
}
/// Generates an AOT snapshot (app.so) of the Dart code.
///
/// Source: [AotElfRelease] in `common.dart`
class ELinuxAotElf extends AotElfBase {
ELinuxAotElf();
@override
String get name => 'elinux_aot_elf';
@override
List<Source> get inputs => <Source>[
const Source.pattern('{BUILD_DIR}/app.dill'),
const Source.hostArtifact(HostArtifact.engineDartBinary),
const Source.artifact(Artifact.skyEnginePath),
// Any type of gen_snapshot is applicable here because engine artifacts
// are assumed to be updated at once, not one by one for each platform
// or build mode.
const Source.artifact(Artifact.genSnapshot, mode: BuildMode.release),
];
@override
List<Source> get outputs => const <Source>[
Source.pattern('{BUILD_DIR}/app.so'),
];
@override
List<Target> get dependencies => const <Target>[
KernelSnapshot(),
];
}
class NativeBundle {
NativeBundle(this.buildInfo, this.targetFile);
final ELinuxBuildInfo buildInfo;
final String targetFile;
final ProcessUtils _processUtils = ProcessUtils(
logger: globals.logger, processManager: globals.processManager);
Future<void> build(Environment environment) async {
final FlutterProject project =
FlutterProject.fromDirectory(environment.projectDir);
final ELinuxProject eLinuxProject = ELinuxProject.fromFlutter(project);
// Clean up the intermediate and output directories.
final Directory eLinuxDir = eLinuxProject.editableDirectory;
final BuildMode buildMode = buildInfo.buildInfo.mode;
final String buildConfig = buildMode.isPrecompiled ? 'release' : 'debug';
final Directory outputDir = environment.outputDir
.childDirectory(buildInfo.targetArch)
.childDirectory(buildConfig);
if (outputDir.existsSync()) {
outputDir.deleteSync(recursive: true);
}
outputDir.createSync(recursive: true);
final Directory outputBundleDir = outputDir.childDirectory('bundle');
if (outputBundleDir.existsSync()) {
outputBundleDir.deleteSync(recursive: true);
}
outputBundleDir.createSync(recursive: true);
final Directory outputBundleLibDir = outputBundleDir.childDirectory('lib');
if (outputBundleLibDir.existsSync()) {
outputBundleLibDir.deleteSync(recursive: true);
}
outputBundleLibDir.createSync(recursive: true);
final Directory outputBundleDataDir =
outputBundleDir.childDirectory('data');
if (outputBundleDataDir.existsSync()) {
outputBundleDataDir.deleteSync(recursive: true);
}
outputBundleDataDir.createSync(recursive: true);
// Copy necessary files
final Directory engineDir =
_getEngineArtifactsDirectory(buildInfo.targetArch, buildMode);
final Directory commonDir =
engineDir.parent.childDirectory('elinux-common');
final File engineBinary = engineDir.childFile('libflutter_engine.so');
final File embedder =
engineDir.childFile(buildInfo.targetBackendType == 'gbm'
? 'libflutter_elinux_gbm.so'
: buildInfo.targetBackendType == 'eglstream'
? 'libflutter_elinux_eglstream.so'
: buildInfo.targetBackendType == 'x11'
? 'libflutter_elinux_x11.so'
: 'libflutter_elinux_wayland.so');
final Directory clientWrapperDir =
commonDir.childDirectory('cpp_client_wrapper');
final Directory pluginsDir =
environment.buildDir.childDirectory('elinux_plugins');
final File pluginsLib = pluginsDir.childFile('libflutter_plugins.so');
if (pluginsLib.existsSync()) {
pluginsLib
.copySync(outputBundleLibDir.childFile(pluginsLib.basename).path);
}
final Directory pluginsUserLibDir = pluginsDir.childDirectory('lib');
if (pluginsUserLibDir.existsSync()) {
pluginsUserLibDir.listSync().whereType<File>().forEach((File lib) =>
lib.copySync(outputBundleLibDir.childFile(lib.basename).path));
}
final Directory flutterDir = eLinuxDir.childDirectory('flutter');
final Directory flutterEphemeralDir =
flutterDir.childDirectory('ephemeral');
// Copy necessary files.
{
if (flutterEphemeralDir.existsSync()) {
flutterEphemeralDir.deleteSync(recursive: true);
}
flutterEphemeralDir.createSync(recursive: true);
flutterEphemeralDir
.childDirectory('cpp_client_wrapper')
.createSync(recursive: true);
copyDirectory(
clientWrapperDir,
flutterEphemeralDir.childDirectory('cpp_client_wrapper'),
);
commonDir.listSync().whereType<File>().forEach((File lib) =>
lib.copySync(flutterEphemeralDir.childFile(lib.basename).path));
engineBinary
.copySync(flutterEphemeralDir.childFile(engineBinary.basename).path);
embedder.copySync(flutterEphemeralDir.childFile(embedder.basename).path);
final File icuData =
commonDir.childDirectory('icu').childFile('icudtl.dat');
icuData.copySync(flutterEphemeralDir.childFile(icuData.basename).path);
if (buildMode.isPrecompiled) {
final File aotSharedLib = environment.buildDir.childFile('app.so');
aotSharedLib.copySync(flutterEphemeralDir.childFile('libapp.so').path);
}
}
// Build the environment that needs to be set for the re-entrant flutter build
// step.
{
final Map<String, String> environment = <String, String>{
if (targetFile != null) 'FLUTTER_TARGET': targetFile,
...buildInfo.buildInfo.toEnvironmentConfig(),
};
if (globals.artifacts is LocalEngineArtifacts) {
final LocalEngineArtifacts localEngineArtifacts =
globals.artifacts as LocalEngineArtifacts;
final String engineOutPath = localEngineArtifacts.engineOutPath;
environment['FLUTTER_ENGINE'] =
globals.fs.path.dirname(globals.fs.path.dirname(engineOutPath));
environment['LOCAL_ENGINE'] = globals.fs.path.basename(engineOutPath);
}
writeGeneratedCmakeConfig(Cache.flutterRoot, eLinuxProject, environment);
//createPluginSymlinks(eLinuxProject.parent);
}
// Run the native build.
final String cmakeBuildType = buildMode.isPrecompiled ? 'Release' : 'Debug';
RunResult result = await _processUtils.run(
<String>[
'cmake',
'-DCMAKE_BUILD_TYPE=$cmakeBuildType',
'-DFLUTTER_TARGET_BACKEND_TYPE=${buildInfo.targetBackendType}',
eLinuxDir.path,
],
workingDirectory: outputDir.path,
environment: <String, String>{'CC': 'clang', 'CXX': 'clang++'},
);
if (result.exitCode != 0) {
throwToolExit('Failed to cmake:\n$result');
}
result = await _processUtils.run(
<String>['cmake', '--build', '.'],
workingDirectory: outputDir.path,
);
if (result.exitCode != 0) {
throwToolExit('Failed to cmake build:\n$result');
}
// Create flutter app's bunle.
result = await _processUtils.run(
<String>['cmake', '--install', '.'],
workingDirectory: outputDir.path,
);
if (result.exitCode != 0) {
throwToolExit('Failed to cmake install:\n$result');
}
{
final Directory flutterAssetsDir =
outputBundleDataDir.childDirectory('flutter_assets');
copyDirectory(
environment.outputDir.childDirectory('flutter_assets'),
flutterAssetsDir,
);
}
}
}
/// Converts [targetArch] to an arch name that corresponds to the `BUILD_ARCH`
/// value used by the eLinux native builder.
String getELinuxBuildArch(String targetArch) {
switch (targetArch) {
case 'arm':
return 'armel';
case 'arm64':
return 'aarch64';
case 'x86':
return 'i586';
default:
return targetArch;
}
}
/// On non-Windows, returns [path] unchanged.
///
/// On Windows, converts Windows-style [path] (e.g. 'C:\x\y') into Unix path
/// ('/c/x/y') and returns.
String getUnixPath(String path) {
if (Platform.isWindows) {
path = path.replaceAll(r'\', '/');
if (path.startsWith(':', 1)) {
path = '/${path[0].toLowerCase()}${path.substring(2)}';
}
}
return path;
}
/// On non-Windows, returns the PATH environment variable.
///
/// On Windows, appends the msys2 executables directory to PATH and returns.
String getDefaultPathVariable() {
final Map<String, String> variables = globals.platform.environment;
return variables.containsKey('PATH') ? variables['PATH'] : '';
}
/// See: [CachedArtifacts._getEngineArtifactsPath]
Directory _getEngineArtifactsDirectory(String arch, BuildMode mode) {
assert(mode != null, 'Need to specify a build mode.');
return globals.cache
.getArtifactDirectory('engine')
.childDirectory('elinux-$arch-${mode.name}');
}
+150
View File
@@ -0,0 +1,150 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Copyright 2014 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.
// @dart = 2.8
import 'package:file/file.dart';
import 'package:flutter_tools/src/android/android_builder.dart';
import 'package:flutter_tools/src/android/gradle.dart';
import 'package:flutter_tools/src/base/analyze_size.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/assemble.dart';
import 'package:flutter_tools/src/commands/build_ios_framework.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/linux/build_linux.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:meta/meta.dart';
import 'elinux_build_target.dart';
import 'elinux_cmake_project.dart';
/// The define to control what eLinux device is built for.
const String kTargetBackendType = 'TargetBackendType';
/// See: [AndroidBuildInfo] in `build_info.dart`
class ELinuxBuildInfo {
const ELinuxBuildInfo(
this.buildInfo, {
@required this.targetArch,
@required this.targetBackendType,
}) : assert(targetArch != null),
assert(targetBackendType != null);
final BuildInfo buildInfo;
final String targetArch;
final String targetBackendType;
}
/// See:
/// - [AndroidBuilder] in `android_builder.dart`
/// - [AndroidGradleBuilder.buildGradleApp] in `gradle.dart`
/// - [BuildIOSFrameworkCommand._produceAppFramework] in `build_ios_framework.dart` (build target)
/// - [AssembleCommand.runCommand] in `assemble.dart` (performance measurement)
/// - [buildLinux] in `build_linux.dart` (code size)
class ELinuxBuilder {
static Future<void> buildBundle({
@required FlutterProject project,
@required ELinuxBuildInfo eLinuxBuildInfo,
@required String targetFile,
SizeAnalyzer sizeAnalyzer,
}) async {
final ELinuxProject elinuxProject = ELinuxProject.fromFlutter(project);
if (!elinuxProject.existsSync()) {
throwToolExit(
'This project is not configured for eLinux.\n'
'To fix this problem, create a new project by running `flutter-elinux create <app-dir>`.',
);
}
final Directory outputDir =
project.directory.childDirectory('build').childDirectory('elinux');
final BuildInfo buildInfo = eLinuxBuildInfo.buildInfo;
final String buildModeName = getNameForBuildMode(buildInfo.mode);
// Used by AotElfBase to generate an AOT snapshot.
final String targetPlatform = getNameForTargetPlatform(
_getTargetPlatformForArch(eLinuxBuildInfo.targetArch));
final Environment environment = Environment(
projectDir: project.directory,
outputDir: outputDir,
buildDir: project.dartTool.childDirectory('flutter_build'),
cacheDir: globals.cache.getRoot(),
flutterRootDir: globals.fs.directory(Cache.flutterRoot),
engineVersion: globals.flutterVersion.engineRevision,
generateDartPluginRegistry: true,
defines: <String, String>{
kTargetFile: targetFile,
kBuildMode: buildModeName,
kTargetPlatform: targetPlatform,
kDartObfuscation: buildInfo.dartObfuscation.toString(),
kSplitDebugInfo: buildInfo.splitDebugInfoPath,
kIconTreeShakerFlag: buildInfo.treeShakeIcons.toString(),
kTrackWidgetCreation: buildInfo.trackWidgetCreation.toString(),
kCodeSizeDirectory: buildInfo.codeSizeDirectory,
if (buildInfo.dartDefines?.isNotEmpty ?? false)
kDartDefines: encodeDartDefines(buildInfo.dartDefines),
if (buildInfo.extraGenSnapshotOptions?.isNotEmpty ?? false)
kExtraGenSnapshotOptions: buildInfo.extraGenSnapshotOptions.join(','),
if (buildInfo.extraFrontEndOptions?.isNotEmpty ?? false)
kExtraFrontEndOptions: buildInfo.extraFrontEndOptions.join(','),
kTargetBackendType: eLinuxBuildInfo.targetBackendType,
},
inputs: <String, String>{
kBundleSkSLPath: buildInfo.bundleSkSLPath,
},
artifacts: globals.artifacts,
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
platform: globals.platform,
);
final Target target = buildInfo.isDebug
? DebugELinuxApplication(eLinuxBuildInfo)
: ReleaseELinuxApplication(eLinuxBuildInfo);
final Status status = globals.logger.startProgress(
'Building an eLinux application with ${eLinuxBuildInfo.targetBackendType} backend in $buildModeName mode for ${eLinuxBuildInfo.targetArch} target...');
try {
final BuildResult result =
await globals.buildSystem.build(target, environment);
if (!result.success) {
for (final ExceptionMeasurement measurement
in result.exceptions.values) {
globals.printError(measurement.exception.toString());
}
throwToolExit('The build failed.');
}
// These pseudo targets cannot be skipped and should be invoked whenever
// the build is run.
await NativeBundle(eLinuxBuildInfo, targetFile).build(environment);
if (buildInfo.performanceMeasurementFile != null) {
final File outFile =
globals.fs.file(buildInfo.performanceMeasurementFile);
// ignore: invalid_use_of_visible_for_testing_member
writePerformanceData(result.performance.values, outFile);
}
} finally {
status.stop();
}
}
}
/// See: [getTargetPlatformForName] in `build_info.dart`
TargetPlatform _getTargetPlatformForArch(String arch) {
switch (arch) {
case 'arm64':
return TargetPlatform.android_arm64;
default:
return TargetPlatform.android_x64;
}
}
+133
View File
@@ -0,0 +1,133 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/os.dart' show OperatingSystemUtils;
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/flutter_cache.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:meta/meta.dart';
/// See: [DevelopmentArtifact] in `cache.dart`
class ELinuxDevelopmentArtifact implements DevelopmentArtifact {
const ELinuxDevelopmentArtifact._(this.name, this.feature);
@override
final String name;
@override
final Feature feature;
static const DevelopmentArtifact elinux =
ELinuxDevelopmentArtifact._('elinux', null);
}
/// Extends [FlutterCache] to register [ELinuxEngineArtifacts].
///
/// See: [FlutterCache] in `flutter_cache.dart`
class ELinuxFlutterCache extends FlutterCache {
ELinuxFlutterCache({
@required Logger logger,
@required FileSystem fileSystem,
@required Platform platform,
@required OperatingSystemUtils osUtils,
}) : super(
logger: logger,
fileSystem: fileSystem,
platform: platform,
osUtils: osUtils) {
registerArtifact(ELinuxEngineArtifacts(this, platform: platform));
}
}
class ELinuxEngineArtifacts extends EngineCachedArtifact {
ELinuxEngineArtifacts(
Cache cache, {
@required Platform platform,
}) : _platform = platform,
super(
'elinux-sdk',
cache,
ELinuxDevelopmentArtifact.elinux,
);
final Platform _platform;
@override
String get version {
final File versionFile = globals.fs
.directory(Cache.flutterRoot)
.parent
.childDirectory('bin')
.childDirectory('internal')
.childFile('engine.version');
return versionFile.existsSync()
? versionFile.readAsStringSync().trim()
: null;
}
String get shortVersion {
if (version != null && version.length >= 10) {
return version.substring(0, 10);
}
return version;
}
/// See: [Cache.storageBaseUrl] in `cache.dart`
String get engineBaseUrl {
final String overrideUrl = _platform.environment['ELINUX_ENGINE_BASE_URL'];
if (overrideUrl == null) {
return 'https://github.com/sony/flutter-embedded-linux/releases';
}
try {
Uri.parse(overrideUrl);
} on FormatException catch (err) {
throwToolExit('"ELINUX_ENGINE_BASE_URL" contains an invalid URI:\n$err');
}
return overrideUrl;
}
@override
List<List<String>> getBinaryDirs() => <List<String>>[
<String>['elinux-common', 'elinux-common.zip'],
<String>['elinux-arm64-debug', 'elinux-arm64-debug.zip'],
<String>['elinux-arm64-profile', 'elinux-arm64-profile.zip'],
<String>['elinux-arm64-release', 'elinux-arm64-release.zip'],
<String>['elinux-x64-debug', 'elinux-x64-debug.zip'],
<String>['elinux-x64-profile', 'elinux-x64-profile.zip'],
<String>['elinux-x64-release', 'elinux-x64-release.zip'],
];
@override
List<String> getLicenseDirs() => const <String>[];
@override
List<String> getPackageDirs() => const <String>[];
@override
Future<void> updateInner(
ArtifactUpdater artifactUpdater,
FileSystem fileSystem,
OperatingSystemUtils operatingSystemUtils,
) async {
final String downloadUrl = '$engineBaseUrl/download/$shortVersion';
for (final List<String> toolsDir in getBinaryDirs()) {
final String cacheDir = toolsDir[0];
final String urlPath = toolsDir[1];
await artifactUpdater.downloadZipArchive(
'Downloading $cacheDir tools...',
Uri.parse('$downloadUrl/$urlPath'),
location.childDirectory(cacheDir),
);
}
}
}
+54
View File
@@ -0,0 +1,54 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2014 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 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/project.dart';
import 'elinux_plugins.dart';
/// The eLinux sub project.
class ELinuxProject extends FlutterProjectPlatform
implements CmakeBasedProject {
ELinuxProject.fromFlutter(this.parent);
@override
final FlutterProject parent;
@override
String get pluginConfigKey => ELinuxPlugin.kConfigKey;
String get _childDirectory => 'elinux';
@override
bool existsSync() => editableDirectory.existsSync() && cmakeFile.existsSync();
@override
File get cmakeFile => editableDirectory.childFile('CMakeLists.txt');
@override
File get managedCmakeFile => managedDirectory.childFile('CMakeLists.txt');
@override
File get generatedCmakeConfigFile =>
ephemeralDirectory.childFile('generated_config.cmake');
@override
File get generatedPluginCmakeFile =>
managedDirectory.childFile('generated_plugins.cmake');
@override
Directory get pluginSymlinkDirectory =>
ephemeralDirectory.childDirectory('.plugin_symlinks');
Directory get editableDirectory =>
parent.directory.childDirectory(_childDirectory);
Directory get managedDirectory => editableDirectory.childDirectory('flutter');
Directory get ephemeralDirectory =>
managedDirectory.childDirectory('ephemeral');
Future<void> ensureReadyForPlatformSpecificTooling() async {}
}
+356
View File
@@ -0,0 +1,356 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2014 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.
// @dart = 2.8
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter_tools/src/android/android_device.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/convert.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/device_port_forwarder.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/protocol_discovery.dart';
import 'package:meta/meta.dart';
import 'package:process/process.dart';
import 'elinux_builder.dart';
import 'elinux_package.dart';
/// eLinux device implementation.
///
/// See: [DesktopDevice] in `desktop_device.dart`
class ELinuxDevice extends Device {
ELinuxDevice(
String id, {
@required bool desktop,
@required String backendType,
@required String targetArch,
@required Logger logger,
@required ProcessManager processManager,
@required OperatingSystemUtils operatingSystemUtils,
}) : _desktop = desktop,
_backendType = backendType,
_targetArch = targetArch,
_logger = logger,
_processManager = processManager,
_operatingSystemUtils = operatingSystemUtils,
super(id,
category: Category.desktop,
platformType: PlatformType.custom,
ephemeral: true);
final bool _desktop;
final String _backendType;
final String _targetArch;
final Logger _logger;
final ProcessManager _processManager;
final OperatingSystemUtils _operatingSystemUtils;
final Set<Process> _runningProcesses = <Process>{};
final ELinuxLogReader _logReader = ELinuxLogReader();
@override
Future<bool> get isLocalEmulator async => false;
@override
Future<String> get emulatorId async => null;
@override
Future<TargetPlatform> get targetPlatform async {
// Use tester as a platform identifer for eLinux.
// There's currently no other choice because getNameForTargetPlatform()
// throws an error for unknown platform types.
return TargetPlatform.tester;
}
@override
bool supportsRuntimeMode(BuildMode buildMode) =>
buildMode != BuildMode.jitRelease;
@override
Future<String> get sdkNameAndVersion async => _operatingSystemUtils.name;
@override
String get name => 'eLinux';
@override
Future<bool> isAppInstalled(ELinuxApp app, {String userIdentifier}) async {
return true;
}
@override
Future<bool> isLatestBuildInstalled(ELinuxApp app) async {
return true;
}
@override
Future<bool> installApp(ELinuxApp app, {String userIdentifier}) async {
return true;
}
@override
Future<bool> uninstallApp(ELinuxApp app, {String userIdentifier}) async {
return true;
}
/// Source: [AndroidDevice.startApp] in `android_device.dart`
@override
Future<LaunchResult> startApp(
ELinuxApp package, {
String mainPath,
String route,
DebuggingOptions debuggingOptions,
Map<String, dynamic> platformArgs,
bool prebuiltApplication = false,
bool ipv6 = false,
String userIdentifier,
}) async {
if (!prebuiltApplication) {
_logger.printTrace('Building app');
await buildForDevice(
package,
buildInfo: debuggingOptions.buildInfo,
mainPath: mainPath,
);
}
// Ensure that the executable is locatable.
final BuildMode buildMode = debuggingOptions?.buildInfo?.mode;
final bool traceStartup = platformArgs['trace-startup'] as bool ?? false;
final String executable = executablePathForDevice(package, buildMode);
const String executableOptions = '--bundle=./';
if (executable == null) {
_logger.printError('Unable to find executable to run');
return LaunchResult.failed();
}
final Process process = await _processManager.start(
<String>[
executable,
executableOptions,
if (_desktop && _backendType == 'wayland') '-d',
...?debuggingOptions?.dartEntrypointArgs,
],
environment: _computeEnvironment(debuggingOptions, traceStartup, route),
);
_runningProcesses.add(process);
unawaited(process.exitCode.then((_) => _runningProcesses.remove(process)));
_logReader.initializeProcess(process);
if (debuggingOptions?.buildInfo?.isRelease == true) {
return LaunchResult.succeeded();
}
final ProtocolDiscovery observatoryDiscovery =
ProtocolDiscovery.observatory(
_logReader,
devicePort: debuggingOptions?.deviceVmServicePort,
hostPort: debuggingOptions?.hostVmServicePort,
ipv6: ipv6,
logger: _logger,
);
try {
final Uri observatoryUri = await observatoryDiscovery.uri;
if (observatoryUri != null) {
onAttached(package, buildMode, process);
return LaunchResult.succeeded(observatoryUri: observatoryUri);
}
_logger.printError(
'Error waiting for a debug connection: '
'The log reader stopped unexpectedly.',
);
} on Exception catch (error) {
_logger.printError('Error waiting for a debug connection: $error');
} finally {
await observatoryDiscovery.cancel();
}
return LaunchResult.failed();
}
@override
Future<bool> stopApp(ELinuxApp app, {String userIdentifier}) async {
bool succeeded = true;
// Walk a copy of _runningProcesses, since the exit handler removes from the
// set.
for (final Process process in Set<Process>.of(_runningProcesses)) {
succeeded &= _processManager.killPid(process.pid);
}
return succeeded;
}
@override
void clearLogs() {}
@override
FutureOr<DeviceLogReader> getLogReader({
ELinuxApp app,
bool includePastLogs = false,
}) =>
_logReader;
@override
DevicePortForwarder get portForwarder => null;
@override
bool isSupported() => true;
@override
bool get supportsScreenshot => false;
@override
bool isSupportedForProject(FlutterProject flutterProject) {
return flutterProject.isModule &&
flutterProject.directory.childDirectory('elinux').existsSync();
}
@override
Future<void> dispose() async {}
Future<void> buildForDevice(
ELinuxApp package, {
String mainPath,
BuildInfo buildInfo,
}) async {
final FlutterProject project = FlutterProject.current();
final ELinuxBuildInfo eLinuxBuildInfo = ELinuxBuildInfo(
buildInfo,
targetArch: _targetArch,
targetBackendType: _backendType,
);
await ELinuxBuilder.buildBundle(
project: project,
targetFile: mainPath,
eLinuxBuildInfo: eLinuxBuildInfo,
);
package = ELinuxApp.fromELinuxProject(project);
}
String executablePathForDevice(ELinuxApp package, BuildMode buildMode) {
return package.executable(buildMode, _targetArch);
}
void onAttached(ELinuxApp package, BuildMode buildMode, Process process) {}
/// Computes a set of environment variables used to pass debugging information
/// to the engine without interfering with application level command line
/// arguments.
///
/// The format of the environment variables is:
/// * FLUTTER_ENGINE_SWITCHES to the number of switches.
/// * FLUTTER_ENGINE_SWITCH_<N> (indexing from 1) to the individual switches.
Map<String, String> _computeEnvironment(
DebuggingOptions debuggingOptions, bool traceStartup, String route) {
int flags = 0;
final Map<String, String> environment = <String, String>{};
void addFlag(String value) {
flags += 1;
environment['FLUTTER_ENGINE_SWITCH_$flags'] = value;
}
void finish() {
environment['FLUTTER_ENGINE_SWITCHES'] = flags.toString();
}
addFlag('enable-dart-profiling=true');
addFlag('enable-background-compilation=true');
if (traceStartup) {
addFlag('trace-startup=true');
}
if (route != null) {
addFlag('route=$route');
}
if (debuggingOptions.enableSoftwareRendering) {
addFlag('enable-software-rendering=true');
}
if (debuggingOptions.skiaDeterministicRendering) {
addFlag('skia-deterministic-rendering=true');
}
if (debuggingOptions.traceSkia) {
addFlag('trace-skia=true');
}
if (debuggingOptions.traceAllowlist != null) {
addFlag('trace-allowlist=${debuggingOptions.traceAllowlist}');
}
if (debuggingOptions.traceSkiaAllowlist != null) {
addFlag('trace-skia-allowlist=${debuggingOptions.traceSkiaAllowlist}');
}
if (debuggingOptions.traceSystrace) {
addFlag('trace-systrace=true');
}
if (debuggingOptions.endlessTraceBuffer) {
addFlag('endless-trace-buffer=true');
}
if (debuggingOptions.dumpSkpOnShaderCompilation) {
addFlag('dump-skp-on-shader-compilation=true');
}
if (debuggingOptions.cacheSkSL) {
addFlag('cache-sksl=true');
}
if (debuggingOptions.purgePersistentCache) {
addFlag('purge-persistent-cache=true');
}
// Options only supported when there is a VM Service connection between the
// tool and the device, usually in debug or profile mode.
if (debuggingOptions.debuggingEnabled) {
if (debuggingOptions.deviceVmServicePort != null) {
addFlag('observatory-port=${debuggingOptions.deviceVmServicePort}');
}
if (debuggingOptions.buildInfo.isDebug) {
addFlag('enable-checked-mode=true');
addFlag('verify-entry-points=true');
}
if (debuggingOptions.startPaused) {
addFlag('start-paused=true');
}
if (debuggingOptions.disableServiceAuthCodes) {
addFlag('disable-service-auth-codes=true');
}
final String dartVmFlags = computeDartVmFlags(debuggingOptions);
if (dartVmFlags.isNotEmpty) {
addFlag('dart-flags=$dartVmFlags');
}
if (debuggingOptions.useTestFonts) {
addFlag('use-test-fonts=true');
}
if (debuggingOptions.verboseSystemLogs) {
addFlag('verbose-logging=true');
}
}
finish();
return environment;
}
}
class ELinuxLogReader extends DeviceLogReader {
final StreamController<List<int>> _inputController =
StreamController<List<int>>.broadcast();
void initializeProcess(Process process) {
process.stdout.listen(_inputController.add);
process.stderr.listen(_inputController.add);
process.exitCode.whenComplete(_inputController.close);
}
@override
Stream<String> get logLines {
return _inputController.stream
.transform(utf8.decoder)
.transform(const LineSplitter());
}
@override
String get name => 'eLinux';
@override
void dispose() {}
}
+132
View File
@@ -0,0 +1,132 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Copyright 2014 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.
// @dart = 2.8
import 'package:flutter_tools/src/android/android_device_discovery.dart';
import 'package:flutter_tools/src/android/android_workflow.dart';
import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/context_runner.dart';
import 'package:flutter_tools/src/custom_devices/custom_devices_config.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/flutter_device_manager.dart';
import 'package:flutter_tools/src/fuchsia/fuchsia_workflow.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/macos/macos_workflow.dart';
import 'package:flutter_tools/src/windows/uwptool.dart';
import 'package:flutter_tools/src/windows/windows_workflow.dart';
import 'package:meta/meta.dart';
import 'package:process/process.dart';
import 'elinux_device.dart';
import 'elinux_doctor.dart';
/// An extended [FlutterDeviceManager] for managing eLinux devices.
class ELinuxDeviceManager extends FlutterDeviceManager {
/// Source: [runInContext] in `context_runner.dart`
ELinuxDeviceManager()
: super(
logger: globals.logger,
processManager: globals.processManager,
platform: globals.platform,
androidSdk: globals.androidSdk,
iosSimulatorUtils: globals.iosSimulatorUtils,
featureFlags: featureFlags,
fileSystem: globals.fs,
iosWorkflow: globals.iosWorkflow,
artifacts: globals.artifacts,
flutterVersion: globals.flutterVersion,
androidWorkflow: androidWorkflow,
config: globals.config,
fuchsiaWorkflow: fuchsiaWorkflow,
xcDevice: globals.xcdevice,
userMessages: globals.userMessages,
windowsWorkflow: windowsWorkflow,
macOSWorkflow: context.get<MacOSWorkflow>(),
operatingSystemUtils: globals.os,
terminal: globals.terminal,
customDevicesConfig: CustomDevicesConfig(
fileSystem: globals.fs,
logger: globals.logger,
platform: globals.platform,
),
uwptool: UwpTool(
artifacts: globals.artifacts,
logger: globals.logger,
processManager: globals.processManager,
),
);
final ELinuxDeviceDiscovery _eLinuxDeviceDiscovery = ELinuxDeviceDiscovery(
eLinuxWorkflow: eLinuxWorkflow,
logger: globals.logger,
processManager: globals.processManager,
);
@override
List<DeviceDiscovery> get deviceDiscoverers => <DeviceDiscovery>[
...super.deviceDiscoverers,
_eLinuxDeviceDiscovery,
];
}
/// Device discovery for eLinux devices.
///
/// Source: [AndroidDevices] in `android_device_discovery.dart`
class ELinuxDeviceDiscovery extends PollingDeviceDiscovery {
ELinuxDeviceDiscovery({
@required ELinuxWorkflow eLinuxWorkflow,
@required ProcessManager processManager,
@required Logger logger,
}) : _eLinuxWorkflow = eLinuxWorkflow,
_logger = logger,
_processManager = processManager,
super('eLinux devices');
final ELinuxWorkflow _eLinuxWorkflow;
final Logger _logger;
final ProcessManager _processManager;
@override
bool get supportsPlatform => _eLinuxWorkflow.appliesToHostPlatform;
@override
bool get canListAnything => _eLinuxWorkflow.canListDevices;
@override
Future<List<Device>> pollingGetDevices({Duration timeout}) async {
if (!canListAnything) {
return const <Device>[];
}
return <Device>[
ELinuxDevice('eLinux',
desktop: true,
targetArch: _getCurrentHostPlatformArchName(),
backendType: 'wayland',
logger: _logger ?? globals.logger,
processManager: _processManager ?? globals.processManager,
operatingSystemUtils: OperatingSystemUtils(
fileSystem: globals.fs,
logger: _logger ?? globals.logger,
platform: globals.platform,
processManager: const LocalProcessManager(),
)),
];
}
@override
Future<List<String>> getDiagnostics() async => const <String>[];
String _getCurrentHostPlatformArchName() {
final HostPlatform hostPlatform = getCurrentHostPlatform();
return getNameForHostPlatformArch(hostPlatform);
}
}
+126
View File
@@ -0,0 +1,126 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:io';
import 'package:flutter_tools/src/android/android_workflow.dart';
import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/doctor.dart';
import 'package:flutter_tools/src/doctor_validator.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/version.dart';
import 'package:meta/meta.dart';
import 'executable.dart';
ELinuxWorkflow get eLinuxWorkflow => context.get<ELinuxWorkflow>();
ELinuxValidator get eLinuxValidator => context.get<ELinuxValidator>();
/// See: [_DefaultDoctorValidatorsProvider] in `doctor.dart`
class ELinuxDoctorValidatorsProvider extends DoctorValidatorsProvider {
@override
List<DoctorValidator> get validators {
final List<DoctorValidator> validators =
DoctorValidatorsProvider.defaultInstance.validators;
return <DoctorValidator>[
validators.first,
eLinuxValidator,
...validators.sublist(1)
];
}
@override
List<Workflow> get workflows => <Workflow>[
...DoctorValidatorsProvider.defaultInstance.workflows,
eLinuxWorkflow,
];
}
/// A validator that checks for eLinux SDK installation.
class ELinuxValidator extends DoctorValidator {
ELinuxValidator() : super('eLinux toolchain - develop for eLinux devices');
bool _validatePackages(List<ValidationMessage> messages) {
return true;
}
/// See: [AndroidValidator.validate] in `android_workflow.dart`
@override
Future<ValidationResult> validate() async {
final List<ValidationMessage> messages = <ValidationMessage>[];
final FlutterVersion version = _FlutterELinuxVersion();
messages.add(ValidationMessage(globals.userMessages.flutterRevision(
version.frameworkRevisionShort,
version.frameworkAge,
version.frameworkCommitDate,
)));
messages.add(ValidationMessage(
globals.userMessages.engineRevision(version.engineRevisionShort)));
if (!_validatePackages(messages)) {
return ValidationResult(ValidationType.partial, messages);
}
return ValidationResult(ValidationType.installed, messages);
}
}
/// The eLinux-specific implementation of a [Workflow].
///
/// See: [AndroidWorkflow] in `android_workflow.dart`
class ELinuxWorkflow extends Workflow {
ELinuxWorkflow({
@required OperatingSystemUtils operatingSystemUtils,
}) : _operatingSystemUtils = operatingSystemUtils;
final OperatingSystemUtils _operatingSystemUtils;
@override
bool get appliesToHostPlatform =>
_operatingSystemUtils.hostPlatform != HostPlatform.linux_arm64;
@override
bool get canLaunchDevices => true;
@override
bool get canListDevices => true;
@override
bool get canListEmulators => false;
}
class _FlutterELinuxVersion extends FlutterVersion {
_FlutterELinuxVersion() : super(workingDirectory: rootPath);
/// See: [Cache.getVersionFor] in `cache.dart`
String _getVersionFor(String artifactName) {
final File versionFile = globals.fs
.directory(rootPath)
.childDirectory('bin')
.childDirectory('internal')
.childFile('$artifactName.version');
return versionFile.existsSync()
? versionFile.readAsStringSync().trim()
: null;
}
@override
String get engineRevision => _getVersionFor('engine');
/// See: [_runGit] in `version.dart`
String _runGit(String command) => globals.processUtils
.runSync(command.split(' '), workingDirectory: rootPath)
.stdout
.trim();
/// This should be overriden because [FlutterVersion._latestGitCommitDate]
/// runs the git log command in the `Cache.flutterRoot` directory.
@override
String get frameworkCommitDate => _runGit(
'git -c log.showSignature=false log -n 1 --pretty=format:%ad --date=iso');
}
+103
View File
@@ -0,0 +1,103 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2014 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.
// @dart = 2.8
import 'package:file/file.dart';
import 'package:flutter_tools/src/application_package.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/cmake.dart';
import 'package:flutter_tools/src/flutter_application_package.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/globals_null_migrated.dart' as globals;
import 'package:flutter_tools/src/project.dart';
import 'package:meta/meta.dart';
import 'elinux_cmake_project.dart';
class ELinuxApplicationPackageFactory extends FlutterApplicationPackageFactory {
ELinuxApplicationPackageFactory()
: super(
androidSdk: globals.androidSdk,
processManager: globals.processManager,
logger: globals.logger,
userMessages: globals.userMessages,
fileSystem: globals.fs,
);
@override
Future<ApplicationPackage> getPackageForPlatform(
TargetPlatform platform, {
BuildInfo buildInfo,
File applicationBinary,
}) async {
if (platform == TargetPlatform.tester) {
return applicationBinary == null
? ELinuxApp.fromELinuxProject(FlutterProject.current())
: ELinuxApp.fromPrebuiltApp(applicationBinary);
}
return super.getPackageForPlatform(platform,
buildInfo: buildInfo, applicationBinary: applicationBinary);
}
}
abstract class ELinuxApp extends ApplicationPackage {
ELinuxApp({@required String projectBundleId}) : super(id: projectBundleId);
factory ELinuxApp.fromELinuxProject(FlutterProject project) {
return BuildableELinuxApp(
project: ELinuxProject.fromFlutter(project),
);
}
factory ELinuxApp.fromPrebuiltApp(FileSystemEntity applicationBinary) {
return PrebuiltELinuxApp(
executable: applicationBinary.path,
);
}
@override
String get displayName => id;
String executable(BuildMode buildMode, String targetArch);
}
class PrebuiltELinuxApp extends ELinuxApp {
PrebuiltELinuxApp({
@required String executable,
}) : _executable = executable,
super(projectBundleId: executable);
final String _executable;
@override
String executable(BuildMode buildMode, String targetArch) => _executable;
@override
String get name => _executable;
}
class BuildableELinuxApp extends ELinuxApp {
BuildableELinuxApp({@required this.project})
: super(projectBundleId: project.parent.manifest.appName);
final ELinuxProject project;
@override
String executable(BuildMode buildMode, String targetArch) {
final String binaryName = getCmakeExecutableName(project);
return globals.fs.path.join(
'build/elinux/',
targetArch,
getNameForBuildMode(buildMode),
'bundle',
binaryName,
);
}
@override
String get name => project.parent.manifest.appName;
}
+462
View File
@@ -0,0 +1,462 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Copyright 2014 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.
// @dart = 2.8
import 'package:file/file.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/build_system/targets/web.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/dart/language_version.dart';
import 'package:flutter_tools/src/dart/package_map.dart';
import 'package:flutter_tools/src/flutter_plugins.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/platform_plugins.dart';
import 'package:flutter_tools/src/plugins.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:meta/meta.dart';
import 'package:package_config/package_config.dart';
import 'package:yaml/yaml.dart';
import 'elinux_cmake_project.dart';
/// Contains the parameters to template a elinux plugin.
///
/// The [name] of the plugin is required. Either [dartPluginClass] or
/// [pluginClass] are required. [pluginClass] will be the entry point to the
/// plugin's native code. If [pluginClass] is not empty, the [fileName]
/// containing the plugin's code is required.
///
/// Source: [LinuxPlugin] in `platform_plugins.dart`
class ELinuxPlugin extends PluginPlatform implements NativeOrDartPlugin {
ELinuxPlugin({
@required this.name,
@required this.directory,
this.pluginClass,
this.dartPluginClass,
this.fileName,
}) : assert(pluginClass != null || dartPluginClass != null);
factory ELinuxPlugin.fromYaml(
String name, Directory directory, YamlMap yaml) {
assert(validate(yaml));
return ELinuxPlugin(
name: name,
directory: directory,
pluginClass: yaml[kPluginClass] as String,
dartPluginClass: yaml[kDartPluginClass] as String,
fileName: yaml['fileName'] as String,
);
}
static bool validate(YamlMap yaml) {
if (yaml == null) {
return false;
}
return yaml[kPluginClass] is String || yaml[kDartPluginClass] is String;
}
static const String kConfigKey = 'elinux';
final String name;
final Directory directory;
final String pluginClass;
final String dartPluginClass;
final String fileName;
@override
bool isNative() => pluginClass != null;
@override
Map<String, dynamic> toMap() {
return <String, dynamic>{
'name': name,
if (pluginClass != null) 'class': pluginClass,
if (dartPluginClass != null) 'dartPluginClass': dartPluginClass,
'file': fileName,
};
}
File get projectFile => directory.childFile('project_def.prop');
final RegExp _propertyFormat = RegExp(r'(\S+)\s*\+?=(.*)');
Map<String, String> _properties;
String getProperty(String key) {
if (_properties == null) {
if (!projectFile.existsSync()) {
return null;
}
_properties = <String, String>{};
for (final String line in projectFile.readAsLinesSync()) {
final Match match = _propertyFormat.firstMatch(line);
if (match == null) {
continue;
}
final String key = match.group(1);
final String value = match.group(2).trim();
_properties[key] = value;
}
}
return _properties.containsKey(key) ? _properties[key] : null;
}
List<String> getPropertyAsAbsolutePaths(String key) {
final String property = getProperty(key);
if (property == null) {
return <String>[];
}
final List<String> paths = <String>[];
for (final String element in property.split(' ')) {
if (globals.fs.path.isAbsolute(element)) {
paths.add(element);
} else {
paths.add(globals.fs.path
.normalize(globals.fs.path.join(directory.path, element)));
}
}
return paths;
}
}
/// Any [FlutterCommand] that invokes [usesPubOption] or [targetFile] should
/// depend on this mixin to ensure plugins are correctly configured for eLinux.
///
/// See: [FlutterCommand.verifyThenRunCommand] in `flutter_command.dart`
mixin ELinuxExtension on FlutterCommand {
String _entrypoint;
bool get _usesTargetOption => argParser.options.containsKey('target');
@override
Future<FlutterCommandResult> verifyThenRunCommand(String commandPath) async {
if (super.shouldRunPub) {
// TODO(swift-kim): Should run pub get first before injecting plugins.
await ensureReadyForELinuxTooling(FlutterProject.current());
}
if (_usesTargetOption) {
_entrypoint =
await _createEntrypoint(FlutterProject.current(), super.targetFile);
}
return super.verifyThenRunCommand(commandPath);
}
@override
String get targetFile => _entrypoint ?? super.targetFile;
}
/// Creates an entrypoint wrapper of [targetFile] and returns its path.
/// This effectively adds support for Dart plugins.
///
/// Source: [WebEntrypointTarget.build] in `web.dart`
Future<String> _createEntrypoint(
FlutterProject project, String targetFile) async {
final List<ELinuxPlugin> dartPlugins =
await findELinuxPlugins(project, dartOnly: true);
if (dartPlugins.isEmpty) {
return targetFile;
}
final ELinuxProject eLinuxProject = ELinuxProject.fromFlutter(project);
if (!eLinuxProject.existsSync()) {
return targetFile;
}
final File entrypoint = eLinuxProject.managedDirectory.childFile('main.dart')
..createSync(recursive: true);
final PackageConfig packageConfig = await loadPackageConfigWithLogging(
project.directory.childFile('.packages'),
logger: globals.logger,
);
final FlutterProject flutterProject = FlutterProject.current();
final LanguageVersion languageVersion = determineLanguageVersion(
globals.fs.file(targetFile),
packageConfig[flutterProject.manifest.appName],
Cache.flutterRoot,
);
final Uri mainUri = globals.fs.file(targetFile).absolute.uri;
final String mainImport =
packageConfig.toPackageUri(mainUri)?.toString() ?? mainUri.toString();
entrypoint.writeAsStringSync('''
//
// Generated file. Do not edit.
//
// @dart=${languageVersion.major}.${languageVersion.minor}
import '$mainImport' as entrypoint;
import 'generated_plugin_registrant.dart';
Future<void> main() async {
registerPlugins();
entrypoint.main();
}
''');
return entrypoint.path;
}
const List<String> _knownPlugins = <String>[
'audioplayers',
'battery',
'battery_plus',
'camera',
'connectivity',
'device_info',
'flutter_tts',
'image_picker',
'integration_test',
'package_info',
'package_info_plus',
'path_provider',
'permission_handler',
'sensors',
'sensors_plus',
'share',
'shared_preferences',
'url_launcher',
'video_player',
'webview_flutter',
'wifi_info_flutter',
];
/// This function must be called whenever [FlutterProject.regeneratePlatformSpecificTooling]
/// or [FlutterProject.ensureReadyForPlatformSpecificTooling] is called.
///
/// See: [FlutterProject.ensureReadyForPlatformSpecificTooling] in `project.dart`
Future<void> ensureReadyForELinuxTooling(FlutterProject project) async {
if (!project.directory.existsSync() ||
project.hasExampleApp ||
project.isPlugin) {
return;
}
final ELinuxProject eLinuxProject = ELinuxProject.fromFlutter(project);
await eLinuxProject.ensureReadyForPlatformSpecificTooling();
await injectELinuxPlugins(project);
}
/// See: [injectPlugins] in `plugins.dart`
Future<void> injectELinuxPlugins(FlutterProject project) async {
final ELinuxProject eLinuxProject = ELinuxProject.fromFlutter(project);
if (eLinuxProject.existsSync()) {
final List<ELinuxPlugin> dartPlugins =
await findELinuxPlugins(project, dartOnly: true);
final List<ELinuxPlugin> nativePlugins =
await findELinuxPlugins(project, nativeOnly: true);
_writeDartPluginRegistrant(eLinuxProject.managedDirectory, dartPlugins);
_writePluginCmakefileTemplate(
eLinuxProject.managedDirectory, nativePlugins);
}
final List<String> plugins =
(await findPlugins(project)).map((Plugin p) => p.name).toList();
for (final String plugin in plugins) {
final String eLinuxPlugin = '${plugin}_elinux';
if (_knownPlugins.contains(plugin) && !plugins.contains(eLinuxPlugin)) {
globals.printStatus(
'$eLinuxPlugin is available on pub.dev. Did you forget to add to pubspec.yaml?',
color: TerminalColor.yellow,
);
}
}
}
/// Source: [findPlugins] in `plugins.dart`
Future<List<ELinuxPlugin>> findELinuxPlugins(
FlutterProject project, {
bool dartOnly = false,
bool nativeOnly = false,
bool throwOnError = true,
}) async {
final List<ELinuxPlugin> plugins = <ELinuxPlugin>[];
final File packagesFile = project.directory.childFile('.packages');
final PackageConfig packageConfig = await loadPackageConfigWithLogging(
packagesFile,
logger: globals.logger,
throwOnError: throwOnError,
);
for (final Package package in packageConfig.packages) {
final Uri packageRoot = package.packageUriRoot.resolve('..');
final ELinuxPlugin plugin = _pluginFromPackage(package.name, packageRoot);
if (plugin == null) {
continue;
} else if (nativeOnly && plugin.pluginClass == null) {
continue;
} else if (dartOnly && plugin.dartPluginClass == null) {
continue;
}
plugins.add(plugin);
}
return plugins;
}
/// Source: [_pluginFromPackage] in `plugins.dart`
ELinuxPlugin _pluginFromPackage(String name, Uri packageRoot) {
final String pubspecPath =
globals.fs.path.fromUri(packageRoot.resolve('pubspec.yaml'));
if (!globals.fs.isFileSync(pubspecPath)) {
return null;
}
dynamic pubspec;
try {
pubspec = loadYaml(globals.fs.file(pubspecPath).readAsStringSync());
} on YamlException catch (err) {
globals.printTrace('Failed to parse plugin manifest for $name: $err');
}
if (pubspec == null) {
return null;
}
final dynamic flutterConfig = pubspec['flutter'];
if (flutterConfig == null || !(flutterConfig.containsKey('plugin') as bool)) {
return null;
}
final Directory packageDir = globals.fs.directory(packageRoot);
globals.printTrace('Found plugin $name at ${packageDir.path}');
final YamlMap pluginYaml = flutterConfig['plugin'] as YamlMap;
if (pluginYaml == null || pluginYaml['platforms'] == null) {
return null;
}
final YamlMap platformsYaml = pluginYaml['platforms'] as YamlMap;
if (platformsYaml == null || platformsYaml[ELinuxPlugin.kConfigKey] == null) {
return null;
}
return ELinuxPlugin.fromYaml(
name,
packageDir.childDirectory('elinux'),
platformsYaml[ELinuxPlugin.kConfigKey] as YamlMap,
);
}
/// See: [_writeWebPluginRegistrant] in `plugins.dart`
void _writeDartPluginRegistrant(
Directory registryDirectory,
List<ELinuxPlugin> plugins,
) {
final List<Map<String, dynamic>> pluginConfigs =
plugins.map((ELinuxPlugin plugin) => plugin.toMap()).toList();
final Map<String, dynamic> context = <String, dynamic>{
'plugins': pluginConfigs,
};
_renderTemplateToFile(
'''
//
// Generated file. Do not edit.
//
// ignore_for_file: lines_longer_than_80_chars
{{#plugins}}
import 'package:{{name}}/{{name}}.dart';
{{/plugins}}
// ignore: public_member_api_docs
void registerPlugins() {
{{#plugins}}
{{dartPluginClass}}.register();
{{/plugins}}
}
''',
context,
registryDirectory.childFile('generated_plugin_registrant.dart').path,
);
}
/// See: [_writeWindowsPluginFiles] in `plugins.dart`
void _writePluginCmakefileTemplate(
Directory registryDirectory,
List<ELinuxPlugin> plugins,
) {
final List<Map<String, dynamic>> pluginConfigs =
plugins.map((ELinuxPlugin plugin) => plugin.toMap()).toList();
final Map<String, dynamic> context = <String, dynamic>{
'plugins': pluginConfigs,
};
_renderTemplateToFile(
'''
//
// Generated file. Do not edit.
//
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
#include <flutter/plugin_registry.h>
// Registers Flutter plugins.
void RegisterPlugins(flutter::PluginRegistry* registry);
#endif // GENERATED_PLUGIN_REGISTRANT_
''',
context,
registryDirectory.childFile('generated_plugin_registrant.h').path,
);
_renderTemplateToFile(
'''
//
// Generated file. Do not edit.
//
// clang-format off
#include "generated_plugin_registrant.h"
void RegisterPlugins(flutter::PluginRegistry* registry) {
}
''',
context,
registryDirectory.childFile('generated_plugin_registrant.cc').path,
);
_renderTemplateToFile(
r'''
#
# Generated file, do not edit.
#
list(APPEND FLUTTER_PLUGIN_LIST
{{#plugins}}
{{name}}
{{/plugins}}
)
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
add_subdirectory(
${USER_PROJECT_PATH}/flutter/plugins/${plugin}/elinux plugins/${plugin})
target_link_libraries(${TARGET}
PRIVATE
${plugin}_plugin
)
list(APPEND PLUGIN_BUNDLED_LIBRARIES
${PROJECT_BINARY_DIR}/plugins/${plugin}/lib${plugin}_plugin.so
)
endforeach(plugin)
''',
context,
registryDirectory.childFile('generated_plugins.cmake').path,
);
}
/// Source: [_renderTemplateToFile] in `plugins.dart` (exact copy)
void _renderTemplateToFile(String template, dynamic context, String filePath) {
final String renderedTemplate = globals.templateRenderer
.renderString(template, context, htmlEscapeValues: false);
final File file = globals.fs.file(filePath);
file.createSync(recursive: true);
file.writeAsStringSync(renderedTemplate);
}
+144
View File
@@ -0,0 +1,144 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Copyright 2014 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.
// @dart = 2.8
import 'dart:io';
import 'package:flutter_tools/executable.dart' as flutter;
import 'package:flutter_tools/runner.dart' as runner;
import 'package:flutter_tools/src/application_package.dart';
import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/template.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/config.dart';
import 'package:flutter_tools/src/commands/devices.dart';
import 'package:flutter_tools/src/commands/doctor.dart';
import 'package:flutter_tools/src/commands/emulators.dart';
import 'package:flutter_tools/src/commands/format.dart';
import 'package:flutter_tools/src/commands/generate_localizations.dart';
import 'package:flutter_tools/src/commands/install.dart';
import 'package:flutter_tools/src/commands/logs.dart';
import 'package:flutter_tools/src/commands/screenshot.dart';
import 'package:flutter_tools/src/commands/symbolize.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/doctor.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/isolated/mustache_template.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:path/path.dart';
import 'commands/analyze.dart';
import 'commands/attach.dart';
import 'commands/build.dart';
import 'commands/clean.dart';
import 'commands/create.dart';
import 'commands/drive.dart';
import 'commands/packages.dart';
import 'commands/precache.dart';
import 'commands/run.dart';
import 'commands/test.dart';
import 'elinux_cache.dart';
import 'elinux_device_discovery.dart';
import 'elinux_doctor.dart';
import 'elinux_package.dart';
/// Main entry point for commands.
///
/// Source: [flutter.main] in `executable.dart` (some commands and options were omitted)
Future<void> main(List<String> args) async {
final bool veryVerbose = args.contains('-vv');
final bool verbose =
args.contains('-v') || args.contains('--verbose') || veryVerbose;
final bool doctor = (args.isNotEmpty && args.first == 'doctor') ||
(args.length == 2 && verbose && args.last == 'doctor');
final bool help = args.contains('-h') ||
args.contains('--help') ||
(args.isNotEmpty && args.first == 'help') ||
(args.length == 1 && verbose);
final bool muteCommandLogging = (help || doctor) && !veryVerbose;
final bool verboseHelp = help && verbose;
final bool hasSpecifiedDeviceId =
args.contains('-d') || args.contains('--device-id');
args = <String>[
'--suppress-analytics', // Suppress flutter analytics by default.
'--no-version-check',
if (!hasSpecifiedDeviceId) ...<String>['--device-id', 'elinux'],
...args,
];
Cache.flutterRoot = join(rootPath, 'flutter');
await runner.run(
args,
() => <FlutterCommand>[
// Commands directly from flutter_tools.
ConfigCommand(verboseHelp: verboseHelp),
DevicesCommand(verboseHelp: verboseHelp),
DoctorCommand(verbose: verbose),
EmulatorsCommand(),
FormatCommand(),
GenerateLocalizationsCommand(
fileSystem: globals.fs,
logger: globals.logger,
),
InstallCommand(),
LogsCommand(),
ScreenshotCommand(),
SymbolizeCommand(stdio: globals.stdio, fileSystem: globals.fs),
// Commands extended for ELinux.
ELinuxAnalyzeCommand(verboseHelp: verboseHelp),
ELinuxAttachCommand(verboseHelp: verboseHelp),
ELinuxBuildCommand(verboseHelp: verboseHelp),
ELinuxCleanCommand(verbose: verbose),
ELinuxCreateCommand(verboseHelp: verboseHelp),
ELinuxDriveCommand(verboseHelp: verboseHelp),
ELinuxPackagesCommand(),
ELinuxPrecacheCommand(
verboseHelp: verboseHelp,
cache: globals.cache,
logger: globals.logger,
platform: globals.platform,
featureFlags: featureFlags,
),
ELinuxRunCommand(verboseHelp: verboseHelp),
ELinuxTestCommand(verboseHelp: verboseHelp),
],
verbose: verbose,
verboseHelp: verboseHelp,
muteCommandLogging: muteCommandLogging,
reportCrashes: false,
overrides: <Type, Generator>{
Cache: () => ELinuxFlutterCache(
fileSystem: globals.fs,
logger: globals.logger,
platform: globals.platform,
osUtils: globals.os,
),
TemplateRenderer: () => const MustacheTemplateRenderer(),
ApplicationPackageFactory: () => ELinuxApplicationPackageFactory(),
DeviceManager: () => ELinuxDeviceManager(),
DoctorValidatorsProvider: () => ELinuxDoctorValidatorsProvider(),
ELinuxWorkflow: () => ELinuxWorkflow(
operatingSystemUtils: globals.os,
),
ELinuxValidator: () => ELinuxValidator(),
},
);
}
/// See: [Cache.defaultFlutterRoot] in `cache.dart`
String get rootPath {
final String scriptPath = Platform.script.toFilePath();
return normalize(join(
scriptPath,
scriptPath.endsWith('.snapshot') ? '../../..' : '../..',
));
}