Reland "Move native assets to isolated/
directory" (#143055)
Reland of https://github.com/flutter/flutter/pull/142709. The revert of the revert is in the first commit, the fix in the commit on top. The move of the fakes for packages/flutter_tools/test/general.shard/resident_runner_test.dart was erroneous before, as it was trying to use setters instead of a private field. This PR changes the private `_devFS` field in the fake to be a public `fakeDevFS` in line with other fakes. ## Original PR description Native assets in other build systems are not built with `package:native_assets_builder` invoking `build.dart` scripts. Instead all packages have their own blaze rules. Therefore we'd like to not depend on `package:native_assets_builder` from flutter tools in g3 at all. This PR aims to move the imports of `native_assets_builder` and `native_assets_cli` into the `isolated/` directory and into the files with a `main` function that are not used in with other build systems. In order to be able to remove all imports in files used by other build systems, two new interfaces are added `HotRunnerNativeAssetsBuilder` and `TestCompilerNativeAssetsBuilder`. New parameters are then piped all the way through from the entry points: * bin/fuchsia_tester.dart * lib/executable.dart The build_system/targets dir is already excluded in other build systems. So, after this PR only the two above files and build_system/targets import from `isolated/native_assets/` and only `isolated/native_assets/` import `package:native_assets_cli` and `package:native_assets_builder`. Context: * https://github.com/flutter/flutter/issues/142041
This commit is contained in:
parent
38c6a5acba
commit
4e70bfae2b
@ -16,6 +16,7 @@ import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/context_runner.dart';
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:flutter_tools/src/isolated/native_assets/test/native_assets.dart';
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
import 'package:flutter_tools/src/reporting/reporting.dart';
|
||||
import 'package:flutter_tools/src/test/coverage_collector.dart';
|
||||
@ -153,6 +154,7 @@ Future<void> run(List<String> args) async {
|
||||
concurrency: math.max(1, globals.platform.numberOfProcessors - 2),
|
||||
icudtlPath: globals.fs.path.absolute(argResults[_kOptionIcudtl] as String),
|
||||
coverageDirectory: coverageDirectory,
|
||||
nativeAssetsBuilder: const TestCompilerNativeAssetsBuilderImpl(),
|
||||
);
|
||||
|
||||
if (collector != null) {
|
||||
|
@ -50,6 +50,8 @@ import 'src/globals.dart' as globals;
|
||||
// Files in `isolated` are intentionally excluded from google3 tooling.
|
||||
import 'src/isolated/build_targets.dart';
|
||||
import 'src/isolated/mustache_template.dart';
|
||||
import 'src/isolated/native_assets/native_assets.dart';
|
||||
import 'src/isolated/native_assets/test/native_assets.dart';
|
||||
import 'src/isolated/resident_web_runner.dart';
|
||||
import 'src/pre_run_validator.dart';
|
||||
import 'src/project_validator.dart';
|
||||
@ -177,6 +179,7 @@ List<FlutterCommand> generateCommands({
|
||||
platform: globals.platform,
|
||||
processInfo: globals.processInfo,
|
||||
fileSystem: globals.fs,
|
||||
nativeAssetsBuilder: const HotRunnerNativeAssetsBuilderImpl(),
|
||||
),
|
||||
BuildCommand(
|
||||
artifacts: globals.artifacts!,
|
||||
@ -237,10 +240,17 @@ List<FlutterCommand> generateCommands({
|
||||
platform: globals.platform,
|
||||
featureFlags: featureFlags,
|
||||
),
|
||||
RunCommand(verboseHelp: verboseHelp),
|
||||
RunCommand(
|
||||
verboseHelp: verboseHelp,
|
||||
nativeAssetsBuilder: const HotRunnerNativeAssetsBuilderImpl(),
|
||||
),
|
||||
ScreenshotCommand(fs: globals.fs),
|
||||
ShellCompletionCommand(),
|
||||
TestCommand(verboseHelp: verboseHelp, verbose: verbose),
|
||||
TestCommand(
|
||||
verboseHelp: verboseHelp,
|
||||
verbose: verbose,
|
||||
nativeAssetsBuilder: const TestCompilerNativeAssetsBuilderImpl(),
|
||||
),
|
||||
UpgradeCommand(verboseHelp: verboseHelp),
|
||||
SymbolizeCommand(
|
||||
stdio: globals.stdio,
|
||||
|
@ -7,18 +7,18 @@ import 'package:native_assets_cli/native_assets_cli_internal.dart' show Asset;
|
||||
import 'package:package_config/package_config_types.dart';
|
||||
|
||||
import '../../android/gradle_utils.dart';
|
||||
import '../../android/native_assets.dart';
|
||||
import '../../base/common.dart';
|
||||
import '../../base/file_system.dart';
|
||||
import '../../base/platform.dart';
|
||||
import '../../build_info.dart';
|
||||
import '../../dart/package_map.dart';
|
||||
import '../../ios/native_assets.dart';
|
||||
import '../../linux/native_assets.dart';
|
||||
import '../../macos/native_assets.dart';
|
||||
import '../../isolated/native_assets/android/native_assets.dart';
|
||||
import '../../isolated/native_assets/ios/native_assets.dart';
|
||||
import '../../isolated/native_assets/linux/native_assets.dart';
|
||||
import '../../isolated/native_assets/macos/native_assets.dart';
|
||||
import '../../isolated/native_assets/native_assets.dart';
|
||||
import '../../isolated/native_assets/windows/native_assets.dart';
|
||||
import '../../macos/xcode.dart';
|
||||
import '../../native_assets.dart';
|
||||
import '../../windows/native_assets.dart';
|
||||
import '../build_system.dart';
|
||||
import '../depfile.dart';
|
||||
import '../exceptions.dart';
|
||||
|
@ -71,6 +71,7 @@ class AttachCommand extends FlutterCommand {
|
||||
required Platform platform,
|
||||
required ProcessInfo processInfo,
|
||||
required FileSystem fileSystem,
|
||||
HotRunnerNativeAssetsBuilder? nativeAssetsBuilder,
|
||||
}) : _hotRunnerFactory = hotRunnerFactory ?? HotRunnerFactory(),
|
||||
_stdio = stdio,
|
||||
_logger = logger,
|
||||
@ -78,7 +79,8 @@ class AttachCommand extends FlutterCommand {
|
||||
_signals = signals,
|
||||
_platform = platform,
|
||||
_processInfo = processInfo,
|
||||
_fileSystem = fileSystem {
|
||||
_fileSystem = fileSystem,
|
||||
_nativeAssetsBuilder = nativeAssetsBuilder {
|
||||
addBuildModeFlags(verboseHelp: verboseHelp, defaultToRelease: false, excludeRelease: true);
|
||||
usesTargetOption();
|
||||
usesPortOptions(verboseHelp: verboseHelp);
|
||||
@ -150,6 +152,7 @@ class AttachCommand extends FlutterCommand {
|
||||
final Platform _platform;
|
||||
final ProcessInfo _processInfo;
|
||||
final FileSystem _fileSystem;
|
||||
final HotRunnerNativeAssetsBuilder? _nativeAssetsBuilder;
|
||||
|
||||
@override
|
||||
final String name = 'attach';
|
||||
@ -416,6 +419,7 @@ known, it can be explicitly provided to attach via the command-line, e.g.
|
||||
device: device,
|
||||
flutterProject: flutterProject,
|
||||
usesIpv6: usesIpv6,
|
||||
nativeAssetsBuilder: _nativeAssetsBuilder,
|
||||
);
|
||||
late AppInstance app;
|
||||
try {
|
||||
@ -449,6 +453,7 @@ known, it can be explicitly provided to attach via the command-line, e.g.
|
||||
device: device,
|
||||
flutterProject: flutterProject,
|
||||
usesIpv6: usesIpv6,
|
||||
nativeAssetsBuilder: _nativeAssetsBuilder,
|
||||
);
|
||||
final Completer<void> onAppStart = Completer<void>.sync();
|
||||
TerminalHandler? terminalHandler;
|
||||
@ -505,6 +510,7 @@ known, it can be explicitly provided to attach via the command-line, e.g.
|
||||
required Device device,
|
||||
required FlutterProject flutterProject,
|
||||
required bool usesIpv6,
|
||||
required HotRunnerNativeAssetsBuilder? nativeAssetsBuilder,
|
||||
}) async {
|
||||
final BuildInfo buildInfo = await getBuildInfo();
|
||||
|
||||
@ -539,6 +545,7 @@ known, it can be explicitly provided to attach via the command-line, e.g.
|
||||
ipv6: usesIpv6,
|
||||
flutterProject: flutterProject,
|
||||
nativeAssetsYamlFile: stringArg(FlutterOptions.kNativeAssetsYamlFile),
|
||||
nativeAssetsBuilder: _nativeAssetsBuilder,
|
||||
analytics: analytics,
|
||||
)
|
||||
: ColdRunner(
|
||||
@ -573,6 +580,7 @@ class HotRunnerFactory {
|
||||
bool ipv6 = false,
|
||||
FlutterProject? flutterProject,
|
||||
String? nativeAssetsYamlFile,
|
||||
required HotRunnerNativeAssetsBuilder? nativeAssetsBuilder,
|
||||
required Analytics analytics,
|
||||
}) => HotRunner(
|
||||
devices,
|
||||
@ -586,6 +594,7 @@ class HotRunnerFactory {
|
||||
stayResident: stayResident,
|
||||
ipv6: ipv6,
|
||||
nativeAssetsYamlFile: nativeAssetsYamlFile,
|
||||
nativeAssetsBuilder: nativeAssetsBuilder,
|
||||
analytics: analytics,
|
||||
);
|
||||
}
|
||||
|
@ -654,6 +654,7 @@ class AppDomain extends Domain {
|
||||
bool machine = true,
|
||||
String? userIdentifier,
|
||||
bool enableDevTools = true,
|
||||
required HotRunnerNativeAssetsBuilder? nativeAssetsBuilder,
|
||||
}) async {
|
||||
if (!await device.supportsRuntimeMode(options.buildInfo.mode)) {
|
||||
throw Exception(
|
||||
@ -705,6 +706,7 @@ class AppDomain extends Domain {
|
||||
hostIsIde: true,
|
||||
machine: machine,
|
||||
analytics: globals.analytics,
|
||||
nativeAssetsBuilder: nativeAssetsBuilder,
|
||||
);
|
||||
} else {
|
||||
runner = ColdRunner(
|
||||
|
@ -334,7 +334,11 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
|
||||
}
|
||||
|
||||
class RunCommand extends RunCommandBase {
|
||||
RunCommand({ bool verboseHelp = false }) : super(verboseHelp: verboseHelp) {
|
||||
RunCommand({
|
||||
bool verboseHelp = false,
|
||||
HotRunnerNativeAssetsBuilder? nativeAssetsBuilder,
|
||||
}) : _nativeAssetsBuilder = nativeAssetsBuilder,
|
||||
super(verboseHelp: verboseHelp) {
|
||||
requiresPubspecYaml();
|
||||
usesFilesystemOptions(hide: !verboseHelp);
|
||||
usesExtraDartFlagOptions(verboseHelp: verboseHelp);
|
||||
@ -418,6 +422,8 @@ class RunCommand extends RunCommandBase {
|
||||
);
|
||||
}
|
||||
|
||||
final HotRunnerNativeAssetsBuilder? _nativeAssetsBuilder;
|
||||
|
||||
@override
|
||||
final String name = 'run';
|
||||
|
||||
@ -660,6 +666,7 @@ class RunCommand extends RunCommandBase {
|
||||
ipv6: ipv6 ?? false,
|
||||
analytics: globals.analytics,
|
||||
nativeAssetsYamlFile: stringArg(FlutterOptions.kNativeAssetsYamlFile),
|
||||
nativeAssetsBuilder: _nativeAssetsBuilder,
|
||||
);
|
||||
} else if (webMode) {
|
||||
return webRunnerFactory!.createWebRunner(
|
||||
@ -733,6 +740,7 @@ class RunCommand extends RunCommandBase {
|
||||
ipv6: ipv6 ?? false,
|
||||
userIdentifier: userIdentifier,
|
||||
enableDevTools: boolArg(FlutterCommand.kEnableDevTools),
|
||||
nativeAssetsBuilder: _nativeAssetsBuilder,
|
||||
);
|
||||
} on Exception catch (error) {
|
||||
throwToolExit(error.toString());
|
||||
|
@ -13,6 +13,7 @@ import '../bundle_builder.dart';
|
||||
import '../devfs.dart';
|
||||
import '../device.dart';
|
||||
import '../globals.dart' as globals;
|
||||
import '../native_assets.dart';
|
||||
import '../project.dart';
|
||||
import '../runner/flutter_command.dart';
|
||||
import '../test/coverage_collector.dart';
|
||||
@ -64,6 +65,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
|
||||
this.testWrapper = const TestWrapper(),
|
||||
this.testRunner = const FlutterTestRunner(),
|
||||
this.verbose = false,
|
||||
this.nativeAssetsBuilder,
|
||||
}) {
|
||||
requiresPubspecYaml();
|
||||
usesPubOption();
|
||||
@ -238,6 +240,8 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
|
||||
/// Interface for running the tester process.
|
||||
final FlutterTestRunner testRunner;
|
||||
|
||||
final TestCompilerNativeAssetsBuilder? nativeAssetsBuilder;
|
||||
|
||||
final bool verbose;
|
||||
|
||||
@visibleForTesting
|
||||
@ -510,6 +514,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
|
||||
integrationTestDevice: integrationTestDevice,
|
||||
integrationTestUserIdentifier: stringArg(FlutterOptions.kDeviceUser),
|
||||
testTimeRecorder: testTimeRecorder,
|
||||
nativeAssetsBuilder: nativeAssetsBuilder,
|
||||
);
|
||||
testTimeRecorder?.stop(TestTimePhases.TestRunner, testRunnerTimeRecorderStopwatch!);
|
||||
|
||||
|
@ -0,0 +1,4 @@
|
||||
The directory structure in here mirrors the directory structure in lib/src/.
|
||||
|
||||
The native assets feature lives in lib/src/isolated/ because this code is not
|
||||
used in other build systems.
|
@ -4,17 +4,17 @@
|
||||
|
||||
import 'package:native_assets_builder/native_assets_builder.dart'
|
||||
show BuildResult, DryRunResult;
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
hide BuildMode;
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
as native_assets_cli;
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
hide BuildMode;
|
||||
|
||||
import '../base/common.dart';
|
||||
import '../base/file_system.dart';
|
||||
import '../build_info.dart';
|
||||
import '../globals.dart' as globals;
|
||||
import '../../../android/android_sdk.dart';
|
||||
import '../../../base/common.dart';
|
||||
import '../../../base/file_system.dart';
|
||||
import '../../../build_info.dart';
|
||||
import '../../../globals.dart' as globals;
|
||||
import '../native_assets.dart';
|
||||
import 'android_sdk.dart';
|
||||
|
||||
/// Dry run the native builds.
|
||||
///
|
@ -9,9 +9,9 @@ import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
as native_assets_cli;
|
||||
|
||||
import '../base/file_system.dart';
|
||||
import '../build_info.dart';
|
||||
import '../globals.dart' as globals;
|
||||
import '../../../base/file_system.dart';
|
||||
import '../../../build_info.dart';
|
||||
import '../../../globals.dart' as globals;
|
||||
|
||||
import '../macos/native_assets_host.dart';
|
||||
import '../native_assets.dart';
|
@ -5,11 +5,11 @@
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
hide BuildMode;
|
||||
|
||||
import '../base/common.dart';
|
||||
import '../base/file_system.dart';
|
||||
import '../base/io.dart';
|
||||
import '../build_info.dart';
|
||||
import '../globals.dart' as globals;
|
||||
import '../../../base/common.dart';
|
||||
import '../../../base/file_system.dart';
|
||||
import '../../../base/io.dart';
|
||||
import '../../../build_info.dart';
|
||||
import '../../../globals.dart' as globals;
|
||||
import '../native_assets.dart';
|
||||
|
||||
/// Dry run the native builds.
|
@ -9,9 +9,9 @@ import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
as native_assets_cli;
|
||||
|
||||
import '../base/file_system.dart';
|
||||
import '../build_info.dart';
|
||||
import '../globals.dart' as globals;
|
||||
import '../../../base/file_system.dart';
|
||||
import '../../../build_info.dart';
|
||||
import '../../../globals.dart' as globals;
|
||||
import '../native_assets.dart';
|
||||
import 'native_assets_host.dart';
|
||||
|
@ -7,12 +7,12 @@
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
hide BuildMode;
|
||||
|
||||
import '../base/common.dart';
|
||||
import '../base/file_system.dart';
|
||||
import '../base/io.dart';
|
||||
import '../build_info.dart';
|
||||
import '../convert.dart';
|
||||
import '../globals.dart' as globals;
|
||||
import '../../../base/common.dart';
|
||||
import '../../../base/file_system.dart';
|
||||
import '../../../base/io.dart';
|
||||
import '../../../build_info.dart';
|
||||
import '../../../convert.dart';
|
||||
import '../../../globals.dart' as globals;
|
||||
|
||||
/// Create an `Info.plist` in [target] for a framework with a single dylib.
|
||||
///
|
@ -0,0 +1,732 @@
|
||||
// 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.
|
||||
|
||||
// Logic for native assets shared between all host OSes.
|
||||
|
||||
import 'package:logging/logging.dart' as logging;
|
||||
import 'package:native_assets_builder/native_assets_builder.dart'
|
||||
as native_assets_builder show NativeAssetsBuildRunner;
|
||||
import 'package:native_assets_builder/native_assets_builder.dart'
|
||||
hide NativeAssetsBuildRunner;
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart';
|
||||
import 'package:package_config/package_config_types.dart';
|
||||
|
||||
import '../../base/common.dart';
|
||||
import '../../base/file_system.dart';
|
||||
import '../../base/logger.dart';
|
||||
import '../../base/platform.dart';
|
||||
import '../../build_info.dart' as build_info;
|
||||
import '../../cache.dart';
|
||||
import '../../features.dart';
|
||||
import '../../globals.dart' as globals;
|
||||
import '../../resident_runner.dart';
|
||||
import '../../run_hot.dart';
|
||||
import 'android/native_assets.dart';
|
||||
import 'ios/native_assets.dart';
|
||||
import 'linux/native_assets.dart';
|
||||
import 'macos/native_assets.dart';
|
||||
import 'macos/native_assets_host.dart';
|
||||
import 'windows/native_assets.dart';
|
||||
|
||||
/// Programmatic API to be used by Dart launchers to invoke native builds.
|
||||
///
|
||||
/// It enables mocking `package:native_assets_builder` package.
|
||||
/// It also enables mocking native toolchain discovery via [cCompilerConfig].
|
||||
abstract class NativeAssetsBuildRunner {
|
||||
/// Whether the project has a `.dart_tools/package_config.json`.
|
||||
///
|
||||
/// If there is no package config, [packagesWithNativeAssets], [build], and
|
||||
/// [dryRun] must not be invoked.
|
||||
Future<bool> hasPackageConfig();
|
||||
|
||||
/// All packages in the transitive dependencies that have a `build.dart`.
|
||||
Future<List<Package>> packagesWithNativeAssets();
|
||||
|
||||
/// Runs all [packagesWithNativeAssets] `build.dart` in dry run.
|
||||
Future<DryRunResult> dryRun({
|
||||
required bool includeParentEnvironment,
|
||||
required LinkModePreference linkModePreference,
|
||||
required OS targetOS,
|
||||
required Uri workingDirectory,
|
||||
});
|
||||
|
||||
/// Runs all [packagesWithNativeAssets] `build.dart`.
|
||||
Future<BuildResult> build({
|
||||
required bool includeParentEnvironment,
|
||||
required BuildMode buildMode,
|
||||
required LinkModePreference linkModePreference,
|
||||
required Target target,
|
||||
required Uri workingDirectory,
|
||||
CCompilerConfig? cCompilerConfig,
|
||||
int? targetAndroidNdkApi,
|
||||
IOSSdk? targetIOSSdk,
|
||||
});
|
||||
|
||||
/// The C compiler config to use for compilation.
|
||||
Future<CCompilerConfig> get cCompilerConfig;
|
||||
|
||||
/// The NDK compiler to use to use for compilation for Android.
|
||||
Future<CCompilerConfig> get ndkCCompilerConfig;
|
||||
}
|
||||
|
||||
/// Uses `package:native_assets_builder` for its implementation.
|
||||
class NativeAssetsBuildRunnerImpl implements NativeAssetsBuildRunner {
|
||||
NativeAssetsBuildRunnerImpl(
|
||||
this.projectUri,
|
||||
this.packageConfig,
|
||||
this.fileSystem,
|
||||
this.logger,
|
||||
);
|
||||
|
||||
final Uri projectUri;
|
||||
final PackageConfig packageConfig;
|
||||
final FileSystem fileSystem;
|
||||
final Logger logger;
|
||||
|
||||
late final logging.Logger _logger = logging.Logger('')
|
||||
..onRecord.listen((logging.LogRecord record) {
|
||||
final int levelValue = record.level.value;
|
||||
final String message = record.message;
|
||||
if (levelValue >= logging.Level.SEVERE.value) {
|
||||
logger.printError(message);
|
||||
} else if (levelValue >= logging.Level.WARNING.value) {
|
||||
logger.printWarning(message);
|
||||
} else if (levelValue >= logging.Level.INFO.value) {
|
||||
logger.printTrace(message);
|
||||
} else {
|
||||
logger.printTrace(message);
|
||||
}
|
||||
});
|
||||
|
||||
late final Uri _dartExecutable = fileSystem.directory(Cache.flutterRoot).uri.resolve('bin/dart');
|
||||
|
||||
late final native_assets_builder.NativeAssetsBuildRunner _buildRunner = native_assets_builder.NativeAssetsBuildRunner(
|
||||
logger: _logger,
|
||||
dartExecutable: _dartExecutable,
|
||||
);
|
||||
|
||||
@override
|
||||
Future<bool> hasPackageConfig() {
|
||||
final File packageConfigJson =
|
||||
fileSystem.directory(projectUri.toFilePath()).childDirectory('.dart_tool').childFile('package_config.json');
|
||||
return packageConfigJson.exists();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Package>> packagesWithNativeAssets() async {
|
||||
final PackageLayout packageLayout = PackageLayout.fromPackageConfig(
|
||||
packageConfig,
|
||||
projectUri.resolve('.dart_tool/package_config.json'),
|
||||
);
|
||||
return packageLayout.packagesWithNativeAssets;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<DryRunResult> dryRun({
|
||||
required bool includeParentEnvironment,
|
||||
required LinkModePreference linkModePreference,
|
||||
required OS targetOS,
|
||||
required Uri workingDirectory,
|
||||
}) {
|
||||
final PackageLayout packageLayout = PackageLayout.fromPackageConfig(
|
||||
packageConfig,
|
||||
projectUri.resolve('.dart_tool/package_config.json'),
|
||||
);
|
||||
return _buildRunner.dryRun(
|
||||
includeParentEnvironment: includeParentEnvironment,
|
||||
linkModePreference: linkModePreference,
|
||||
targetOs: targetOS,
|
||||
workingDirectory: workingDirectory,
|
||||
packageLayout: packageLayout,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<BuildResult> build({
|
||||
required bool includeParentEnvironment,
|
||||
required BuildMode buildMode,
|
||||
required LinkModePreference linkModePreference,
|
||||
required Target target,
|
||||
required Uri workingDirectory,
|
||||
CCompilerConfig? cCompilerConfig,
|
||||
int? targetAndroidNdkApi,
|
||||
IOSSdk? targetIOSSdk,
|
||||
}) {
|
||||
final PackageLayout packageLayout = PackageLayout.fromPackageConfig(
|
||||
packageConfig,
|
||||
projectUri.resolve('.dart_tool/package_config.json'),
|
||||
);
|
||||
return _buildRunner.build(
|
||||
buildMode: buildMode,
|
||||
cCompilerConfig: cCompilerConfig,
|
||||
includeParentEnvironment: includeParentEnvironment,
|
||||
linkModePreference: linkModePreference,
|
||||
target: target,
|
||||
targetAndroidNdkApi: targetAndroidNdkApi,
|
||||
targetIOSSdk: targetIOSSdk,
|
||||
workingDirectory: workingDirectory,
|
||||
packageLayout: packageLayout,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
late final Future<CCompilerConfig> cCompilerConfig = () {
|
||||
if (globals.platform.isMacOS || globals.platform.isIOS) {
|
||||
return cCompilerConfigMacOS();
|
||||
}
|
||||
if (globals.platform.isLinux) {
|
||||
return cCompilerConfigLinux();
|
||||
}
|
||||
if (globals.platform.isWindows) {
|
||||
return cCompilerConfigWindows();
|
||||
}
|
||||
if (globals.platform.isAndroid) {
|
||||
throwToolExit('Should use ndkCCompilerConfig for Android.');
|
||||
}
|
||||
throwToolExit('Unknown target OS.');
|
||||
}();
|
||||
|
||||
@override
|
||||
late final Future<CCompilerConfig> ndkCCompilerConfig = () {
|
||||
return cCompilerConfigAndroid();
|
||||
}();
|
||||
}
|
||||
|
||||
/// Write [assets] to `native_assets.yaml` in [yamlParentDirectory].
|
||||
Future<Uri> writeNativeAssetsYaml(
|
||||
Iterable<Asset> assets,
|
||||
Uri yamlParentDirectory,
|
||||
FileSystem fileSystem,
|
||||
) async {
|
||||
globals.logger.printTrace('Writing native_assets.yaml.');
|
||||
final String nativeAssetsDartContents = assets.toNativeAssetsFile();
|
||||
final Directory parentDirectory = fileSystem.directory(yamlParentDirectory);
|
||||
if (!await parentDirectory.exists()) {
|
||||
await parentDirectory.create(recursive: true);
|
||||
}
|
||||
final File nativeAssetsFile = parentDirectory.childFile('native_assets.yaml');
|
||||
await nativeAssetsFile.writeAsString(nativeAssetsDartContents);
|
||||
globals.logger.printTrace('Writing ${nativeAssetsFile.path} done.');
|
||||
return nativeAssetsFile.uri;
|
||||
}
|
||||
|
||||
/// Select the native asset build mode for a given Flutter build mode.
|
||||
BuildMode nativeAssetsBuildMode(build_info.BuildMode buildMode) {
|
||||
switch (buildMode) {
|
||||
case build_info.BuildMode.debug:
|
||||
return BuildMode.debug;
|
||||
case build_info.BuildMode.jitRelease:
|
||||
case build_info.BuildMode.profile:
|
||||
case build_info.BuildMode.release:
|
||||
return BuildMode.release;
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether this project does not yet have a package config file.
|
||||
///
|
||||
/// A project has no package config when `pub get` has not yet been run.
|
||||
///
|
||||
/// Native asset builds cannot be run without a package config. If there is
|
||||
/// no package config, leave a logging trace about that.
|
||||
Future<bool> _hasNoPackageConfig(NativeAssetsBuildRunner buildRunner) async {
|
||||
final bool packageConfigExists = await buildRunner.hasPackageConfig();
|
||||
if (!packageConfigExists) {
|
||||
globals.logger.printTrace('No package config found. Skipping native assets compilation.');
|
||||
}
|
||||
return !packageConfigExists;
|
||||
}
|
||||
|
||||
Future<bool> nativeBuildRequired(NativeAssetsBuildRunner buildRunner) async {
|
||||
if (await _hasNoPackageConfig(buildRunner)) {
|
||||
return false;
|
||||
}
|
||||
final List<Package> packagesWithNativeAssets = await buildRunner.packagesWithNativeAssets();
|
||||
if (packagesWithNativeAssets.isEmpty) {
|
||||
globals.logger.printTrace(
|
||||
'No packages with native assets. Skipping native assets compilation.',
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!featureFlags.isNativeAssetsEnabled) {
|
||||
final String packageNames = packagesWithNativeAssets.map((Package p) => p.name).join(' ');
|
||||
throwToolExit(
|
||||
'Package(s) $packageNames require the native assets feature to be enabled. '
|
||||
'Enable using `flutter config --enable-native-assets`.',
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Ensures that either this project has no native assets, or that native assets
|
||||
/// are supported on that operating system.
|
||||
///
|
||||
/// Exits the tool if the above condition is not satisfied.
|
||||
Future<void> ensureNoNativeAssetsOrOsIsSupported(
|
||||
Uri workingDirectory,
|
||||
String os,
|
||||
FileSystem fileSystem,
|
||||
NativeAssetsBuildRunner buildRunner,
|
||||
) async {
|
||||
if (await _hasNoPackageConfig(buildRunner)) {
|
||||
return;
|
||||
}
|
||||
final List<Package> packagesWithNativeAssets = await buildRunner.packagesWithNativeAssets();
|
||||
if (packagesWithNativeAssets.isEmpty) {
|
||||
globals.logger.printTrace(
|
||||
'No packages with native assets. Skipping native assets compilation.',
|
||||
);
|
||||
return;
|
||||
}
|
||||
final String packageNames = packagesWithNativeAssets.map((Package p) => p.name).join(' ');
|
||||
throwToolExit(
|
||||
'Package(s) $packageNames require the native assets feature. '
|
||||
'This feature has not yet been implemented for `$os`. '
|
||||
'For more info see https://github.com/flutter/flutter/issues/129757.',
|
||||
);
|
||||
}
|
||||
|
||||
/// Ensure all native assets have a linkmode declared to be dynamic loading.
|
||||
///
|
||||
/// In JIT, the link mode must always be dynamic linking.
|
||||
/// In AOT, the static linking has not yet been implemented in Dart:
|
||||
/// https://github.com/dart-lang/sdk/issues/49418.
|
||||
///
|
||||
/// Therefore, ensure all `build.dart` scripts return only dynamic libraries.
|
||||
void ensureNoLinkModeStatic(List<Asset> nativeAssets) {
|
||||
final Iterable<Asset> staticAssets = nativeAssets.whereLinkMode(LinkMode.static);
|
||||
if (staticAssets.isNotEmpty) {
|
||||
final String assetIds = staticAssets.map((Asset a) => a.id).toSet().join(', ');
|
||||
throwToolExit(
|
||||
'Native asset(s) $assetIds have their link mode set to static, '
|
||||
'but this is not yet supported. '
|
||||
'For more info see https://github.com/dart-lang/sdk/issues/49418.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// This should be the same for different archs, debug/release, etc.
|
||||
/// It should work for all macOS.
|
||||
Uri nativeAssetsBuildUri(Uri projectUri, OS os) {
|
||||
final String buildDir = build_info.getBuildDirectory();
|
||||
return projectUri.resolve('$buildDir/native_assets/$os/');
|
||||
}
|
||||
|
||||
class HotRunnerNativeAssetsBuilderImpl implements HotRunnerNativeAssetsBuilder {
|
||||
const HotRunnerNativeAssetsBuilderImpl();
|
||||
|
||||
@override
|
||||
Future<Uri?> dryRun({
|
||||
required Uri projectUri,
|
||||
required FileSystem fileSystem,
|
||||
required List<FlutterDevice> flutterDevices,
|
||||
required PackageConfig packageConfig,
|
||||
required Logger logger,
|
||||
}) async {
|
||||
final NativeAssetsBuildRunner buildRunner = NativeAssetsBuildRunnerImpl(
|
||||
projectUri,
|
||||
packageConfig,
|
||||
fileSystem,
|
||||
globals.logger,
|
||||
);
|
||||
return dryRunNativeAssets(
|
||||
projectUri: projectUri,
|
||||
fileSystem: fileSystem,
|
||||
buildRunner: buildRunner,
|
||||
flutterDevices: flutterDevices,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the native asset id to dylib mapping to embed in the kernel file.
|
||||
///
|
||||
/// Run hot compiles a kernel file that is pushed to the device after hot
|
||||
/// restart. We need to embed the native assets mapping in order to access
|
||||
/// native assets after hot restart.
|
||||
Future<Uri?> dryRunNativeAssets({
|
||||
required Uri projectUri,
|
||||
required FileSystem fileSystem,
|
||||
required NativeAssetsBuildRunner buildRunner,
|
||||
required List<FlutterDevice> flutterDevices,
|
||||
}) async {
|
||||
if (flutterDevices.length != 1) {
|
||||
return dryRunNativeAssetsMultipleOSes(
|
||||
projectUri: projectUri,
|
||||
fileSystem: fileSystem,
|
||||
targetPlatforms: flutterDevices.map((FlutterDevice d) => d.targetPlatform).nonNulls,
|
||||
buildRunner: buildRunner,
|
||||
);
|
||||
}
|
||||
final FlutterDevice flutterDevice = flutterDevices.single;
|
||||
final build_info.TargetPlatform targetPlatform = flutterDevice.targetPlatform!;
|
||||
|
||||
final Uri? nativeAssetsYaml;
|
||||
switch (targetPlatform) {
|
||||
case build_info.TargetPlatform.darwin:
|
||||
nativeAssetsYaml = await dryRunNativeAssetsMacOS(
|
||||
projectUri: projectUri,
|
||||
fileSystem: fileSystem,
|
||||
buildRunner: buildRunner,
|
||||
);
|
||||
case build_info.TargetPlatform.ios:
|
||||
nativeAssetsYaml = await dryRunNativeAssetsIOS(
|
||||
projectUri: projectUri,
|
||||
fileSystem: fileSystem,
|
||||
buildRunner: buildRunner,
|
||||
);
|
||||
case build_info.TargetPlatform.tester:
|
||||
if (const LocalPlatform().isMacOS) {
|
||||
nativeAssetsYaml = await dryRunNativeAssetsMacOS(
|
||||
projectUri: projectUri,
|
||||
flutterTester: true,
|
||||
fileSystem: fileSystem,
|
||||
buildRunner: buildRunner,
|
||||
);
|
||||
} else if (const LocalPlatform().isLinux) {
|
||||
nativeAssetsYaml = await dryRunNativeAssetsLinux(
|
||||
projectUri: projectUri,
|
||||
flutterTester: true,
|
||||
fileSystem: fileSystem,
|
||||
buildRunner: buildRunner,
|
||||
);
|
||||
} else if (const LocalPlatform().isWindows) {
|
||||
nativeAssetsYaml = await dryRunNativeAssetsWindows(
|
||||
projectUri: projectUri,
|
||||
flutterTester: true,
|
||||
fileSystem: fileSystem,
|
||||
buildRunner: buildRunner,
|
||||
);
|
||||
} else {
|
||||
await nativeBuildRequired(buildRunner);
|
||||
nativeAssetsYaml = null;
|
||||
}
|
||||
case build_info.TargetPlatform.linux_arm64:
|
||||
case build_info.TargetPlatform.linux_x64:
|
||||
nativeAssetsYaml = await dryRunNativeAssetsLinux(
|
||||
projectUri: projectUri,
|
||||
fileSystem: fileSystem,
|
||||
buildRunner: buildRunner,
|
||||
);
|
||||
case build_info.TargetPlatform.windows_arm64:
|
||||
case build_info.TargetPlatform.windows_x64:
|
||||
nativeAssetsYaml = await dryRunNativeAssetsWindows(
|
||||
projectUri: projectUri,
|
||||
fileSystem: fileSystem,
|
||||
buildRunner: buildRunner,
|
||||
);
|
||||
case build_info.TargetPlatform.android_arm:
|
||||
case build_info.TargetPlatform.android_arm64:
|
||||
case build_info.TargetPlatform.android_x64:
|
||||
case build_info.TargetPlatform.android_x86:
|
||||
case build_info.TargetPlatform.android:
|
||||
nativeAssetsYaml = await dryRunNativeAssetsAndroid(
|
||||
projectUri: projectUri,
|
||||
fileSystem: fileSystem,
|
||||
buildRunner: buildRunner,
|
||||
);
|
||||
case build_info.TargetPlatform.fuchsia_arm64:
|
||||
case build_info.TargetPlatform.fuchsia_x64:
|
||||
case build_info.TargetPlatform.web_javascript:
|
||||
await ensureNoNativeAssetsOrOsIsSupported(
|
||||
projectUri,
|
||||
targetPlatform.toString(),
|
||||
fileSystem,
|
||||
buildRunner,
|
||||
);
|
||||
nativeAssetsYaml = null;
|
||||
}
|
||||
return nativeAssetsYaml;
|
||||
}
|
||||
|
||||
/// Dry run the native builds for multiple OSes.
|
||||
///
|
||||
/// Needed for `flutter run -d all`.
|
||||
Future<Uri?> dryRunNativeAssetsMultipleOSes({
|
||||
required NativeAssetsBuildRunner buildRunner,
|
||||
required Uri projectUri,
|
||||
required FileSystem fileSystem,
|
||||
required Iterable<build_info.TargetPlatform> targetPlatforms,
|
||||
}) async {
|
||||
if (await nativeBuildRequired(buildRunner)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Uri buildUri = buildUriMultiple(projectUri);
|
||||
final Iterable<Asset> nativeAssetPaths = <Asset>[
|
||||
if (targetPlatforms.contains(build_info.TargetPlatform.darwin) ||
|
||||
(targetPlatforms.contains(build_info.TargetPlatform.tester) && OS.current == OS.macOS))
|
||||
...await dryRunNativeAssetsMacOSInternal(
|
||||
fileSystem,
|
||||
projectUri,
|
||||
false,
|
||||
buildRunner,
|
||||
),
|
||||
if (targetPlatforms.contains(build_info.TargetPlatform.linux_arm64) ||
|
||||
targetPlatforms.contains(build_info.TargetPlatform.linux_x64) ||
|
||||
(targetPlatforms.contains(build_info.TargetPlatform.tester) && OS.current == OS.linux))
|
||||
...await dryRunNativeAssetsLinuxInternal(
|
||||
fileSystem,
|
||||
projectUri,
|
||||
false,
|
||||
buildRunner,
|
||||
),
|
||||
if (targetPlatforms.contains(build_info.TargetPlatform.windows_arm64) ||
|
||||
targetPlatforms.contains(build_info.TargetPlatform.windows_x64) ||
|
||||
(targetPlatforms.contains(build_info.TargetPlatform.tester) && OS.current == OS.windows))
|
||||
...await dryRunNativeAssetsWindowsInternal(
|
||||
fileSystem,
|
||||
projectUri,
|
||||
false,
|
||||
buildRunner,
|
||||
),
|
||||
if (targetPlatforms.contains(build_info.TargetPlatform.ios))
|
||||
...await dryRunNativeAssetsIOSInternal(
|
||||
fileSystem,
|
||||
projectUri,
|
||||
buildRunner,
|
||||
),
|
||||
if (targetPlatforms.contains(build_info.TargetPlatform.android) ||
|
||||
targetPlatforms.contains(build_info.TargetPlatform.android_arm) ||
|
||||
targetPlatforms.contains(build_info.TargetPlatform.android_arm64) ||
|
||||
targetPlatforms.contains(build_info.TargetPlatform.android_x64) ||
|
||||
targetPlatforms.contains(build_info.TargetPlatform.android_x86))
|
||||
...await dryRunNativeAssetsAndroidInternal(
|
||||
fileSystem,
|
||||
projectUri,
|
||||
buildRunner,
|
||||
),
|
||||
];
|
||||
final Uri nativeAssetsUri = await writeNativeAssetsYaml(nativeAssetPaths, buildUri, fileSystem);
|
||||
return nativeAssetsUri;
|
||||
}
|
||||
|
||||
/// With `flutter run -d all` we need a place to store the native assets
|
||||
/// mapping for multiple OSes combined.
|
||||
Uri buildUriMultiple(Uri projectUri) {
|
||||
final String buildDir = build_info.getBuildDirectory();
|
||||
return projectUri.resolve('$buildDir/native_assets/multiple/');
|
||||
}
|
||||
|
||||
/// Dry run the native builds.
|
||||
///
|
||||
/// This does not build native assets, it only simulates what the final paths
|
||||
/// of all assets will be so that this can be embedded in the kernel file.
|
||||
Future<Uri?> dryRunNativeAssetsSingleArchitecture({
|
||||
required NativeAssetsBuildRunner buildRunner,
|
||||
required Uri projectUri,
|
||||
bool flutterTester = false,
|
||||
required FileSystem fileSystem,
|
||||
required OS os,
|
||||
}) async {
|
||||
if (!await nativeBuildRequired(buildRunner)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Uri buildUri = nativeAssetsBuildUri(projectUri, os);
|
||||
final Iterable<Asset> nativeAssetPaths = await dryRunNativeAssetsSingleArchitectureInternal(
|
||||
fileSystem,
|
||||
projectUri,
|
||||
flutterTester,
|
||||
buildRunner,
|
||||
os,
|
||||
);
|
||||
final Uri nativeAssetsUri = await writeNativeAssetsYaml(
|
||||
nativeAssetPaths,
|
||||
buildUri,
|
||||
fileSystem,
|
||||
);
|
||||
return nativeAssetsUri;
|
||||
}
|
||||
|
||||
Future<Iterable<Asset>> dryRunNativeAssetsSingleArchitectureInternal(
|
||||
FileSystem fileSystem,
|
||||
Uri projectUri,
|
||||
bool flutterTester,
|
||||
NativeAssetsBuildRunner buildRunner,
|
||||
OS targetOS,
|
||||
) async {
|
||||
final Uri buildUri = nativeAssetsBuildUri(projectUri, targetOS);
|
||||
|
||||
globals.logger.printTrace('Dry running native assets for $targetOS.');
|
||||
|
||||
final DryRunResult dryRunResult = await buildRunner.dryRun(
|
||||
linkModePreference: LinkModePreference.dynamic,
|
||||
targetOS: targetOS,
|
||||
workingDirectory: projectUri,
|
||||
includeParentEnvironment: true,
|
||||
);
|
||||
ensureNativeAssetsBuildSucceed(dryRunResult);
|
||||
final List<Asset> nativeAssets = dryRunResult.assets;
|
||||
ensureNoLinkModeStatic(nativeAssets);
|
||||
globals.logger.printTrace('Dry running native assets for $targetOS done.');
|
||||
final Uri? absolutePath = flutterTester ? buildUri : null;
|
||||
final Map<Asset, Asset> assetTargetLocations = _assetTargetLocationsSingleArchitecture(
|
||||
nativeAssets,
|
||||
absolutePath,
|
||||
);
|
||||
final Iterable<Asset> nativeAssetPaths = assetTargetLocations.values;
|
||||
return nativeAssetPaths;
|
||||
}
|
||||
|
||||
/// Builds native assets.
|
||||
///
|
||||
/// If [targetPlatform] is omitted, the current target architecture is used.
|
||||
///
|
||||
/// If [flutterTester] is true, absolute paths are emitted in the native
|
||||
/// assets mapping. This can be used for JIT mode without sandbox on the host.
|
||||
/// This is used in `flutter test` and `flutter run -d flutter-tester`.
|
||||
Future<(Uri? nativeAssetsYaml, List<Uri> dependencies)> buildNativeAssetsSingleArchitecture({
|
||||
required NativeAssetsBuildRunner buildRunner,
|
||||
build_info.TargetPlatform? targetPlatform,
|
||||
required Uri projectUri,
|
||||
required build_info.BuildMode buildMode,
|
||||
bool flutterTester = false,
|
||||
Uri? yamlParentDirectory,
|
||||
required FileSystem fileSystem,
|
||||
}) async {
|
||||
final Target target = targetPlatform != null ? _getNativeTarget(targetPlatform) : Target.current;
|
||||
final OS targetOS = target.os;
|
||||
final Uri buildUri = nativeAssetsBuildUri(projectUri, targetOS);
|
||||
final Directory buildDir = fileSystem.directory(buildUri);
|
||||
if (!await buildDir.exists()) {
|
||||
// CMake requires the folder to exist to do copying.
|
||||
await buildDir.create(recursive: true);
|
||||
}
|
||||
if (!await nativeBuildRequired(buildRunner)) {
|
||||
final Uri nativeAssetsYaml = await writeNativeAssetsYaml(
|
||||
<Asset>[],
|
||||
yamlParentDirectory ?? buildUri,
|
||||
fileSystem,
|
||||
);
|
||||
return (nativeAssetsYaml, <Uri>[]);
|
||||
}
|
||||
|
||||
final BuildMode buildModeCli = nativeAssetsBuildMode(buildMode);
|
||||
|
||||
globals.logger.printTrace('Building native assets for $target $buildModeCli.');
|
||||
final BuildResult result = await buildRunner.build(
|
||||
linkModePreference: LinkModePreference.dynamic,
|
||||
target: target,
|
||||
buildMode: buildModeCli,
|
||||
workingDirectory: projectUri,
|
||||
includeParentEnvironment: true,
|
||||
cCompilerConfig: await buildRunner.cCompilerConfig,
|
||||
);
|
||||
ensureNativeAssetsBuildSucceed(result);
|
||||
final List<Asset> nativeAssets = result.assets;
|
||||
final Set<Uri> dependencies = result.dependencies.toSet();
|
||||
ensureNoLinkModeStatic(nativeAssets);
|
||||
globals.logger.printTrace('Building native assets for $target done.');
|
||||
final Uri? absolutePath = flutterTester ? buildUri : null;
|
||||
final Map<Asset, Asset> assetTargetLocations = _assetTargetLocationsSingleArchitecture(nativeAssets, absolutePath);
|
||||
await _copyNativeAssetsSingleArchitecture(
|
||||
buildUri,
|
||||
assetTargetLocations,
|
||||
buildMode,
|
||||
fileSystem,
|
||||
);
|
||||
final Uri nativeAssetsUri = await writeNativeAssetsYaml(
|
||||
assetTargetLocations.values,
|
||||
yamlParentDirectory ?? buildUri,
|
||||
fileSystem,
|
||||
);
|
||||
return (nativeAssetsUri, dependencies.toList());
|
||||
}
|
||||
|
||||
Map<Asset, Asset> _assetTargetLocationsSingleArchitecture(
|
||||
List<Asset> nativeAssets,
|
||||
Uri? absolutePath,
|
||||
) {
|
||||
return <Asset, Asset>{
|
||||
for (final Asset asset in nativeAssets)
|
||||
asset: _targetLocationSingleArchitecture(
|
||||
asset,
|
||||
absolutePath,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
Asset _targetLocationSingleArchitecture(Asset asset, Uri? absolutePath) {
|
||||
final AssetPath path = asset.path;
|
||||
switch (path) {
|
||||
case AssetSystemPath _:
|
||||
case AssetInExecutable _:
|
||||
case AssetInProcess _:
|
||||
return asset;
|
||||
case AssetAbsolutePath _:
|
||||
final String fileName = path.uri.pathSegments.last;
|
||||
Uri uri;
|
||||
if (absolutePath != null) {
|
||||
// Flutter tester needs full host paths.
|
||||
uri = absolutePath.resolve(fileName);
|
||||
} else {
|
||||
// Flutter Desktop needs "absolute" paths inside the app.
|
||||
// "relative" in the context of native assets would be relative to the
|
||||
// kernel or aot snapshot.
|
||||
uri = Uri(path: fileName);
|
||||
}
|
||||
return asset.copyWith(path: AssetAbsolutePath(uri));
|
||||
}
|
||||
throw Exception('Unsupported asset path type ${path.runtimeType} in asset $asset');
|
||||
}
|
||||
|
||||
/// Extract the [Target] from a [TargetPlatform].
|
||||
///
|
||||
/// Does not cover MacOS, iOS, and Android as these pass the architecture
|
||||
/// in other enums.
|
||||
Target _getNativeTarget(build_info.TargetPlatform targetPlatform) {
|
||||
switch (targetPlatform) {
|
||||
case build_info.TargetPlatform.linux_x64:
|
||||
return Target.linuxX64;
|
||||
case build_info.TargetPlatform.linux_arm64:
|
||||
return Target.linuxArm64;
|
||||
case build_info.TargetPlatform.windows_x64:
|
||||
return Target.windowsX64;
|
||||
case build_info.TargetPlatform.windows_arm64:
|
||||
return Target.windowsArm64;
|
||||
case build_info.TargetPlatform.android:
|
||||
case build_info.TargetPlatform.ios:
|
||||
case build_info.TargetPlatform.darwin:
|
||||
case build_info.TargetPlatform.fuchsia_arm64:
|
||||
case build_info.TargetPlatform.fuchsia_x64:
|
||||
case build_info.TargetPlatform.tester:
|
||||
case build_info.TargetPlatform.web_javascript:
|
||||
case build_info.TargetPlatform.android_arm:
|
||||
case build_info.TargetPlatform.android_arm64:
|
||||
case build_info.TargetPlatform.android_x64:
|
||||
case build_info.TargetPlatform.android_x86:
|
||||
throw Exception('Unknown targetPlatform: $targetPlatform.');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _copyNativeAssetsSingleArchitecture(
|
||||
Uri buildUri,
|
||||
Map<Asset, Asset> assetTargetLocations,
|
||||
build_info.BuildMode buildMode,
|
||||
FileSystem fileSystem,
|
||||
) async {
|
||||
if (assetTargetLocations.isNotEmpty) {
|
||||
globals.logger.printTrace('Copying native assets to ${buildUri.toFilePath()}.');
|
||||
final Directory buildDir = fileSystem.directory(buildUri.toFilePath());
|
||||
if (!buildDir.existsSync()) {
|
||||
buildDir.createSync(recursive: true);
|
||||
}
|
||||
for (final MapEntry<Asset, Asset> assetMapping in assetTargetLocations.entries) {
|
||||
final Uri source = (assetMapping.key.path as AssetAbsolutePath).uri;
|
||||
final Uri target = (assetMapping.value.path as AssetAbsolutePath).uri;
|
||||
final Uri targetUri = buildUri.resolveUri(target);
|
||||
final String targetFullPath = targetUri.toFilePath();
|
||||
await fileSystem.file(source).copy(targetFullPath);
|
||||
}
|
||||
globals.logger.printTrace('Copying native assets done.');
|
||||
}
|
||||
}
|
||||
|
||||
void ensureNativeAssetsBuildSucceed(DryRunResult result) {
|
||||
if (!result.success) {
|
||||
throwToolExit(
|
||||
'Building native assets failed. See the logs for more details.',
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
// 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.
|
||||
|
||||
// Logic for native assets shared between all host OSes.
|
||||
|
||||
import '../../../base/os.dart';
|
||||
import '../../../base/platform.dart';
|
||||
import '../../../build_info.dart';
|
||||
import '../../../globals.dart' as globals;
|
||||
import '../../../native_assets.dart';
|
||||
import '../../../project.dart';
|
||||
import '../linux/native_assets.dart';
|
||||
import '../macos/native_assets.dart';
|
||||
import '../native_assets.dart';
|
||||
import '../windows/native_assets.dart';
|
||||
|
||||
class TestCompilerNativeAssetsBuilderImpl
|
||||
implements TestCompilerNativeAssetsBuilder {
|
||||
const TestCompilerNativeAssetsBuilderImpl();
|
||||
|
||||
@override
|
||||
Future<Uri?> build(BuildInfo buildInfo) =>
|
||||
testCompilerBuildNativeAssets(buildInfo);
|
||||
}
|
||||
|
||||
Future<Uri?> testCompilerBuildNativeAssets(BuildInfo buildInfo) async {
|
||||
Uri? nativeAssetsYaml;
|
||||
if (!buildInfo.buildNativeAssets) {
|
||||
nativeAssetsYaml = null;
|
||||
} else {
|
||||
final Uri projectUri = FlutterProject.current().directory.uri;
|
||||
final NativeAssetsBuildRunner buildRunner = NativeAssetsBuildRunnerImpl(
|
||||
projectUri,
|
||||
buildInfo.packageConfig,
|
||||
globals.fs,
|
||||
globals.logger,
|
||||
);
|
||||
if (globals.platform.isMacOS) {
|
||||
(nativeAssetsYaml, _) = await buildNativeAssetsMacOS(
|
||||
buildMode: buildInfo.mode,
|
||||
projectUri: projectUri,
|
||||
flutterTester: true,
|
||||
fileSystem: globals.fs,
|
||||
buildRunner: buildRunner,
|
||||
);
|
||||
} else if (globals.platform.isLinux) {
|
||||
(nativeAssetsYaml, _) = await buildNativeAssetsLinux(
|
||||
buildMode: buildInfo.mode,
|
||||
projectUri: projectUri,
|
||||
flutterTester: true,
|
||||
fileSystem: globals.fs,
|
||||
buildRunner: buildRunner,
|
||||
);
|
||||
} else if (globals.platform.isWindows) {
|
||||
final TargetPlatform targetPlatform;
|
||||
if (globals.os.hostPlatform == HostPlatform.windows_x64) {
|
||||
targetPlatform = TargetPlatform.windows_x64;
|
||||
} else {
|
||||
targetPlatform = TargetPlatform.windows_arm64;
|
||||
}
|
||||
(nativeAssetsYaml, _) = await buildNativeAssetsWindows(
|
||||
buildMode: buildInfo.mode,
|
||||
targetPlatform: targetPlatform,
|
||||
projectUri: projectUri,
|
||||
flutterTester: true,
|
||||
fileSystem: globals.fs,
|
||||
buildRunner: buildRunner,
|
||||
);
|
||||
} else {
|
||||
await ensureNoNativeAssetsOrOsIsSupported(
|
||||
projectUri,
|
||||
const LocalPlatform().operatingSystem,
|
||||
globals.fs,
|
||||
buildRunner,
|
||||
);
|
||||
}
|
||||
}
|
||||
return nativeAssetsYaml;
|
||||
}
|
@ -5,11 +5,11 @@
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
hide BuildMode;
|
||||
|
||||
import '../base/file_system.dart';
|
||||
import '../build_info.dart';
|
||||
import '../globals.dart' as globals;
|
||||
import '../../../base/file_system.dart';
|
||||
import '../../../build_info.dart';
|
||||
import '../../../globals.dart' as globals;
|
||||
import '../../../windows/visual_studio.dart';
|
||||
import '../native_assets.dart';
|
||||
import 'visual_studio.dart';
|
||||
|
||||
/// Dry run the native builds.
|
||||
///
|
||||
@ -66,7 +66,6 @@ Future<(Uri? nativeAssetsYaml, List<Uri> dependencies)>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Future<CCompilerConfig> cCompilerConfigWindows() async {
|
||||
final VisualStudio visualStudio = VisualStudio(
|
||||
fileSystem: globals.fs,
|
@ -2,702 +2,10 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Logic for native assets shared between all host OSes.
|
||||
import 'build_info.dart';
|
||||
|
||||
import 'package:logging/logging.dart' as logging;
|
||||
import 'package:native_assets_builder/native_assets_builder.dart' hide NativeAssetsBuildRunner;
|
||||
import 'package:native_assets_builder/native_assets_builder.dart' as native_assets_builder show NativeAssetsBuildRunner;
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart';
|
||||
import 'package:package_config/package_config_types.dart';
|
||||
|
||||
import 'android/native_assets.dart';
|
||||
import 'base/common.dart';
|
||||
import 'base/file_system.dart';
|
||||
import 'base/logger.dart';
|
||||
import 'base/platform.dart';
|
||||
import 'build_info.dart' as build_info;
|
||||
import 'cache.dart';
|
||||
import 'features.dart';
|
||||
import 'globals.dart' as globals;
|
||||
import 'ios/native_assets.dart';
|
||||
import 'linux/native_assets.dart';
|
||||
import 'macos/native_assets.dart';
|
||||
import 'macos/native_assets_host.dart';
|
||||
import 'resident_runner.dart';
|
||||
import 'windows/native_assets.dart';
|
||||
|
||||
/// Programmatic API to be used by Dart launchers to invoke native builds.
|
||||
///
|
||||
/// It enables mocking `package:native_assets_builder` package.
|
||||
/// It also enables mocking native toolchain discovery via [cCompilerConfig].
|
||||
abstract class NativeAssetsBuildRunner {
|
||||
/// Whether the project has a `.dart_tools/package_config.json`.
|
||||
///
|
||||
/// If there is no package config, [packagesWithNativeAssets], [build], and
|
||||
/// [dryRun] must not be invoked.
|
||||
Future<bool> hasPackageConfig();
|
||||
|
||||
/// All packages in the transitive dependencies that have a `build.dart`.
|
||||
Future<List<Package>> packagesWithNativeAssets();
|
||||
|
||||
/// Runs all [packagesWithNativeAssets] `build.dart` in dry run.
|
||||
Future<DryRunResult> dryRun({
|
||||
required bool includeParentEnvironment,
|
||||
required LinkModePreference linkModePreference,
|
||||
required OS targetOS,
|
||||
required Uri workingDirectory,
|
||||
});
|
||||
|
||||
/// Runs all [packagesWithNativeAssets] `build.dart`.
|
||||
Future<BuildResult> build({
|
||||
required bool includeParentEnvironment,
|
||||
required BuildMode buildMode,
|
||||
required LinkModePreference linkModePreference,
|
||||
required Target target,
|
||||
required Uri workingDirectory,
|
||||
CCompilerConfig? cCompilerConfig,
|
||||
int? targetAndroidNdkApi,
|
||||
IOSSdk? targetIOSSdk,
|
||||
});
|
||||
|
||||
/// The C compiler config to use for compilation.
|
||||
Future<CCompilerConfig> get cCompilerConfig;
|
||||
|
||||
/// The NDK compiler to use to use for compilation for Android.
|
||||
Future<CCompilerConfig> get ndkCCompilerConfig;
|
||||
}
|
||||
|
||||
/// Uses `package:native_assets_builder` for its implementation.
|
||||
class NativeAssetsBuildRunnerImpl implements NativeAssetsBuildRunner {
|
||||
NativeAssetsBuildRunnerImpl(
|
||||
this.projectUri,
|
||||
this.packageConfig,
|
||||
this.fileSystem,
|
||||
this.logger,
|
||||
);
|
||||
|
||||
final Uri projectUri;
|
||||
final PackageConfig packageConfig;
|
||||
final FileSystem fileSystem;
|
||||
final Logger logger;
|
||||
|
||||
late final logging.Logger _logger = logging.Logger('')
|
||||
..onRecord.listen((logging.LogRecord record) {
|
||||
final int levelValue = record.level.value;
|
||||
final String message = record.message;
|
||||
if (levelValue >= logging.Level.SEVERE.value) {
|
||||
logger.printError(message);
|
||||
} else if (levelValue >= logging.Level.WARNING.value) {
|
||||
logger.printWarning(message);
|
||||
} else if (levelValue >= logging.Level.INFO.value) {
|
||||
logger.printTrace(message);
|
||||
} else {
|
||||
logger.printTrace(message);
|
||||
}
|
||||
});
|
||||
|
||||
late final Uri _dartExecutable = fileSystem.directory(Cache.flutterRoot).uri.resolve('bin/dart');
|
||||
|
||||
late final native_assets_builder.NativeAssetsBuildRunner _buildRunner = native_assets_builder.NativeAssetsBuildRunner(
|
||||
logger: _logger,
|
||||
dartExecutable: _dartExecutable,
|
||||
);
|
||||
|
||||
@override
|
||||
Future<bool> hasPackageConfig() {
|
||||
final File packageConfigJson =
|
||||
fileSystem.directory(projectUri.toFilePath()).childDirectory('.dart_tool').childFile('package_config.json');
|
||||
return packageConfigJson.exists();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Package>> packagesWithNativeAssets() async {
|
||||
final PackageLayout packageLayout = PackageLayout.fromPackageConfig(
|
||||
packageConfig,
|
||||
projectUri.resolve('.dart_tool/package_config.json'),
|
||||
);
|
||||
return packageLayout.packagesWithNativeAssets;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<DryRunResult> dryRun({
|
||||
required bool includeParentEnvironment,
|
||||
required LinkModePreference linkModePreference,
|
||||
required OS targetOS,
|
||||
required Uri workingDirectory,
|
||||
}) {
|
||||
final PackageLayout packageLayout = PackageLayout.fromPackageConfig(
|
||||
packageConfig,
|
||||
projectUri.resolve('.dart_tool/package_config.json'),
|
||||
);
|
||||
return _buildRunner.dryRun(
|
||||
includeParentEnvironment: includeParentEnvironment,
|
||||
linkModePreference: linkModePreference,
|
||||
targetOs: targetOS,
|
||||
workingDirectory: workingDirectory,
|
||||
packageLayout: packageLayout,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<BuildResult> build({
|
||||
required bool includeParentEnvironment,
|
||||
required BuildMode buildMode,
|
||||
required LinkModePreference linkModePreference,
|
||||
required Target target,
|
||||
required Uri workingDirectory,
|
||||
CCompilerConfig? cCompilerConfig,
|
||||
int? targetAndroidNdkApi,
|
||||
IOSSdk? targetIOSSdk,
|
||||
}) {
|
||||
final PackageLayout packageLayout = PackageLayout.fromPackageConfig(
|
||||
packageConfig,
|
||||
projectUri.resolve('.dart_tool/package_config.json'),
|
||||
);
|
||||
return _buildRunner.build(
|
||||
buildMode: buildMode,
|
||||
cCompilerConfig: cCompilerConfig,
|
||||
includeParentEnvironment: includeParentEnvironment,
|
||||
linkModePreference: linkModePreference,
|
||||
target: target,
|
||||
targetAndroidNdkApi: targetAndroidNdkApi,
|
||||
targetIOSSdk: targetIOSSdk,
|
||||
workingDirectory: workingDirectory,
|
||||
packageLayout: packageLayout,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
late final Future<CCompilerConfig> cCompilerConfig = () {
|
||||
if (globals.platform.isMacOS || globals.platform.isIOS) {
|
||||
return cCompilerConfigMacOS();
|
||||
}
|
||||
if (globals.platform.isLinux) {
|
||||
return cCompilerConfigLinux();
|
||||
}
|
||||
if (globals.platform.isWindows) {
|
||||
return cCompilerConfigWindows();
|
||||
}
|
||||
if (globals.platform.isAndroid) {
|
||||
throwToolExit('Should use ndkCCompilerConfig for Android.');
|
||||
}
|
||||
throwToolExit('Unknown target OS.');
|
||||
}();
|
||||
|
||||
@override
|
||||
late final Future<CCompilerConfig> ndkCCompilerConfig = () {
|
||||
return cCompilerConfigAndroid();
|
||||
}();
|
||||
}
|
||||
|
||||
/// Write [assets] to `native_assets.yaml` in [yamlParentDirectory].
|
||||
Future<Uri> writeNativeAssetsYaml(
|
||||
Iterable<Asset> assets,
|
||||
Uri yamlParentDirectory,
|
||||
FileSystem fileSystem,
|
||||
) async {
|
||||
globals.logger.printTrace('Writing native_assets.yaml.');
|
||||
final String nativeAssetsDartContents = assets.toNativeAssetsFile();
|
||||
final Directory parentDirectory = fileSystem.directory(yamlParentDirectory);
|
||||
if (!await parentDirectory.exists()) {
|
||||
await parentDirectory.create(recursive: true);
|
||||
}
|
||||
final File nativeAssetsFile = parentDirectory.childFile('native_assets.yaml');
|
||||
await nativeAssetsFile.writeAsString(nativeAssetsDartContents);
|
||||
globals.logger.printTrace('Writing ${nativeAssetsFile.path} done.');
|
||||
return nativeAssetsFile.uri;
|
||||
}
|
||||
|
||||
/// Select the native asset build mode for a given Flutter build mode.
|
||||
BuildMode nativeAssetsBuildMode(build_info.BuildMode buildMode) {
|
||||
switch (buildMode) {
|
||||
case build_info.BuildMode.debug:
|
||||
return BuildMode.debug;
|
||||
case build_info.BuildMode.jitRelease:
|
||||
case build_info.BuildMode.profile:
|
||||
case build_info.BuildMode.release:
|
||||
return BuildMode.release;
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether this project does not yet have a package config file.
|
||||
///
|
||||
/// A project has no package config when `pub get` has not yet been run.
|
||||
///
|
||||
/// Native asset builds cannot be run without a package config. If there is
|
||||
/// no package config, leave a logging trace about that.
|
||||
Future<bool> _hasNoPackageConfig(NativeAssetsBuildRunner buildRunner) async {
|
||||
final bool packageConfigExists = await buildRunner.hasPackageConfig();
|
||||
if (!packageConfigExists) {
|
||||
globals.logger.printTrace('No package config found. Skipping native assets compilation.');
|
||||
}
|
||||
return !packageConfigExists;
|
||||
}
|
||||
|
||||
Future<bool> nativeBuildRequired(NativeAssetsBuildRunner buildRunner) async {
|
||||
if (await _hasNoPackageConfig(buildRunner)) {
|
||||
return false;
|
||||
}
|
||||
final List<Package> packagesWithNativeAssets = await buildRunner.packagesWithNativeAssets();
|
||||
if (packagesWithNativeAssets.isEmpty) {
|
||||
globals.logger.printTrace(
|
||||
'No packages with native assets. Skipping native assets compilation.',
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!featureFlags.isNativeAssetsEnabled) {
|
||||
final String packageNames = packagesWithNativeAssets.map((Package p) => p.name).join(' ');
|
||||
throwToolExit(
|
||||
'Package(s) $packageNames require the native assets feature to be enabled. '
|
||||
'Enable using `flutter config --enable-native-assets`.',
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Ensures that either this project has no native assets, or that native assets
|
||||
/// are supported on that operating system.
|
||||
///
|
||||
/// Exits the tool if the above condition is not satisfied.
|
||||
Future<void> ensureNoNativeAssetsOrOsIsSupported(
|
||||
Uri workingDirectory,
|
||||
String os,
|
||||
FileSystem fileSystem,
|
||||
NativeAssetsBuildRunner buildRunner,
|
||||
) async {
|
||||
if (await _hasNoPackageConfig(buildRunner)) {
|
||||
return;
|
||||
}
|
||||
final List<Package> packagesWithNativeAssets = await buildRunner.packagesWithNativeAssets();
|
||||
if (packagesWithNativeAssets.isEmpty) {
|
||||
globals.logger.printTrace(
|
||||
'No packages with native assets. Skipping native assets compilation.',
|
||||
);
|
||||
return;
|
||||
}
|
||||
final String packageNames = packagesWithNativeAssets.map((Package p) => p.name).join(' ');
|
||||
throwToolExit(
|
||||
'Package(s) $packageNames require the native assets feature. '
|
||||
'This feature has not yet been implemented for `$os`. '
|
||||
'For more info see https://github.com/flutter/flutter/issues/129757.',
|
||||
);
|
||||
}
|
||||
|
||||
/// Ensure all native assets have a linkmode declared to be dynamic loading.
|
||||
///
|
||||
/// In JIT, the link mode must always be dynamic linking.
|
||||
/// In AOT, the static linking has not yet been implemented in Dart:
|
||||
/// https://github.com/dart-lang/sdk/issues/49418.
|
||||
///
|
||||
/// Therefore, ensure all `build.dart` scripts return only dynamic libraries.
|
||||
void ensureNoLinkModeStatic(List<Asset> nativeAssets) {
|
||||
final Iterable<Asset> staticAssets = nativeAssets.whereLinkMode(LinkMode.static);
|
||||
if (staticAssets.isNotEmpty) {
|
||||
final String assetIds = staticAssets.map((Asset a) => a.id).toSet().join(', ');
|
||||
throwToolExit(
|
||||
'Native asset(s) $assetIds have their link mode set to static, '
|
||||
'but this is not yet supported. '
|
||||
'For more info see https://github.com/dart-lang/sdk/issues/49418.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// This should be the same for different archs, debug/release, etc.
|
||||
/// It should work for all macOS.
|
||||
Uri nativeAssetsBuildUri(Uri projectUri, OS os) {
|
||||
final String buildDir = build_info.getBuildDirectory();
|
||||
return projectUri.resolve('$buildDir/native_assets/$os/');
|
||||
}
|
||||
|
||||
/// Gets the native asset id to dylib mapping to embed in the kernel file.
|
||||
///
|
||||
/// Run hot compiles a kernel file that is pushed to the device after hot
|
||||
/// restart. We need to embed the native assets mapping in order to access
|
||||
/// native assets after hot restart.
|
||||
Future<Uri?> dryRunNativeAssets({
|
||||
required Uri projectUri,
|
||||
required FileSystem fileSystem,
|
||||
required NativeAssetsBuildRunner buildRunner,
|
||||
required List<FlutterDevice> flutterDevices,
|
||||
}) async {
|
||||
if (flutterDevices.length != 1) {
|
||||
return dryRunNativeAssetsMultipleOSes(
|
||||
projectUri: projectUri,
|
||||
fileSystem: fileSystem,
|
||||
targetPlatforms: flutterDevices.map((FlutterDevice d) => d.targetPlatform).nonNulls,
|
||||
buildRunner: buildRunner,
|
||||
);
|
||||
}
|
||||
final FlutterDevice flutterDevice = flutterDevices.single;
|
||||
final build_info.TargetPlatform targetPlatform = flutterDevice.targetPlatform!;
|
||||
|
||||
final Uri? nativeAssetsYaml;
|
||||
switch (targetPlatform) {
|
||||
case build_info.TargetPlatform.darwin:
|
||||
nativeAssetsYaml = await dryRunNativeAssetsMacOS(
|
||||
projectUri: projectUri,
|
||||
fileSystem: fileSystem,
|
||||
buildRunner: buildRunner,
|
||||
);
|
||||
case build_info.TargetPlatform.ios:
|
||||
nativeAssetsYaml = await dryRunNativeAssetsIOS(
|
||||
projectUri: projectUri,
|
||||
fileSystem: fileSystem,
|
||||
buildRunner: buildRunner,
|
||||
);
|
||||
case build_info.TargetPlatform.tester:
|
||||
if (const LocalPlatform().isMacOS) {
|
||||
nativeAssetsYaml = await dryRunNativeAssetsMacOS(
|
||||
projectUri: projectUri,
|
||||
flutterTester: true,
|
||||
fileSystem: fileSystem,
|
||||
buildRunner: buildRunner,
|
||||
);
|
||||
} else if (const LocalPlatform().isLinux) {
|
||||
nativeAssetsYaml = await dryRunNativeAssetsLinux(
|
||||
projectUri: projectUri,
|
||||
flutterTester: true,
|
||||
fileSystem: fileSystem,
|
||||
buildRunner: buildRunner,
|
||||
);
|
||||
} else if (const LocalPlatform().isWindows) {
|
||||
nativeAssetsYaml = await dryRunNativeAssetsWindows(
|
||||
projectUri: projectUri,
|
||||
flutterTester: true,
|
||||
fileSystem: fileSystem,
|
||||
buildRunner: buildRunner,
|
||||
);
|
||||
} else {
|
||||
await nativeBuildRequired(buildRunner);
|
||||
nativeAssetsYaml = null;
|
||||
}
|
||||
case build_info.TargetPlatform.linux_arm64:
|
||||
case build_info.TargetPlatform.linux_x64:
|
||||
nativeAssetsYaml = await dryRunNativeAssetsLinux(
|
||||
projectUri: projectUri,
|
||||
fileSystem: fileSystem,
|
||||
buildRunner: buildRunner,
|
||||
);
|
||||
case build_info.TargetPlatform.windows_arm64:
|
||||
case build_info.TargetPlatform.windows_x64:
|
||||
nativeAssetsYaml = await dryRunNativeAssetsWindows(
|
||||
projectUri: projectUri,
|
||||
fileSystem: fileSystem,
|
||||
buildRunner: buildRunner,
|
||||
);
|
||||
case build_info.TargetPlatform.android_arm:
|
||||
case build_info.TargetPlatform.android_arm64:
|
||||
case build_info.TargetPlatform.android_x64:
|
||||
case build_info.TargetPlatform.android_x86:
|
||||
case build_info.TargetPlatform.android:
|
||||
nativeAssetsYaml = await dryRunNativeAssetsAndroid(
|
||||
projectUri: projectUri,
|
||||
fileSystem: fileSystem,
|
||||
buildRunner: buildRunner,
|
||||
);
|
||||
case build_info.TargetPlatform.fuchsia_arm64:
|
||||
case build_info.TargetPlatform.fuchsia_x64:
|
||||
case build_info.TargetPlatform.web_javascript:
|
||||
await ensureNoNativeAssetsOrOsIsSupported(
|
||||
projectUri,
|
||||
targetPlatform.toString(),
|
||||
fileSystem,
|
||||
buildRunner,
|
||||
);
|
||||
nativeAssetsYaml = null;
|
||||
}
|
||||
return nativeAssetsYaml;
|
||||
}
|
||||
|
||||
/// Dry run the native builds for multiple OSes.
|
||||
///
|
||||
/// Needed for `flutter run -d all`.
|
||||
Future<Uri?> dryRunNativeAssetsMultipleOSes({
|
||||
required NativeAssetsBuildRunner buildRunner,
|
||||
required Uri projectUri,
|
||||
required FileSystem fileSystem,
|
||||
required Iterable<build_info.TargetPlatform> targetPlatforms,
|
||||
}) async {
|
||||
if (await nativeBuildRequired(buildRunner)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Uri buildUri = buildUriMultiple(projectUri);
|
||||
final Iterable<Asset> nativeAssetPaths = <Asset>[
|
||||
if (targetPlatforms.contains(build_info.TargetPlatform.darwin) ||
|
||||
(targetPlatforms.contains(build_info.TargetPlatform.tester) && OS.current == OS.macOS))
|
||||
...await dryRunNativeAssetsMacOSInternal(
|
||||
fileSystem,
|
||||
projectUri,
|
||||
false,
|
||||
buildRunner,
|
||||
),
|
||||
if (targetPlatforms.contains(build_info.TargetPlatform.linux_arm64) ||
|
||||
targetPlatforms.contains(build_info.TargetPlatform.linux_x64) ||
|
||||
(targetPlatforms.contains(build_info.TargetPlatform.tester) && OS.current == OS.linux))
|
||||
...await dryRunNativeAssetsLinuxInternal(
|
||||
fileSystem,
|
||||
projectUri,
|
||||
false,
|
||||
buildRunner,
|
||||
),
|
||||
if (targetPlatforms.contains(build_info.TargetPlatform.windows_arm64) ||
|
||||
targetPlatforms.contains(build_info.TargetPlatform.windows_x64) ||
|
||||
(targetPlatforms.contains(build_info.TargetPlatform.tester) && OS.current == OS.windows))
|
||||
...await dryRunNativeAssetsWindowsInternal(
|
||||
fileSystem,
|
||||
projectUri,
|
||||
false,
|
||||
buildRunner,
|
||||
),
|
||||
if (targetPlatforms.contains(build_info.TargetPlatform.ios))
|
||||
...await dryRunNativeAssetsIOSInternal(
|
||||
fileSystem,
|
||||
projectUri,
|
||||
buildRunner,
|
||||
),
|
||||
if (targetPlatforms.contains(build_info.TargetPlatform.android) ||
|
||||
targetPlatforms.contains(build_info.TargetPlatform.android_arm) ||
|
||||
targetPlatforms.contains(build_info.TargetPlatform.android_arm64) ||
|
||||
targetPlatforms.contains(build_info.TargetPlatform.android_x64) ||
|
||||
targetPlatforms.contains(build_info.TargetPlatform.android_x86))
|
||||
...await dryRunNativeAssetsAndroidInternal(
|
||||
fileSystem,
|
||||
projectUri,
|
||||
buildRunner,
|
||||
),
|
||||
];
|
||||
final Uri nativeAssetsUri = await writeNativeAssetsYaml(nativeAssetPaths, buildUri, fileSystem);
|
||||
return nativeAssetsUri;
|
||||
}
|
||||
|
||||
/// With `flutter run -d all` we need a place to store the native assets
|
||||
/// mapping for multiple OSes combined.
|
||||
Uri buildUriMultiple(Uri projectUri) {
|
||||
final String buildDir = build_info.getBuildDirectory();
|
||||
return projectUri.resolve('$buildDir/native_assets/multiple/');
|
||||
}
|
||||
|
||||
/// Dry run the native builds.
|
||||
///
|
||||
/// This does not build native assets, it only simulates what the final paths
|
||||
/// of all assets will be so that this can be embedded in the kernel file.
|
||||
Future<Uri?> dryRunNativeAssetsSingleArchitecture({
|
||||
required NativeAssetsBuildRunner buildRunner,
|
||||
required Uri projectUri,
|
||||
bool flutterTester = false,
|
||||
required FileSystem fileSystem,
|
||||
required OS os,
|
||||
}) async {
|
||||
if (!await nativeBuildRequired(buildRunner)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Uri buildUri = nativeAssetsBuildUri(projectUri, os);
|
||||
final Iterable<Asset> nativeAssetPaths = await dryRunNativeAssetsSingleArchitectureInternal(
|
||||
fileSystem,
|
||||
projectUri,
|
||||
flutterTester,
|
||||
buildRunner,
|
||||
os,
|
||||
);
|
||||
final Uri nativeAssetsUri = await writeNativeAssetsYaml(
|
||||
nativeAssetPaths,
|
||||
buildUri,
|
||||
fileSystem,
|
||||
);
|
||||
return nativeAssetsUri;
|
||||
}
|
||||
|
||||
Future<Iterable<Asset>> dryRunNativeAssetsSingleArchitectureInternal(
|
||||
FileSystem fileSystem,
|
||||
Uri projectUri,
|
||||
bool flutterTester,
|
||||
NativeAssetsBuildRunner buildRunner,
|
||||
OS targetOS,
|
||||
) async {
|
||||
final Uri buildUri = nativeAssetsBuildUri(projectUri, targetOS);
|
||||
|
||||
globals.logger.printTrace('Dry running native assets for $targetOS.');
|
||||
|
||||
final DryRunResult dryRunResult = await buildRunner.dryRun(
|
||||
linkModePreference: LinkModePreference.dynamic,
|
||||
targetOS: targetOS,
|
||||
workingDirectory: projectUri,
|
||||
includeParentEnvironment: true,
|
||||
);
|
||||
ensureNativeAssetsBuildSucceed(dryRunResult);
|
||||
final List<Asset> nativeAssets = dryRunResult.assets;
|
||||
ensureNoLinkModeStatic(nativeAssets);
|
||||
globals.logger.printTrace('Dry running native assets for $targetOS done.');
|
||||
final Uri? absolutePath = flutterTester ? buildUri : null;
|
||||
final Map<Asset, Asset> assetTargetLocations = _assetTargetLocationsSingleArchitecture(
|
||||
nativeAssets,
|
||||
absolutePath,
|
||||
);
|
||||
final Iterable<Asset> nativeAssetPaths = assetTargetLocations.values;
|
||||
return nativeAssetPaths;
|
||||
}
|
||||
|
||||
/// Builds native assets.
|
||||
///
|
||||
/// If [targetPlatform] is omitted, the current target architecture is used.
|
||||
///
|
||||
/// If [flutterTester] is true, absolute paths are emitted in the native
|
||||
/// assets mapping. This can be used for JIT mode without sandbox on the host.
|
||||
/// This is used in `flutter test` and `flutter run -d flutter-tester`.
|
||||
Future<(Uri? nativeAssetsYaml, List<Uri> dependencies)> buildNativeAssetsSingleArchitecture({
|
||||
required NativeAssetsBuildRunner buildRunner,
|
||||
build_info.TargetPlatform? targetPlatform,
|
||||
required Uri projectUri,
|
||||
required build_info.BuildMode buildMode,
|
||||
bool flutterTester = false,
|
||||
Uri? yamlParentDirectory,
|
||||
required FileSystem fileSystem,
|
||||
}) async {
|
||||
final Target target = targetPlatform != null ? _getNativeTarget(targetPlatform) : Target.current;
|
||||
final OS targetOS = target.os;
|
||||
final Uri buildUri = nativeAssetsBuildUri(projectUri, targetOS);
|
||||
final Directory buildDir = fileSystem.directory(buildUri);
|
||||
if (!await buildDir.exists()) {
|
||||
// CMake requires the folder to exist to do copying.
|
||||
await buildDir.create(recursive: true);
|
||||
}
|
||||
if (!await nativeBuildRequired(buildRunner)) {
|
||||
final Uri nativeAssetsYaml = await writeNativeAssetsYaml(
|
||||
<Asset>[],
|
||||
yamlParentDirectory ?? buildUri,
|
||||
fileSystem,
|
||||
);
|
||||
return (nativeAssetsYaml, <Uri>[]);
|
||||
}
|
||||
|
||||
final BuildMode buildModeCli = nativeAssetsBuildMode(buildMode);
|
||||
|
||||
globals.logger.printTrace('Building native assets for $target $buildModeCli.');
|
||||
final BuildResult result = await buildRunner.build(
|
||||
linkModePreference: LinkModePreference.dynamic,
|
||||
target: target,
|
||||
buildMode: buildModeCli,
|
||||
workingDirectory: projectUri,
|
||||
includeParentEnvironment: true,
|
||||
cCompilerConfig: await buildRunner.cCompilerConfig,
|
||||
);
|
||||
ensureNativeAssetsBuildSucceed(result);
|
||||
final List<Asset> nativeAssets = result.assets;
|
||||
final Set<Uri> dependencies = result.dependencies.toSet();
|
||||
ensureNoLinkModeStatic(nativeAssets);
|
||||
globals.logger.printTrace('Building native assets for $target done.');
|
||||
final Uri? absolutePath = flutterTester ? buildUri : null;
|
||||
final Map<Asset, Asset> assetTargetLocations = _assetTargetLocationsSingleArchitecture(nativeAssets, absolutePath);
|
||||
await _copyNativeAssetsSingleArchitecture(
|
||||
buildUri,
|
||||
assetTargetLocations,
|
||||
buildMode,
|
||||
fileSystem,
|
||||
);
|
||||
final Uri nativeAssetsUri = await writeNativeAssetsYaml(
|
||||
assetTargetLocations.values,
|
||||
yamlParentDirectory ?? buildUri,
|
||||
fileSystem,
|
||||
);
|
||||
return (nativeAssetsUri, dependencies.toList());
|
||||
}
|
||||
|
||||
Map<Asset, Asset> _assetTargetLocationsSingleArchitecture(
|
||||
List<Asset> nativeAssets,
|
||||
Uri? absolutePath,
|
||||
) {
|
||||
return <Asset, Asset>{
|
||||
for (final Asset asset in nativeAssets)
|
||||
asset: _targetLocationSingleArchitecture(
|
||||
asset,
|
||||
absolutePath,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
Asset _targetLocationSingleArchitecture(Asset asset, Uri? absolutePath) {
|
||||
final AssetPath path = asset.path;
|
||||
switch (path) {
|
||||
case AssetSystemPath _:
|
||||
case AssetInExecutable _:
|
||||
case AssetInProcess _:
|
||||
return asset;
|
||||
case AssetAbsolutePath _:
|
||||
final String fileName = path.uri.pathSegments.last;
|
||||
Uri uri;
|
||||
if (absolutePath != null) {
|
||||
// Flutter tester needs full host paths.
|
||||
uri = absolutePath.resolve(fileName);
|
||||
} else {
|
||||
// Flutter Desktop needs "absolute" paths inside the app.
|
||||
// "relative" in the context of native assets would be relative to the
|
||||
// kernel or aot snapshot.
|
||||
uri = Uri(path: fileName);
|
||||
}
|
||||
return asset.copyWith(path: AssetAbsolutePath(uri));
|
||||
}
|
||||
throw Exception('Unsupported asset path type ${path.runtimeType} in asset $asset');
|
||||
}
|
||||
|
||||
/// Extract the [Target] from a [TargetPlatform].
|
||||
///
|
||||
/// Does not cover MacOS, iOS, and Android as these pass the architecture
|
||||
/// in other enums.
|
||||
Target _getNativeTarget(build_info.TargetPlatform targetPlatform) {
|
||||
switch (targetPlatform) {
|
||||
case build_info.TargetPlatform.linux_x64:
|
||||
return Target.linuxX64;
|
||||
case build_info.TargetPlatform.linux_arm64:
|
||||
return Target.linuxArm64;
|
||||
case build_info.TargetPlatform.windows_x64:
|
||||
return Target.windowsX64;
|
||||
case build_info.TargetPlatform.windows_arm64:
|
||||
return Target.windowsArm64;
|
||||
case build_info.TargetPlatform.android:
|
||||
case build_info.TargetPlatform.ios:
|
||||
case build_info.TargetPlatform.darwin:
|
||||
case build_info.TargetPlatform.fuchsia_arm64:
|
||||
case build_info.TargetPlatform.fuchsia_x64:
|
||||
case build_info.TargetPlatform.tester:
|
||||
case build_info.TargetPlatform.web_javascript:
|
||||
case build_info.TargetPlatform.android_arm:
|
||||
case build_info.TargetPlatform.android_arm64:
|
||||
case build_info.TargetPlatform.android_x64:
|
||||
case build_info.TargetPlatform.android_x86:
|
||||
throw Exception('Unknown targetPlatform: $targetPlatform.');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _copyNativeAssetsSingleArchitecture(
|
||||
Uri buildUri,
|
||||
Map<Asset, Asset> assetTargetLocations,
|
||||
build_info.BuildMode buildMode,
|
||||
FileSystem fileSystem,
|
||||
) async {
|
||||
if (assetTargetLocations.isNotEmpty) {
|
||||
globals.logger.printTrace('Copying native assets to ${buildUri.toFilePath()}.');
|
||||
final Directory buildDir = fileSystem.directory(buildUri.toFilePath());
|
||||
if (!buildDir.existsSync()) {
|
||||
buildDir.createSync(recursive: true);
|
||||
}
|
||||
for (final MapEntry<Asset, Asset> assetMapping in assetTargetLocations.entries) {
|
||||
final Uri source = (assetMapping.key.path as AssetAbsolutePath).uri;
|
||||
final Uri target = (assetMapping.value.path as AssetAbsolutePath).uri;
|
||||
final Uri targetUri = buildUri.resolveUri(target);
|
||||
final String targetFullPath = targetUri.toFilePath();
|
||||
await fileSystem.file(source).copy(targetFullPath);
|
||||
}
|
||||
globals.logger.printTrace('Copying native assets done.');
|
||||
}
|
||||
}
|
||||
|
||||
void ensureNativeAssetsBuildSucceed(DryRunResult result) {
|
||||
if (!result.success) {
|
||||
throwToolExit(
|
||||
'Building native assets failed. See the logs for more details.',
|
||||
);
|
||||
}
|
||||
/// An interface to enable overriding native assets build logic in other
|
||||
/// build systems.
|
||||
abstract class TestCompilerNativeAssetsBuilder {
|
||||
Future<Uri?> build(BuildInfo buildInfo);
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ import 'dart/package_map.dart';
|
||||
import 'devfs.dart';
|
||||
import 'device.dart';
|
||||
import 'globals.dart' as globals;
|
||||
import 'native_assets.dart';
|
||||
import 'project.dart';
|
||||
import 'reporting/reporting.dart';
|
||||
import 'resident_runner.dart';
|
||||
@ -93,13 +92,13 @@ class HotRunner extends ResidentRunner {
|
||||
StopwatchFactory stopwatchFactory = const StopwatchFactory(),
|
||||
ReloadSourcesHelper reloadSourcesHelper = defaultReloadSourcesHelper,
|
||||
ReassembleHelper reassembleHelper = _defaultReassembleHelper,
|
||||
NativeAssetsBuildRunner? buildRunner,
|
||||
HotRunnerNativeAssetsBuilder? nativeAssetsBuilder,
|
||||
String? nativeAssetsYamlFile,
|
||||
required Analytics analytics,
|
||||
}) : _stopwatchFactory = stopwatchFactory,
|
||||
_reloadSourcesHelper = reloadSourcesHelper,
|
||||
_reassembleHelper = reassembleHelper,
|
||||
_buildRunner = buildRunner,
|
||||
_nativeAssetsBuilder = nativeAssetsBuilder,
|
||||
_nativeAssetsYamlFile = nativeAssetsYamlFile,
|
||||
_analytics = analytics,
|
||||
super(
|
||||
@ -139,7 +138,7 @@ class HotRunner extends ResidentRunner {
|
||||
String? _sdkName;
|
||||
bool? _emulator;
|
||||
|
||||
NativeAssetsBuildRunner? _buildRunner;
|
||||
final HotRunnerNativeAssetsBuilder? _nativeAssetsBuilder;
|
||||
final String? _nativeAssetsYamlFile;
|
||||
|
||||
String? flavor;
|
||||
@ -374,17 +373,12 @@ class HotRunner extends ResidentRunner {
|
||||
nativeAssetsYaml = globals.fs.path.toUri(_nativeAssetsYamlFile);
|
||||
} else {
|
||||
final Uri projectUri = Uri.directory(projectRootPath);
|
||||
_buildRunner ??= NativeAssetsBuildRunnerImpl(
|
||||
projectUri,
|
||||
debuggingOptions.buildInfo.packageConfig,
|
||||
fileSystem,
|
||||
globals.logger,
|
||||
);
|
||||
nativeAssetsYaml = await dryRunNativeAssets(
|
||||
nativeAssetsYaml = await _nativeAssetsBuilder?.dryRun(
|
||||
projectUri: projectUri,
|
||||
fileSystem: fileSystem,
|
||||
buildRunner: _buildRunner!,
|
||||
flutterDevices: flutterDevices,
|
||||
logger: logger,
|
||||
packageConfig: debuggingOptions.buildInfo.packageConfig,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1727,3 +1721,15 @@ class ReasonForCancelling {
|
||||
return '$message.\nTry performing a hot restart instead.';
|
||||
}
|
||||
}
|
||||
|
||||
/// An interface to enable overriding native assets build logic in other
|
||||
/// build systems.
|
||||
abstract class HotRunnerNativeAssetsBuilder {
|
||||
Future<Uri?> dryRun({
|
||||
required Uri projectUri,
|
||||
required FileSystem fileSystem,
|
||||
required List<FlutterDevice> flutterDevices,
|
||||
required PackageConfig packageConfig,
|
||||
required Logger logger,
|
||||
});
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import '../convert.dart';
|
||||
import '../dart/language_version.dart';
|
||||
import '../device.dart';
|
||||
import '../globals.dart' as globals;
|
||||
import '../native_assets.dart';
|
||||
import '../project.dart';
|
||||
import '../test/test_wrapper.dart';
|
||||
|
||||
@ -69,6 +70,7 @@ FlutterPlatform installHook({
|
||||
String? integrationTestUserIdentifier,
|
||||
TestTimeRecorder? testTimeRecorder,
|
||||
UriConverter? uriConverter,
|
||||
TestCompilerNativeAssetsBuilder? nativeAssetsBuilder,
|
||||
}) {
|
||||
assert(enableVmService || enableObservatory || (!debuggingOptions.startPaused && debuggingOptions.hostVmServicePort == null));
|
||||
|
||||
@ -99,6 +101,7 @@ FlutterPlatform installHook({
|
||||
integrationTestUserIdentifier: integrationTestUserIdentifier,
|
||||
testTimeRecorder: testTimeRecorder,
|
||||
uriConverter: uriConverter,
|
||||
nativeAssetsBuilder: nativeAssetsBuilder,
|
||||
);
|
||||
platformPluginRegistration(platform);
|
||||
return platform;
|
||||
@ -291,6 +294,7 @@ class FlutterPlatform extends PlatformPlugin {
|
||||
this.integrationTestUserIdentifier,
|
||||
this.testTimeRecorder,
|
||||
this.uriConverter,
|
||||
this.nativeAssetsBuilder,
|
||||
});
|
||||
|
||||
final String shellPath;
|
||||
@ -307,6 +311,7 @@ class FlutterPlatform extends PlatformPlugin {
|
||||
final FlutterProject? flutterProject;
|
||||
final String? icudtlPath;
|
||||
final TestTimeRecorder? testTimeRecorder;
|
||||
final TestCompilerNativeAssetsBuilder? nativeAssetsBuilder;
|
||||
|
||||
// This can be used by internal projects that require custom logic for converting package: URIs to local paths.
|
||||
final UriConverter? uriConverter;
|
||||
@ -465,7 +470,13 @@ class FlutterPlatform extends PlatformPlugin {
|
||||
// running this with a debugger attached. Initialize the resident
|
||||
// compiler in this case.
|
||||
if (debuggingOptions.startPaused) {
|
||||
compiler ??= TestCompiler(debuggingOptions.buildInfo, flutterProject, precompiledDillPath: precompiledDillPath, testTimeRecorder: testTimeRecorder);
|
||||
compiler ??= TestCompiler(
|
||||
debuggingOptions.buildInfo,
|
||||
flutterProject,
|
||||
precompiledDillPath: precompiledDillPath,
|
||||
testTimeRecorder: testTimeRecorder,
|
||||
nativeAssetsBuilder: nativeAssetsBuilder,
|
||||
);
|
||||
final Uri uri = globals.fs.file(path).uri;
|
||||
// Trigger a compilation to initialize the resident compiler.
|
||||
unawaited(compiler!.compile(uri));
|
||||
@ -487,7 +498,12 @@ class FlutterPlatform extends PlatformPlugin {
|
||||
// Integration test device takes care of the compilation.
|
||||
if (integrationTestDevice == null) {
|
||||
// Lazily instantiate compiler so it is built only if it is actually used.
|
||||
compiler ??= TestCompiler(debuggingOptions.buildInfo, flutterProject, testTimeRecorder: testTimeRecorder);
|
||||
compiler ??= TestCompiler(
|
||||
debuggingOptions.buildInfo,
|
||||
flutterProject,
|
||||
testTimeRecorder: testTimeRecorder,
|
||||
nativeAssetsBuilder: nativeAssetsBuilder,
|
||||
);
|
||||
mainDart = await compiler!.compile(globals.fs.file(mainDart).uri);
|
||||
|
||||
if (mainDart == null) {
|
||||
|
@ -7,6 +7,7 @@ import '../base/file_system.dart';
|
||||
import '../base/io.dart';
|
||||
import '../device.dart';
|
||||
import '../globals.dart' as globals;
|
||||
import '../native_assets.dart';
|
||||
import '../project.dart';
|
||||
import '../web/chrome.dart';
|
||||
import '../web/memory_fs.dart';
|
||||
@ -53,6 +54,7 @@ abstract class FlutterTestRunner {
|
||||
Device? integrationTestDevice,
|
||||
String? integrationTestUserIdentifier,
|
||||
TestTimeRecorder? testTimeRecorder,
|
||||
TestCompilerNativeAssetsBuilder? nativeAssetsBuilder,
|
||||
});
|
||||
}
|
||||
|
||||
@ -91,6 +93,7 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner {
|
||||
Device? integrationTestDevice,
|
||||
String? integrationTestUserIdentifier,
|
||||
TestTimeRecorder? testTimeRecorder,
|
||||
TestCompilerNativeAssetsBuilder? nativeAssetsBuilder,
|
||||
}) async {
|
||||
// Configure package:test to use the Flutter engine for child processes.
|
||||
final String shellPath = globals.artifacts!.getArtifactPath(Artifact.flutterTester);
|
||||
@ -210,6 +213,7 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner {
|
||||
integrationTestDevice: integrationTestDevice,
|
||||
integrationTestUserIdentifier: integrationTestUserIdentifier,
|
||||
testTimeRecorder: testTimeRecorder,
|
||||
nativeAssetsBuilder: nativeAssetsBuilder,
|
||||
);
|
||||
|
||||
try {
|
||||
|
@ -10,18 +10,13 @@ import 'package:meta/meta.dart';
|
||||
|
||||
import '../artifacts.dart';
|
||||
import '../base/file_system.dart';
|
||||
import '../base/os.dart' show HostPlatform;
|
||||
import '../base/platform.dart';
|
||||
import '../build_info.dart';
|
||||
import '../bundle.dart';
|
||||
import '../compile.dart';
|
||||
import '../flutter_plugins.dart';
|
||||
import '../globals.dart' as globals;
|
||||
import '../linux/native_assets.dart';
|
||||
import '../macos/native_assets.dart';
|
||||
import '../native_assets.dart';
|
||||
import '../project.dart';
|
||||
import '../windows/native_assets.dart';
|
||||
import 'test_time_recorder.dart';
|
||||
|
||||
/// A request to the [TestCompiler] for recompilation.
|
||||
@ -51,9 +46,11 @@ class TestCompiler {
|
||||
/// If [testTimeRecorder] is passed, times will be recorded in it.
|
||||
TestCompiler(
|
||||
this.buildInfo,
|
||||
this.flutterProject,
|
||||
{ String? precompiledDillPath, this.testTimeRecorder }
|
||||
) : testFilePath = precompiledDillPath ?? globals.fs.path.join(
|
||||
this.flutterProject, {
|
||||
String? precompiledDillPath,
|
||||
this.testTimeRecorder,
|
||||
TestCompilerNativeAssetsBuilder? nativeAssetsBuilder,
|
||||
}) : testFilePath = precompiledDillPath ?? globals.fs.path.join(
|
||||
flutterProject!.directory.path,
|
||||
getBuildDirectory(),
|
||||
'test_cache',
|
||||
@ -62,7 +59,8 @@ class TestCompiler {
|
||||
dartDefines: buildInfo.dartDefines,
|
||||
extraFrontEndOptions: buildInfo.extraFrontEndOptions,
|
||||
)),
|
||||
shouldCopyDillFile = precompiledDillPath == null {
|
||||
shouldCopyDillFile = precompiledDillPath == null,
|
||||
_nativeAssetsBuilder = nativeAssetsBuilder {
|
||||
// Compiler maintains and updates single incremental dill file.
|
||||
// Incremental compilation requests done for each test copy that file away
|
||||
// for independent execution.
|
||||
@ -83,6 +81,7 @@ class TestCompiler {
|
||||
final String testFilePath;
|
||||
final bool shouldCopyDillFile;
|
||||
final TestTimeRecorder? testTimeRecorder;
|
||||
final TestCompilerNativeAssetsBuilder? _nativeAssetsBuilder;
|
||||
|
||||
|
||||
ResidentCompiler? compiler;
|
||||
@ -170,57 +169,7 @@ class TestCompiler {
|
||||
invalidatedRegistrantFiles.add(flutterProject!.dartPluginRegistrant.absolute.uri);
|
||||
}
|
||||
|
||||
Uri? nativeAssetsYaml;
|
||||
if (!buildInfo.buildNativeAssets) {
|
||||
nativeAssetsYaml = null;
|
||||
} else {
|
||||
final Uri projectUri = FlutterProject.current().directory.uri;
|
||||
final NativeAssetsBuildRunner buildRunner = NativeAssetsBuildRunnerImpl(
|
||||
projectUri,
|
||||
buildInfo.packageConfig,
|
||||
globals.fs,
|
||||
globals.logger,
|
||||
);
|
||||
if (globals.platform.isMacOS) {
|
||||
(nativeAssetsYaml, _) = await buildNativeAssetsMacOS(
|
||||
buildMode: buildInfo.mode,
|
||||
projectUri: projectUri,
|
||||
flutterTester: true,
|
||||
fileSystem: globals.fs,
|
||||
buildRunner: buildRunner,
|
||||
);
|
||||
} else if (globals.platform.isLinux) {
|
||||
(nativeAssetsYaml, _) = await buildNativeAssetsLinux(
|
||||
buildMode: buildInfo.mode,
|
||||
projectUri: projectUri,
|
||||
flutterTester: true,
|
||||
fileSystem: globals.fs,
|
||||
buildRunner: buildRunner,
|
||||
);
|
||||
} else if (globals.platform.isWindows) {
|
||||
final TargetPlatform targetPlatform;
|
||||
if (globals.os.hostPlatform == HostPlatform.windows_x64) {
|
||||
targetPlatform = TargetPlatform.windows_x64;
|
||||
} else {
|
||||
targetPlatform = TargetPlatform.windows_arm64;
|
||||
}
|
||||
(nativeAssetsYaml, _) = await buildNativeAssetsWindows(
|
||||
buildMode: buildInfo.mode,
|
||||
targetPlatform: targetPlatform,
|
||||
projectUri: projectUri,
|
||||
flutterTester: true,
|
||||
fileSystem: globals.fs,
|
||||
buildRunner: buildRunner,
|
||||
);
|
||||
} else {
|
||||
await ensureNoNativeAssetsOrOsIsSupported(
|
||||
projectUri,
|
||||
const LocalPlatform().operatingSystem,
|
||||
globals.fs,
|
||||
buildRunner,
|
||||
);
|
||||
}
|
||||
}
|
||||
final Uri? nativeAssetsYaml = await _nativeAssetsBuilder?.build(buildInfo);
|
||||
|
||||
final CompilerOutput? compilerOutput = await compiler!.recompile(
|
||||
request.mainUri,
|
||||
|
@ -1203,6 +1203,7 @@ class FakeHotRunnerFactory extends Fake implements HotRunnerFactory {
|
||||
FlutterProject? flutterProject,
|
||||
Analytics? analytics,
|
||||
String? nativeAssetsYamlFile,
|
||||
HotRunnerNativeAssetsBuilder? nativeAssetsBuilder,
|
||||
}) {
|
||||
if (_artifactTester != null) {
|
||||
for (final FlutterDevice device in devices) {
|
||||
|
@ -29,6 +29,7 @@ import 'package:flutter_tools/src/macos/macos_ipad_device.dart';
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
import 'package:flutter_tools/src/reporting/reporting.dart';
|
||||
import 'package:flutter_tools/src/resident_runner.dart';
|
||||
import 'package:flutter_tools/src/run_hot.dart';
|
||||
import 'package:flutter_tools/src/runner/flutter_command.dart';
|
||||
import 'package:flutter_tools/src/vmservice.dart';
|
||||
import 'package:test/fake.dart';
|
||||
@ -1578,6 +1579,7 @@ class CapturingAppDomain extends AppDomain {
|
||||
String? userIdentifier,
|
||||
bool enableDevTools = true,
|
||||
String? flavor,
|
||||
HotRunnerNativeAssetsBuilder? nativeAssetsBuilder,
|
||||
}) async {
|
||||
this.userIdentifier = userIdentifier;
|
||||
this.enableDevTools = enableDevTools;
|
||||
|
@ -14,6 +14,7 @@ import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/commands/test.dart';
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:flutter_tools/src/native_assets.dart';
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
import 'package:flutter_tools/src/runner/flutter_command.dart';
|
||||
import 'package:flutter_tools/src/test/coverage_collector.dart';
|
||||
@ -1124,6 +1125,7 @@ class FakeFlutterTestRunner implements FlutterTestRunner {
|
||||
Device? integrationTestDevice,
|
||||
String? integrationTestUserIdentifier,
|
||||
TestTimeRecorder? testTimeRecorder,
|
||||
TestCompilerNativeAssetsBuilder? nativeAssetsBuilder,
|
||||
}) async {
|
||||
lastEnableVmServiceValue = enableVmService;
|
||||
lastDebuggingOptionsValue = debuggingOptions;
|
||||
|
231
packages/flutter_tools/test/general.shard/hot_shared.dart
Normal file
231
packages/flutter_tools/test/general.shard/hot_shared.dart
Normal file
@ -0,0 +1,231 @@
|
||||
// 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/application_package.dart';
|
||||
import 'package:flutter_tools/src/asset.dart';
|
||||
import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/build_system/tools/shader_compiler.dart';
|
||||
import 'package:flutter_tools/src/compile.dart';
|
||||
import 'package:flutter_tools/src/devfs.dart';
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
import 'package:flutter_tools/src/resident_runner.dart';
|
||||
import 'package:flutter_tools/src/run_hot.dart';
|
||||
import 'package:flutter_tools/src/vmservice.dart';
|
||||
import 'package:package_config/package_config.dart';
|
||||
import 'package:test/fake.dart';
|
||||
import 'package:vm_service/vm_service.dart' as vm_service;
|
||||
|
||||
class FakeDevFs extends Fake implements DevFS {
|
||||
@override
|
||||
Future<void> destroy() async { }
|
||||
|
||||
@override
|
||||
List<Uri> sources = <Uri>[];
|
||||
|
||||
@override
|
||||
DateTime? lastCompiled;
|
||||
|
||||
@override
|
||||
PackageConfig? lastPackageConfig;
|
||||
|
||||
@override
|
||||
Set<String> assetPathsToEvict = <String>{};
|
||||
|
||||
@override
|
||||
Set<String> shaderPathsToEvict= <String>{};
|
||||
|
||||
@override
|
||||
Set<String> scenePathsToEvict= <String>{};
|
||||
|
||||
@override
|
||||
Uri? baseUri;
|
||||
}
|
||||
|
||||
class FakeDevice extends Fake implements Device {
|
||||
FakeDevice({
|
||||
TargetPlatform targetPlatform = TargetPlatform.tester,
|
||||
}) : _targetPlatform = targetPlatform;
|
||||
|
||||
final TargetPlatform _targetPlatform;
|
||||
|
||||
bool disposed = false;
|
||||
|
||||
@override
|
||||
bool isSupported() => true;
|
||||
|
||||
@override
|
||||
bool supportsHotReload = true;
|
||||
|
||||
@override
|
||||
bool supportsHotRestart = true;
|
||||
|
||||
@override
|
||||
bool supportsFlutterExit = true;
|
||||
|
||||
@override
|
||||
Future<TargetPlatform> get targetPlatform async => _targetPlatform;
|
||||
|
||||
@override
|
||||
Future<String> get sdkNameAndVersion async => 'Tester';
|
||||
|
||||
@override
|
||||
Future<bool> get isLocalEmulator async => false;
|
||||
|
||||
@override
|
||||
String get name => 'Fake Device';
|
||||
|
||||
@override
|
||||
Future<bool> stopApp(
|
||||
ApplicationPackage? app, {
|
||||
String? userIdentifier,
|
||||
}) async {
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> dispose() async {
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
class FakeFlutterDevice extends Fake implements FlutterDevice {
|
||||
FakeFlutterDevice(this.device);
|
||||
|
||||
bool stoppedEchoingDeviceLog = false;
|
||||
late Future<UpdateFSReport> Function() updateDevFSReportCallback;
|
||||
|
||||
@override
|
||||
final FakeDevice device;
|
||||
|
||||
@override
|
||||
Future<void> stopEchoingDeviceLog() async {
|
||||
stoppedEchoingDeviceLog = true;
|
||||
}
|
||||
|
||||
@override
|
||||
DevFS? devFS = FakeDevFs();
|
||||
|
||||
@override
|
||||
FlutterVmService get vmService => FakeFlutterVmService();
|
||||
|
||||
@override
|
||||
ResidentCompiler? generator;
|
||||
|
||||
@override
|
||||
Future<UpdateFSReport> updateDevFS({
|
||||
Uri? mainUri,
|
||||
String? target,
|
||||
AssetBundle? bundle,
|
||||
DateTime? firstBuildTime,
|
||||
bool bundleFirstUpload = false,
|
||||
bool bundleDirty = false,
|
||||
bool fullRestart = false,
|
||||
String? projectRootPath,
|
||||
String? pathToReload,
|
||||
required String dillOutputPath,
|
||||
required List<Uri> invalidatedFiles,
|
||||
required PackageConfig packageConfig,
|
||||
}) => updateDevFSReportCallback();
|
||||
|
||||
@override
|
||||
TargetPlatform? get targetPlatform => device._targetPlatform;
|
||||
}
|
||||
|
||||
class TestFlutterDevice extends FlutterDevice {
|
||||
TestFlutterDevice({
|
||||
required Device device,
|
||||
required this.exception,
|
||||
required ResidentCompiler generator,
|
||||
}) : super(device, buildInfo: BuildInfo.debug, generator: generator, developmentShaderCompiler: const FakeShaderCompiler());
|
||||
|
||||
/// The exception to throw when the connect method is called.
|
||||
final Exception exception;
|
||||
|
||||
@override
|
||||
Future<void> connect({
|
||||
ReloadSources? reloadSources,
|
||||
Restart? restart,
|
||||
CompileExpression? compileExpression,
|
||||
GetSkSLMethod? getSkSLMethod,
|
||||
FlutterProject? flutterProject,
|
||||
PrintStructuredErrorLogMethod? printStructuredErrorLogMethod,
|
||||
bool disableServiceAuthCodes = false,
|
||||
bool enableDds = true,
|
||||
bool cacheStartupProfile = false,
|
||||
bool? ipv6 = false,
|
||||
int? hostVmServicePort,
|
||||
int? ddsPort,
|
||||
bool allowExistingDdsInstance = false,
|
||||
}) async {
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
class TestHotRunnerConfig extends HotRunnerConfig {
|
||||
TestHotRunnerConfig({this.successfulHotRestartSetup, this.successfulHotReloadSetup});
|
||||
bool? successfulHotRestartSetup;
|
||||
bool? successfulHotReloadSetup;
|
||||
bool shutdownHookCalled = false;
|
||||
bool updateDevFSCompleteCalled = false;
|
||||
|
||||
@override
|
||||
Future<bool?> setupHotRestart() async {
|
||||
assert(successfulHotRestartSetup != null, 'setupHotRestart is not expected to be called in this test.');
|
||||
return successfulHotRestartSetup;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool?> setupHotReload() async {
|
||||
assert(successfulHotReloadSetup != null, 'setupHotReload is not expected to be called in this test.');
|
||||
return successfulHotReloadSetup;
|
||||
}
|
||||
|
||||
@override
|
||||
void updateDevFSComplete() {
|
||||
updateDevFSCompleteCalled = true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> runPreShutdownOperations() async {
|
||||
shutdownHookCalled = true;
|
||||
}
|
||||
}
|
||||
|
||||
class FakeResidentCompiler extends Fake implements ResidentCompiler {
|
||||
@override
|
||||
void accept() {}
|
||||
}
|
||||
|
||||
class FakeFlutterVmService extends Fake implements FlutterVmService {
|
||||
@override
|
||||
vm_service.VmService get service => FakeVmService();
|
||||
|
||||
@override
|
||||
Future<List<FlutterView>> getFlutterViews({bool returnEarly = false, Duration delay = const Duration(milliseconds: 50)}) async {
|
||||
return <FlutterView>[];
|
||||
}
|
||||
}
|
||||
|
||||
class FakeVmService extends Fake implements vm_service.VmService {
|
||||
@override
|
||||
Future<vm_service.VM> getVM() async => FakeVm();
|
||||
}
|
||||
|
||||
class FakeVm extends Fake implements vm_service.VM {
|
||||
@override
|
||||
List<vm_service.IsolateRef> get isolates => <vm_service.IsolateRef>[];
|
||||
}
|
||||
|
||||
class FakeShaderCompiler implements DevelopmentShaderCompiler {
|
||||
const FakeShaderCompiler();
|
||||
|
||||
@override
|
||||
void configureCompiler(TargetPlatform? platform) { }
|
||||
|
||||
@override
|
||||
Future<DevFSContent> recompileShader(DevFSContent inputShader) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
@ -3,37 +3,25 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:file/memory.dart';
|
||||
import 'package:flutter_tools/src/application_package.dart';
|
||||
import 'package:flutter_tools/src/artifacts.dart';
|
||||
import 'package:flutter_tools/src/asset.dart';
|
||||
import 'package:flutter_tools/src/base/file_system.dart';
|
||||
import 'package:flutter_tools/src/base/io.dart';
|
||||
import 'package:flutter_tools/src/base/platform.dart';
|
||||
import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/build_system/tools/shader_compiler.dart';
|
||||
import 'package:flutter_tools/src/compile.dart';
|
||||
import 'package:flutter_tools/src/devfs.dart';
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:flutter_tools/src/features.dart';
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
import 'package:flutter_tools/src/reporting/reporting.dart';
|
||||
import 'package:flutter_tools/src/resident_devtools_handler.dart';
|
||||
import 'package:flutter_tools/src/resident_runner.dart';
|
||||
import 'package:flutter_tools/src/run_hot.dart';
|
||||
import 'package:flutter_tools/src/vmservice.dart';
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
hide BuildMode, Target;
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
as native_assets_cli;
|
||||
import 'package:package_config/package_config.dart';
|
||||
import 'package:test/fake.dart';
|
||||
import 'package:unified_analytics/unified_analytics.dart';
|
||||
import 'package:vm_service/vm_service.dart' as vm_service;
|
||||
|
||||
import '../src/common.dart';
|
||||
import '../src/context.dart';
|
||||
import '../src/fakes.dart';
|
||||
import 'fake_native_assets_build_runner.dart';
|
||||
import 'hot_shared.dart';
|
||||
|
||||
void main() {
|
||||
group('validateReloadReport', () {
|
||||
@ -625,352 +613,4 @@ void main() {
|
||||
expect(flutterDevice2.stoppedEchoingDeviceLog, true);
|
||||
});
|
||||
});
|
||||
|
||||
group('native assets', () {
|
||||
late TestHotRunnerConfig testingConfig;
|
||||
late FileSystem fileSystem;
|
||||
late FakeAnalytics fakeAnalytics;
|
||||
|
||||
setUp(() {
|
||||
fileSystem = MemoryFileSystem.test();
|
||||
testingConfig = TestHotRunnerConfig(
|
||||
successfulHotRestartSetup: true,
|
||||
);
|
||||
fakeAnalytics = getInitializedFakeAnalyticsInstance(
|
||||
fs: fileSystem,
|
||||
fakeFlutterVersion: FakeFlutterVersion(),
|
||||
);
|
||||
});
|
||||
testUsingContext('native assets restart', () async {
|
||||
final FakeDevice device = FakeDevice();
|
||||
final FakeFlutterDevice fakeFlutterDevice = FakeFlutterDevice(device);
|
||||
final List<FlutterDevice> devices = <FlutterDevice>[
|
||||
fakeFlutterDevice,
|
||||
];
|
||||
|
||||
fakeFlutterDevice.updateDevFSReportCallback = () async => UpdateFSReport(
|
||||
success: true,
|
||||
invalidatedSourcesCount: 6,
|
||||
syncedBytes: 8,
|
||||
scannedSourcesCount: 16,
|
||||
compileDuration: const Duration(seconds: 16),
|
||||
transferDuration: const Duration(seconds: 32),
|
||||
);
|
||||
|
||||
(fakeFlutterDevice.devFS! as FakeDevFs).baseUri = Uri.parse('file:///base_uri');
|
||||
|
||||
final FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner(
|
||||
packagesWithNativeAssetsResult: <Package>[
|
||||
Package('bar', fileSystem.currentDirectory.uri),
|
||||
],
|
||||
dryRunResult: FakeNativeAssetsBuilderResult(
|
||||
assets: <Asset>[
|
||||
Asset(
|
||||
id: 'package:bar/bar.dart',
|
||||
linkMode: LinkMode.dynamic,
|
||||
target: native_assets_cli.Target.macOSArm64,
|
||||
path: AssetAbsolutePath(Uri.file('bar.dylib')),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
final HotRunner hotRunner = HotRunner(
|
||||
devices,
|
||||
debuggingOptions: DebuggingOptions.disabled(BuildInfo.debug),
|
||||
target: 'main.dart',
|
||||
devtoolsHandler: createNoOpHandler,
|
||||
buildRunner: buildRunner,
|
||||
analytics: fakeAnalytics,
|
||||
);
|
||||
final OperationResult result = await hotRunner.restart(fullRestart: true);
|
||||
expect(result.isOk, true);
|
||||
// Hot restart does not require rerunning anything for native assets.
|
||||
// The previous native assets mapping should be used.
|
||||
expect(buildRunner.buildInvocations, 0);
|
||||
expect(buildRunner.dryRunInvocations, 0);
|
||||
expect(buildRunner.hasPackageConfigInvocations, 0);
|
||||
expect(buildRunner.packagesWithNativeAssetsInvocations, 0);
|
||||
}, overrides: <Type, Generator>{
|
||||
HotRunnerConfig: () => testingConfig,
|
||||
Artifacts: () => Artifacts.test(),
|
||||
FileSystem: () => fileSystem,
|
||||
Platform: () => FakePlatform(),
|
||||
ProcessManager: () => FakeProcessManager.empty(),
|
||||
FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true, isMacOSEnabled: true),
|
||||
});
|
||||
|
||||
testUsingContext('native assets run unsupported', () async {
|
||||
final FakeDevice device = FakeDevice(targetPlatform: TargetPlatform.fuchsia_arm64);
|
||||
final FakeFlutterDevice fakeFlutterDevice = FakeFlutterDevice(device);
|
||||
final List<FlutterDevice> devices = <FlutterDevice>[
|
||||
fakeFlutterDevice,
|
||||
];
|
||||
|
||||
fakeFlutterDevice.updateDevFSReportCallback = () async => UpdateFSReport(
|
||||
success: true,
|
||||
invalidatedSourcesCount: 6,
|
||||
syncedBytes: 8,
|
||||
scannedSourcesCount: 16,
|
||||
compileDuration: const Duration(seconds: 16),
|
||||
transferDuration: const Duration(seconds: 32),
|
||||
);
|
||||
|
||||
(fakeFlutterDevice.devFS! as FakeDevFs).baseUri = Uri.parse('file:///base_uri');
|
||||
|
||||
final FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner(
|
||||
packagesWithNativeAssetsResult: <Package>[
|
||||
Package('bar', fileSystem.currentDirectory.uri),
|
||||
],
|
||||
dryRunResult: FakeNativeAssetsBuilderResult(
|
||||
assets: <Asset>[
|
||||
Asset(
|
||||
id: 'package:bar/bar.dart',
|
||||
linkMode: LinkMode.dynamic,
|
||||
target: native_assets_cli.Target.macOSArm64,
|
||||
path: AssetAbsolutePath(Uri.file('bar.dylib')),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
final HotRunner hotRunner = HotRunner(
|
||||
devices,
|
||||
debuggingOptions: DebuggingOptions.disabled(BuildInfo.debug),
|
||||
target: 'main.dart',
|
||||
devtoolsHandler: createNoOpHandler,
|
||||
buildRunner: buildRunner,
|
||||
analytics: fakeAnalytics,
|
||||
);
|
||||
expect(
|
||||
() => hotRunner.run(),
|
||||
throwsToolExit( message:
|
||||
'Package(s) bar require the native assets feature. '
|
||||
'This feature has not yet been implemented for `TargetPlatform.fuchsia_arm64`. '
|
||||
'For more info see https://github.com/flutter/flutter/issues/129757.',
|
||||
)
|
||||
);
|
||||
|
||||
}, overrides: <Type, Generator>{
|
||||
HotRunnerConfig: () => testingConfig,
|
||||
Artifacts: () => Artifacts.test(),
|
||||
FileSystem: () => fileSystem,
|
||||
Platform: () => FakePlatform(),
|
||||
ProcessManager: () => FakeProcessManager.empty(),
|
||||
FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true, isMacOSEnabled: true),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class FakeDevFs extends Fake implements DevFS {
|
||||
@override
|
||||
Future<void> destroy() async { }
|
||||
|
||||
@override
|
||||
List<Uri> sources = <Uri>[];
|
||||
|
||||
@override
|
||||
DateTime? lastCompiled;
|
||||
|
||||
@override
|
||||
PackageConfig? lastPackageConfig;
|
||||
|
||||
@override
|
||||
Set<String> assetPathsToEvict = <String>{};
|
||||
|
||||
@override
|
||||
Set<String> shaderPathsToEvict= <String>{};
|
||||
|
||||
@override
|
||||
Set<String> scenePathsToEvict= <String>{};
|
||||
|
||||
@override
|
||||
Uri? baseUri;
|
||||
}
|
||||
|
||||
class FakeDevice extends Fake implements Device {
|
||||
FakeDevice({
|
||||
TargetPlatform targetPlatform = TargetPlatform.tester,
|
||||
}) : _targetPlatform = targetPlatform;
|
||||
|
||||
final TargetPlatform _targetPlatform;
|
||||
|
||||
bool disposed = false;
|
||||
|
||||
@override
|
||||
bool isSupported() => true;
|
||||
|
||||
@override
|
||||
bool supportsHotReload = true;
|
||||
|
||||
@override
|
||||
bool supportsHotRestart = true;
|
||||
|
||||
@override
|
||||
bool supportsFlutterExit = true;
|
||||
|
||||
@override
|
||||
Future<TargetPlatform> get targetPlatform async => _targetPlatform;
|
||||
|
||||
@override
|
||||
Future<String> get sdkNameAndVersion async => 'Tester';
|
||||
|
||||
@override
|
||||
Future<bool> get isLocalEmulator async => false;
|
||||
|
||||
@override
|
||||
String get name => 'Fake Device';
|
||||
|
||||
@override
|
||||
Future<bool> stopApp(
|
||||
ApplicationPackage? app, {
|
||||
String? userIdentifier,
|
||||
}) async {
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> dispose() async {
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
class FakeFlutterDevice extends Fake implements FlutterDevice {
|
||||
FakeFlutterDevice(this.device);
|
||||
|
||||
bool stoppedEchoingDeviceLog = false;
|
||||
late Future<UpdateFSReport> Function() updateDevFSReportCallback;
|
||||
|
||||
@override
|
||||
final FakeDevice device;
|
||||
|
||||
@override
|
||||
Future<void> stopEchoingDeviceLog() async {
|
||||
stoppedEchoingDeviceLog = true;
|
||||
}
|
||||
|
||||
@override
|
||||
DevFS? devFS = FakeDevFs();
|
||||
|
||||
@override
|
||||
FlutterVmService get vmService => FakeFlutterVmService();
|
||||
|
||||
@override
|
||||
ResidentCompiler? generator;
|
||||
|
||||
@override
|
||||
Future<UpdateFSReport> updateDevFS({
|
||||
Uri? mainUri,
|
||||
String? target,
|
||||
AssetBundle? bundle,
|
||||
DateTime? firstBuildTime,
|
||||
bool bundleFirstUpload = false,
|
||||
bool bundleDirty = false,
|
||||
bool fullRestart = false,
|
||||
String? projectRootPath,
|
||||
String? pathToReload,
|
||||
required String dillOutputPath,
|
||||
required List<Uri> invalidatedFiles,
|
||||
required PackageConfig packageConfig,
|
||||
}) => updateDevFSReportCallback();
|
||||
|
||||
@override
|
||||
TargetPlatform? get targetPlatform => device._targetPlatform;
|
||||
}
|
||||
|
||||
class TestFlutterDevice extends FlutterDevice {
|
||||
TestFlutterDevice({
|
||||
required Device device,
|
||||
required this.exception,
|
||||
required ResidentCompiler generator,
|
||||
}) : super(device, buildInfo: BuildInfo.debug, generator: generator, developmentShaderCompiler: const FakeShaderCompiler());
|
||||
|
||||
/// The exception to throw when the connect method is called.
|
||||
final Exception exception;
|
||||
|
||||
@override
|
||||
Future<void> connect({
|
||||
ReloadSources? reloadSources,
|
||||
Restart? restart,
|
||||
CompileExpression? compileExpression,
|
||||
GetSkSLMethod? getSkSLMethod,
|
||||
FlutterProject? flutterProject,
|
||||
PrintStructuredErrorLogMethod? printStructuredErrorLogMethod,
|
||||
bool disableServiceAuthCodes = false,
|
||||
bool enableDds = true,
|
||||
bool cacheStartupProfile = false,
|
||||
bool? ipv6 = false,
|
||||
int? hostVmServicePort,
|
||||
int? ddsPort,
|
||||
bool allowExistingDdsInstance = false,
|
||||
}) async {
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
class TestHotRunnerConfig extends HotRunnerConfig {
|
||||
TestHotRunnerConfig({this.successfulHotRestartSetup, this.successfulHotReloadSetup});
|
||||
bool? successfulHotRestartSetup;
|
||||
bool? successfulHotReloadSetup;
|
||||
bool shutdownHookCalled = false;
|
||||
bool updateDevFSCompleteCalled = false;
|
||||
|
||||
@override
|
||||
Future<bool?> setupHotRestart() async {
|
||||
assert(successfulHotRestartSetup != null, 'setupHotRestart is not expected to be called in this test.');
|
||||
return successfulHotRestartSetup;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool?> setupHotReload() async {
|
||||
assert(successfulHotReloadSetup != null, 'setupHotReload is not expected to be called in this test.');
|
||||
return successfulHotReloadSetup;
|
||||
}
|
||||
|
||||
@override
|
||||
void updateDevFSComplete() {
|
||||
updateDevFSCompleteCalled = true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> runPreShutdownOperations() async {
|
||||
shutdownHookCalled = true;
|
||||
}
|
||||
}
|
||||
|
||||
class FakeResidentCompiler extends Fake implements ResidentCompiler {
|
||||
@override
|
||||
void accept() {}
|
||||
}
|
||||
|
||||
class FakeFlutterVmService extends Fake implements FlutterVmService {
|
||||
@override
|
||||
vm_service.VmService get service => FakeVmService();
|
||||
|
||||
@override
|
||||
Future<List<FlutterView>> getFlutterViews({bool returnEarly = false, Duration delay = const Duration(milliseconds: 50)}) async {
|
||||
return <FlutterView>[];
|
||||
}
|
||||
}
|
||||
|
||||
class FakeVmService extends Fake implements vm_service.VmService {
|
||||
@override
|
||||
Future<vm_service.VM> getVM() async => FakeVm();
|
||||
}
|
||||
|
||||
class FakeVm extends Fake implements vm_service.VM {
|
||||
@override
|
||||
List<vm_service.IsolateRef> get isolates => <vm_service.IsolateRef>[];
|
||||
}
|
||||
|
||||
class FakeShaderCompiler implements DevelopmentShaderCompiler {
|
||||
const FakeShaderCompiler();
|
||||
|
||||
@override
|
||||
void configureCompiler(TargetPlatform? platform) { }
|
||||
|
||||
@override
|
||||
Future<DevFSContent> recompileShader(DevFSContent inputShader) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
import 'package:file/file.dart';
|
||||
import 'package:file/memory.dart';
|
||||
import 'package:file_testing/file_testing.dart';
|
||||
import 'package:flutter_tools/src/android/native_assets.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';
|
||||
@ -15,15 +14,16 @@ import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/build_system/build_system.dart';
|
||||
import 'package:flutter_tools/src/features.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:flutter_tools/src/isolated/native_assets/android/native_assets.dart';
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
as native_assets_cli;
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
hide BuildMode, Target;
|
||||
import 'package:package_config/package_config_types.dart';
|
||||
|
||||
import '../../src/common.dart';
|
||||
import '../../src/context.dart';
|
||||
import '../../src/fakes.dart';
|
||||
import '../../../src/common.dart';
|
||||
import '../../../src/context.dart';
|
||||
import '../../../src/fakes.dart';
|
||||
import '../fake_native_assets_build_runner.dart';
|
||||
|
||||
void main() {
|
@ -12,14 +12,14 @@ import 'package:flutter_tools/src/build_system/build_system.dart';
|
||||
import 'package:flutter_tools/src/build_system/exceptions.dart';
|
||||
import 'package:flutter_tools/src/build_system/targets/native_assets.dart';
|
||||
import 'package:flutter_tools/src/features.dart';
|
||||
import 'package:flutter_tools/src/native_assets.dart';
|
||||
import 'package:flutter_tools/src/isolated/native_assets/native_assets.dart';
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
as native_assets_cli;
|
||||
import 'package:package_config/package_config.dart' show Package;
|
||||
|
||||
import '../../../src/common.dart';
|
||||
import '../../../src/context.dart';
|
||||
import '../../../src/fakes.dart';
|
||||
import '../../../../src/common.dart';
|
||||
import '../../../../src/context.dart';
|
||||
import '../../../../src/fakes.dart';
|
||||
import '../../fake_native_assets_build_runner.dart';
|
||||
|
||||
void main() {
|
@ -2,7 +2,11 @@
|
||||
// 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/native_assets.dart';
|
||||
import 'package:file/src/interface/file_system.dart';
|
||||
import 'package:flutter_tools/src/base/logger.dart';
|
||||
import 'package:flutter_tools/src/isolated/native_assets/native_assets.dart';
|
||||
import 'package:flutter_tools/src/resident_runner.dart';
|
||||
import 'package:flutter_tools/src/run_hot.dart';
|
||||
import 'package:native_assets_builder/native_assets_builder.dart'
|
||||
as native_assets_builder;
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart';
|
||||
@ -95,3 +99,25 @@ final class FakeNativeAssetsBuilderResult
|
||||
@override
|
||||
final bool success;
|
||||
}
|
||||
|
||||
class FakeHotRunnerNativeAssetsBuilder implements HotRunnerNativeAssetsBuilder {
|
||||
FakeHotRunnerNativeAssetsBuilder(this.buildRunner);
|
||||
|
||||
final NativeAssetsBuildRunner buildRunner;
|
||||
|
||||
@override
|
||||
Future<Uri?> dryRun({
|
||||
required Uri projectUri,
|
||||
required FileSystem fileSystem,
|
||||
required List<FlutterDevice> flutterDevices,
|
||||
required PackageConfig packageConfig,
|
||||
required Logger logger,
|
||||
}) {
|
||||
return dryRunNativeAssets(
|
||||
projectUri: projectUri,
|
||||
fileSystem: fileSystem,
|
||||
buildRunner: buildRunner,
|
||||
flutterDevices: flutterDevices,
|
||||
);
|
||||
}
|
||||
}
|
164
packages/flutter_tools/test/general.shard/isolated/hot_test.dart
Normal file
164
packages/flutter_tools/test/general.shard/isolated/hot_test.dart
Normal file
@ -0,0 +1,164 @@
|
||||
// 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:file/memory.dart';
|
||||
import 'package:flutter_tools/src/artifacts.dart';
|
||||
import 'package:flutter_tools/src/base/file_system.dart';
|
||||
import 'package:flutter_tools/src/base/platform.dart';
|
||||
import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/devfs.dart';
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:flutter_tools/src/features.dart';
|
||||
import 'package:flutter_tools/src/resident_devtools_handler.dart';
|
||||
import 'package:flutter_tools/src/resident_runner.dart';
|
||||
import 'package:flutter_tools/src/run_hot.dart';
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
hide BuildMode, Target;
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
as native_assets_cli;
|
||||
import 'package:package_config/package_config.dart';
|
||||
import 'package:unified_analytics/unified_analytics.dart';
|
||||
|
||||
import '../../src/common.dart';
|
||||
import '../../src/context.dart';
|
||||
import '../../src/fakes.dart';
|
||||
import '../hot_shared.dart';
|
||||
import 'fake_native_assets_build_runner.dart';
|
||||
|
||||
void main() {
|
||||
group('native assets', () {
|
||||
late TestHotRunnerConfig testingConfig;
|
||||
late FileSystem fileSystem;
|
||||
late FakeAnalytics fakeAnalytics;
|
||||
|
||||
setUp(() {
|
||||
fileSystem = MemoryFileSystem.test();
|
||||
testingConfig = TestHotRunnerConfig(
|
||||
successfulHotRestartSetup: true,
|
||||
);
|
||||
fakeAnalytics = getInitializedFakeAnalyticsInstance(
|
||||
fs: fileSystem,
|
||||
fakeFlutterVersion: FakeFlutterVersion(),
|
||||
);
|
||||
});
|
||||
testUsingContext('native assets restart', () async {
|
||||
final FakeDevice device = FakeDevice();
|
||||
final FakeFlutterDevice fakeFlutterDevice = FakeFlutterDevice(device);
|
||||
final List<FlutterDevice> devices = <FlutterDevice>[
|
||||
fakeFlutterDevice,
|
||||
];
|
||||
|
||||
fakeFlutterDevice.updateDevFSReportCallback = () async => UpdateFSReport(
|
||||
success: true,
|
||||
invalidatedSourcesCount: 6,
|
||||
syncedBytes: 8,
|
||||
scannedSourcesCount: 16,
|
||||
compileDuration: const Duration(seconds: 16),
|
||||
transferDuration: const Duration(seconds: 32),
|
||||
);
|
||||
|
||||
(fakeFlutterDevice.devFS! as FakeDevFs).baseUri = Uri.parse('file:///base_uri');
|
||||
|
||||
final FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner(
|
||||
packagesWithNativeAssetsResult: <Package>[
|
||||
Package('bar', fileSystem.currentDirectory.uri),
|
||||
],
|
||||
dryRunResult: FakeNativeAssetsBuilderResult(
|
||||
assets: <Asset>[
|
||||
Asset(
|
||||
id: 'package:bar/bar.dart',
|
||||
linkMode: LinkMode.dynamic,
|
||||
target: native_assets_cli.Target.macOSArm64,
|
||||
path: AssetAbsolutePath(Uri.file('bar.dylib')),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
final HotRunner hotRunner = HotRunner(
|
||||
devices,
|
||||
debuggingOptions: DebuggingOptions.disabled(BuildInfo.debug),
|
||||
target: 'main.dart',
|
||||
devtoolsHandler: createNoOpHandler,
|
||||
nativeAssetsBuilder: FakeHotRunnerNativeAssetsBuilder(buildRunner),
|
||||
analytics: fakeAnalytics,
|
||||
);
|
||||
final OperationResult result = await hotRunner.restart(fullRestart: true);
|
||||
expect(result.isOk, true);
|
||||
// Hot restart does not require rerunning anything for native assets.
|
||||
// The previous native assets mapping should be used.
|
||||
expect(buildRunner.buildInvocations, 0);
|
||||
expect(buildRunner.dryRunInvocations, 0);
|
||||
expect(buildRunner.hasPackageConfigInvocations, 0);
|
||||
expect(buildRunner.packagesWithNativeAssetsInvocations, 0);
|
||||
}, overrides: <Type, Generator>{
|
||||
HotRunnerConfig: () => testingConfig,
|
||||
Artifacts: () => Artifacts.test(),
|
||||
FileSystem: () => fileSystem,
|
||||
Platform: () => FakePlatform(),
|
||||
ProcessManager: () => FakeProcessManager.empty(),
|
||||
FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true, isMacOSEnabled: true),
|
||||
});
|
||||
|
||||
testUsingContext('native assets run unsupported', () async {
|
||||
final FakeDevice device = FakeDevice(targetPlatform: TargetPlatform.fuchsia_arm64);
|
||||
final FakeFlutterDevice fakeFlutterDevice = FakeFlutterDevice(device);
|
||||
final List<FlutterDevice> devices = <FlutterDevice>[
|
||||
fakeFlutterDevice,
|
||||
];
|
||||
|
||||
fakeFlutterDevice.updateDevFSReportCallback = () async => UpdateFSReport(
|
||||
success: true,
|
||||
invalidatedSourcesCount: 6,
|
||||
syncedBytes: 8,
|
||||
scannedSourcesCount: 16,
|
||||
compileDuration: const Duration(seconds: 16),
|
||||
transferDuration: const Duration(seconds: 32),
|
||||
);
|
||||
|
||||
(fakeFlutterDevice.devFS! as FakeDevFs).baseUri = Uri.parse('file:///base_uri');
|
||||
|
||||
final FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner(
|
||||
packagesWithNativeAssetsResult: <Package>[
|
||||
Package('bar', fileSystem.currentDirectory.uri),
|
||||
],
|
||||
dryRunResult: FakeNativeAssetsBuilderResult(
|
||||
assets: <Asset>[
|
||||
Asset(
|
||||
id: 'package:bar/bar.dart',
|
||||
linkMode: LinkMode.dynamic,
|
||||
target: native_assets_cli.Target.macOSArm64,
|
||||
path: AssetAbsolutePath(Uri.file('bar.dylib')),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
final HotRunner hotRunner = HotRunner(
|
||||
devices,
|
||||
debuggingOptions: DebuggingOptions.disabled(BuildInfo.debug),
|
||||
target: 'main.dart',
|
||||
devtoolsHandler: createNoOpHandler,
|
||||
nativeAssetsBuilder: FakeHotRunnerNativeAssetsBuilder(buildRunner),
|
||||
analytics: fakeAnalytics,
|
||||
);
|
||||
expect(
|
||||
() => hotRunner.run(),
|
||||
throwsToolExit( message:
|
||||
'Package(s) bar require the native assets feature. '
|
||||
'This feature has not yet been implemented for `TargetPlatform.fuchsia_arm64`. '
|
||||
'For more info see https://github.com/flutter/flutter/issues/129757.',
|
||||
)
|
||||
);
|
||||
|
||||
}, overrides: <Type, Generator>{
|
||||
HotRunnerConfig: () => testingConfig,
|
||||
Artifacts: () => Artifacts.test(),
|
||||
FileSystem: () => fileSystem,
|
||||
Platform: () => FakePlatform(),
|
||||
ProcessManager: () => FakeProcessManager.empty(),
|
||||
FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true, isMacOSEnabled: true),
|
||||
});
|
||||
});
|
||||
}
|
@ -13,16 +13,16 @@ import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/build_system/build_system.dart';
|
||||
import 'package:flutter_tools/src/features.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:flutter_tools/src/ios/native_assets.dart';
|
||||
import 'package:flutter_tools/src/isolated/native_assets/ios/native_assets.dart';
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
hide BuildMode, Target;
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
as native_assets_cli;
|
||||
import 'package:package_config/package_config_types.dart';
|
||||
|
||||
import '../../src/common.dart';
|
||||
import '../../src/context.dart';
|
||||
import '../../src/fakes.dart';
|
||||
import '../../../src/common.dart';
|
||||
import '../../../src/context.dart';
|
||||
import '../../../src/fakes.dart';
|
||||
import '../fake_native_assets_build_runner.dart';
|
||||
|
||||
void main() {
|
@ -15,17 +15,17 @@ import 'package:flutter_tools/src/build_system/build_system.dart';
|
||||
import 'package:flutter_tools/src/dart/package_map.dart';
|
||||
import 'package:flutter_tools/src/features.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:flutter_tools/src/linux/native_assets.dart';
|
||||
import 'package:flutter_tools/src/native_assets.dart';
|
||||
import 'package:flutter_tools/src/isolated/native_assets/linux/native_assets.dart';
|
||||
import 'package:flutter_tools/src/isolated/native_assets/native_assets.dart';
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
hide BuildMode, Target;
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
as native_assets_cli;
|
||||
import 'package:package_config/package_config_types.dart';
|
||||
|
||||
import '../../src/common.dart';
|
||||
import '../../src/context.dart';
|
||||
import '../../src/fakes.dart';
|
||||
import '../../../src/common.dart';
|
||||
import '../../../src/context.dart';
|
||||
import '../../../src/fakes.dart';
|
||||
import '../fake_native_assets_build_runner.dart';
|
||||
|
||||
void main() {
|
@ -2,9 +2,9 @@
|
||||
// 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/macos/native_assets_host.dart';
|
||||
import 'package:flutter_tools/src/isolated/native_assets/macos/native_assets_host.dart';
|
||||
|
||||
import '../../src/common.dart';
|
||||
import '../../../src/common.dart';
|
||||
|
||||
void main() {
|
||||
test('framework name', () {
|
@ -13,17 +13,17 @@ import 'package:flutter_tools/src/build_system/build_system.dart';
|
||||
import 'package:flutter_tools/src/dart/package_map.dart';
|
||||
import 'package:flutter_tools/src/features.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:flutter_tools/src/macos/native_assets.dart';
|
||||
import 'package:flutter_tools/src/native_assets.dart';
|
||||
import 'package:flutter_tools/src/isolated/native_assets/macos/native_assets.dart';
|
||||
import 'package:flutter_tools/src/isolated/native_assets/native_assets.dart';
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
hide BuildMode, Target;
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
as native_assets_cli;
|
||||
import 'package:package_config/package_config_types.dart';
|
||||
|
||||
import '../../src/common.dart';
|
||||
import '../../src/context.dart';
|
||||
import '../../src/fakes.dart';
|
||||
import '../../../src/common.dart';
|
||||
import '../../../src/context.dart';
|
||||
import '../../../src/fakes.dart';
|
||||
import '../fake_native_assets_build_runner.dart';
|
||||
|
||||
void main() {
|
@ -0,0 +1,121 @@
|
||||
// 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/build_info.dart';
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:flutter_tools/src/features.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:flutter_tools/src/resident_devtools_handler.dart';
|
||||
import 'package:flutter_tools/src/resident_runner.dart';
|
||||
import 'package:flutter_tools/src/run_hot.dart';
|
||||
import 'package:unified_analytics/unified_analytics.dart';
|
||||
|
||||
import '../../src/common.dart';
|
||||
import '../../src/context.dart';
|
||||
import '../../src/fake_vm_services.dart';
|
||||
import '../../src/fakes.dart';
|
||||
import '../../src/testbed.dart';
|
||||
import '../resident_runner_helpers.dart';
|
||||
import 'fake_native_assets_build_runner.dart';
|
||||
|
||||
void main() {
|
||||
late Testbed testbed;
|
||||
late FakeFlutterDevice flutterDevice;
|
||||
late FakeDevFS devFS;
|
||||
late ResidentRunner residentRunner;
|
||||
late FakeDevice device;
|
||||
late FakeAnalytics fakeAnalytics;
|
||||
FakeVmServiceHost? fakeVmServiceHost;
|
||||
|
||||
setUp(() {
|
||||
testbed = Testbed(setup: () {
|
||||
fakeAnalytics = getInitializedFakeAnalyticsInstance(
|
||||
fs: globals.fs,
|
||||
fakeFlutterVersion: FakeFlutterVersion(),
|
||||
);
|
||||
|
||||
globals.fs.file('.packages')
|
||||
.writeAsStringSync('\n');
|
||||
globals.fs.file(globals.fs.path.join('build', 'app.dill'))
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync('ABC');
|
||||
residentRunner = HotRunner(
|
||||
<FlutterDevice>[
|
||||
flutterDevice,
|
||||
],
|
||||
stayResident: false,
|
||||
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
|
||||
target: 'main.dart',
|
||||
devtoolsHandler: createNoOpHandler,
|
||||
analytics: fakeAnalytics,
|
||||
);
|
||||
});
|
||||
device = FakeDevice();
|
||||
devFS = FakeDevFS();
|
||||
flutterDevice = FakeFlutterDevice()
|
||||
..testUri = testUri
|
||||
..vmServiceHost = (() => fakeVmServiceHost)
|
||||
..device = device
|
||||
..fakeDevFS = devFS;
|
||||
});
|
||||
|
||||
testUsingContext(
|
||||
'use the nativeAssetsYamlFile when provided',
|
||||
() => testbed.run(() async {
|
||||
final FakeDevice device = FakeDevice(
|
||||
targetPlatform: TargetPlatform.darwin,
|
||||
sdkNameAndVersion: 'Macos',
|
||||
);
|
||||
final FakeResidentCompiler residentCompiler = FakeResidentCompiler();
|
||||
final FakeFlutterDevice flutterDevice = FakeFlutterDevice()
|
||||
..testUri = testUri
|
||||
..vmServiceHost = (() => fakeVmServiceHost)
|
||||
..device = device
|
||||
..fakeDevFS = devFS
|
||||
..targetPlatform = TargetPlatform.darwin
|
||||
..generator = residentCompiler;
|
||||
|
||||
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
|
||||
listViews,
|
||||
listViews,
|
||||
]);
|
||||
globals.fs
|
||||
.file(globals.fs.path.join('lib', 'main.dart'))
|
||||
.createSync(recursive: true);
|
||||
final FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner();
|
||||
residentRunner = HotRunner(
|
||||
<FlutterDevice>[
|
||||
flutterDevice,
|
||||
],
|
||||
stayResident: false,
|
||||
debuggingOptions: DebuggingOptions.enabled(const BuildInfo(
|
||||
BuildMode.debug,
|
||||
'',
|
||||
treeShakeIcons: false,
|
||||
trackWidgetCreation: true,
|
||||
)),
|
||||
target: 'main.dart',
|
||||
devtoolsHandler: createNoOpHandler,
|
||||
nativeAssetsBuilder: FakeHotRunnerNativeAssetsBuilder(buildRunner),
|
||||
analytics: fakeAnalytics,
|
||||
nativeAssetsYamlFile: 'foo.yaml',
|
||||
);
|
||||
|
||||
final int? result = await residentRunner.run();
|
||||
expect(result, 0);
|
||||
|
||||
expect(buildRunner.buildInvocations, 0);
|
||||
expect(buildRunner.dryRunInvocations, 0);
|
||||
expect(buildRunner.hasPackageConfigInvocations, 0);
|
||||
expect(buildRunner.packagesWithNativeAssetsInvocations, 0);
|
||||
|
||||
expect(residentCompiler.recompileCalled, true);
|
||||
expect(residentCompiler.receivedNativeAssetsYaml, globals.fs.path.toUri('foo.yaml'));
|
||||
}),
|
||||
overrides: <Type, Generator>{
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true, isMacOSEnabled: true),
|
||||
});
|
||||
}
|
@ -14,17 +14,17 @@ import 'package:flutter_tools/src/build_system/build_system.dart';
|
||||
import 'package:flutter_tools/src/dart/package_map.dart';
|
||||
import 'package:flutter_tools/src/features.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:flutter_tools/src/native_assets.dart';
|
||||
import 'package:flutter_tools/src/windows/native_assets.dart';
|
||||
import 'package:flutter_tools/src/isolated/native_assets/native_assets.dart';
|
||||
import 'package:flutter_tools/src/isolated/native_assets/windows/native_assets.dart';
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
hide BuildMode, Target;
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
as native_assets_cli;
|
||||
import 'package:package_config/package_config_types.dart';
|
||||
|
||||
import '../../src/common.dart';
|
||||
import '../../src/context.dart';
|
||||
import '../../src/fakes.dart';
|
||||
import '../../../src/common.dart';
|
||||
import '../../../src/context.dart';
|
||||
import '../../../src/fakes.dart';
|
||||
import '../fake_native_assets_build_runner.dart';
|
||||
|
||||
void main() {
|
@ -0,0 +1,529 @@
|
||||
// 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 'dart:async';
|
||||
|
||||
import 'package:dds/dds.dart' as dds;
|
||||
import 'package:flutter_tools/src/application_package.dart';
|
||||
import 'package:flutter_tools/src/asset.dart';
|
||||
import 'package:flutter_tools/src/base/dds.dart';
|
||||
import 'package:flutter_tools/src/base/file_system.dart';
|
||||
import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/build_system/tools/scene_importer.dart';
|
||||
import 'package:flutter_tools/src/build_system/tools/shader_compiler.dart';
|
||||
import 'package:flutter_tools/src/compile.dart';
|
||||
import 'package:flutter_tools/src/devfs.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/resident_runner.dart';
|
||||
import 'package:flutter_tools/src/run_cold.dart';
|
||||
import 'package:flutter_tools/src/run_hot.dart';
|
||||
import 'package:flutter_tools/src/vmservice.dart';
|
||||
import 'package:package_config/package_config.dart';
|
||||
import 'package:test/fake.dart';
|
||||
import 'package:vm_service/vm_service.dart' as vm_service;
|
||||
|
||||
import '../src/fake_vm_services.dart';
|
||||
|
||||
final vm_service.Event fakeUnpausedEvent = vm_service.Event(
|
||||
kind: vm_service.EventKind.kResume,
|
||||
timestamp: 0
|
||||
);
|
||||
|
||||
final vm_service.Event fakePausedEvent = vm_service.Event(
|
||||
kind: vm_service.EventKind.kPauseException,
|
||||
timestamp: 0
|
||||
);
|
||||
|
||||
final vm_service.Isolate fakeUnpausedIsolate = vm_service.Isolate(
|
||||
id: '1',
|
||||
pauseEvent: fakeUnpausedEvent,
|
||||
breakpoints: <vm_service.Breakpoint>[],
|
||||
extensionRPCs: <String>[],
|
||||
libraries: <vm_service.LibraryRef>[
|
||||
vm_service.LibraryRef(
|
||||
id: '1',
|
||||
uri: 'file:///hello_world/main.dart',
|
||||
name: '',
|
||||
),
|
||||
],
|
||||
livePorts: 0,
|
||||
name: 'test',
|
||||
number: '1',
|
||||
pauseOnExit: false,
|
||||
runnable: true,
|
||||
startTime: 0,
|
||||
isSystemIsolate: false,
|
||||
isolateFlags: <vm_service.IsolateFlag>[],
|
||||
);
|
||||
|
||||
final vm_service.Isolate fakePausedIsolate = vm_service.Isolate(
|
||||
id: '1',
|
||||
pauseEvent: fakePausedEvent,
|
||||
breakpoints: <vm_service.Breakpoint>[
|
||||
vm_service.Breakpoint(
|
||||
breakpointNumber: 123,
|
||||
id: 'test-breakpoint',
|
||||
location: vm_service.SourceLocation(
|
||||
tokenPos: 0,
|
||||
script: vm_service.ScriptRef(id: 'test-script', uri: 'foo.dart'),
|
||||
),
|
||||
enabled: true,
|
||||
resolved: true,
|
||||
),
|
||||
],
|
||||
libraries: <vm_service.LibraryRef>[],
|
||||
livePorts: 0,
|
||||
name: 'test',
|
||||
number: '1',
|
||||
pauseOnExit: false,
|
||||
runnable: true,
|
||||
startTime: 0,
|
||||
isSystemIsolate: false,
|
||||
isolateFlags: <vm_service.IsolateFlag>[],
|
||||
);
|
||||
|
||||
final vm_service.VM fakeVM = vm_service.VM(
|
||||
isolates: <vm_service.IsolateRef>[fakeUnpausedIsolate],
|
||||
pid: 1,
|
||||
hostCPU: '',
|
||||
isolateGroups: <vm_service.IsolateGroupRef>[],
|
||||
targetCPU: '',
|
||||
startTime: 0,
|
||||
name: 'dart',
|
||||
architectureBits: 64,
|
||||
operatingSystem: '',
|
||||
version: '',
|
||||
systemIsolateGroups: <vm_service.IsolateGroupRef>[],
|
||||
systemIsolates: <vm_service.IsolateRef>[],
|
||||
);
|
||||
|
||||
final FlutterView fakeFlutterView = FlutterView(
|
||||
id: 'a',
|
||||
uiIsolate: fakeUnpausedIsolate,
|
||||
);
|
||||
|
||||
final FakeVmServiceRequest listViews = FakeVmServiceRequest(
|
||||
method: kListViewsMethod,
|
||||
jsonResponse: <String, Object>{
|
||||
'views': <Object>[
|
||||
fakeFlutterView.toJson(),
|
||||
],
|
||||
},
|
||||
);
|
||||
|
||||
const FakeVmServiceRequest setAssetBundlePath = FakeVmServiceRequest(
|
||||
method: '_flutter.setAssetBundlePath',
|
||||
args: <String, Object>{
|
||||
'viewId': 'a',
|
||||
'assetDirectory': 'build/flutter_assets',
|
||||
'isolateId': '1',
|
||||
}
|
||||
);
|
||||
|
||||
const FakeVmServiceRequest evict = FakeVmServiceRequest(
|
||||
method: 'ext.flutter.evict',
|
||||
args: <String, Object>{
|
||||
'value': 'asset',
|
||||
'isolateId': '1',
|
||||
}
|
||||
);
|
||||
|
||||
const FakeVmServiceRequest evictShader = FakeVmServiceRequest(
|
||||
method: 'ext.ui.window.reinitializeShader',
|
||||
args: <String, Object>{
|
||||
'assetKey': 'foo.frag',
|
||||
'isolateId': '1',
|
||||
}
|
||||
);
|
||||
|
||||
final Uri testUri = Uri.parse('foo://bar');
|
||||
|
||||
// This implements [dds.DartDevelopmentService], not the [DartDevelopmentService]
|
||||
// interface from package:flutter_tools.
|
||||
class FakeDartDevelopmentService extends Fake implements dds.DartDevelopmentService {
|
||||
@override
|
||||
Future<void> get done => Future<void>.value();
|
||||
|
||||
@override
|
||||
Uri? get uri => null;
|
||||
}
|
||||
|
||||
class FakeDartDevelopmentServiceException implements dds.DartDevelopmentServiceException {
|
||||
FakeDartDevelopmentServiceException({this.message = defaultMessage});
|
||||
|
||||
@override
|
||||
final int errorCode = dds.DartDevelopmentServiceException.existingDdsInstanceError;
|
||||
|
||||
@override
|
||||
final String message;
|
||||
static const String defaultMessage = 'A DDS instance is already connected at http://localhost:8181';
|
||||
}
|
||||
|
||||
class TestFlutterDevice extends FlutterDevice {
|
||||
TestFlutterDevice(super.device, { Stream<Uri>? vmServiceUris })
|
||||
: _vmServiceUris = vmServiceUris, super(buildInfo: BuildInfo.debug, developmentShaderCompiler: const FakeShaderCompiler());
|
||||
|
||||
final Stream<Uri>? _vmServiceUris;
|
||||
|
||||
@override
|
||||
Stream<Uri> get vmServiceUris => _vmServiceUris!;
|
||||
}
|
||||
|
||||
class ThrowingForwardingFileSystem extends ForwardingFileSystem {
|
||||
ThrowingForwardingFileSystem(super.delegate);
|
||||
|
||||
@override
|
||||
File file(dynamic path) {
|
||||
if (path == 'foo') {
|
||||
throw const FileSystemException();
|
||||
}
|
||||
return delegate.file(path);
|
||||
}
|
||||
}
|
||||
|
||||
class FakeFlutterDevice extends Fake implements FlutterDevice {
|
||||
FakeVmServiceHost? Function()? vmServiceHost;
|
||||
Uri? testUri;
|
||||
UpdateFSReport report = UpdateFSReport(
|
||||
success: true,
|
||||
invalidatedSourcesCount: 1,
|
||||
);
|
||||
Exception? reportError;
|
||||
Exception? runColdError;
|
||||
int runHotCode = 0;
|
||||
int runColdCode = 0;
|
||||
|
||||
@override
|
||||
ResidentCompiler? generator;
|
||||
|
||||
@override
|
||||
DevelopmentShaderCompiler get developmentShaderCompiler => const FakeShaderCompiler();
|
||||
|
||||
@override
|
||||
TargetPlatform targetPlatform = TargetPlatform.android;
|
||||
|
||||
@override
|
||||
Stream<Uri?> get vmServiceUris => Stream<Uri?>.value(testUri);
|
||||
|
||||
@override
|
||||
FlutterVmService? get vmService => vmServiceHost?.call()?.vmService;
|
||||
|
||||
DevFS? fakeDevFS;
|
||||
|
||||
@override
|
||||
DevFS? get devFS => fakeDevFS;
|
||||
|
||||
@override
|
||||
set devFS(DevFS? value) { }
|
||||
|
||||
@override
|
||||
Device? device;
|
||||
|
||||
@override
|
||||
Future<void> stopEchoingDeviceLog() async { }
|
||||
|
||||
@override
|
||||
Future<void> initLogReader() async { }
|
||||
|
||||
@override
|
||||
Future<Uri> setupDevFS(String fsName, Directory rootDirectory) async {
|
||||
return testUri!;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> runHot({required HotRunner hotRunner, String? route}) async {
|
||||
return runHotCode;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> runCold({required ColdRunner coldRunner, String? route}) async {
|
||||
if (runColdError != null) {
|
||||
throw runColdError!;
|
||||
}
|
||||
return runColdCode;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> connect({
|
||||
ReloadSources? reloadSources,
|
||||
Restart? restart,
|
||||
CompileExpression? compileExpression,
|
||||
GetSkSLMethod? getSkSLMethod,
|
||||
FlutterProject? flutterProject,
|
||||
PrintStructuredErrorLogMethod? printStructuredErrorLogMethod,
|
||||
int? hostVmServicePort,
|
||||
int? ddsPort,
|
||||
bool disableServiceAuthCodes = false,
|
||||
bool enableDds = true,
|
||||
bool cacheStartupProfile = false,
|
||||
required bool allowExistingDdsInstance,
|
||||
bool ipv6 = false,
|
||||
}) async { }
|
||||
|
||||
@override
|
||||
Future<UpdateFSReport> updateDevFS({
|
||||
required Uri mainUri,
|
||||
String? target,
|
||||
AssetBundle? bundle,
|
||||
DateTime? firstBuildTime,
|
||||
bool bundleFirstUpload = false,
|
||||
bool bundleDirty = false,
|
||||
bool fullRestart = false,
|
||||
String? projectRootPath,
|
||||
required String pathToReload,
|
||||
required String dillOutputPath,
|
||||
required List<Uri> invalidatedFiles,
|
||||
required PackageConfig packageConfig,
|
||||
}) async {
|
||||
if (reportError != null) {
|
||||
throw reportError!;
|
||||
}
|
||||
return report;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> updateReloadStatus(bool wasReloadSuccessful) async { }
|
||||
}
|
||||
|
||||
class FakeDelegateFlutterDevice extends FlutterDevice {
|
||||
FakeDelegateFlutterDevice(
|
||||
super.device,
|
||||
BuildInfo buildInfo,
|
||||
ResidentCompiler residentCompiler,
|
||||
this.fakeDevFS,
|
||||
) : super(buildInfo: buildInfo, generator: residentCompiler, developmentShaderCompiler: const FakeShaderCompiler());
|
||||
|
||||
@override
|
||||
Future<void> connect({
|
||||
ReloadSources? reloadSources,
|
||||
Restart? restart,
|
||||
bool enableDds = true,
|
||||
bool cacheStartupProfile = false,
|
||||
bool disableServiceAuthCodes = false,
|
||||
bool ipv6 = false,
|
||||
CompileExpression? compileExpression,
|
||||
GetSkSLMethod? getSkSLMethod,
|
||||
FlutterProject? flutterProject,
|
||||
int? hostVmServicePort,
|
||||
int? ddsPort,
|
||||
PrintStructuredErrorLogMethod? printStructuredErrorLogMethod,
|
||||
bool allowExistingDdsInstance = false,
|
||||
}) async { }
|
||||
|
||||
|
||||
final DevFS fakeDevFS;
|
||||
|
||||
@override
|
||||
DevFS? get devFS => fakeDevFS;
|
||||
|
||||
@override
|
||||
set devFS(DevFS? value) {}
|
||||
}
|
||||
|
||||
class FakeResidentCompiler extends Fake implements ResidentCompiler {
|
||||
CompilerOutput? nextOutput;
|
||||
bool didSuppressErrors = false;
|
||||
Uri? receivedNativeAssetsYaml;
|
||||
bool recompileCalled = false;
|
||||
|
||||
@override
|
||||
Future<CompilerOutput?> recompile(
|
||||
Uri mainUri,
|
||||
List<Uri>? invalidatedFiles, {
|
||||
required String outputPath,
|
||||
required PackageConfig packageConfig,
|
||||
String? projectRootPath,
|
||||
required FileSystem fs,
|
||||
bool suppressErrors = false,
|
||||
bool checkDartPluginRegistry = false,
|
||||
File? dartPluginRegistrant,
|
||||
Uri? nativeAssetsYaml,
|
||||
}) async {
|
||||
recompileCalled = true;
|
||||
receivedNativeAssetsYaml = nativeAssetsYaml;
|
||||
didSuppressErrors = suppressErrors;
|
||||
return nextOutput ?? const CompilerOutput('foo.dill', 0, <Uri>[]);
|
||||
}
|
||||
|
||||
@override
|
||||
void accept() { }
|
||||
|
||||
@override
|
||||
void reset() { }
|
||||
}
|
||||
|
||||
class FakeProjectFileInvalidator extends Fake implements ProjectFileInvalidator {
|
||||
@override
|
||||
Future<InvalidationResult> findInvalidated({
|
||||
required DateTime? lastCompiled,
|
||||
required List<Uri> urisToMonitor,
|
||||
required String packagesPath,
|
||||
required PackageConfig packageConfig,
|
||||
bool asyncScanning = false,
|
||||
}) async {
|
||||
return InvalidationResult(
|
||||
packageConfig: packageConfig,
|
||||
uris: <Uri>[Uri.parse('file:///hello_world/main.dart'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
class FakeDevice extends Fake implements Device {
|
||||
FakeDevice({
|
||||
String sdkNameAndVersion = 'Android',
|
||||
TargetPlatform targetPlatform = TargetPlatform.android_arm,
|
||||
bool isLocalEmulator = false,
|
||||
this.supportsHotRestart = true,
|
||||
this.supportsScreenshot = true,
|
||||
this.supportsFlutterExit = true,
|
||||
}) : _isLocalEmulator = isLocalEmulator,
|
||||
_targetPlatform = targetPlatform,
|
||||
_sdkNameAndVersion = sdkNameAndVersion;
|
||||
|
||||
final bool _isLocalEmulator;
|
||||
final TargetPlatform _targetPlatform;
|
||||
final String _sdkNameAndVersion;
|
||||
|
||||
bool disposed = false;
|
||||
bool appStopped = false;
|
||||
bool failScreenshot = false;
|
||||
|
||||
@override
|
||||
bool supportsHotRestart;
|
||||
|
||||
@override
|
||||
bool supportsScreenshot;
|
||||
|
||||
@override
|
||||
bool supportsFlutterExit;
|
||||
|
||||
@override
|
||||
PlatformType get platformType => _targetPlatform == TargetPlatform.web_javascript
|
||||
? PlatformType.web
|
||||
: PlatformType.android;
|
||||
|
||||
@override
|
||||
Future<String> get sdkNameAndVersion async => _sdkNameAndVersion;
|
||||
|
||||
@override
|
||||
Future<TargetPlatform> get targetPlatform async => _targetPlatform;
|
||||
|
||||
@override
|
||||
Future<bool> get isLocalEmulator async => _isLocalEmulator;
|
||||
|
||||
@override
|
||||
String get name => 'FakeDevice';
|
||||
|
||||
@override
|
||||
late DartDevelopmentService dds;
|
||||
|
||||
@override
|
||||
Future<void> dispose() async {
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> stopApp(ApplicationPackage? app, {String? userIdentifier}) async {
|
||||
appStopped = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> takeScreenshot(File outputFile) async {
|
||||
if (failScreenshot) {
|
||||
throw Exception();
|
||||
}
|
||||
outputFile.writeAsBytesSync(List<int>.generate(1024, (int i) => i));
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<DeviceLogReader> getLogReader({
|
||||
ApplicationPackage? app,
|
||||
bool includePastLogs = false,
|
||||
}) => NoOpDeviceLogReader(name);
|
||||
|
||||
@override
|
||||
DevicePortForwarder portForwarder = const NoOpDevicePortForwarder();
|
||||
}
|
||||
|
||||
class FakeDevFS extends Fake implements DevFS {
|
||||
@override
|
||||
DateTime? lastCompiled = DateTime(2000);
|
||||
|
||||
@override
|
||||
PackageConfig? lastPackageConfig = PackageConfig.empty;
|
||||
|
||||
@override
|
||||
List<Uri> sources = <Uri>[];
|
||||
|
||||
@override
|
||||
Uri baseUri = Uri();
|
||||
|
||||
@override
|
||||
Future<void> destroy() async { }
|
||||
|
||||
@override
|
||||
Set<String> assetPathsToEvict = <String>{};
|
||||
|
||||
@override
|
||||
Set<String> shaderPathsToEvict = <String>{};
|
||||
|
||||
@override
|
||||
Set<String> scenePathsToEvict = <String>{};
|
||||
|
||||
@override
|
||||
bool didUpdateFontManifest = false;
|
||||
|
||||
UpdateFSReport nextUpdateReport = UpdateFSReport(success: true);
|
||||
|
||||
@override
|
||||
bool hasSetAssetDirectory = false;
|
||||
|
||||
@override
|
||||
Future<Uri> create() async {
|
||||
return Uri();
|
||||
}
|
||||
|
||||
@override
|
||||
void resetLastCompiled() {
|
||||
lastCompiled = null;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<UpdateFSReport> update({
|
||||
required Uri mainUri,
|
||||
required ResidentCompiler generator,
|
||||
required bool trackWidgetCreation,
|
||||
required String pathToReload,
|
||||
required List<Uri> invalidatedFiles,
|
||||
required PackageConfig packageConfig,
|
||||
required String dillOutputPath,
|
||||
required DevelopmentShaderCompiler shaderCompiler,
|
||||
DevelopmentSceneImporter? sceneImporter,
|
||||
DevFSWriter? devFSWriter,
|
||||
String? target,
|
||||
AssetBundle? bundle,
|
||||
DateTime? firstBuildTime,
|
||||
bool bundleFirstUpload = false,
|
||||
bool fullRestart = false,
|
||||
String? projectRootPath,
|
||||
File? dartPluginRegistrant,
|
||||
}) async {
|
||||
return nextUpdateReport;
|
||||
}
|
||||
}
|
||||
|
||||
class FakeShaderCompiler implements DevelopmentShaderCompiler {
|
||||
const FakeShaderCompiler();
|
||||
|
||||
@override
|
||||
void configureCompiler(TargetPlatform? platform) { }
|
||||
|
||||
@override
|
||||
Future<DevFSContent> recompileShader(DevFSContent inputShader) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
@ -7,9 +7,7 @@ import 'dart:async';
|
||||
import 'package:dds/dds.dart' as dds;
|
||||
import 'package:file/memory.dart';
|
||||
import 'package:file_testing/file_testing.dart';
|
||||
import 'package:flutter_tools/src/application_package.dart';
|
||||
import 'package:flutter_tools/src/artifacts.dart';
|
||||
import 'package:flutter_tools/src/asset.dart';
|
||||
import 'package:flutter_tools/src/base/command_help.dart';
|
||||
import 'package:flutter_tools/src/base/common.dart';
|
||||
import 'package:flutter_tools/src/base/dds.dart';
|
||||
@ -18,14 +16,10 @@ import 'package:flutter_tools/src/base/io.dart' as io;
|
||||
import 'package:flutter_tools/src/base/logger.dart';
|
||||
import 'package:flutter_tools/src/base/platform.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/tools/scene_importer.dart';
|
||||
import 'package:flutter_tools/src/build_system/tools/shader_compiler.dart';
|
||||
import 'package:flutter_tools/src/compile.dart';
|
||||
import 'package:flutter_tools/src/convert.dart';
|
||||
import 'package:flutter_tools/src/devfs.dart';
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:flutter_tools/src/device_port_forwarder.dart';
|
||||
import 'package:flutter_tools/src/features.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
@ -36,12 +30,6 @@ import 'package:flutter_tools/src/run_cold.dart';
|
||||
import 'package:flutter_tools/src/run_hot.dart';
|
||||
import 'package:flutter_tools/src/version.dart';
|
||||
import 'package:flutter_tools/src/vmservice.dart';
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
hide BuildMode, Target;
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart'
|
||||
as native_assets_cli;
|
||||
import 'package:package_config/package_config.dart';
|
||||
import 'package:test/fake.dart';
|
||||
import 'package:unified_analytics/src/enums.dart';
|
||||
import 'package:unified_analytics/unified_analytics.dart';
|
||||
import 'package:vm_service/vm_service.dart' as vm_service;
|
||||
@ -51,121 +39,7 @@ import '../src/context.dart';
|
||||
import '../src/fake_vm_services.dart';
|
||||
import '../src/fakes.dart';
|
||||
import '../src/testbed.dart';
|
||||
import 'fake_native_assets_build_runner.dart';
|
||||
|
||||
final vm_service.Event fakeUnpausedEvent = vm_service.Event(
|
||||
kind: vm_service.EventKind.kResume,
|
||||
timestamp: 0
|
||||
);
|
||||
|
||||
final vm_service.Event fakePausedEvent = vm_service.Event(
|
||||
kind: vm_service.EventKind.kPauseException,
|
||||
timestamp: 0
|
||||
);
|
||||
|
||||
final vm_service.Isolate fakeUnpausedIsolate = vm_service.Isolate(
|
||||
id: '1',
|
||||
pauseEvent: fakeUnpausedEvent,
|
||||
breakpoints: <vm_service.Breakpoint>[],
|
||||
extensionRPCs: <String>[],
|
||||
libraries: <vm_service.LibraryRef>[
|
||||
vm_service.LibraryRef(
|
||||
id: '1',
|
||||
uri: 'file:///hello_world/main.dart',
|
||||
name: '',
|
||||
),
|
||||
],
|
||||
livePorts: 0,
|
||||
name: 'test',
|
||||
number: '1',
|
||||
pauseOnExit: false,
|
||||
runnable: true,
|
||||
startTime: 0,
|
||||
isSystemIsolate: false,
|
||||
isolateFlags: <vm_service.IsolateFlag>[],
|
||||
);
|
||||
|
||||
final vm_service.Isolate fakePausedIsolate = vm_service.Isolate(
|
||||
id: '1',
|
||||
pauseEvent: fakePausedEvent,
|
||||
breakpoints: <vm_service.Breakpoint>[
|
||||
vm_service.Breakpoint(
|
||||
breakpointNumber: 123,
|
||||
id: 'test-breakpoint',
|
||||
location: vm_service.SourceLocation(
|
||||
tokenPos: 0,
|
||||
script: vm_service.ScriptRef(id: 'test-script', uri: 'foo.dart'),
|
||||
),
|
||||
enabled: true,
|
||||
resolved: true,
|
||||
),
|
||||
],
|
||||
libraries: <vm_service.LibraryRef>[],
|
||||
livePorts: 0,
|
||||
name: 'test',
|
||||
number: '1',
|
||||
pauseOnExit: false,
|
||||
runnable: true,
|
||||
startTime: 0,
|
||||
isSystemIsolate: false,
|
||||
isolateFlags: <vm_service.IsolateFlag>[],
|
||||
);
|
||||
|
||||
final vm_service.VM fakeVM = vm_service.VM(
|
||||
isolates: <vm_service.IsolateRef>[fakeUnpausedIsolate],
|
||||
pid: 1,
|
||||
hostCPU: '',
|
||||
isolateGroups: <vm_service.IsolateGroupRef>[],
|
||||
targetCPU: '',
|
||||
startTime: 0,
|
||||
name: 'dart',
|
||||
architectureBits: 64,
|
||||
operatingSystem: '',
|
||||
version: '',
|
||||
systemIsolateGroups: <vm_service.IsolateGroupRef>[],
|
||||
systemIsolates: <vm_service.IsolateRef>[],
|
||||
);
|
||||
|
||||
final FlutterView fakeFlutterView = FlutterView(
|
||||
id: 'a',
|
||||
uiIsolate: fakeUnpausedIsolate,
|
||||
);
|
||||
|
||||
final FakeVmServiceRequest listViews = FakeVmServiceRequest(
|
||||
method: kListViewsMethod,
|
||||
jsonResponse: <String, Object>{
|
||||
'views': <Object>[
|
||||
fakeFlutterView.toJson(),
|
||||
],
|
||||
},
|
||||
);
|
||||
|
||||
const FakeVmServiceRequest setAssetBundlePath = FakeVmServiceRequest(
|
||||
method: '_flutter.setAssetBundlePath',
|
||||
args: <String, Object>{
|
||||
'viewId': 'a',
|
||||
'assetDirectory': 'build/flutter_assets',
|
||||
'isolateId': '1',
|
||||
}
|
||||
);
|
||||
|
||||
const FakeVmServiceRequest evict = FakeVmServiceRequest(
|
||||
method: 'ext.flutter.evict',
|
||||
args: <String, Object>{
|
||||
'value': 'asset',
|
||||
'isolateId': '1',
|
||||
}
|
||||
);
|
||||
|
||||
const FakeVmServiceRequest evictShader = FakeVmServiceRequest(
|
||||
method: 'ext.ui.window.reinitializeShader',
|
||||
args: <String, Object>{
|
||||
'assetKey': 'foo.frag',
|
||||
'isolateId': '1',
|
||||
}
|
||||
);
|
||||
|
||||
final Uri testUri = Uri.parse('foo://bar');
|
||||
import 'resident_runner_helpers.dart';
|
||||
|
||||
void main() {
|
||||
late Testbed testbed;
|
||||
@ -205,7 +79,7 @@ void main() {
|
||||
..testUri = testUri
|
||||
..vmServiceHost = (() => fakeVmServiceHost)
|
||||
..device = device
|
||||
.._devFS = devFS;
|
||||
..fakeDevFS = devFS;
|
||||
});
|
||||
|
||||
testUsingContext('ResidentRunner can attach to device successfully', () => testbed.run(() async {
|
||||
@ -471,7 +345,7 @@ void main() {
|
||||
connectionInfoCompleter: futureConnectionInfo,
|
||||
));
|
||||
await futureAppStart.future;
|
||||
flutterDevice._devFS = null;
|
||||
flutterDevice.fakeDevFS = null;
|
||||
|
||||
final OperationResult result = await residentRunner.restart();
|
||||
expect(result.fatal, false);
|
||||
@ -2437,88 +2311,6 @@ flutter:
|
||||
expect(fakeVmServiceHost!.hasRemainingExpectations, false);
|
||||
}));
|
||||
|
||||
testUsingContext(
|
||||
'native assets',
|
||||
() => testbed.run(() async {
|
||||
final FileSystem fileSystem = globals.fs;
|
||||
final Environment environment = Environment.test(
|
||||
fileSystem.currentDirectory,
|
||||
inputs: <String, String>{},
|
||||
artifacts: Artifacts.test(),
|
||||
processManager: FakeProcessManager.empty(),
|
||||
fileSystem: fileSystem,
|
||||
logger: BufferLogger.test(),
|
||||
);
|
||||
final Uri projectUri = environment.projectDir.uri;
|
||||
|
||||
final FakeDevice device = FakeDevice(
|
||||
targetPlatform: TargetPlatform.darwin,
|
||||
sdkNameAndVersion: 'Macos',
|
||||
);
|
||||
final FakeResidentCompiler residentCompiler = FakeResidentCompiler();
|
||||
final FakeFlutterDevice flutterDevice = FakeFlutterDevice()
|
||||
..testUri = testUri
|
||||
..vmServiceHost = (() => fakeVmServiceHost)
|
||||
..device = device
|
||||
.._devFS = devFS
|
||||
..targetPlatform = TargetPlatform.darwin
|
||||
..generator = residentCompiler;
|
||||
|
||||
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
|
||||
listViews,
|
||||
listViews,
|
||||
]);
|
||||
globals.fs
|
||||
.file(globals.fs.path.join('lib', 'main.dart'))
|
||||
.createSync(recursive: true);
|
||||
final FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner(
|
||||
packagesWithNativeAssetsResult: <Package>[
|
||||
Package('bar', projectUri),
|
||||
],
|
||||
dryRunResult: FakeNativeAssetsBuilderResult(
|
||||
assets: <Asset>[
|
||||
Asset(
|
||||
id: 'package:bar/bar.dart',
|
||||
linkMode: LinkMode.dynamic,
|
||||
target: native_assets_cli.Target.macOSArm64,
|
||||
path: AssetAbsolutePath(Uri.file('bar.dylib')),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
residentRunner = HotRunner(
|
||||
<FlutterDevice>[
|
||||
flutterDevice,
|
||||
],
|
||||
stayResident: false,
|
||||
debuggingOptions: DebuggingOptions.enabled(const BuildInfo(
|
||||
BuildMode.debug,
|
||||
'',
|
||||
treeShakeIcons: false,
|
||||
trackWidgetCreation: true,
|
||||
)),
|
||||
target: 'main.dart',
|
||||
devtoolsHandler: createNoOpHandler,
|
||||
buildRunner: buildRunner,
|
||||
analytics: fakeAnalytics,
|
||||
);
|
||||
|
||||
final int? result = await residentRunner.run();
|
||||
expect(result, 0);
|
||||
|
||||
expect(buildRunner.buildInvocations, 0);
|
||||
expect(buildRunner.dryRunInvocations, 1);
|
||||
expect(buildRunner.hasPackageConfigInvocations, 1);
|
||||
expect(buildRunner.packagesWithNativeAssetsInvocations, 1);
|
||||
|
||||
expect(residentCompiler.recompileCalled, true);
|
||||
expect(residentCompiler.receivedNativeAssetsYaml.toString(), endsWith('native_assets/macos/native_assets.yaml'));
|
||||
}),
|
||||
overrides: <Type, Generator>{
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true, isMacOSEnabled: true),
|
||||
});
|
||||
|
||||
testUsingContext(
|
||||
'use the nativeAssetsYamlFile when provided',
|
||||
() => testbed.run(() async {
|
||||
@ -2531,7 +2323,7 @@ flutter:
|
||||
..testUri = testUri
|
||||
..vmServiceHost = (() => fakeVmServiceHost)
|
||||
..device = device
|
||||
.._devFS = devFS
|
||||
..fakeDevFS = devFS
|
||||
..targetPlatform = TargetPlatform.darwin
|
||||
..generator = residentCompiler;
|
||||
|
||||
@ -2542,7 +2334,6 @@ flutter:
|
||||
globals.fs
|
||||
.file(globals.fs.path.join('lib', 'main.dart'))
|
||||
.createSync(recursive: true);
|
||||
final FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner();
|
||||
residentRunner = HotRunner(
|
||||
<FlutterDevice>[
|
||||
flutterDevice,
|
||||
@ -2556,7 +2347,6 @@ flutter:
|
||||
)),
|
||||
target: 'main.dart',
|
||||
devtoolsHandler: createNoOpHandler,
|
||||
buildRunner: buildRunner,
|
||||
analytics: fakeAnalytics,
|
||||
nativeAssetsYamlFile: 'foo.yaml',
|
||||
);
|
||||
@ -2564,11 +2354,6 @@ flutter:
|
||||
final int? result = await residentRunner.run();
|
||||
expect(result, 0);
|
||||
|
||||
expect(buildRunner.buildInvocations, 0);
|
||||
expect(buildRunner.dryRunInvocations, 0);
|
||||
expect(buildRunner.hasPackageConfigInvocations, 0);
|
||||
expect(buildRunner.packagesWithNativeAssetsInvocations, 0);
|
||||
|
||||
expect(residentCompiler.recompileCalled, true);
|
||||
expect(residentCompiler.receivedNativeAssetsYaml, globals.fs.path.toUri('foo.yaml'));
|
||||
}),
|
||||
@ -2577,390 +2362,3 @@ flutter:
|
||||
FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true, isMacOSEnabled: true),
|
||||
});
|
||||
}
|
||||
|
||||
// This implements [dds.DartDevelopmentService], not the [DartDevelopmentService]
|
||||
// interface from package:flutter_tools.
|
||||
class FakeDartDevelopmentService extends Fake implements dds.DartDevelopmentService {
|
||||
@override
|
||||
Future<void> get done => Future<void>.value();
|
||||
|
||||
@override
|
||||
Uri? get uri => null;
|
||||
}
|
||||
|
||||
class FakeDartDevelopmentServiceException implements dds.DartDevelopmentServiceException {
|
||||
FakeDartDevelopmentServiceException({this.message = defaultMessage});
|
||||
|
||||
@override
|
||||
final int errorCode = dds.DartDevelopmentServiceException.existingDdsInstanceError;
|
||||
|
||||
@override
|
||||
final String message;
|
||||
static const String defaultMessage = 'A DDS instance is already connected at http://localhost:8181';
|
||||
}
|
||||
|
||||
class TestFlutterDevice extends FlutterDevice {
|
||||
TestFlutterDevice(super.device, { Stream<Uri>? vmServiceUris })
|
||||
: _vmServiceUris = vmServiceUris, super(buildInfo: BuildInfo.debug, developmentShaderCompiler: const FakeShaderCompiler());
|
||||
|
||||
final Stream<Uri>? _vmServiceUris;
|
||||
|
||||
@override
|
||||
Stream<Uri> get vmServiceUris => _vmServiceUris!;
|
||||
}
|
||||
|
||||
class ThrowingForwardingFileSystem extends ForwardingFileSystem {
|
||||
ThrowingForwardingFileSystem(super.delegate);
|
||||
|
||||
@override
|
||||
File file(dynamic path) {
|
||||
if (path == 'foo') {
|
||||
throw const FileSystemException();
|
||||
}
|
||||
return delegate.file(path);
|
||||
}
|
||||
}
|
||||
|
||||
class FakeFlutterDevice extends Fake implements FlutterDevice {
|
||||
FakeVmServiceHost? Function()? vmServiceHost;
|
||||
Uri? testUri;
|
||||
UpdateFSReport report = UpdateFSReport(
|
||||
success: true,
|
||||
invalidatedSourcesCount: 1,
|
||||
);
|
||||
Exception? reportError;
|
||||
Exception? runColdError;
|
||||
int runHotCode = 0;
|
||||
int runColdCode = 0;
|
||||
|
||||
@override
|
||||
ResidentCompiler? generator;
|
||||
|
||||
@override
|
||||
DevelopmentShaderCompiler get developmentShaderCompiler => const FakeShaderCompiler();
|
||||
|
||||
@override
|
||||
TargetPlatform targetPlatform = TargetPlatform.android;
|
||||
|
||||
@override
|
||||
Stream<Uri?> get vmServiceUris => Stream<Uri?>.value(testUri);
|
||||
|
||||
@override
|
||||
FlutterVmService? get vmService => vmServiceHost?.call()?.vmService;
|
||||
|
||||
DevFS? _devFS;
|
||||
|
||||
@override
|
||||
DevFS? get devFS => _devFS;
|
||||
|
||||
@override
|
||||
set devFS(DevFS? value) { }
|
||||
|
||||
@override
|
||||
Device? device;
|
||||
|
||||
@override
|
||||
Future<void> stopEchoingDeviceLog() async { }
|
||||
|
||||
@override
|
||||
Future<void> initLogReader() async { }
|
||||
|
||||
@override
|
||||
Future<Uri> setupDevFS(String fsName, Directory rootDirectory) async {
|
||||
return testUri!;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> runHot({required HotRunner hotRunner, String? route}) async {
|
||||
return runHotCode;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> runCold({required ColdRunner coldRunner, String? route}) async {
|
||||
if (runColdError != null) {
|
||||
throw runColdError!;
|
||||
}
|
||||
return runColdCode;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> connect({
|
||||
ReloadSources? reloadSources,
|
||||
Restart? restart,
|
||||
CompileExpression? compileExpression,
|
||||
GetSkSLMethod? getSkSLMethod,
|
||||
FlutterProject? flutterProject,
|
||||
PrintStructuredErrorLogMethod? printStructuredErrorLogMethod,
|
||||
int? hostVmServicePort,
|
||||
int? ddsPort,
|
||||
bool disableServiceAuthCodes = false,
|
||||
bool enableDds = true,
|
||||
bool cacheStartupProfile = false,
|
||||
required bool allowExistingDdsInstance,
|
||||
bool ipv6 = false,
|
||||
}) async { }
|
||||
|
||||
@override
|
||||
Future<UpdateFSReport> updateDevFS({
|
||||
required Uri mainUri,
|
||||
String? target,
|
||||
AssetBundle? bundle,
|
||||
DateTime? firstBuildTime,
|
||||
bool bundleFirstUpload = false,
|
||||
bool bundleDirty = false,
|
||||
bool fullRestart = false,
|
||||
String? projectRootPath,
|
||||
required String pathToReload,
|
||||
required String dillOutputPath,
|
||||
required List<Uri> invalidatedFiles,
|
||||
required PackageConfig packageConfig,
|
||||
}) async {
|
||||
if (reportError != null) {
|
||||
throw reportError!;
|
||||
}
|
||||
return report;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> updateReloadStatus(bool wasReloadSuccessful) async { }
|
||||
}
|
||||
|
||||
class FakeDelegateFlutterDevice extends FlutterDevice {
|
||||
FakeDelegateFlutterDevice(
|
||||
super.device,
|
||||
BuildInfo buildInfo,
|
||||
ResidentCompiler residentCompiler,
|
||||
this.fakeDevFS,
|
||||
) : super(buildInfo: buildInfo, generator: residentCompiler, developmentShaderCompiler: const FakeShaderCompiler());
|
||||
|
||||
@override
|
||||
Future<void> connect({
|
||||
ReloadSources? reloadSources,
|
||||
Restart? restart,
|
||||
bool enableDds = true,
|
||||
bool cacheStartupProfile = false,
|
||||
bool disableServiceAuthCodes = false,
|
||||
bool ipv6 = false,
|
||||
CompileExpression? compileExpression,
|
||||
GetSkSLMethod? getSkSLMethod,
|
||||
FlutterProject? flutterProject,
|
||||
int? hostVmServicePort,
|
||||
int? ddsPort,
|
||||
PrintStructuredErrorLogMethod? printStructuredErrorLogMethod,
|
||||
bool allowExistingDdsInstance = false,
|
||||
}) async { }
|
||||
|
||||
|
||||
final DevFS fakeDevFS;
|
||||
|
||||
@override
|
||||
DevFS? get devFS => fakeDevFS;
|
||||
|
||||
@override
|
||||
set devFS(DevFS? value) {}
|
||||
}
|
||||
|
||||
class FakeResidentCompiler extends Fake implements ResidentCompiler {
|
||||
CompilerOutput? nextOutput;
|
||||
bool didSuppressErrors = false;
|
||||
Uri? receivedNativeAssetsYaml;
|
||||
bool recompileCalled = false;
|
||||
|
||||
@override
|
||||
Future<CompilerOutput?> recompile(
|
||||
Uri mainUri,
|
||||
List<Uri>? invalidatedFiles, {
|
||||
required String outputPath,
|
||||
required PackageConfig packageConfig,
|
||||
String? projectRootPath,
|
||||
required FileSystem fs,
|
||||
bool suppressErrors = false,
|
||||
bool checkDartPluginRegistry = false,
|
||||
File? dartPluginRegistrant,
|
||||
Uri? nativeAssetsYaml,
|
||||
}) async {
|
||||
recompileCalled = true;
|
||||
receivedNativeAssetsYaml = nativeAssetsYaml;
|
||||
didSuppressErrors = suppressErrors;
|
||||
return nextOutput ?? const CompilerOutput('foo.dill', 0, <Uri>[]);
|
||||
}
|
||||
|
||||
@override
|
||||
void accept() { }
|
||||
|
||||
@override
|
||||
void reset() { }
|
||||
}
|
||||
|
||||
class FakeProjectFileInvalidator extends Fake implements ProjectFileInvalidator {
|
||||
@override
|
||||
Future<InvalidationResult> findInvalidated({
|
||||
required DateTime? lastCompiled,
|
||||
required List<Uri> urisToMonitor,
|
||||
required String packagesPath,
|
||||
required PackageConfig packageConfig,
|
||||
bool asyncScanning = false,
|
||||
}) async {
|
||||
return InvalidationResult(
|
||||
packageConfig: packageConfig,
|
||||
uris: <Uri>[Uri.parse('file:///hello_world/main.dart'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
class FakeDevice extends Fake implements Device {
|
||||
FakeDevice({
|
||||
String sdkNameAndVersion = 'Android',
|
||||
TargetPlatform targetPlatform = TargetPlatform.android_arm,
|
||||
bool isLocalEmulator = false,
|
||||
this.supportsHotRestart = true,
|
||||
this.supportsScreenshot = true,
|
||||
this.supportsFlutterExit = true,
|
||||
}) : _isLocalEmulator = isLocalEmulator,
|
||||
_targetPlatform = targetPlatform,
|
||||
_sdkNameAndVersion = sdkNameAndVersion;
|
||||
|
||||
final bool _isLocalEmulator;
|
||||
final TargetPlatform _targetPlatform;
|
||||
final String _sdkNameAndVersion;
|
||||
|
||||
bool disposed = false;
|
||||
bool appStopped = false;
|
||||
bool failScreenshot = false;
|
||||
|
||||
@override
|
||||
bool supportsHotRestart;
|
||||
|
||||
@override
|
||||
bool supportsScreenshot;
|
||||
|
||||
@override
|
||||
bool supportsFlutterExit;
|
||||
|
||||
@override
|
||||
PlatformType get platformType => _targetPlatform == TargetPlatform.web_javascript
|
||||
? PlatformType.web
|
||||
: PlatformType.android;
|
||||
|
||||
@override
|
||||
Future<String> get sdkNameAndVersion async => _sdkNameAndVersion;
|
||||
|
||||
@override
|
||||
Future<TargetPlatform> get targetPlatform async => _targetPlatform;
|
||||
|
||||
@override
|
||||
Future<bool> get isLocalEmulator async => _isLocalEmulator;
|
||||
|
||||
@override
|
||||
String get name => 'FakeDevice';
|
||||
|
||||
@override
|
||||
late DartDevelopmentService dds;
|
||||
|
||||
@override
|
||||
Future<void> dispose() async {
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> stopApp(ApplicationPackage? app, {String? userIdentifier}) async {
|
||||
appStopped = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> takeScreenshot(File outputFile) async {
|
||||
if (failScreenshot) {
|
||||
throw Exception();
|
||||
}
|
||||
outputFile.writeAsBytesSync(List<int>.generate(1024, (int i) => i));
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<DeviceLogReader> getLogReader({
|
||||
ApplicationPackage? app,
|
||||
bool includePastLogs = false,
|
||||
}) => NoOpDeviceLogReader(name);
|
||||
|
||||
@override
|
||||
DevicePortForwarder portForwarder = const NoOpDevicePortForwarder();
|
||||
}
|
||||
|
||||
class FakeDevFS extends Fake implements DevFS {
|
||||
@override
|
||||
DateTime? lastCompiled = DateTime(2000);
|
||||
|
||||
@override
|
||||
PackageConfig? lastPackageConfig = PackageConfig.empty;
|
||||
|
||||
@override
|
||||
List<Uri> sources = <Uri>[];
|
||||
|
||||
@override
|
||||
Uri baseUri = Uri();
|
||||
|
||||
@override
|
||||
Future<void> destroy() async { }
|
||||
|
||||
@override
|
||||
Set<String> assetPathsToEvict = <String>{};
|
||||
|
||||
@override
|
||||
Set<String> shaderPathsToEvict = <String>{};
|
||||
|
||||
@override
|
||||
Set<String> scenePathsToEvict = <String>{};
|
||||
|
||||
@override
|
||||
bool didUpdateFontManifest = false;
|
||||
|
||||
UpdateFSReport nextUpdateReport = UpdateFSReport(success: true);
|
||||
|
||||
@override
|
||||
bool hasSetAssetDirectory = false;
|
||||
|
||||
@override
|
||||
Future<Uri> create() async {
|
||||
return Uri();
|
||||
}
|
||||
|
||||
@override
|
||||
void resetLastCompiled() {
|
||||
lastCompiled = null;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<UpdateFSReport> update({
|
||||
required Uri mainUri,
|
||||
required ResidentCompiler generator,
|
||||
required bool trackWidgetCreation,
|
||||
required String pathToReload,
|
||||
required List<Uri> invalidatedFiles,
|
||||
required PackageConfig packageConfig,
|
||||
required String dillOutputPath,
|
||||
required DevelopmentShaderCompiler shaderCompiler,
|
||||
DevelopmentSceneImporter? sceneImporter,
|
||||
DevFSWriter? devFSWriter,
|
||||
String? target,
|
||||
AssetBundle? bundle,
|
||||
DateTime? firstBuildTime,
|
||||
bool bundleFirstUpload = false,
|
||||
bool fullRestart = false,
|
||||
String? projectRootPath,
|
||||
File? dartPluginRegistrant,
|
||||
}) async {
|
||||
return nextUpdateReport;
|
||||
}
|
||||
}
|
||||
|
||||
class FakeShaderCompiler implements DevelopmentShaderCompiler {
|
||||
const FakeShaderCompiler();
|
||||
|
||||
@override
|
||||
void configureCompiler(TargetPlatform? platform) { }
|
||||
|
||||
@override
|
||||
Future<DevFSContent> recompileShader(DevFSContent inputShader) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
@ -21,9 +21,9 @@ import 'package:flutter_tools/src/base/logger.dart';
|
||||
import 'package:flutter_tools/src/base/os.dart';
|
||||
import 'package:native_assets_cli/native_assets_cli_internal.dart';
|
||||
|
||||
import '../src/common.dart';
|
||||
import 'test_utils.dart' show ProcessResultMatcher, fileSystem, platform;
|
||||
import 'transition_test_utils.dart';
|
||||
import '../../src/common.dart';
|
||||
import '../test_utils.dart' show ProcessResultMatcher, fileSystem, platform;
|
||||
import '../transition_test_utils.dart';
|
||||
|
||||
final String hostOs = platform.operatingSystem;
|
||||
|
Loading…
x
Reference in New Issue
Block a user