Add release and profile support for Windows (#57749)

Builds and bundles an 'app.so' containing AOT data, and downloads and packages the release/profile artifacts for those builds, rather than always using the debug artifacts.

Fixes https://github.com/flutter/flutter/issues/38477
Fixes https://github.com/flutter/flutter/issues/39664
This commit is contained in:
stuartmorgan 2020-05-28 12:17:56 -07:00 committed by GitHub
parent ca0d60087b
commit 9989c54cb1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 237 additions and 79 deletions

View file

@ -44,12 +44,12 @@ or
final String flutterExecutable = path.join(
flutterRoot, 'bin', Platform.isWindows ? 'flutter.bat' : 'flutter');
final String target = targetPlatform == 'windows-x64'
? 'debug_bundle_windows_assets'
: 'debug_bundle_linux_assets';
// TODO(jonahwilliams): currently all builds are debug builds. Remove the
final String bundlePlatform = targetPlatform == 'windows-x64' ? 'windows' : 'linux';
// TODO(jonahwilliams): currently all Linux builds are debug builds. Remove the
// hardcoded mode when profile and release support is added.
final String bundleMode = targetPlatform == 'windows-x64' ? buildMode : 'debug';
final String target = '${bundleMode}_bundle_${bundlePlatform}_assets';
final Process assembleProcess = await Process.start(
flutterExecutable,
<String>[
@ -61,7 +61,7 @@ or
'--output=build',
'-dTargetPlatform=$targetPlatform',
'-dTrackWidgetCreation=$trackWidgetCreation',
'-dBuildMode=debug',
'-dBuildMode=$bundleMode',
'-dTargetFile=$flutterTarget',
'-dTreeShakeIcons="$treeShakeIcons"',
'-dDartObfuscation=$dartObfuscation',

View file

@ -62,8 +62,8 @@ class AotBuilder {
case TargetPlatform.android_x64:
expectSo = true;
target = buildInfo.isRelease
? const AotElfRelease()
: const AotElfProfile();
? const AotElfRelease(TargetPlatform.android_arm)
: const AotElfProfile(TargetPlatform.android_arm);
}
Status status;

View file

@ -23,6 +23,7 @@ enum Artifact {
flutterMacOSFramework,
vmSnapshotData,
isolateSnapshotData,
icuData,
platformKernelDill,
platformLibrariesJson,
flutterPatchedSdkPath,
@ -86,6 +87,8 @@ String _artifactToFileName(Artifact artifact, [ TargetPlatform platform, BuildMo
return 'vm_isolate_snapshot.bin';
case Artifact.isolateSnapshotData:
return 'isolate_snapshot.bin';
case Artifact.icuData:
return 'icudtl.dat';
case Artifact.platformKernelDill:
return 'platform_strong.dill';
case Artifact.platformLibrariesJson:
@ -212,12 +215,12 @@ class CachedArtifacts extends Artifacts {
case TargetPlatform.ios:
return _getIosArtifactPath(artifact, platform, mode);
case TargetPlatform.darwin_x64:
return _getDarwinArtifactPath(artifact, platform, mode);
case TargetPlatform.linux_x64:
case TargetPlatform.windows_x64:
return _getDesktopArtifactPath(artifact, platform, mode);
case TargetPlatform.fuchsia_arm64:
case TargetPlatform.fuchsia_x64:
return _getFuchsiaArtifactPath(artifact, platform, mode);
case TargetPlatform.linux_x64:
case TargetPlatform.windows_x64:
case TargetPlatform.tester:
case TargetPlatform.web_javascript:
default: // could be null, but that can't be specified as a case.
@ -230,7 +233,7 @@ class CachedArtifacts extends Artifacts {
return _fileSystem.path.basename(_getEngineArtifactsPath(platform, mode));
}
String _getDarwinArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode mode) {
String _getDesktopArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode mode) {
// When platform is null, a generic host platform artifact is being requested
// and not the gen_snapshot for darwin as a target platform.
if (platform != null && artifact == Artifact.genSnapshot) {
@ -331,6 +334,7 @@ class CachedArtifacts extends Artifacts {
case Artifact.vmSnapshotData:
case Artifact.isolateSnapshotData:
case Artifact.frontendServerSnapshotForEngineDartSdk:
case Artifact.icuData:
final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path;
final String platformDirName = getNameForTargetPlatform(platform);
return _fileSystem.path.join(engineArtifactsPath, platformDirName, _artifactToFileName(artifact, platform, mode));
@ -491,6 +495,8 @@ class LocalEngineArtifacts extends Artifacts {
case Artifact.isolateSnapshotData:
case Artifact.vmSnapshotData:
return _fileSystem.path.join(engineOutPath, 'gen', 'flutter', 'lib', 'snapshot', artifactFileName);
case Artifact.icuData:
return _fileSystem.path.join(engineOutPath, artifactFileName);
case Artifact.platformKernelDill:
if (platform == TargetPlatform.fuchsia_x64 || platform == TargetPlatform.fuchsia_arm64) {
return _fileSystem.path.join(engineOutPath, 'flutter_runner_patched_sdk', artifactFileName);

View file

@ -298,6 +298,7 @@ class AOTSnapshotter {
TargetPlatform.android_x64,
TargetPlatform.ios,
TargetPlatform.darwin_x64,
TargetPlatform.windows_x64,
].contains(platform);
}
}

View file

@ -153,7 +153,7 @@ class ProfileAndroidApplication extends CopyFlutterAotBundle {
@override
List<Target> get dependencies => const <Target>[
AotElfProfile(),
AotElfProfile(TargetPlatform.android_arm),
AotAndroidAssetBundle(),
];
}
@ -167,7 +167,7 @@ class ReleaseAndroidApplication extends CopyFlutterAotBundle {
@override
List<Target> get dependencies => const <Target>[
AotElfRelease(),
AotElfRelease(TargetPlatform.android_arm),
AotAndroidAssetBundle(),
];
}

View file

@ -312,20 +312,20 @@ abstract class AotElfBase extends Target {
/// Generate an ELF binary from a dart kernel file in profile mode.
class AotElfProfile extends AotElfBase {
const AotElfProfile();
const AotElfProfile(this.targetPlatform);
@override
String get name => 'aot_elf_profile';
@override
List<Source> get inputs => const <Source>[
Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/dart.dart'),
Source.pattern('{BUILD_DIR}/app.dill'),
Source.pattern('{PROJECT_DIR}/.packages'),
Source.artifact(Artifact.engineDartBinary),
Source.artifact(Artifact.skyEnginePath),
List<Source> get inputs => <Source>[
const Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/dart.dart'),
const Source.pattern('{BUILD_DIR}/app.dill'),
const Source.pattern('{PROJECT_DIR}/.packages'),
const Source.artifact(Artifact.engineDartBinary),
const Source.artifact(Artifact.skyEnginePath),
Source.artifact(Artifact.genSnapshot,
platform: TargetPlatform.android_arm,
platform: targetPlatform,
mode: BuildMode.profile,
),
];
@ -339,24 +339,26 @@ class AotElfProfile extends AotElfBase {
List<Target> get dependencies => const <Target>[
KernelSnapshot(),
];
final TargetPlatform targetPlatform;
}
/// Generate an ELF binary from a dart kernel file in release mode.
class AotElfRelease extends AotElfBase {
const AotElfRelease();
const AotElfRelease(this.targetPlatform);
@override
String get name => 'aot_elf_release';
@override
List<Source> get inputs => const <Source>[
Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/dart.dart'),
Source.pattern('{BUILD_DIR}/app.dill'),
Source.pattern('{PROJECT_DIR}/.packages'),
Source.artifact(Artifact.engineDartBinary),
Source.artifact(Artifact.skyEnginePath),
List<Source> get inputs => <Source>[
const Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/dart.dart'),
const Source.pattern('{BUILD_DIR}/app.dill'),
const Source.pattern('{PROJECT_DIR}/.packages'),
const Source.artifact(Artifact.engineDartBinary),
const Source.artifact(Artifact.skyEnginePath),
Source.artifact(Artifact.genSnapshot,
platform: TargetPlatform.android_arm,
platform: targetPlatform,
mode: BuildMode.release,
),
];
@ -370,6 +372,8 @@ class AotElfRelease extends AotElfBase {
List<Target> get dependencies => const <Target>[
KernelSnapshot(),
];
final TargetPlatform targetPlatform;
}
/// Copies the pre-built flutter aot bundle.

View file

@ -7,8 +7,9 @@ import 'package:meta/meta.dart';
import '../../base/file_system.dart';
import '../depfile.dart';
/// Unpack the engine artifact list [artifacts] from [engineSourcePath] and
/// [clientSourcePaths] (if provided) into a directory [outputDirectory].
/// Unpack the engine artifact list [artifacts] from [engineSourcePath], ICU
/// data (if provided), and [clientSourcePaths] (if provided) into a directory
/// [outputDirectory].
///
/// Returns a [Depfile] including all copied files.
///
@ -20,6 +21,7 @@ Depfile unpackDesktopArtifacts({
@required Directory outputDirectory,
@required String engineSourcePath,
List<String> clientSourcePaths,
String icuDataPath,
}) {
final List<File> inputs = <File>[];
final List<File> outputs = <File>[];
@ -30,7 +32,7 @@ Depfile unpackDesktopArtifacts({
if (entityType == FileSystemEntityType.notFound
|| entityType == FileSystemEntityType.directory
|| entityType == FileSystemEntityType.link) {
throw Exception('Unsupported file type: $entityType');
throw Exception('Unsupported file type "$entityType" for $entityPath');
}
assert(entityType == FileSystemEntityType.file);
final String outputPath = fileSystem.path.join(
@ -46,6 +48,13 @@ Depfile unpackDesktopArtifacts({
inputs.add(inputFile);
outputs.add(destinationFile);
}
if (icuDataPath != null) {
final File inputFile = fileSystem.file(icuDataPath);
final File outputFile = fileSystem.file(fileSystem.path.join(outputDirectory.path, inputFile.basename));
inputFile.copySync(outputFile.path);
inputs.add(inputFile);
outputs.add(outputFile);
}
if (clientSourcePaths == null) {
return Depfile(inputs, outputs);
}

View file

@ -23,7 +23,6 @@ const List<String> _kWindowsArtifacts = <String>[
'flutter_messenger.h',
'flutter_plugin_registrar.h',
'flutter_windows.h',
'icudtl.dat',
];
const String _kWindowsDepfile = 'windows_engine_sources.d';
@ -78,6 +77,10 @@ class UnpackWindows extends Target {
engineSourcePath: engineSourcePath,
outputDirectory: outputDirectory,
clientSourcePaths: <String>[clientSourcePath],
icuDataPath: environment.artifacts.getArtifactPath(
Artifact.icuData,
platform: TargetPlatform.windows_x64
)
);
final DepfileService depfileService = DepfileService(
fileSystem: environment.fileSystem,
@ -90,12 +93,9 @@ class UnpackWindows extends Target {
}
}
/// Creates a debug bundle for the Windows desktop target.
class DebugBundleWindowsAssets extends Target {
const DebugBundleWindowsAssets();
@override
String get name => 'debug_bundle_windows_assets';
/// Creates a bundle for the Windows desktop target.
abstract class BundleWindowsAssets extends Target {
const BundleWindowsAssets();
@override
List<Target> get dependencies => const <Target>[
@ -105,17 +105,11 @@ class DebugBundleWindowsAssets extends Target {
@override
List<Source> get inputs => const <Source>[
Source.pattern('{BUILD_DIR}/app.dill'),
Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/windows.dart'),
Source.pattern('{PROJECT_DIR}/pubspec.yaml'),
...IconTreeShaker.inputs,
];
@override
List<Source> get outputs => const <Source>[
Source.pattern('{OUTPUT_DIR}/flutter_assets/kernel_blob.bin'),
];
@override
List<String> get depfiles => const <String>[
'flutter_assets.d',
@ -124,7 +118,7 @@ class DebugBundleWindowsAssets extends Target {
@override
Future<void> build(Environment environment) async {
if (environment.defines[kBuildMode] == null) {
throw MissingDefineException(kBuildMode, 'debug_bundle_windows_assets');
throw MissingDefineException(kBuildMode, 'bundle_windows_assets');
}
final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]);
final Directory outputDirectory = environment.outputDir
@ -149,3 +143,89 @@ class DebugBundleWindowsAssets extends Target {
);
}
}
/// A wrapper for AOT compilation that copies app.so into the output directory.
class WindowsAotBundle extends Target {
/// Create a [WindowsAotBundle] wrapper for [aotTarget].
const WindowsAotBundle(this.aotTarget);
/// The [AotElfBase] subclass that produces the app.so.
final AotElfBase aotTarget;
@override
String get name => 'windows_aot_bundle';
@override
List<Source> get inputs => const <Source>[
Source.pattern('{BUILD_DIR}/app.so'),
];
@override
List<Source> get outputs => const <Source>[
Source.pattern('{OUTPUT_DIR}/windows/app.so'),
];
@override
List<Target> get dependencies => <Target>[
aotTarget,
];
@override
Future<void> build(Environment environment) async {
final File outputFile = environment.buildDir.childFile('app.so');
final Directory outputDirectory = environment.outputDir.childDirectory('windows');
if (!outputDirectory.existsSync()) {
outputDirectory.createSync(recursive: true);
}
outputFile.copySync(outputDirectory.childFile('app.so').path);
}
}
class ReleaseBundleWindowsAssets extends BundleWindowsAssets {
const ReleaseBundleWindowsAssets();
@override
String get name => 'release_bundle_windows_assets';
@override
List<Source> get outputs => const <Source>[];
@override
List<Target> get dependencies => <Target>[
...super.dependencies,
const WindowsAotBundle(AotElfRelease(TargetPlatform.windows_x64)),
];
}
class ProfileBundleWindowsAssets extends BundleWindowsAssets {
const ProfileBundleWindowsAssets();
@override
String get name => 'profile_bundle_windows_assets';
@override
List<Source> get outputs => const <Source>[];
@override
List<Target> get dependencies => <Target>[
...super.dependencies,
const WindowsAotBundle(AotElfProfile(TargetPlatform.windows_x64)),
];
}
class DebugBundleWindowsAssets extends BundleWindowsAssets {
const DebugBundleWindowsAssets();
@override
String get name => 'debug_bundle_windows_assets';
@override
List<Source> get inputs => <Source>[
const Source.pattern('{BUILD_DIR}/app.dill'),
];
@override
List<Source> get outputs => <Source>[
const Source.pattern('{OUTPUT_DIR}/flutter_assets/kernel_blob.bin'),
];
}

View file

@ -29,8 +29,8 @@ const List<Target> _kDefaultTargets = <Target>[
// Shared targets
CopyAssets(),
KernelSnapshot(),
AotElfProfile(),
AotElfRelease(),
AotElfProfile(TargetPlatform.android_arm),
AotElfRelease(TargetPlatform.android_arm),
AotAssemblyProfile(),
AotAssemblyRelease(),
// macOS targets
@ -63,6 +63,8 @@ const List<Target> _kDefaultTargets = <Target>[
// Windows targets
UnpackWindows(),
DebugBundleWindowsAssets(),
ProfileBundleWindowsAssets(),
ReleaseBundleWindowsAssets(),
];
/// Assemble provides a low level API to interact with the flutter tool build

View file

@ -7,6 +7,7 @@ import '../base/common.dart';
import '../base/file_system.dart';
import '../base/logger.dart';
import '../base/process.dart';
import '../base/utils.dart';
import '../build_info.dart';
import '../cache.dart';
import '../globals.dart' as globals;
@ -57,15 +58,6 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, {
'Please run `flutter doctor` for more details.');
}
if (!buildInfo.isDebug) {
const String warning = '🚧 ';
globals.printStatus(warning * 20);
globals.printStatus('Warning: Only debug is currently implemented for Windows. This is effectively a debug build.');
globals.printStatus('See https://github.com/flutter/flutter/issues/38477 for details and updates.');
globals.printStatus(warning * 20);
globals.printStatus('');
}
final String buildScript = globals.fs.path.join(
Cache.flutterRoot,
'packages',
@ -74,7 +66,7 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, {
'vs_build.bat',
);
final String configuration = buildInfo.isDebug ? 'Debug' : 'Release';
final String configuration = toTitleCase(getNameForBuildMode(buildInfo.mode ?? BuildMode.release));
final String solutionPath = windowsProject.solutionFile.path;
final Stopwatch sw = Stopwatch()..start();
final Status status = globals.logger.startProgress(

View file

@ -116,7 +116,7 @@
</Message>
</PostBuildEvent>
<CustomBuildStep>
<Command>"$(ProjectDir)scripts\bundle_assets_and_deps" "$(FLUTTER_EPHEMERAL_DIR)\" "$(OutputPath)" "$(OutputPath)..\Plugins\" "$(TargetFileName)"</Command>
<Command>"$(ProjectDir)scripts\bundle_assets_and_deps" "$(FLUTTER_EPHEMERAL_DIR)\" "$(OutputPath)" "$(OutputPath)..\Plugins\" "$(TargetFileName)" "$(Configuration)"</Command>
</CustomBuildStep>
<CustomBuildStep>
<Message>Bundling dependencies</Message>
@ -165,7 +165,7 @@
</Message>
</PostBuildEvent>
<CustomBuildStep>
<Command>"$(ProjectDir)scripts\bundle_assets_and_deps" "$(FLUTTER_EPHEMERAL_DIR)\" "$(OutputPath)" "$(OutputPath)..\Plugins\" "$(TargetFileName)"</Command>
<Command>"$(ProjectDir)scripts\bundle_assets_and_deps" "$(FLUTTER_EPHEMERAL_DIR)\" "$(OutputPath)" "$(OutputPath)..\Plugins\" "$(TargetFileName)" "$(Configuration)"</Command>
</CustomBuildStep>
<CustomBuildStep>
<Message>Bundling dependencies</Message>
@ -214,7 +214,7 @@
</Message>
</PostBuildEvent>
<CustomBuildStep>
<Command>"$(ProjectDir)scripts\bundle_assets_and_deps" "$(FLUTTER_EPHEMERAL_DIR)\" "$(OutputPath)" "$(OutputPath)..\Plugins\" "$(TargetFileName)"</Command>
<Command>"$(ProjectDir)scripts\bundle_assets_and_deps" "$(FLUTTER_EPHEMERAL_DIR)\" "$(OutputPath)" "$(OutputPath)..\Plugins\" "$(TargetFileName)" "$(Configuration)"</Command>
</CustomBuildStep>
<CustomBuildStep>
<Message>Bundling dependencies</Message>

View file

@ -4,6 +4,7 @@ set FLUTTER_CACHE_DIR=%~1
set BUNDLE_DIR=%~2
set PLUGIN_DIR=%~3
set EXE_NAME=%~4
set BUILD_MODE=%~5
set DATA_DIR=%BUNDLE_DIR%data
@ -14,18 +15,24 @@ if %errorlevel% neq 0 exit /b %errorlevel%
echo %EXE_NAME%>"%FLUTTER_CACHE_DIR%exe_filename"
:: Copy the Flutter assets to the data directory.
set FLUTTER_APP_DIR=%~dp0..\..
set FLUTTER_BUILD_DIR=%~dp0..\..\build\
set ASSET_DIR_NAME=flutter_assets
set TARGET_ASSET_DIR=%DATA_DIR%\%ASSET_DIR_NAME%
if exist "%TARGET_ASSET_DIR%" call rmdir /s /q "%TARGET_ASSET_DIR%"
if %errorlevel% neq 0 exit /b %errorlevel%
call xcopy /s /e /i /q "%FLUTTER_APP_DIR%\build\%ASSET_DIR_NAME%" "%TARGET_ASSET_DIR%"
call xcopy /s /e /i /q "%FLUTTER_BUILD_DIR%%ASSET_DIR_NAME%" "%TARGET_ASSET_DIR%"
if %errorlevel% neq 0 exit /b %errorlevel%
:: Copy the icudtl.dat file from the Flutter tree to the data directory.
call xcopy /y /d /q "%FLUTTER_CACHE_DIR%icudtl.dat" "%DATA_DIR%"
if %errorlevel% neq 0 exit /b %errorlevel%
:: For non-debug modes, copy app.so into the data directory.
if not %BUILD_MODE% == "Debug" (
call xcopy /y /d /q "%FLUTTER_BUILD_DIR%windows\app.so" "%DATA_DIR%"
if %errorlevel% neq 0 exit /b %errorlevel%
)
:: Copy the Flutter DLL to the target location.
call xcopy /y /d /q "%FLUTTER_CACHE_DIR%flutter_windows.dll" "%BUNDLE_DIR%"
if %errorlevel% neq 0 exit /b %errorlevel%

View file

@ -304,31 +304,28 @@ void main() {
FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true),
});
testUsingContext('Release build prints an under-construction warning', () async {
testUsingContext('Windows profile build passes Profile configuration', () async {
final BuildWindowsCommand command = BuildWindowsCommand()
..visualStudioOverride = mockVisualStudio;
applyMocksToCommand(command);
setUpMockProjectFilesForBuild();
when(mockVisualStudio.vcvarsPath).thenReturn(vcvarsPath);
when(mockProcessManager.start(
<String>[
when(mockProcessManager.start(<String>[
fileSystem.path.join(flutterRoot, 'packages', 'flutter_tools', 'bin', 'vs_build.bat'),
vcvarsPath,
fileSystem.path.basename(solutionPath),
'Release',
'Profile',
],
environment: <String, String>{},
workingDirectory: fileSystem.path.dirname(solutionPath))).thenAnswer((Invocation invocation) async {
workingDirectory: fileSystem.path.dirname(solutionPath))
).thenAnswer((Invocation invocation) async {
return mockProcess;
},
);
});
await createTestCommandRunner(command).run(
const <String>['windows', '--no-pub']
const <String>['windows', '--profile', '--no-pub']
);
expect(testLogger.statusText, contains('🚧'));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,

View file

@ -333,7 +333,7 @@ void main() {
]);
androidEnvironment.buildDir.childFile('app.dill').createSync(recursive: true);
await const AotElfProfile().build(androidEnvironment);
await const AotElfProfile(TargetPlatform.android_arm).build(androidEnvironment);
expect(processManager.hasRemainingExpectations, false);
}));
@ -341,14 +341,14 @@ void main() {
test('AotElfProfile throws error if missing build mode', () => testbed.run(() async {
androidEnvironment.defines.remove(kBuildMode);
expect(const AotElfProfile().build(androidEnvironment),
expect(const AotElfProfile(TargetPlatform.android_arm).build(androidEnvironment),
throwsA(isA<MissingDefineException>()));
}));
test('AotElfProfile throws error if missing target platform', () => testbed.run(() async {
androidEnvironment.defines.remove(kTargetPlatform);
expect(const AotElfProfile().build(androidEnvironment),
expect(const AotElfProfile(TargetPlatform.android_arm).build(androidEnvironment),
throwsA(isA<MissingDefineException>()));
}));
@ -594,7 +594,7 @@ void main() {
]),
]);
await const AotElfRelease().build(androidEnvironment);
await const AotElfRelease(TargetPlatform.android_arm).build(androidEnvironment);
expect(processManager.hasRemainingExpectations, false);
}));

View file

@ -8,6 +8,7 @@ import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/file_system.dart';
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/depfile.dart';
import 'package:flutter_tools/src/build_system/targets/dart.dart';
@ -67,6 +68,11 @@ void main() {
mode: anyNamed('mode'),
platform: anyNamed('platform')
)).thenReturn(r'C:\bin\cache\artifacts\engine\windows-x64\cpp_client_wrapper\');
when(artifacts.getArtifactPath(
Artifact.icuData,
mode: anyNamed('mode'),
platform: anyNamed('platform')
)).thenReturn(r'C:\bin\cache\artifacts\engine\windows-x64\icudtl.dat');
for (final String path in kRequiredFiles) {
fileSystem.file(path).createSync(recursive: true);
}
@ -158,6 +164,60 @@ void main() {
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('ProfileBundleWindowsAssets creates correct bundle structure', () async {
final Environment environment = Environment.test(
fileSystem.currentDirectory,
artifacts: MockArtifacts(),
processManager: FakeProcessManager.any(),
fileSystem: fileSystem,
logger: BufferLogger.test(),
defines: <String, String>{
kBuildMode: 'profile',
}
);
environment.buildDir.childFile('app.so').createSync(recursive: true);
await const WindowsAotBundle(AotElfProfile(TargetPlatform.windows_x64)).build(environment);
await const ProfileBundleWindowsAssets().build(environment);
// Depfile is created and so is copied.
expect(environment.buildDir.childFile('flutter_assets.d'), exists);
expect(fileSystem.file(r'C:\windows\app.so'), exists);
expect(fileSystem.file(r'C:\flutter_assets\kernel_blob.bin').existsSync(), false);
expect(fileSystem.file(r'C:\flutter_assets\AssetManifest.json'), exists);
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('ReleaseBundleWindowsAssets creates correct bundle structure', () async {
final Environment environment = Environment.test(
fileSystem.currentDirectory,
artifacts: MockArtifacts(),
processManager: FakeProcessManager.any(),
fileSystem: fileSystem,
logger: BufferLogger.test(),
defines: <String, String>{
kBuildMode: 'release',
}
);
environment.buildDir.childFile('app.so').createSync(recursive: true);
await const WindowsAotBundle(AotElfRelease(TargetPlatform.windows_x64)).build(environment);
await const ReleaseBundleWindowsAssets().build(environment);
// Depfile is created and so is copied.
expect(environment.buildDir.childFile('flutter_assets.d'), exists);
expect(fileSystem.file(r'C:\windows\app.so'), exists);
expect(fileSystem.file(r'C:\flutter_assets\kernel_blob.bin').existsSync(), false);
expect(fileSystem.file(r'C:\flutter_assets\AssetManifest.json'), exists);
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
});
}
class MockArtifacts extends Mock implements Artifacts {}