Unverified Commit 1f8e9ff7 authored by Hannes Winkler's avatar Hannes Winkler Committed by GitHub

[tool] cleanup bundle builder a bit (#80740)

parent ff54fc6d
......@@ -84,34 +84,88 @@ class BundleBuilder {
/// The default `manifestPath` is `pubspec.yaml`
Future<void> build({
@required TargetPlatform platform,
BuildInfo buildInfo,
@required BuildInfo buildInfo,
FlutterProject project,
String mainPath,
String manifestPath = defaultManifestPath,
String applicationKernelFilePath,
String depfilePath,
String assetDirPath,
bool trackWidgetCreation = false,
List<String> extraFrontEndOptions = const <String>[],
List<String> extraGenSnapshotOptions = const <String>[],
List<String> fileSystemRoots,
String fileSystemScheme,
@required bool treeShakeIcons,
@visibleForTesting BuildSystem buildSystem
}) async {
project ??= FlutterProject.current();
mainPath ??= defaultMainPath;
depfilePath ??= defaultDepfilePath;
assetDirPath ??= getAssetBuildDirectory();
final FlutterProject flutterProject = FlutterProject.current();
await buildWithAssemble(
buildMode: buildInfo.mode,
targetPlatform: platform,
mainPath: mainPath,
flutterProject: flutterProject,
outputDir: assetDirPath,
depfilePath: depfilePath,
trackWidgetCreation: trackWidgetCreation,
treeShakeIcons: treeShakeIcons,
dartDefines: buildInfo.dartDefines,
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 by the CopyFlutterBundle target
kBuildMode: getNameForBuildMode(buildInfo.mode),
// used by the KernelSnapshot target
kTargetPlatform: getNameForTargetPlatform(platform),
kTargetFile: mainPath,
kTrackWidgetCreation: buildInfo.trackWidgetCreation.toString(),
if (buildInfo.extraFrontEndOptions.isNotEmpty)
kExtraFrontEndOptions: buildInfo.extraFrontEndOptions.join(','),
if (buildInfo.extraGenSnapshotOptions.isNotEmpty)
kExtraGenSnapshotOptions: buildInfo.extraGenSnapshotOptions.join(','),
if (buildInfo.fileSystemRoots != null && buildInfo.fileSystemRoots.isNotEmpty)
kFileSystemRoots: buildInfo.fileSystemRoots?.join(','),
kFileSystemScheme: buildInfo.fileSystemScheme,
if (buildInfo.dartDefines.isNotEmpty)
kDartDefines: encodeDartDefines(buildInfo.dartDefines),
// used by the CopyFlutterBundle target too, inside the copyAssets
// call after the snapshot was built
kIconTreeShakerFlag: buildInfo.treeShakeIcons.toString(),
kDeferredComponents: 'false'
},
artifacts: globals.artifacts,
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
platform: globals.platform,
);
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.');
}
if (depfilePath != null) {
final Depfile depfile = Depfile(result.inputFiles, result.outputFiles);
final File outputDepfile = globals.fs.file(depfilePath);
if (!outputDepfile.parent.existsSync()) {
outputDepfile.parent.createSync(recursive: true);
}
final DepfileService depfileService = DepfileService(
fileSystem: globals.fs,
logger: globals.logger,
);
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');
......@@ -123,74 +177,6 @@ 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,
bool trackWidgetCreation,
@required bool treeShakeIcons,
List<String> dartDefines,
}) async {
// If the precompiled flag was not passed, force us into debug mode.
final Environment environment = Environment(
projectDir: flutterProject.directory,
outputDir: globals.fs.directory(outputDir),
buildDir: flutterProject.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>{
kTargetFile: mainPath,
kBuildMode: getNameForBuildMode(buildMode),
kTargetPlatform: getNameForTargetPlatform(targetPlatform),
kTrackWidgetCreation: trackWidgetCreation?.toString(),
kIconTreeShakerFlag: treeShakeIcons ? 'true' : null,
if (dartDefines != null && dartDefines.isNotEmpty)
kDartDefines: encodeDartDefines(dartDefines),
},
artifacts: globals.artifacts,
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
platform: globals.platform,
);
final Target target = buildMode == BuildMode.debug
? const CopyFlutterBundle()
: const ReleaseCopyFlutterBundle();
final BuildResult result = await globals.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.');
}
if (depfilePath != null) {
final Depfile depfile = Depfile(result.inputFiles, result.outputFiles);
final File outputDepfile = globals.fs.file(depfilePath);
if (!outputDepfile.parent.existsSync()) {
outputDepfile.parent.createSync(recursive: true);
}
final DepfileService depfileService = DepfileService(
fileSystem: globals.fs,
logger: globals.logger,
);
depfileService.writeToFile(depfile, outputDepfile);
}
}
Future<AssetBundle> buildAssets({
String manifestPath,
String assetDirPath,
......
......@@ -119,12 +119,6 @@ class BuildBundleCommand extends BuildSubCommand {
manifestPath: defaultManifestPath,
depfilePath: stringArg('depfile'),
assetDirPath: stringArg('asset-dir'),
trackWidgetCreation: boolArg('track-widget-creation'),
extraFrontEndOptions: buildInfo.extraFrontEndOptions,
extraGenSnapshotOptions: buildInfo.extraGenSnapshotOptions,
fileSystemRoots: stringsArg(FlutterOptions.kFileSystemRoot),
fileSystemScheme: stringArg(FlutterOptions.kFileSystemScheme),
treeShakeIcons: buildInfo.treeShakeIcons,
);
return FlutterCommandResult.success();
}
......
......@@ -639,7 +639,6 @@ class CustomDevice extends Device {
mainPath: mainPath,
depfilePath: defaultDepfilePath,
assetDirPath: assetBundleDir,
treeShakeIcons: false,
);
// if we have a post build step (needed for some embedders), execute it
......
......@@ -167,9 +167,7 @@ class FlutterTesterDevice extends Device {
buildInfo: buildInfo,
mainPath: mainPath,
applicationKernelFilePath: applicationKernelFilePath,
trackWidgetCreation: buildInfo.trackWidgetCreation,
platform: getTargetPlatformForName(getNameForHostPlatform(_operatingSystemUtils.hostPlatform)),
treeShakeIcons: buildInfo.treeShakeIcons,
assetDirPath: assetDirectory.path,
);
......
......@@ -43,12 +43,6 @@ void main() {
applicationKernelFilePath: anyNamed('applicationKernelFilePath'),
depfilePath: anyNamed('depfilePath'),
assetDirPath: anyNamed('assetDirPath'),
trackWidgetCreation: anyNamed('trackWidgetCreation'),
extraFrontEndOptions: anyNamed('extraFrontEndOptions'),
extraGenSnapshotOptions: anyNamed('extraGenSnapshotOptions'),
fileSystemRoots: anyNamed('fileSystemRoots'),
fileSystemScheme: anyNamed('fileSystemScheme'),
treeShakeIcons: anyNamed('treeShakeIcons'),
),
).thenAnswer((_) => Future<void>.value());
});
......@@ -223,11 +217,13 @@ void main() {
}, overrides: <Type, Generator>{
BuildSystem: () => TestBuildSystem.all(BuildResult(success: true), (Target target, Environment environment) {
expect(environment.defines, <String, String>{
kTargetFile: globals.fs.path.join('lib', 'main.dart'),
kBuildMode: 'debug',
kTargetPlatform: 'android-arm',
kTargetFile: globals.fs.path.join('lib', 'main.dart'),
kTrackWidgetCreation: 'true',
kIconTreeShakerFlag: null,
kFileSystemScheme: 'org-dartlang-root',
kIconTreeShakerFlag: 'false',
kDeferredComponents: 'false'
});
}),
FileSystem: () => MemoryFileSystem.test(),
......@@ -250,12 +246,133 @@ void main() {
}, overrides: <Type, Generator>{
BuildSystem: () => TestBuildSystem.all(BuildResult(success: true), (Target target, Environment environment) {
expect(environment.defines, <String, String>{
kTargetFile: globals.fs.path.join('lib', 'main.dart'),
kBuildMode: 'debug',
kTargetPlatform: 'android-arm',
kTargetFile: globals.fs.path.join('lib', 'main.dart'),
kTrackWidgetCreation: 'true',
kIconTreeShakerFlag: null,
kFileSystemScheme: 'org-dartlang-root',
kDartDefines: 'Zm9vPWJhcg==',
kIconTreeShakerFlag: 'false',
kDeferredComponents: 'false'
});
}),
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('passes filesystem-scheme through', () async {
globals.fs.file('lib/main.dart').createSync(recursive: true);
globals.fs.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync();
final CommandRunner<void> runner = createTestCommandRunner(BuildBundleCommand());
await runner.run(<String>[
'bundle',
'--no-pub',
'--debug',
'--target-platform=android-arm',
'--filesystem-scheme=org-dartlang-root2',
]);
}, overrides: <Type, Generator>{
BuildSystem: () => TestBuildSystem.all(BuildResult(success: true), (Target target, Environment environment) {
expect(environment.defines, <String, String>{
kBuildMode: 'debug',
kTargetPlatform: 'android-arm',
kTargetFile: globals.fs.path.join('lib', 'main.dart'),
kTrackWidgetCreation: 'true',
kFileSystemScheme: 'org-dartlang-root2',
kIconTreeShakerFlag: 'false',
kDeferredComponents: 'false'
});
}),
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('passes filesystem-roots through', () async {
globals.fs.file('lib/main.dart').createSync(recursive: true);
globals.fs.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync();
final CommandRunner<void> runner = createTestCommandRunner(BuildBundleCommand());
await runner.run(<String>[
'bundle',
'--no-pub',
'--debug',
'--target-platform=android-arm',
'--filesystem-root=test1,test2'
]);
}, overrides: <Type, Generator>{
BuildSystem: () => TestBuildSystem.all(BuildResult(success: true), (Target target, Environment environment) {
expect(environment.defines, <String, String>{
kBuildMode: 'debug',
kTargetPlatform: 'android-arm',
kTargetFile: globals.fs.path.join('lib', 'main.dart'),
kTrackWidgetCreation: 'true',
kFileSystemScheme: 'org-dartlang-root',
kFileSystemRoots: 'test1,test2',
kIconTreeShakerFlag: 'false',
kDeferredComponents: 'false'
});
}),
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('passes extra frontend-options through', () async {
globals.fs.file('lib/main.dart').createSync(recursive: true);
globals.fs.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync();
final CommandRunner<void> runner = createTestCommandRunner(BuildBundleCommand());
await runner.run(<String>[
'bundle',
'--no-pub',
'--debug',
'--target-platform=android-arm',
'--extra-front-end-options=--testflag,--testflag2'
]);
}, overrides: <Type, Generator>{
BuildSystem: () => TestBuildSystem.all(BuildResult(success: true), (Target target, Environment environment) {
expect(environment.defines, <String, String>{
kBuildMode: 'debug',
kTargetPlatform: 'android-arm',
kTargetFile: globals.fs.path.join('lib', 'main.dart'),
kTrackWidgetCreation: 'true',
kFileSystemScheme: 'org-dartlang-root',
kExtraFrontEndOptions: '--testflag,--testflag2',
kIconTreeShakerFlag: 'false',
kDeferredComponents: 'false'
});
}),
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('passes extra gen_snapshot-options through', () async {
globals.fs.file('lib/main.dart').createSync(recursive: true);
globals.fs.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync();
final CommandRunner<void> runner = createTestCommandRunner(BuildBundleCommand());
await runner.run(<String>[
'bundle',
'--no-pub',
'--debug',
'--target-platform=android-arm',
'--extra-gen-snapshot-options=--testflag,--testflag2'
]);
}, overrides: <Type, Generator>{
BuildSystem: () => TestBuildSystem.all(BuildResult(success: true), (Target target, Environment environment) {
expect(environment.defines, <String, String>{
kBuildMode: 'debug',
kTargetPlatform: 'android-arm',
kTargetFile: globals.fs.path.join('lib', 'main.dart'),
kTrackWidgetCreation: 'true',
kFileSystemScheme: 'org-dartlang-root',
kExtraGenSnapshotOptions: '--testflag,--testflag2',
kIconTreeShakerFlag: 'false',
kDeferredComponents: 'false'
});
}),
FileSystem: () => MemoryFileSystem.test(),
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:file/memory.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/build_system/targets/common.dart';
import 'package:flutter_tools/src/build_system/targets/icon_tree_shaker.dart';
import 'package:flutter_tools/src/bundle.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/globals_null_migrated.dart' as globals;
import '../src/common.dart';
import '../src/context.dart';
import '../src/test_build_system.dart';
import '../src/testbed.dart';
// Tests for BundleBuilder.
void main() {
testUsingContext('Copies assets to expected directory after building', () async {
final BuildSystem buildSystem = TestBuildSystem.all(
BuildResult(success: true),
(Target target, Environment environment) {
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);
}
);
await BundleBuilder().build(
platform: TargetPlatform.ios,
buildInfo: const BuildInfo(
BuildMode.debug,
null,
treeShakeIcons: false
),
project: FlutterProject.fromDirectoryTest(globals.fs.currentDirectory),
mainPath: globals.fs.path.join('lib', 'main.dart'),
assetDirPath: 'example',
depfilePath: 'example.d',
buildSystem: buildSystem
);
expect(globals.fs.file(globals.fs.path.join('example', 'kernel_blob.bin')).existsSync(), true);
expect(globals.fs.file(globals.fs.path.join('example', 'LICENSE')).existsSync(), true);
expect(globals.fs.file(globals.fs.path.join('example.d')).existsSync(), false);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('Handles build system failure', () {
expect(
() => BundleBuilder().build(
platform: TargetPlatform.ios,
buildInfo: const BuildInfo(
BuildMode.debug,
null,
treeShakeIcons: false
),
project: FlutterProject.fromDirectoryTest(globals.fs.currentDirectory),
mainPath: 'lib/main.dart',
assetDirPath: 'example',
depfilePath: 'example.d',
buildSystem: TestBuildSystem.all(BuildResult(success: false))
),
throwsToolExit()
);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('Passes correct defines to build system', () async {
final FlutterProject project = FlutterProject.fromDirectoryTest(globals.fs.currentDirectory);
final String mainPath = globals.fs.path.join('lib', 'main.dart');
const String assetDirPath = 'example';
const String depfilePath = 'example.d';
Environment env;
final BuildSystem buildSystem = TestBuildSystem.all(
BuildResult(success: true),
(Target target, Environment environment) {
env = environment;
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);
}
);
await BundleBuilder().build(
platform: TargetPlatform.ios,
buildInfo: const BuildInfo(
BuildMode.debug,
null,
trackWidgetCreation: true,
extraFrontEndOptions: <String>['test1', 'test2'],
extraGenSnapshotOptions: <String>['test3', 'test4'],
fileSystemRoots: <String>['test5', 'test6'],
fileSystemScheme: 'test7',
dartDefines: <String>['test8', 'test9'],
treeShakeIcons: true,
),
project: project,
mainPath: mainPath,
assetDirPath: assetDirPath,
depfilePath: depfilePath,
buildSystem: buildSystem
);
expect(env, isNotNull);
expect(env.defines[kBuildMode], 'debug');
expect(env.defines[kTargetPlatform], 'ios');
expect(env.defines[kTargetFile], mainPath);
expect(env.defines[kTrackWidgetCreation], 'true');
expect(env.defines[kExtraFrontEndOptions], 'test1,test2');
expect(env.defines[kExtraGenSnapshotOptions], 'test3,test4');
expect(env.defines[kFileSystemRoots], 'test5,test6');
expect(env.defines[kFileSystemScheme], 'test7');
expect(env.defines[kDartDefines], encodeDartDefines(<String>['test8', 'test9']));
expect(env.defines[kIconTreeShakerFlag], 'true');
expect(env.defines[kDeferredComponents], 'false');
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
}
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:file/memory.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:flutter_tools/src/globals_null_migrated.dart' as globals;
import '../src/common.dart';
import '../src/context.dart';
import '../src/test_build_system.dart';
// Tests for the temporary flutter assemble/bundle shim.
void main() {
testUsingContext('Copies assets to expected directory after building', () async {
await buildWithAssemble(
buildMode: BuildMode.debug,
flutterProject: FlutterProject.fromDirectoryTest(globals.fs.currentDirectory),
mainPath: globals.fs.path.join('lib', 'main.dart'),
outputDir: 'example',
targetPlatform: TargetPlatform.ios,
depfilePath: 'example.d',
treeShakeIcons: false,
);
expect(globals.fs.file(globals.fs.path.join('example', 'kernel_blob.bin')).existsSync(), true);
expect(globals.fs.file(globals.fs.path.join('example', 'LICENSE')).existsSync(), true);
expect(globals.fs.file(globals.fs.path.join('example.d')).existsSync(), false);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
BuildSystem: () => TestBuildSystem.all(BuildResult(success: true), (Target target, Environment environment) {
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);
}),
});
testUsingContext('Handles build system failure', () {
expect(() => buildWithAssemble(
buildMode: BuildMode.debug,
flutterProject: FlutterProject.fromDirectoryTest(globals.fs.currentDirectory),
mainPath: 'lib/main.dart',
outputDir: 'example',
targetPlatform: TargetPlatform.linux_x64,
depfilePath: 'example.d',
treeShakeIcons: false,
), throwsToolExit());
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
BuildSystem: () => TestBuildSystem.all(BuildResult(success: false)),
});
}
......@@ -10,6 +10,7 @@ import 'package:file/src/interface/directory.dart';
import 'package:file/src/interface/file.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/bundle.dart';
import 'package:flutter_tools/src/convert.dart';
import 'package:flutter_tools/src/custom_devices/custom_device.dart';
......@@ -22,6 +23,7 @@ import 'package:flutter_tools/src/globals_null_migrated.dart' as globals;
import 'package:file/memory.dart';
import 'package:file/file.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:meta/meta.dart';
import 'package:test/fake.dart';
import '../../src/common.dart';
......@@ -526,16 +528,12 @@ class FakeBundleBuilder extends Fake implements BundleBuilder {
Future<void> build({
TargetPlatform platform,
BuildInfo buildInfo,
FlutterProject project,
String mainPath,
String manifestPath = defaultManifestPath,
String applicationKernelFilePath,
String depfilePath,
String assetDirPath,
bool trackWidgetCreation = false,
List<String> extraFrontEndOptions = const <String>[],
List<String> extraGenSnapshotOptions = const <String>[],
List<String> fileSystemRoots,
String fileSystemScheme,
bool treeShakeIcons
@visibleForTesting BuildSystem buildSystem
}) async {}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment