mirror of
https://github.com/flutter/flutter
synced 2024-10-13 11:42:54 +00:00
Re-Re-Re-land implement flutter build bundle with assemble (#41302)
This commit is contained in:
parent
d2a95ee344
commit
9bd02a1787
|
@ -139,7 +139,7 @@ Future<void> main() async {
|
|||
await runProjectTest((FlutterProject project) async {
|
||||
section('gradlew assembleDebug');
|
||||
await project.runGradleTask('assembleDebug');
|
||||
final String errorMessage = validateSnapshotDependency(project, 'build/app.dill');
|
||||
final String errorMessage = validateSnapshotDependency(project, 'kernel_blob.bin');
|
||||
if (errorMessage != null) {
|
||||
throw TaskResult.failure(errorMessage);
|
||||
}
|
||||
|
|
|
@ -389,25 +389,29 @@ Future<ProcessResult> _resultOfGradleTask({String workingDirectory, String task,
|
|||
|
||||
class _Dependencies {
|
||||
_Dependencies(String depfilePath) {
|
||||
final RegExp _separatorExpr = RegExp(r'([^\\]) ');
|
||||
final RegExp _escapeExpr = RegExp(r'\\(.)');
|
||||
|
||||
// Depfile format:
|
||||
// outfile1 outfile2 : file1.dart file2.dart file3.dart file\ 4.dart
|
||||
final String contents = File(depfilePath).readAsStringSync();
|
||||
final List<String> colonSeparated = contents.split(': ');
|
||||
target = colonSeparated[0].trim();
|
||||
dependencies = colonSeparated[1]
|
||||
// Put every file on right-hand side on the separate line
|
||||
final List<String> colonSeparated = contents.split(':');
|
||||
targets = _processList(colonSeparated[0].trim());
|
||||
dependencies = _processList(colonSeparated[1].trim());
|
||||
}
|
||||
|
||||
final RegExp _separatorExpr = RegExp(r'([^\\]) ');
|
||||
final RegExp _escapeExpr = RegExp(r'\\(.)');
|
||||
|
||||
Set<String> _processList(String rawText) {
|
||||
return rawText
|
||||
// Put every file on right-hand side on the separate line
|
||||
.replaceAllMapped(_separatorExpr, (Match match) => '${match.group(1)}\n')
|
||||
.split('\n')
|
||||
// Expand escape sequences, so that '\ ', for example,ß becomes ' '
|
||||
// Expand escape sequences, so that '\ ', for example,ß becomes ' '
|
||||
.map<String>((String path) => path.replaceAllMapped(_escapeExpr, (Match match) => match.group(1)).trim())
|
||||
.where((String path) => path.isNotEmpty)
|
||||
.toSet();
|
||||
}
|
||||
|
||||
String target;
|
||||
Set<String> targets;
|
||||
Set<String> dependencies;
|
||||
}
|
||||
|
||||
|
@ -416,6 +420,6 @@ String validateSnapshotDependency(FlutterProject project, String expectedTarget)
|
|||
final _Dependencies deps = _Dependencies(
|
||||
path.join(project.rootPath, 'build', 'app', 'intermediates',
|
||||
'flutter', 'debug', 'android-arm', 'snapshot_blob.bin.d'));
|
||||
return deps.target == expectedTarget ? null :
|
||||
'Dependency file should have $expectedTarget as target. Instead has ${deps.target}';
|
||||
return deps.targets.any((String target) => target.contains(expectedTarget)) ? null :
|
||||
'Dependency file should have $expectedTarget as target. Instead has ${deps.targets}';
|
||||
}
|
||||
|
|
|
@ -92,6 +92,9 @@ String _artifactToFileName(Artifact artifact, [ TargetPlatform platform, BuildMo
|
|||
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
||||
return 'frontend_server.dart.snapshot';
|
||||
case Artifact.engineDartBinary:
|
||||
if (platform == TargetPlatform.windows_x64) {
|
||||
return 'dart.exe';
|
||||
}
|
||||
return 'dart';
|
||||
case Artifact.dart2jsSnapshot:
|
||||
return 'dart2js.dart.snapshot';
|
||||
|
@ -265,7 +268,7 @@ class CachedArtifacts extends Artifacts {
|
|||
case Artifact.engineDartSdkPath:
|
||||
return dartSdkPath;
|
||||
case Artifact.engineDartBinary:
|
||||
return fs.path.join(dartSdkPath, 'bin', _artifactToFileName(artifact));
|
||||
return fs.path.join(dartSdkPath, 'bin', _artifactToFileName(artifact, platform));
|
||||
case Artifact.platformKernelDill:
|
||||
return fs.path.join(_getFlutterPatchedSdkPath(mode), _artifactToFileName(artifact));
|
||||
case Artifact.platformLibrariesJson:
|
||||
|
|
|
@ -10,6 +10,7 @@ import 'package:crypto/crypto.dart';
|
|||
import 'package:meta/meta.dart';
|
||||
import 'package:pool/pool.dart';
|
||||
|
||||
import '../base/context.dart';
|
||||
import '../base/file_system.dart';
|
||||
import '../base/platform.dart';
|
||||
import '../cache.dart';
|
||||
|
@ -21,6 +22,9 @@ import 'source.dart';
|
|||
|
||||
export 'source.dart';
|
||||
|
||||
/// The [BuildSystem] instance.
|
||||
BuildSystem get buildSystem => context.get<BuildSystem>();
|
||||
|
||||
/// Configuration for the build system itself.
|
||||
class BuildSystemConfig {
|
||||
/// Create a new [BuildSystemConfig].
|
||||
|
@ -497,14 +501,14 @@ class _BuildInstance {
|
|||
}
|
||||
if (canSkip) {
|
||||
skipped = true;
|
||||
printStatus('Skipping target: ${node.target.name}');
|
||||
printTrace('Skipping target: ${node.target.name}');
|
||||
for (File output in node.outputs) {
|
||||
outputFiles[output.path] = output;
|
||||
}
|
||||
} else {
|
||||
printStatus('${node.target.name}: Starting due to ${node.invalidatedReasons}');
|
||||
printTrace('${node.target.name}: Starting due to ${node.invalidatedReasons}');
|
||||
await node.target.build(environment);
|
||||
printStatus('${node.target.name}: Complete');
|
||||
printTrace('${node.target.name}: Complete');
|
||||
|
||||
// Update hashes for output files.
|
||||
await fileCache.hashFiles(node.outputs);
|
||||
|
@ -515,7 +519,10 @@ class _BuildInstance {
|
|||
// Delete outputs from previous stages that are no longer a part of the build.
|
||||
for (String previousOutput in node.previousOutputs) {
|
||||
if (!outputFiles.containsKey(previousOutput)) {
|
||||
fs.file(previousOutput).deleteSync();
|
||||
final File previousFile = fs.file(previousOutput);
|
||||
if (previousFile.existsSync()) {
|
||||
previousFile.deleteSync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ class FileHashStore {
|
|||
FileStorage fileStorage;
|
||||
try {
|
||||
fileStorage = FileStorage.fromBuffer(data);
|
||||
} on FormatException {
|
||||
} catch (err) {
|
||||
printTrace('Filestorage format changed');
|
||||
_cacheFile.deleteSync();
|
||||
return;
|
||||
|
@ -123,7 +123,7 @@ class FileHashStore {
|
|||
printTrace('Persisting file store');
|
||||
final File file = _cacheFile;
|
||||
if (!file.existsSync()) {
|
||||
file.createSync();
|
||||
file.createSync(recursive: true);
|
||||
}
|
||||
final List<FileHash> fileHashes = <FileHash>[];
|
||||
for (MapEntry<String, String> entry in currentHashes.entries) {
|
||||
|
|
|
@ -48,6 +48,43 @@ class AssetBehavior extends SourceBehavior {
|
|||
}
|
||||
}
|
||||
|
||||
/// A specific asset behavior for building bundles.
|
||||
class AssetOutputBehavior extends SourceBehavior {
|
||||
const AssetOutputBehavior();
|
||||
|
||||
@override
|
||||
List<File> inputs(Environment environment) {
|
||||
final AssetBundle assetBundle = AssetBundleFactory.instance.createBundle();
|
||||
assetBundle.build(
|
||||
manifestPath: environment.projectDir.childFile('pubspec.yaml').path,
|
||||
packagesPath: environment.projectDir.childFile('.packages').path,
|
||||
);
|
||||
// Filter the file type to remove the files that are generated by this
|
||||
// command as inputs.
|
||||
final List<File> results = <File>[];
|
||||
final Iterable<DevFSFileContent> files = assetBundle.entries.values.whereType<DevFSFileContent>();
|
||||
for (DevFSFileContent devFsContent in files) {
|
||||
results.add(fs.file(devFsContent.file.path));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
@override
|
||||
List<File> outputs(Environment environment) {
|
||||
final AssetBundle assetBundle = AssetBundleFactory.instance.createBundle();
|
||||
assetBundle.build(
|
||||
manifestPath: environment.projectDir.childFile('pubspec.yaml').path,
|
||||
packagesPath: environment.projectDir.childFile('.packages').path,
|
||||
);
|
||||
final List<File> results = <File>[];
|
||||
for (String key in assetBundle.entries.keys) {
|
||||
final File file = fs.file(fs.path.join(environment.outputDir.path, key));
|
||||
results.add(file);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
/// Copy the assets defined in the flutter manifest into a build directory.
|
||||
class CopyAssets extends Target {
|
||||
const CopyAssets();
|
||||
|
|
|
@ -2,17 +2,22 @@
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:pool/pool.dart';
|
||||
|
||||
import '../../artifacts.dart';
|
||||
import '../../asset.dart';
|
||||
import '../../base/build.dart';
|
||||
import '../../base/file_system.dart';
|
||||
import '../../base/platform.dart';
|
||||
import '../../build_info.dart';
|
||||
import '../../compile.dart';
|
||||
import '../../dart/package_map.dart';
|
||||
import '../../devfs.dart';
|
||||
import '../../globals.dart';
|
||||
import '../../project.dart';
|
||||
import '../build_system.dart';
|
||||
import '../exceptions.dart';
|
||||
import 'assets.dart';
|
||||
|
||||
/// The define to pass a [BuildMode].
|
||||
const String kBuildMode= 'BuildMode';
|
||||
|
@ -55,6 +60,111 @@ List<File> listDartSources(Environment environment) {
|
|||
return dartFiles;
|
||||
}
|
||||
|
||||
/// Copies the prebuilt flutter bundle.
|
||||
// This is a one-off rule for implementing build bundle in terms of assemble.
|
||||
class CopyFlutterBundle extends Target {
|
||||
const CopyFlutterBundle();
|
||||
|
||||
@override
|
||||
String get name => 'copy_flutter_bundle';
|
||||
|
||||
@override
|
||||
List<Source> get inputs => const <Source>[
|
||||
Source.artifact(Artifact.vmSnapshotData, mode: BuildMode.debug),
|
||||
Source.artifact(Artifact.isolateSnapshotData, mode: BuildMode.debug),
|
||||
Source.pattern('{BUILD_DIR}/app.dill'),
|
||||
Source.behavior(AssetOutputBehavior())
|
||||
];
|
||||
|
||||
@override
|
||||
List<Source> get outputs => const <Source>[
|
||||
Source.pattern('{OUTPUT_DIR}/vm_snapshot_data'),
|
||||
Source.pattern('{OUTPUT_DIR}/isolate_snapshot_data'),
|
||||
Source.pattern('{OUTPUT_DIR}/kernel_blob.bin'),
|
||||
Source.pattern('{OUTPUT_DIR}/AssetManifest.json'),
|
||||
Source.pattern('{OUTPUT_DIR}/FontManifest.json'),
|
||||
Source.pattern('{OUTPUT_DIR}/LICENSE'),
|
||||
Source.behavior(AssetOutputBehavior())
|
||||
];
|
||||
|
||||
@override
|
||||
Future<void> build(Environment environment) async {
|
||||
if (environment.defines[kBuildMode] == null) {
|
||||
throw MissingDefineException(kBuildMode, 'copy_flutter_bundle');
|
||||
}
|
||||
final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]);
|
||||
|
||||
// We're not smart enough to only remove assets that are removed. If
|
||||
// anything changes blow away the whole directory.
|
||||
if (environment.outputDir.existsSync()) {
|
||||
environment.outputDir.deleteSync(recursive: true);
|
||||
}
|
||||
environment.outputDir.createSync(recursive: true);
|
||||
|
||||
// Only copy the prebuilt runtimes and kernel blob in debug mode.
|
||||
if (buildMode == BuildMode.debug) {
|
||||
final String vmSnapshotData = artifacts.getArtifactPath(Artifact.vmSnapshotData, mode: BuildMode.debug);
|
||||
final String isolateSnapshotData = artifacts.getArtifactPath(Artifact.isolateSnapshotData, mode: BuildMode.debug);
|
||||
environment.buildDir.childFile('app.dill')
|
||||
.copySync(environment.outputDir.childFile('kernel_blob.bin').path);
|
||||
fs.file(vmSnapshotData)
|
||||
.copySync(environment.outputDir.childFile('vm_snapshot_data').path);
|
||||
fs.file(isolateSnapshotData)
|
||||
.copySync(environment.outputDir.childFile('isolate_snapshot_data').path);
|
||||
}
|
||||
|
||||
final AssetBundle assetBundle = AssetBundleFactory.instance.createBundle();
|
||||
await assetBundle.build();
|
||||
final Pool pool = Pool(64);
|
||||
await Future.wait<void>(
|
||||
assetBundle.entries.entries.map<Future<void>>((MapEntry<String, DevFSContent> entry) async {
|
||||
final PoolResource resource = await pool.request();
|
||||
try {
|
||||
final File file = fs.file(fs.path.join(environment.outputDir.path, entry.key));
|
||||
file.parent.createSync(recursive: true);
|
||||
final DevFSContent content = entry.value;
|
||||
if (content is DevFSFileContent && content.file is File) {
|
||||
await (content.file as File).copy(file.path);
|
||||
} else {
|
||||
await file.writeAsBytes(await entry.value.contentsAsBytes());
|
||||
}
|
||||
} finally {
|
||||
resource.release();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@override
|
||||
List<Target> get dependencies => const <Target>[
|
||||
KernelSnapshot(),
|
||||
];
|
||||
}
|
||||
|
||||
/// Copies the prebuilt flutter bundle for release mode.
|
||||
class ReleaseCopyFlutterBundle extends CopyFlutterBundle {
|
||||
const ReleaseCopyFlutterBundle();
|
||||
|
||||
@override
|
||||
String get name => 'release_flutter_bundle';
|
||||
|
||||
@override
|
||||
List<Source> get inputs => const <Source>[
|
||||
Source.behavior(AssetOutputBehavior())
|
||||
];
|
||||
|
||||
@override
|
||||
List<Source> get outputs => const <Source>[
|
||||
Source.pattern('{OUTPUT_DIR}/AssetManifest.json'),
|
||||
Source.pattern('{OUTPUT_DIR}/FontManifest.json'),
|
||||
Source.pattern('{OUTPUT_DIR}/LICENSE'),
|
||||
Source.behavior(AssetOutputBehavior())
|
||||
];
|
||||
|
||||
@override
|
||||
List<Target> get dependencies => const <Target>[];
|
||||
}
|
||||
|
||||
|
||||
/// Generate a snapshot of the dart code used in the program.
|
||||
class KernelSnapshot extends Target {
|
||||
const KernelSnapshot();
|
||||
|
@ -91,8 +201,7 @@ class KernelSnapshot extends Target {
|
|||
final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]);
|
||||
final String targetFile = environment.defines[kTargetFile] ?? fs.path.join('lib', 'main.dart');
|
||||
final String packagesPath = environment.projectDir.childFile('.packages').path;
|
||||
final PackageUriMapper packageUriMapper = PackageUriMapper(targetFile,
|
||||
packagesPath, null, null);
|
||||
final String targetFileAbsolute = fs.file(targetFile).absolute.path;
|
||||
|
||||
final CompilerOutput output = await compiler.compile(
|
||||
sdkRoot: artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath, mode: buildMode),
|
||||
|
@ -101,12 +210,11 @@ class KernelSnapshot extends Target {
|
|||
targetModel: TargetModel.flutter,
|
||||
targetProductVm: buildMode == BuildMode.release,
|
||||
outputFilePath: environment.buildDir.childFile('app.dill').path,
|
||||
depFilePath: null,
|
||||
packagesPath: packagesPath,
|
||||
linkPlatformKernelIn: buildMode == BuildMode.release,
|
||||
mainPath: packageUriMapper.map(targetFile)?.toString() ?? targetFile,
|
||||
mainPath: targetFileAbsolute,
|
||||
);
|
||||
if (output.errorCount != 0) {
|
||||
if (output == null || output.errorCount != 0) {
|
||||
throw Exception('Errors during snapshot creation: $output');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,10 @@ import 'artifacts.dart';
|
|||
import 'asset.dart';
|
||||
import 'base/common.dart';
|
||||
import 'base/file_system.dart';
|
||||
import 'base/platform.dart';
|
||||
import 'build_info.dart';
|
||||
import 'build_system/build_system.dart';
|
||||
import 'build_system/targets/dart.dart';
|
||||
import 'compile.dart';
|
||||
import 'dart/package_map.dart';
|
||||
import 'devfs.dart';
|
||||
|
@ -69,6 +72,7 @@ class BundleBuilder {
|
|||
List<String> extraGenSnapshotOptions = const <String>[],
|
||||
List<String> fileSystemRoots,
|
||||
String fileSystemScheme,
|
||||
bool shouldBuildWithAssemble = false,
|
||||
}) async {
|
||||
mainPath ??= defaultMainPath;
|
||||
depfilePath ??= defaultDepfilePath;
|
||||
|
@ -77,6 +81,18 @@ class BundleBuilder {
|
|||
applicationKernelFilePath ??= getDefaultApplicationKernelPath(trackWidgetCreation: trackWidgetCreation);
|
||||
final FlutterProject flutterProject = FlutterProject.current();
|
||||
|
||||
if (shouldBuildWithAssemble) {
|
||||
await buildWithAssemble(
|
||||
buildMode: buildMode ?? BuildMode.debug,
|
||||
targetPlatform: platform,
|
||||
mainPath: mainPath,
|
||||
flutterProject: flutterProject,
|
||||
outputDir: assetDirPath,
|
||||
depfilePath: depfilePath,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
DevFSContent kernelContent;
|
||||
if (!precompiledSnapshot) {
|
||||
if ((extraFrontEndOptions != null) && extraFrontEndOptions.isNotEmpty) {
|
||||
|
@ -124,6 +140,66 @@ class BundleBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
/// Build an application bundle using flutter assemble.
|
||||
///
|
||||
/// This is a temporary shim to migrate the build implementations.
|
||||
Future<void> buildWithAssemble({
|
||||
@required FlutterProject flutterProject,
|
||||
@required BuildMode buildMode,
|
||||
@required TargetPlatform targetPlatform,
|
||||
@required String mainPath,
|
||||
@required String outputDir,
|
||||
@required String depfilePath,
|
||||
}) async {
|
||||
final Environment environment = Environment(
|
||||
projectDir: flutterProject.directory,
|
||||
outputDir: fs.directory(outputDir),
|
||||
buildDir: flutterProject.dartTool.childDirectory('flutter_build'),
|
||||
defines: <String, String>{
|
||||
kTargetFile: mainPath,
|
||||
kBuildMode: getNameForBuildMode(buildMode),
|
||||
kTargetPlatform: getNameForTargetPlatform(targetPlatform),
|
||||
}
|
||||
);
|
||||
final Target target = buildMode == BuildMode.debug
|
||||
? const CopyFlutterBundle()
|
||||
: const ReleaseCopyFlutterBundle();
|
||||
final BuildResult result = await buildSystem.build(target, environment);
|
||||
|
||||
if (!result.success) {
|
||||
for (ExceptionMeasurement measurement in result.exceptions.values) {
|
||||
printError(measurement.exception.toString());
|
||||
printError(measurement.stackTrace.toString());
|
||||
}
|
||||
throwToolExit('Failed to build bundle.');
|
||||
}
|
||||
|
||||
// Output depfile format:
|
||||
final StringBuffer buffer = StringBuffer();
|
||||
buffer.write('flutter_bundle');
|
||||
_writeFilesToBuffer(result.outputFiles, buffer);
|
||||
buffer.write(': ');
|
||||
_writeFilesToBuffer(result.inputFiles, buffer);
|
||||
|
||||
final File depfile = fs.file(depfilePath);
|
||||
if (!depfile.parent.existsSync()) {
|
||||
depfile.parent.createSync(recursive: true);
|
||||
}
|
||||
depfile.writeAsStringSync(buffer.toString());
|
||||
}
|
||||
|
||||
void _writeFilesToBuffer(List<File> files, StringBuffer buffer) {
|
||||
for (File outputFile in files) {
|
||||
if (platform.isWindows) {
|
||||
// Paths in a depfile have to be escaped on windows.
|
||||
final String escapedPath = outputFile.path.replaceAll(r'\', r'\\');
|
||||
buffer.write(' $escapedPath');
|
||||
} else {
|
||||
buffer.write(' ${outputFile.path}');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<AssetBundle> buildAssets({
|
||||
String manifestPath,
|
||||
String assetDirPath,
|
||||
|
|
|
@ -84,8 +84,6 @@ abstract class CodegenDaemon {
|
|||
/// Only a subset of the arguments provided to the [KernelCompiler] are
|
||||
/// supported here. Using the build pipeline implies a fixed multiroot
|
||||
/// filesystem and requires a pubspec.
|
||||
///
|
||||
/// This is only safe to use if [experimentalBuildEnabled] is true.
|
||||
class CodeGeneratingKernelCompiler implements KernelCompiler {
|
||||
const CodeGeneratingKernelCompiler();
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
import 'package:meta/meta.dart';
|
||||
|
||||
import '../base/common.dart';
|
||||
import '../base/context.dart';
|
||||
import '../base/file_system.dart';
|
||||
import '../build_system/build_system.dart';
|
||||
import '../build_system/targets/assets.dart';
|
||||
|
@ -18,9 +17,6 @@ import '../globals.dart';
|
|||
import '../project.dart';
|
||||
import '../runner/flutter_command.dart';
|
||||
|
||||
/// The [BuildSystem] instance.
|
||||
BuildSystem get buildSystem => context.get<BuildSystem>();
|
||||
|
||||
/// All currently implemented targets.
|
||||
const List<Target> _kDefaultTargets = <Target>[
|
||||
UnpackLinux(),
|
||||
|
|
|
@ -131,6 +131,7 @@ class BuildBundleCommand extends BuildSubCommand {
|
|||
extraGenSnapshotOptions: argResults[FlutterOptions.kExtraGenSnapshotOptions],
|
||||
fileSystemScheme: argResults['filesystem-scheme'],
|
||||
fileSystemRoots: argResults['filesystem-root'],
|
||||
shouldBuildWithAssemble: true,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -274,6 +274,11 @@ class KernelCompiler {
|
|||
if (packagesPath != null) {
|
||||
mainUri = PackageUriMapper.findUri(mainPath, packagesPath, fileSystemScheme, fileSystemRoots);
|
||||
}
|
||||
// TODO(jonahwilliams): The output file must already exist, but this seems
|
||||
// unnecessary.
|
||||
if (outputFilePath != null && !fs.isFileSync(outputFilePath)) {
|
||||
fs.file(outputFilePath).createSync(recursive: true);
|
||||
}
|
||||
final List<String> command = <String>[
|
||||
engineDartPath,
|
||||
frontendServer,
|
||||
|
|
|
@ -235,6 +235,31 @@ void main() {
|
|||
expect(environment.buildDir.childFile('foo.out').existsSync(), false);
|
||||
}));
|
||||
|
||||
test('Does not crash when filesytem and cache are out of sync', () => testbed.run(() async {
|
||||
final TestTarget testTarget = TestTarget((Environment environment) async {
|
||||
environment.buildDir.childFile('foo.out').createSync();
|
||||
})
|
||||
..inputs = const <Source>[Source.pattern('{PROJECT_DIR}/foo.dart')]
|
||||
..outputs = const <Source>[Source.pattern('{BUILD_DIR}/foo.out')];
|
||||
fs.file('foo.dart').createSync();
|
||||
|
||||
await buildSystem.build(testTarget, environment);
|
||||
|
||||
expect(environment.buildDir.childFile('foo.out').existsSync(), true);
|
||||
environment.buildDir.childFile('foo.out').deleteSync();
|
||||
|
||||
final TestTarget testTarget2 = TestTarget((Environment environment) async {
|
||||
environment.buildDir.childFile('bar.out').createSync();
|
||||
})
|
||||
..inputs = const <Source>[Source.pattern('{PROJECT_DIR}/foo.dart')]
|
||||
..outputs = const <Source>[Source.pattern('{BUILD_DIR}/bar.out')];
|
||||
|
||||
await buildSystem.build(testTarget2, environment);
|
||||
|
||||
expect(environment.buildDir.childFile('bar.out').existsSync(), true);
|
||||
expect(environment.buildDir.childFile('foo.out').existsSync(), false);
|
||||
}));
|
||||
|
||||
test('reruns build if stamp is corrupted', () => testbed.run(() async {
|
||||
final TestTarget testTarget = TestTarget((Environment envionment) async {
|
||||
environment.buildDir.childFile('foo.out').createSync();
|
||||
|
|
|
@ -68,4 +68,17 @@ void main() {
|
|||
expect(fileStorage.files.single.hash, currentHash);
|
||||
expect(fileStorage.files.single.path, file.resolveSymbolicLinksSync());
|
||||
}));
|
||||
|
||||
test('handles persisting with a missing build directory', () => testbed.run(() {
|
||||
final File file = fs.file('foo.dart')
|
||||
..createSync()
|
||||
..writeAsStringSync('hello');
|
||||
final FileHashStore fileCache = FileHashStore(environment);
|
||||
fileCache.initialize();
|
||||
environment.buildDir.deleteSync(recursive: true);
|
||||
|
||||
fileCache.hashFiles(<File>[file]);
|
||||
// Does not throw.
|
||||
fileCache.persist();
|
||||
}));
|
||||
}
|
||||
|
|
|
@ -81,6 +81,7 @@ flutter_tools:lib/''');
|
|||
fs.path.join('bin', 'cache', 'pkg', 'sky_engine', 'sdk_ext',
|
||||
'vmservice_io.dart'),
|
||||
fs.path.join('bin', 'cache', 'dart-sdk', 'bin', 'dart'),
|
||||
fs.path.join('bin', 'cache', 'dart-sdk', 'bin', 'dart.exe'),
|
||||
fs.path.join(engineArtifacts, getNameForHostPlatform(hostPlatform),
|
||||
'frontend_server.dart.snapshot'),
|
||||
fs.path.join(engineArtifacts, 'android-arm-profile',
|
||||
|
@ -116,6 +117,33 @@ flutter_tools:lib/''');
|
|||
expect(result.exceptions.values.single.exception, isInstanceOf<MissingDefineException>());
|
||||
}));
|
||||
|
||||
test('kernel_snapshot handles null result from kernel compilation', () => testbed.run(() async {
|
||||
final FakeKernelCompilerFactory fakeKernelCompilerFactory = kernelCompilerFactory;
|
||||
fakeKernelCompilerFactory.kernelCompiler = MockKernelCompiler();
|
||||
when(fakeKernelCompilerFactory.kernelCompiler.compile(
|
||||
sdkRoot: anyNamed('sdkRoot'),
|
||||
mainPath: anyNamed('mainPath'),
|
||||
outputFilePath: anyNamed('outputFilePath'),
|
||||
depFilePath: anyNamed('depFilePath'),
|
||||
targetModel: anyNamed('targetModel'),
|
||||
linkPlatformKernelIn: anyNamed('linkPlatformKernelIn'),
|
||||
aot: anyNamed('aot'),
|
||||
trackWidgetCreation: anyNamed('trackWidgetCreation'),
|
||||
extraFrontEndOptions: anyNamed('extraFrontEndOptions'),
|
||||
packagesPath: anyNamed('packagesPath'),
|
||||
fileSystemRoots: anyNamed('fileSystemRoots'),
|
||||
fileSystemScheme: anyNamed('fileSystemScheme'),
|
||||
targetProductVm: anyNamed('targetProductVm'),
|
||||
platformDill: anyNamed('platformDill'),
|
||||
initializeFromDill: anyNamed('initializeFromDill'),
|
||||
)).thenAnswer((Invocation invocation) async {
|
||||
return null;
|
||||
});
|
||||
final BuildResult result = await buildSystem.build(const KernelSnapshot(), androidEnvironment);
|
||||
|
||||
expect(result.exceptions.values.single.exception, isInstanceOf<Exception>());
|
||||
}));
|
||||
|
||||
test('kernel_snapshot does not use track widget creation on profile builds', () => testbed.run(() async {
|
||||
final MockKernelCompiler mockKernelCompiler = MockKernelCompiler();
|
||||
when(kernelCompilerFactory.create(any)).thenAnswer((Invocation _) async {
|
||||
|
@ -342,7 +370,7 @@ class FakeGenSnapshot implements GenSnapshot {
|
|||
}
|
||||
|
||||
class FakeKernelCompilerFactory implements KernelCompilerFactory {
|
||||
FakeKernelCompiler kernelCompiler = FakeKernelCompiler();
|
||||
KernelCompiler kernelCompiler = FakeKernelCompiler();
|
||||
|
||||
@override
|
||||
Future<KernelCompiler> create(FlutterProject flutterProject) async {
|
||||
|
@ -362,7 +390,6 @@ class FakeKernelCompiler implements KernelCompiler {
|
|||
bool aot = false,
|
||||
bool trackWidgetCreation,
|
||||
List<String> extraFrontEndOptions,
|
||||
String incrementalCompilerByteStorePath,
|
||||
String packagesPath,
|
||||
List<String> fileSystemRoots,
|
||||
String fileSystemScheme,
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
// Copyright 2019 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter_tools/src/base/common.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/build_system.dart';
|
||||
import 'package:flutter_tools/src/bundle.dart';
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import '../src/common.dart';
|
||||
import '../src/testbed.dart';
|
||||
|
||||
// Tests for the temporary flutter assemble/bundle shim.
|
||||
void main() {
|
||||
Testbed testbed;
|
||||
|
||||
setUp(() {
|
||||
testbed = Testbed(overrides: <Type, Generator>{
|
||||
BuildSystem: () => MockBuildSystem(),
|
||||
});
|
||||
});
|
||||
|
||||
test('Copies assets to expected directory after building', () => testbed.run(() async {
|
||||
when(buildSystem.build(any, any)).thenAnswer((Invocation invocation) async {
|
||||
final Environment environment = invocation.positionalArguments[1];
|
||||
environment.outputDir.childFile('kernel_blob.bin').createSync(recursive: true);
|
||||
environment.outputDir.childFile('isolate_snapshot_data').createSync();
|
||||
environment.outputDir.childFile('vm_snapshot_data').createSync();
|
||||
environment.outputDir.childFile('LICENSE').createSync(recursive: true);
|
||||
return BuildResult(success: true);
|
||||
});
|
||||
await buildWithAssemble(
|
||||
buildMode: BuildMode.debug,
|
||||
flutterProject: FlutterProject.current(),
|
||||
mainPath: fs.path.join('lib', 'main.dart'),
|
||||
outputDir: 'example',
|
||||
targetPlatform: TargetPlatform.ios,
|
||||
depfilePath: 'example.d',
|
||||
);
|
||||
expect(fs.file(fs.path.join('example', 'kernel_blob.bin')).existsSync(), true);
|
||||
expect(fs.file(fs.path.join('example', 'LICENSE')).existsSync(), true);
|
||||
expect(fs.file(fs.path.join('example.d')).existsSync(), true);
|
||||
}));
|
||||
|
||||
test('Handles build system failure', () => testbed.run(() {
|
||||
when(buildSystem.build(any, any)).thenAnswer((Invocation _) async {
|
||||
return BuildResult(
|
||||
success: false,
|
||||
exceptions: <String, ExceptionMeasurement>{},
|
||||
);
|
||||
});
|
||||
|
||||
expect(() => buildWithAssemble(
|
||||
buildMode: BuildMode.debug,
|
||||
flutterProject: FlutterProject.current(),
|
||||
mainPath: 'lib/main.dart',
|
||||
outputDir: 'example',
|
||||
targetPlatform: TargetPlatform.linux_x64,
|
||||
depfilePath: 'example.d',
|
||||
), throwsA(isInstanceOf<ToolExit>()));
|
||||
}));
|
||||
}
|
||||
|
||||
class MockBuildSystem extends Mock implements BuildSystem {}
|
Loading…
Reference in a new issue