mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

Reland of https://github.com/flutter/flutter/pull/132985. Fixes the path to AssetManifest.bin in flavors_test_ios
218 lines
7.6 KiB
Dart
218 lines
7.6 KiB
Dart
// 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:meta/meta.dart';
|
|
import 'package:pool/pool.dart';
|
|
|
|
import 'asset.dart' hide defaultManifestPath;
|
|
import 'base/common.dart';
|
|
import 'base/file_system.dart';
|
|
import 'base/logger.dart';
|
|
import 'build_info.dart';
|
|
import 'build_system/build_system.dart';
|
|
import 'build_system/depfile.dart';
|
|
import 'build_system/targets/common.dart';
|
|
import 'build_system/targets/scene_importer.dart';
|
|
import 'build_system/targets/shader_compiler.dart';
|
|
import 'bundle.dart';
|
|
import 'cache.dart';
|
|
import 'devfs.dart';
|
|
import 'globals.dart' as globals;
|
|
import 'project.dart';
|
|
|
|
/// Provides a `build` method that builds the bundle.
|
|
class BundleBuilder {
|
|
/// Builds the bundle for the given target platform.
|
|
///
|
|
/// The default `mainPath` is `lib/main.dart`.
|
|
/// The default `manifestPath` is `pubspec.yaml`.
|
|
///
|
|
/// If [buildNativeAssets], native assets are built and the mapping for native
|
|
/// assets lookup at runtime is embedded in the kernel file, otherwise an
|
|
/// empty native assets mapping is embedded in the kernel file.
|
|
Future<void> build({
|
|
required TargetPlatform platform,
|
|
required BuildInfo buildInfo,
|
|
FlutterProject? project,
|
|
String? mainPath,
|
|
String manifestPath = defaultManifestPath,
|
|
String? applicationKernelFilePath,
|
|
String? depfilePath,
|
|
String? assetDirPath,
|
|
bool buildNativeAssets = true,
|
|
@visibleForTesting BuildSystem? buildSystem,
|
|
}) async {
|
|
project ??= FlutterProject.current();
|
|
mainPath ??= defaultMainPath;
|
|
depfilePath ??= defaultDepfilePath;
|
|
assetDirPath ??= getAssetBuildDirectory();
|
|
buildSystem ??= globals.buildSystem;
|
|
|
|
// If the precompiled flag was not passed, force us into debug mode.
|
|
final Environment environment = Environment(
|
|
projectDir: project.directory,
|
|
outputDir: globals.fs.directory(assetDirPath),
|
|
buildDir: project.dartTool.childDirectory('flutter_build'),
|
|
cacheDir: globals.cache.getRoot(),
|
|
flutterRootDir: globals.fs.directory(Cache.flutterRoot),
|
|
engineVersion: globals.artifacts!.isLocalEngine
|
|
? null
|
|
: globals.flutterVersion.engineRevision,
|
|
defines: <String, String>{
|
|
// used by the KernelSnapshot target
|
|
kTargetPlatform: getNameForTargetPlatform(platform),
|
|
kTargetFile: mainPath,
|
|
kDeferredComponents: 'false',
|
|
...buildInfo.toBuildSystemEnvironment(),
|
|
if (!buildNativeAssets) kNativeAssets: 'false'
|
|
},
|
|
artifacts: globals.artifacts!,
|
|
fileSystem: globals.fs,
|
|
logger: globals.logger,
|
|
processManager: globals.processManager,
|
|
usage: globals.flutterUsage,
|
|
analytics: globals.analytics,
|
|
platform: globals.platform,
|
|
generateDartPluginRegistry: true,
|
|
);
|
|
final Target target = buildInfo.mode == BuildMode.debug
|
|
? const CopyFlutterBundle()
|
|
: const ReleaseCopyFlutterBundle();
|
|
final BuildResult result = await buildSystem.build(target, environment);
|
|
|
|
if (!result.success) {
|
|
for (final ExceptionMeasurement measurement in result.exceptions.values) {
|
|
globals.printError('Target ${measurement.target} failed: ${measurement.exception}',
|
|
stackTrace: measurement.fatal
|
|
? measurement.stackTrace
|
|
: null,
|
|
);
|
|
}
|
|
throwToolExit('Failed to build bundle.');
|
|
}
|
|
final Depfile depfile = Depfile(result.inputFiles, result.outputFiles);
|
|
final File outputDepfile = globals.fs.file(depfilePath);
|
|
if (!outputDepfile.parent.existsSync()) {
|
|
outputDepfile.parent.createSync(recursive: true);
|
|
}
|
|
environment.depFileService.writeToFile(depfile, outputDepfile);
|
|
|
|
// Work around for flutter_tester placing kernel artifacts in odd places.
|
|
if (applicationKernelFilePath != null) {
|
|
final File outputDill = globals.fs.directory(assetDirPath).childFile('kernel_blob.bin');
|
|
if (outputDill.existsSync()) {
|
|
outputDill.copySync(applicationKernelFilePath);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
Future<AssetBundle?> buildAssets({
|
|
required String manifestPath,
|
|
String? assetDirPath,
|
|
String? packagesPath,
|
|
TargetPlatform? targetPlatform,
|
|
String? flavor,
|
|
}) async {
|
|
assetDirPath ??= getAssetBuildDirectory();
|
|
packagesPath ??= globals.fs.path.absolute('.packages');
|
|
|
|
// Build the asset bundle.
|
|
final AssetBundle assetBundle = AssetBundleFactory.instance.createBundle();
|
|
final int result = await assetBundle.build(
|
|
manifestPath: manifestPath,
|
|
packagesPath: packagesPath,
|
|
targetPlatform: targetPlatform,
|
|
flavor: flavor,
|
|
);
|
|
if (result != 0) {
|
|
return null;
|
|
}
|
|
|
|
return assetBundle;
|
|
}
|
|
|
|
Future<void> writeBundle(
|
|
Directory bundleDir,
|
|
Map<String, DevFSContent> assetEntries,
|
|
Map<String, AssetKind> entryKinds, {
|
|
Logger? loggerOverride,
|
|
required TargetPlatform targetPlatform,
|
|
}) async {
|
|
loggerOverride ??= globals.logger;
|
|
if (bundleDir.existsSync()) {
|
|
try {
|
|
bundleDir.deleteSync(recursive: true);
|
|
} on FileSystemException catch (err) {
|
|
loggerOverride.printWarning(
|
|
'Failed to clean up asset directory ${bundleDir.path}: $err\n'
|
|
'To clean build artifacts, use the command "flutter clean".'
|
|
);
|
|
}
|
|
}
|
|
bundleDir.createSync(recursive: true);
|
|
|
|
final ShaderCompiler shaderCompiler = ShaderCompiler(
|
|
processManager: globals.processManager,
|
|
logger: globals.logger,
|
|
fileSystem: globals.fs,
|
|
artifacts: globals.artifacts!,
|
|
);
|
|
|
|
final SceneImporter sceneImporter = SceneImporter(
|
|
processManager: globals.processManager,
|
|
logger: globals.logger,
|
|
fileSystem: globals.fs,
|
|
artifacts: globals.artifacts!,
|
|
);
|
|
|
|
// Limit number of open files to avoid running out of file descriptors.
|
|
final Pool pool = Pool(64);
|
|
await Future.wait<void>(
|
|
assetEntries.entries.map<Future<void>>((MapEntry<String, DevFSContent> entry) async {
|
|
final PoolResource resource = await pool.request();
|
|
try {
|
|
// This will result in strange looking files, for example files with `/`
|
|
// on Windows or files that end up getting URI encoded such as `#.ext`
|
|
// to `%23.ext`. However, we have to keep it this way since the
|
|
// platform channels in the framework will URI encode these values,
|
|
// and the native APIs will look for files this way.
|
|
final File file = globals.fs.file(globals.fs.path.join(bundleDir.path, entry.key));
|
|
final AssetKind assetKind = entryKinds[entry.key] ?? AssetKind.regular;
|
|
file.parent.createSync(recursive: true);
|
|
final DevFSContent devFSContent = entry.value;
|
|
if (devFSContent is DevFSFileContent) {
|
|
final File input = devFSContent.file as File;
|
|
bool doCopy = true;
|
|
switch (assetKind) {
|
|
case AssetKind.regular:
|
|
break;
|
|
case AssetKind.font:
|
|
break;
|
|
case AssetKind.shader:
|
|
doCopy = !await shaderCompiler.compileShader(
|
|
input: input,
|
|
outputPath: file.path,
|
|
target: ShaderTarget.sksl, // TODO(zanderso): configure impeller target when enabled.
|
|
json: targetPlatform == TargetPlatform.web_javascript,
|
|
);
|
|
case AssetKind.model:
|
|
doCopy = !await sceneImporter.importScene(
|
|
input: input,
|
|
outputPath: file.path,
|
|
);
|
|
}
|
|
if (doCopy) {
|
|
input.copySync(file.path);
|
|
}
|
|
} else {
|
|
await file.writeAsBytes(await entry.value.contentsAsBytes());
|
|
}
|
|
} finally {
|
|
resource.release();
|
|
}
|
|
}));
|
|
}
|