mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Refactor flutter.gradle to use assemble directly (#43876)
Removes multiple re-entrant calls of bundle and aot and replaces them with a single call to assemble. This restores full caching and will allow follow-up performance improvements when building multiple ABIs
This commit is contained in:
parent
c1d029b84f
commit
978fada33c
@ -218,11 +218,11 @@ Future<void> main() async {
|
||||
final String analyticsOutput = analyticsOutputFile.readAsStringSync();
|
||||
if (!analyticsOutput.contains('cd24: android-arm64')
|
||||
|| !analyticsOutput.contains('cd25: true')
|
||||
|| !analyticsOutput.contains('viewName: build/bundle')) {
|
||||
|| !analyticsOutput.contains('viewName: assemble')) {
|
||||
return TaskResult.failure(
|
||||
'Building outer app produced the following analytics: "$analyticsOutput"'
|
||||
'but not the expected strings: "cd24: android-arm64", "cd25: true" and '
|
||||
'"viewName: build/bundle"'
|
||||
'"viewName: assemble"'
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -396,7 +396,7 @@ Future<ProcessResult> _resultOfGradleTask({String workingDirectory, String task,
|
||||
String validateSnapshotDependency(FlutterProject project, String expectedTarget) {
|
||||
final File snapshotBlob = File(
|
||||
path.join(project.rootPath, 'build', 'app', 'intermediates',
|
||||
'flutter', 'debug', 'android-arm', 'snapshot_blob.bin.d'));
|
||||
'flutter', 'debug', 'android-arm', 'flutter_build.d'));
|
||||
|
||||
assert(snapshotBlob.existsSync());
|
||||
final String contentSnapshot = snapshotBlob.readAsStringSync();
|
||||
|
@ -520,22 +520,6 @@ class FlutterPlugin implements Plugin<Project> {
|
||||
if (project.hasProperty('track-widget-creation')) {
|
||||
trackWidgetCreationValue = project.property('track-widget-creation').toBoolean()
|
||||
}
|
||||
String compilationTraceFilePathValue = null
|
||||
if (project.hasProperty('compilation-trace-file')) {
|
||||
compilationTraceFilePathValue = project.property('compilation-trace-file')
|
||||
}
|
||||
Boolean createPatchValue = false
|
||||
if (project.hasProperty('patch')) {
|
||||
createPatchValue = project.property('patch').toBoolean()
|
||||
}
|
||||
Integer buildNumberValue = null
|
||||
if (project.hasProperty('build-number')) {
|
||||
buildNumberValue = project.property('build-number').toInteger()
|
||||
}
|
||||
String baselineDirValue = null
|
||||
if (project.hasProperty('baseline-dir')) {
|
||||
baselineDirValue = project.property('baseline-dir')
|
||||
}
|
||||
String extraFrontEndOptionsValue = null
|
||||
if (project.hasProperty('extra-front-end-options')) {
|
||||
extraFrontEndOptionsValue = project.property('extra-front-end-options')
|
||||
@ -574,10 +558,6 @@ class FlutterPlugin implements Plugin<Project> {
|
||||
fileSystemRoots fileSystemRootsValue
|
||||
fileSystemScheme fileSystemSchemeValue
|
||||
trackWidgetCreation trackWidgetCreationValue
|
||||
compilationTraceFilePath compilationTraceFilePathValue
|
||||
createPatch createPatchValue
|
||||
buildNumber buildNumberValue
|
||||
baselineDir baselineDirValue
|
||||
targetPlatform targetArch
|
||||
sourceDir project.file(project.flutter.source)
|
||||
intermediateDir project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/${variant.name}/${targetArch}")
|
||||
@ -698,7 +678,7 @@ abstract class BaseFlutterTask extends DefaultTask {
|
||||
String localEngineSrcPath
|
||||
@Input
|
||||
String targetPath
|
||||
@Optional @Input
|
||||
@Optional
|
||||
Boolean verbose
|
||||
@Optional @Input
|
||||
String[] fileSystemRoots
|
||||
@ -707,14 +687,6 @@ abstract class BaseFlutterTask extends DefaultTask {
|
||||
@Input
|
||||
Boolean trackWidgetCreation
|
||||
@Optional @Input
|
||||
String compilationTraceFilePath
|
||||
@Optional @Input
|
||||
Boolean createPatch
|
||||
@Optional @Input
|
||||
Integer buildNumber
|
||||
@Optional @Input
|
||||
String baselineDir
|
||||
@Optional @Input
|
||||
String targetPlatform
|
||||
@Input
|
||||
String abi
|
||||
@ -729,15 +701,8 @@ abstract class BaseFlutterTask extends DefaultTask {
|
||||
FileCollection getDependenciesFiles() {
|
||||
FileCollection depfiles = project.files()
|
||||
|
||||
// Include the kernel compiler depfile, since kernel compile is the
|
||||
// first stage of AOT build in this mode, and it includes all the Dart
|
||||
// sources.
|
||||
depfiles += project.files("${intermediateDir}/kernel_compile.d")
|
||||
|
||||
// Include Core JIT kernel compiler depfile, since kernel compile is
|
||||
// the first stage of JIT builds in this mode, and it includes all the
|
||||
// Dart sources.
|
||||
depfiles += project.files("${intermediateDir}/snapshot_blob.bin.d")
|
||||
// Includes all sources used in the flutter compilation.
|
||||
depfiles += project.files("${intermediateDir}/flutter_build.d")
|
||||
return depfiles
|
||||
}
|
||||
|
||||
@ -748,88 +713,38 @@ abstract class BaseFlutterTask extends DefaultTask {
|
||||
|
||||
intermediateDir.mkdirs()
|
||||
|
||||
if (buildMode == "profile" || buildMode == "release") {
|
||||
project.exec {
|
||||
executable flutterExecutable.absolutePath
|
||||
workingDir sourceDir
|
||||
if (localEngine != null) {
|
||||
args "--local-engine", localEngine
|
||||
args "--local-engine-src-path", localEngineSrcPath
|
||||
}
|
||||
args "build", "aot"
|
||||
args "--suppress-analytics"
|
||||
args "--quiet"
|
||||
args "--target", targetPath
|
||||
args "--output-dir", "${intermediateDir}"
|
||||
args "--target-platform", "${targetPlatform}"
|
||||
if (extraFrontEndOptions != null) {
|
||||
args "--extra-front-end-options", "${extraFrontEndOptions}"
|
||||
}
|
||||
if (extraGenSnapshotOptions != null) {
|
||||
args "--extra-gen-snapshot-options", "${extraGenSnapshotOptions}"
|
||||
}
|
||||
args "--${buildMode}"
|
||||
}
|
||||
}
|
||||
|
||||
project.exec {
|
||||
executable flutterExecutable.absolutePath
|
||||
workingDir sourceDir
|
||||
|
||||
if (localEngine != null) {
|
||||
args "--local-engine", localEngine
|
||||
args "--local-engine-src-path", localEngineSrcPath
|
||||
}
|
||||
args "build", "bundle"
|
||||
args "--target", targetPath
|
||||
args "--target-platform", "${targetPlatform}"
|
||||
if (verbose) {
|
||||
args "--verbose"
|
||||
} else {
|
||||
args "--quiet"
|
||||
}
|
||||
if (fileSystemRoots != null) {
|
||||
for (root in fileSystemRoots) {
|
||||
args "--filesystem-root", root
|
||||
}
|
||||
}
|
||||
if (fileSystemScheme != null) {
|
||||
args "--filesystem-scheme", fileSystemScheme
|
||||
}
|
||||
if (trackWidgetCreation) {
|
||||
args "--track-widget-creation"
|
||||
}
|
||||
if (compilationTraceFilePath != null) {
|
||||
args "--compilation-trace-file", compilationTraceFilePath
|
||||
}
|
||||
if (createPatch) {
|
||||
args "--patch"
|
||||
args "--build-number", project.android.defaultConfig.versionCode
|
||||
if (buildNumber != null) {
|
||||
assert buildNumber == project.android.defaultConfig.versionCode
|
||||
}
|
||||
}
|
||||
if (baselineDir != null) {
|
||||
args "--baseline-dir", baselineDir
|
||||
}
|
||||
args "assemble"
|
||||
args "--depfile", "${intermediateDir}/flutter_build.d"
|
||||
args "--output", "${intermediateDir}"
|
||||
args "-dTargetFile=${targetPath}"
|
||||
args "-dTargetPlatform=${targetPlatform}"
|
||||
args "-dBuildMode=${buildMode}"
|
||||
if (extraFrontEndOptions != null) {
|
||||
args "--extra-front-end-options", "${extraFrontEndOptions}"
|
||||
args "-dExtraFrontEndOptions=${extraFrontEndOptions}"
|
||||
}
|
||||
if (extraGenSnapshotOptions != null) {
|
||||
args "--extra-gen-snapshot-options", "${extraGenSnapshotOptions}"
|
||||
}
|
||||
if (buildMode == "release" || buildMode == "profile") {
|
||||
args "--precompiled"
|
||||
} else {
|
||||
args "--depfile", "${intermediateDir}/snapshot_blob.bin.d"
|
||||
}
|
||||
args "--asset-dir", "${intermediateDir}/flutter_assets"
|
||||
if (buildMode == "debug") {
|
||||
args "--debug"
|
||||
args "-dExtraGenSnapshotOptions=${extraGenSnapshotOptions}"
|
||||
}
|
||||
if (buildMode == "profile") {
|
||||
args "--profile"
|
||||
args "profile_android_application"
|
||||
}
|
||||
if (buildMode == "release") {
|
||||
args "--release"
|
||||
args "release_android_application"
|
||||
}
|
||||
if (buildMode == "debug") {
|
||||
args "debug_android_application"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -859,21 +774,17 @@ class FlutterTask extends BaseFlutterTask {
|
||||
}
|
||||
|
||||
FileCollection readDependencies(File dependenciesFile) {
|
||||
if (dependenciesFile.exists()) {
|
||||
try {
|
||||
// Dependencies file has Makefile syntax:
|
||||
// <target> <files>: <source> <files> <separated> <by> <non-escaped space>
|
||||
String depText = dependenciesFile.text
|
||||
// So we split list of files by non-escaped(by backslash) space,
|
||||
def matcher = depText.split(': ')[1] =~ /(\\ |[^\s])+/
|
||||
// then we replace all escaped spaces with regular spaces
|
||||
def depList = matcher.collect{it[0].replaceAll("\\\\ ", " ")}
|
||||
return project.files(depList)
|
||||
} catch (Exception e) {
|
||||
logger.error("Error reading dependency file ${dependenciesFile}: ${e}")
|
||||
}
|
||||
}
|
||||
return project.files()
|
||||
if (dependenciesFile.exists()) {
|
||||
// Dependencies file has Makefile syntax:
|
||||
// <target> <files>: <source> <files> <separated> <by> <non-escaped space>
|
||||
String depText = dependenciesFile.text
|
||||
// So we split list of files by non-escaped(by backslash) space,
|
||||
def matcher = depText.split(': ')[1] =~ /(\\ |[^\s])+/
|
||||
// then we replace all escaped spaces with regular spaces
|
||||
def depList = matcher.collect{it[0].replaceAll("\\\\ ", " ")}
|
||||
return project.files(depList)
|
||||
}
|
||||
return project.files();
|
||||
}
|
||||
|
||||
@InputFiles
|
||||
@ -882,23 +793,7 @@ class FlutterTask extends BaseFlutterTask {
|
||||
for (File depfile in getDependenciesFiles()) {
|
||||
sources += readDependencies(depfile)
|
||||
}
|
||||
if (!sources.isEmpty()) {
|
||||
// We have a dependencies file. Add a dependency on gen_snapshot as well, since the
|
||||
// snapshots have to be rebuilt if it changes.
|
||||
sources += readDependencies(project.file("${intermediateDir}/gen_snapshot.d"))
|
||||
sources += readDependencies(project.file("${intermediateDir}/frontend_server.d"))
|
||||
if (localEngineSrcPath != null) {
|
||||
sources += project.files("$localEngineSrcPath/$localEngine")
|
||||
}
|
||||
// Finally, add a dependency on pubspec.yaml as well.
|
||||
return sources + project.files('pubspec.yaml')
|
||||
}
|
||||
// No dependencies file (or problems parsing it). Fall back to source files.
|
||||
return project.fileTree(
|
||||
dir: sourceDir,
|
||||
exclude: ['android', 'ios'],
|
||||
include: ['**/*.dart', 'pubspec.yaml']
|
||||
)
|
||||
return sources + project.files('pubspec.yaml')
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
|
124
packages/flutter_tools/lib/src/build_system/targets/android.dart
Normal file
124
packages/flutter_tools/lib/src/build_system/targets/android.dart
Normal file
@ -0,0 +1,124 @@
|
||||
// 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 '../../artifacts.dart';
|
||||
import '../../base/file_system.dart';
|
||||
import '../../build_info.dart';
|
||||
import '../../globals.dart';
|
||||
import '../build_system.dart';
|
||||
import '../depfile.dart';
|
||||
import '../exceptions.dart';
|
||||
import 'assets.dart';
|
||||
import 'dart.dart';
|
||||
|
||||
/// Prepares the asset bundle in the format expected by flutter.gradle.
|
||||
///
|
||||
/// The vm_snapshot_data, isolate_snapshot_data, and kernel_blob.bin are
|
||||
/// expected to be in the root output directory.
|
||||
///
|
||||
/// All assets and manifests are included from flutter_assets/**.
|
||||
abstract class AndroidAssetBundle extends Target {
|
||||
const AndroidAssetBundle();
|
||||
|
||||
@override
|
||||
List<Source> get inputs => const <Source>[
|
||||
Source.pattern('{BUILD_DIR}/app.dill'),
|
||||
Source.depfile('flutter_assets.d'),
|
||||
];
|
||||
|
||||
@override
|
||||
List<Source> get outputs => const <Source>[
|
||||
Source.depfile('flutter_assets.d'),
|
||||
];
|
||||
|
||||
@override
|
||||
Future<void> build(Environment environment) async {
|
||||
if (environment.defines[kBuildMode] == null) {
|
||||
throw MissingDefineException(kBuildMode, name);
|
||||
}
|
||||
final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]);
|
||||
final Directory outputDirectory = environment.outputDir
|
||||
.childDirectory('flutter_assets')
|
||||
..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(outputDirectory.childFile('kernel_blob.bin').path);
|
||||
fs.file(vmSnapshotData)
|
||||
.copySync(outputDirectory.childFile('vm_snapshot_data').path);
|
||||
fs.file(isolateSnapshotData)
|
||||
.copySync(outputDirectory.childFile('isolate_snapshot_data').path);
|
||||
}
|
||||
final Depfile assetDepfile = await copyAssets(environment, outputDirectory);
|
||||
assetDepfile.writeToFile(environment.buildDir.childFile('flutter_assets.d'));
|
||||
}
|
||||
|
||||
@override
|
||||
List<Target> get dependencies => const <Target>[
|
||||
KernelSnapshot(),
|
||||
];
|
||||
}
|
||||
|
||||
/// An implementation of [AndroidAssetBundle] that includes dependencies on vm
|
||||
/// and isolate data.
|
||||
class DebugAndroidApplication extends AndroidAssetBundle {
|
||||
const DebugAndroidApplication();
|
||||
|
||||
@override
|
||||
String get name => 'debug_android_application';
|
||||
|
||||
@override
|
||||
List<Source> get inputs => <Source>[
|
||||
...super.inputs,
|
||||
const Source.artifact(Artifact.vmSnapshotData, mode: BuildMode.debug),
|
||||
const Source.artifact(Artifact.isolateSnapshotData, mode: BuildMode.debug),
|
||||
];
|
||||
|
||||
@override
|
||||
List<Source> get outputs => <Source>[
|
||||
...super.outputs,
|
||||
const Source.pattern('{OUTPUT_DIR}/vm_snapshot_data'),
|
||||
const Source.pattern('{OUTPUT_DIR}/isolate_snapshot_data'),
|
||||
const Source.pattern('{OUTPUT_DIR}/kernel_blob.bin'),
|
||||
];
|
||||
}
|
||||
|
||||
/// An implementation of [AndroidAssetBundle] that only includes assets.
|
||||
class AotAndroidAssetBundle extends AndroidAssetBundle {
|
||||
const AotAndroidAssetBundle();
|
||||
|
||||
@override
|
||||
String get name => 'aot_android_asset_bundle';
|
||||
}
|
||||
|
||||
/// Build a profile android application's Dart artifacts.
|
||||
class ProfileAndroidApplication extends CopyFlutterAotBundle {
|
||||
const ProfileAndroidApplication();
|
||||
|
||||
@override
|
||||
String get name => 'profile_android_application';
|
||||
|
||||
@override
|
||||
List<Target> get dependencies => const <Target>[
|
||||
AotElfProfile(),
|
||||
AotAndroidAssetBundle(),
|
||||
];
|
||||
}
|
||||
|
||||
/// Build a release android application's Dart artifacts.
|
||||
class ReleaseAndroidApplication extends CopyFlutterAotBundle {
|
||||
const ReleaseAndroidApplication();
|
||||
|
||||
@override
|
||||
String get name => 'release_android_application';
|
||||
|
||||
@override
|
||||
List<Target> get dependencies => const <Target>[
|
||||
AotElfRelease(),
|
||||
AotAndroidAssetBundle(),
|
||||
];
|
||||
}
|
@ -29,6 +29,27 @@ const String kBitcodeFlag = 'EnableBitcode';
|
||||
/// Whether to enable or disable track widget creation.
|
||||
const String kTrackWidgetCreation = 'TrackWidgetCreation';
|
||||
|
||||
/// Additional configuration passed to the dart front end.
|
||||
///
|
||||
/// This is expected to be a comma separated list of strings.
|
||||
const String kExtraFrontEndOptions = 'ExtraFrontEndOptions';
|
||||
|
||||
/// Additional configuration passed to gen_snapshot.
|
||||
///
|
||||
/// This is expected to be a comma separated list of strings.
|
||||
const String kExtraGenSnapshotOptions = 'ExtraGenSnapshotOptions';
|
||||
|
||||
/// Alternative scheme for file URIs.
|
||||
///
|
||||
/// May be used along with [kFileSystemRoots] to support a multiroot
|
||||
/// filesystem.
|
||||
const String kFileSystemScheme = 'FileSystemScheme';
|
||||
|
||||
/// Additional filesystem roots.
|
||||
///
|
||||
/// If provided, must be used along with [kFileSystemScheme].
|
||||
const String kFileSystemRoots = 'FileSystemRoots';
|
||||
|
||||
/// The define to control what iOS architectures are built for.
|
||||
///
|
||||
/// This is expected to be a comma-separated list of architectures. If not
|
||||
@ -156,6 +177,13 @@ class KernelSnapshot extends Target {
|
||||
final bool trackWidgetCreation = environment.defines[kTrackWidgetCreation] != 'false';
|
||||
final TargetPlatform targetPlatform = getTargetPlatformForName(environment.defines[kTargetPlatform]);
|
||||
|
||||
// This configuration is all optional.
|
||||
final List<String> extraFrontEndOptions = <String>[
|
||||
...?environment.defines[kExtraFrontEndOptions]?.split(',')
|
||||
];
|
||||
final List<String> fileSystemRoots = environment.defines[kFileSystemRoots]?.split(',');
|
||||
final String fileSystemScheme = environment.defines[kFileSystemScheme];
|
||||
|
||||
TargetModel targetModel = TargetModel.flutter;
|
||||
if (targetPlatform == TargetPlatform.fuchsia_x64 ||
|
||||
targetPlatform == TargetPlatform.fuchsia_arm64) {
|
||||
@ -177,6 +205,9 @@ class KernelSnapshot extends Target {
|
||||
linkPlatformKernelIn: buildMode.isPrecompiled,
|
||||
mainPath: targetFileAbsolute,
|
||||
depFilePath: environment.buildDir.childFile('kernel_snapshot.d').path,
|
||||
extraFrontEndOptions: extraFrontEndOptions,
|
||||
fileSystemRoots: fileSystemRoots,
|
||||
fileSystemScheme: fileSystemScheme,
|
||||
);
|
||||
if (output == null || output.errorCount != 0) {
|
||||
throw Exception('Errors during snapshot creation: $output');
|
||||
@ -301,11 +332,12 @@ abstract class CopyFlutterAotBundle extends Target {
|
||||
}
|
||||
}
|
||||
|
||||
// This is a one-off rule for implementing build aot in terms of assemble.
|
||||
class ProfileCopyFlutterAotBundle extends CopyFlutterAotBundle {
|
||||
const ProfileCopyFlutterAotBundle();
|
||||
|
||||
@override
|
||||
String get name => 'profile_copy_aot_flutter_bundle';
|
||||
String get name => 'profile_android_flutter_bundle';
|
||||
|
||||
@override
|
||||
List<Target> get dependencies => const <Target>[
|
||||
@ -313,11 +345,12 @@ class ProfileCopyFlutterAotBundle extends CopyFlutterAotBundle {
|
||||
];
|
||||
}
|
||||
|
||||
// This is a one-off rule for implementing build aot in terms of assemble.
|
||||
class ReleaseCopyFlutterAotBundle extends CopyFlutterAotBundle {
|
||||
const ReleaseCopyFlutterAotBundle();
|
||||
|
||||
@override
|
||||
String get name => 'release_copy_aot_flutter_bundle';
|
||||
String get name => 'release_android_flutter_bundle';
|
||||
|
||||
@override
|
||||
List<Target> get dependencies => const <Target>[
|
||||
|
@ -7,6 +7,8 @@ import 'package:meta/meta.dart';
|
||||
import '../base/common.dart';
|
||||
import '../base/file_system.dart';
|
||||
import '../build_system/build_system.dart';
|
||||
import '../build_system/depfile.dart';
|
||||
import '../build_system/targets/android.dart';
|
||||
import '../build_system/targets/assets.dart';
|
||||
import '../build_system/targets/dart.dart';
|
||||
import '../build_system/targets/ios.dart';
|
||||
@ -16,6 +18,7 @@ import '../build_system/targets/web.dart';
|
||||
import '../build_system/targets/windows.dart';
|
||||
import '../globals.dart';
|
||||
import '../project.dart';
|
||||
import '../reporting/reporting.dart';
|
||||
import '../runner/flutter_command.dart';
|
||||
|
||||
/// All currently implemented targets.
|
||||
@ -33,6 +36,13 @@ const List<Target> _kDefaultTargets = <Target>[
|
||||
ReleaseMacOSBundleFlutterAssets(),
|
||||
DebugBundleLinuxAssets(),
|
||||
WebReleaseBundle(),
|
||||
DebugAndroidApplication(),
|
||||
ProfileAndroidApplication(),
|
||||
ReleaseAndroidApplication(),
|
||||
// These are one-off rules for bundle and aot compat
|
||||
ReleaseCopyFlutterAotBundle(),
|
||||
ProfileCopyFlutterAotBundle(),
|
||||
CopyFlutterBundle(),
|
||||
];
|
||||
|
||||
/// Assemble provides a low level API to interact with the flutter tool build
|
||||
@ -44,6 +54,9 @@ class AssembleCommand extends FlutterCommand {
|
||||
abbr: 'd',
|
||||
help: 'Allows passing configuration to a target with --define=target=key=value.',
|
||||
);
|
||||
argParser.addOption('depfile', help: 'A file path where a depfile will be written. '
|
||||
'This contains all build inputs and outputs in a make style syntax'
|
||||
);
|
||||
argParser.addOption('build-inputs', help: 'A file path where a newline '
|
||||
'separated file containing all inputs used will be written after a build.'
|
||||
' This file is not included as a build input or output. This file is not'
|
||||
@ -68,6 +81,19 @@ class AssembleCommand extends FlutterCommand {
|
||||
@override
|
||||
String get name => 'assemble';
|
||||
|
||||
@override
|
||||
Future<Map<CustomDimensions, String>> get usageValues async {
|
||||
final FlutterProject futterProject = FlutterProject.current();
|
||||
if (futterProject == null) {
|
||||
return const <CustomDimensions, String>{};
|
||||
}
|
||||
final Environment localEnvironment = environment;
|
||||
return <CustomDimensions, String>{
|
||||
CustomDimensions.commandBuildBundleTargetPlatform: localEnvironment.defines['TargetPlatform'],
|
||||
CustomDimensions.commandBuildBundleIsModule: '${futterProject.isModule}',
|
||||
};
|
||||
}
|
||||
|
||||
/// The target we are building.
|
||||
Target get target {
|
||||
if (argResults.rest.isEmpty) {
|
||||
@ -125,18 +151,22 @@ class AssembleCommand extends FlutterCommand {
|
||||
));
|
||||
if (!result.success) {
|
||||
for (MapEntry<String, ExceptionMeasurement> data in result.exceptions.entries) {
|
||||
printError('Target ${data.key} failed: ${data.value.exception}');
|
||||
printError('${data.value.exception}');
|
||||
printError('Target ${data.key} failed: ${data.value.exception}', stackTrace: data.value.stackTrace);
|
||||
}
|
||||
throwToolExit('build failed.');
|
||||
}
|
||||
printStatus('build succeeded.');
|
||||
printTrace('build succeeded.');
|
||||
if (argResults.wasParsed('build-inputs')) {
|
||||
writeListIfChanged(result.inputFiles, argResults['build-inputs']);
|
||||
}
|
||||
if (argResults.wasParsed('build-outputs')) {
|
||||
writeListIfChanged(result.outputFiles, argResults['build-outputs']);
|
||||
}
|
||||
if (argResults.wasParsed('depfile')) {
|
||||
final File depfileFile = fs.file(argResults['depfile']);
|
||||
final Depfile depfile = Depfile(result.inputFiles, result.outputFiles);
|
||||
depfile.writeToFile(fs.file(depfileFile));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import 'dart:async';
|
||||
import '../android/android_builder.dart';
|
||||
import '../base/os.dart';
|
||||
import '../build_info.dart';
|
||||
import '../cache.dart';
|
||||
import '../project.dart';
|
||||
import '../reporting/reporting.dart';
|
||||
import '../runner/flutter_command.dart' show FlutterCommandResult;
|
||||
@ -33,6 +34,12 @@ class BuildAarCommand extends BuildSubCommand {
|
||||
@override
|
||||
final String name = 'aar';
|
||||
|
||||
@override
|
||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => <DevelopmentArtifact>{
|
||||
DevelopmentArtifact.androidGenSnapshot,
|
||||
DevelopmentArtifact.universal,
|
||||
};
|
||||
|
||||
@override
|
||||
Future<Map<CustomDimensions, String>> get usageValues async {
|
||||
final Map<CustomDimensions, String> usage = <CustomDimensions, String>{};
|
||||
|
@ -7,6 +7,7 @@ import 'dart:async';
|
||||
import '../android/android_builder.dart';
|
||||
import '../base/terminal.dart';
|
||||
import '../build_info.dart';
|
||||
import '../cache.dart';
|
||||
import '../globals.dart';
|
||||
import '../project.dart';
|
||||
import '../reporting/reporting.dart';
|
||||
@ -41,6 +42,12 @@ class BuildApkCommand extends BuildSubCommand {
|
||||
@override
|
||||
final String name = 'apk';
|
||||
|
||||
@override
|
||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => <DevelopmentArtifact>{
|
||||
DevelopmentArtifact.androidGenSnapshot,
|
||||
DevelopmentArtifact.universal,
|
||||
};
|
||||
|
||||
@override
|
||||
final String description = 'Build an Android APK file from your app.\n\n'
|
||||
'This command can build debug and release versions of your application. \'debug\' builds support '
|
||||
|
@ -6,6 +6,7 @@ import 'dart:async';
|
||||
|
||||
import '../android/android_builder.dart';
|
||||
import '../build_info.dart';
|
||||
import '../cache.dart';
|
||||
import '../project.dart';
|
||||
import '../reporting/reporting.dart';
|
||||
import '../runner/flutter_command.dart' show FlutterCommandResult;
|
||||
@ -34,6 +35,12 @@ class BuildAppBundleCommand extends BuildSubCommand {
|
||||
@override
|
||||
final String name = 'appbundle';
|
||||
|
||||
@override
|
||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => <DevelopmentArtifact>{
|
||||
DevelopmentArtifact.androidGenSnapshot,
|
||||
DevelopmentArtifact.universal,
|
||||
};
|
||||
|
||||
@override
|
||||
final String description =
|
||||
'Build an Android App Bundle file from your app.\n\n'
|
||||
|
@ -39,7 +39,7 @@ void main() {
|
||||
await commandRunner.run(<String>['assemble', '-o Output', 'debug_macos_bundle_flutter_assets']);
|
||||
final BufferLogger bufferLogger = logger;
|
||||
|
||||
expect(bufferLogger.statusText.trim(), 'build succeeded.');
|
||||
expect(bufferLogger.traceText, contains('build succeeded.'));
|
||||
}));
|
||||
|
||||
test('Throws ToolExit if not provided with output', () => testbed.run(() async {
|
||||
|
@ -0,0 +1,87 @@
|
||||
// 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/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/android.dart';
|
||||
import 'package:flutter_tools/src/build_system/targets/dart.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
|
||||
import '../../../src/common.dart';
|
||||
import '../../../src/testbed.dart';
|
||||
|
||||
void main() {
|
||||
final Testbed testbed = Testbed(overrides: <Type, Generator>{
|
||||
Cache: () => FakeCache(),
|
||||
});
|
||||
|
||||
testbed.test('debug bundle contains expected resources', () async {
|
||||
final Environment environment = Environment(
|
||||
outputDir: fs.directory('out')..createSync(),
|
||||
projectDir: fs.currentDirectory,
|
||||
buildDir: fs.currentDirectory,
|
||||
defines: <String, String>{
|
||||
kBuildMode: 'debug',
|
||||
}
|
||||
);
|
||||
environment.buildDir.createSync(recursive: true);
|
||||
|
||||
// create pre-requisites.
|
||||
environment.buildDir.childFile('app.dill')
|
||||
..writeAsStringSync('abcd');
|
||||
final Directory hostDirectory = fs.currentDirectory
|
||||
.childDirectory(getNameForHostPlatform(getCurrentHostPlatform()))
|
||||
..createSync(recursive: true);
|
||||
hostDirectory.childFile('vm_isolate_snapshot.bin').createSync();
|
||||
hostDirectory.childFile('isolate_snapshot.bin').createSync();
|
||||
|
||||
|
||||
await const DebugAndroidApplication().build(environment);
|
||||
|
||||
expect(fs.file(fs.path.join('out', 'flutter_assets', 'isolate_snapshot_data')).existsSync(), true);
|
||||
expect(fs.file(fs.path.join('out', 'flutter_assets', 'vm_snapshot_data')).existsSync(), true);
|
||||
expect(fs.file(fs.path.join('out', 'flutter_assets', 'kernel_blob.bin')).existsSync(), true);
|
||||
});
|
||||
|
||||
testbed.test('profile bundle contains expected resources', () async {
|
||||
final Environment environment = Environment(
|
||||
outputDir: fs.directory('out')..createSync(),
|
||||
projectDir: fs.currentDirectory,
|
||||
buildDir: fs.currentDirectory,
|
||||
defines: <String, String>{
|
||||
kBuildMode: 'profile',
|
||||
}
|
||||
);
|
||||
environment.buildDir.createSync(recursive: true);
|
||||
|
||||
// create pre-requisites.
|
||||
environment.buildDir.childFile('app.so')
|
||||
..writeAsStringSync('abcd');
|
||||
|
||||
await const ProfileAndroidApplication().build(environment);
|
||||
|
||||
expect(fs.file(fs.path.join('out', 'app.so')).existsSync(), true);
|
||||
});
|
||||
|
||||
testbed.test('release bundle contains expected resources', () async {
|
||||
final Environment environment = Environment(
|
||||
outputDir: fs.directory('out')..createSync(),
|
||||
projectDir: fs.currentDirectory,
|
||||
buildDir: fs.currentDirectory,
|
||||
defines: <String, String>{
|
||||
kBuildMode: 'release',
|
||||
}
|
||||
);
|
||||
environment.buildDir.createSync(recursive: true);
|
||||
|
||||
// create pre-requisites.
|
||||
environment.buildDir.childFile('app.so')
|
||||
..writeAsStringSync('abcd');
|
||||
|
||||
await const ReleaseAndroidApplication().build(environment);
|
||||
|
||||
expect(fs.file(fs.path.join('out', 'app.so')).existsSync(), true);
|
||||
});
|
||||
}
|
@ -159,6 +159,9 @@ flutter_tools:lib/''');
|
||||
depFilePath: anyNamed('depFilePath'),
|
||||
packagesPath: anyNamed('packagesPath'),
|
||||
mainPath: anyNamed('mainPath'),
|
||||
extraFrontEndOptions: anyNamed('extraFrontEndOptions'),
|
||||
fileSystemRoots: anyNamed('fileSystemRoots'),
|
||||
fileSystemScheme: anyNamed('fileSystemScheme'),
|
||||
linkPlatformKernelIn: anyNamed('linkPlatformKernelIn'),
|
||||
)).thenAnswer((Invocation _) async {
|
||||
return const CompilerOutput('example', 0, <Uri>[]);
|
||||
@ -184,6 +187,9 @@ flutter_tools:lib/''');
|
||||
depFilePath: anyNamed('depFilePath'),
|
||||
packagesPath: anyNamed('packagesPath'),
|
||||
mainPath: anyNamed('mainPath'),
|
||||
extraFrontEndOptions: anyNamed('extraFrontEndOptions'),
|
||||
fileSystemRoots: anyNamed('fileSystemRoots'),
|
||||
fileSystemScheme: anyNamed('fileSystemScheme'),
|
||||
linkPlatformKernelIn: false,
|
||||
)).thenAnswer((Invocation _) async {
|
||||
return const CompilerOutput('example', 0, <Uri>[]);
|
||||
@ -211,6 +217,9 @@ flutter_tools:lib/''');
|
||||
depFilePath: anyNamed('depFilePath'),
|
||||
packagesPath: anyNamed('packagesPath'),
|
||||
mainPath: anyNamed('mainPath'),
|
||||
extraFrontEndOptions: anyNamed('extraFrontEndOptions'),
|
||||
fileSystemRoots: anyNamed('fileSystemRoots'),
|
||||
fileSystemScheme: anyNamed('fileSystemScheme'),
|
||||
linkPlatformKernelIn: false,
|
||||
)).thenAnswer((Invocation _) async {
|
||||
return const CompilerOutput('example', 0, <Uri>[]);
|
||||
|
@ -22,8 +22,10 @@ import 'package:flutter_tools/src/dart/pub.dart';
|
||||
import 'package:flutter_tools/src/features.dart';
|
||||
import 'package:flutter_tools/src/reporting/reporting.dart';
|
||||
import 'package:flutter_tools/src/version.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:process/process.dart';
|
||||
|
||||
import 'common.dart' as tester;
|
||||
import 'context.dart';
|
||||
import 'fake_process_manager.dart';
|
||||
import 'throwing_pub.dart';
|
||||
@ -86,6 +88,16 @@ class Testbed {
|
||||
final FutureOr<void> Function() _setup;
|
||||
final Map<Type, Generator> _overrides;
|
||||
|
||||
/// Runs the `test` within a tool zone.
|
||||
///
|
||||
/// Unlike [run], this sets up a test group on its own.
|
||||
@isTest
|
||||
void test<T>(String name, FutureOr<T> Function() test, {Map<Type, Generator> overrides}) {
|
||||
tester.test(name, () {
|
||||
return run(test, overrides: overrides);
|
||||
});
|
||||
}
|
||||
|
||||
/// Runs `test` within a tool zone.
|
||||
///
|
||||
/// `overrides` may be used to provide new context values for the single test
|
||||
@ -801,3 +813,95 @@ class DelegateLogger implements Logger {
|
||||
@override
|
||||
bool get supportsColor => delegate.supportsColor;
|
||||
}
|
||||
|
||||
/// An implementation of the Cache which does not download or require locking.
|
||||
class FakeCache implements Cache {
|
||||
@override
|
||||
bool includeAllPlatforms;
|
||||
|
||||
@override
|
||||
bool useUnsignedMacBinaries;
|
||||
|
||||
@override
|
||||
Future<bool> areRemoteArtifactsAvailable({String engineVersion, bool includeAllPlatforms = true}) async {
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
String get dartSdkVersion => null;
|
||||
|
||||
@override
|
||||
MapEntry<String, String> get dyLdLibEntry => null;
|
||||
|
||||
@override
|
||||
String get engineRevision => null;
|
||||
|
||||
@override
|
||||
Directory getArtifactDirectory(String name) {
|
||||
return fs.currentDirectory;
|
||||
}
|
||||
|
||||
@override
|
||||
Directory getCacheArtifacts() {
|
||||
return fs.currentDirectory;
|
||||
}
|
||||
|
||||
@override
|
||||
Directory getCacheDir(String name) {
|
||||
return fs.currentDirectory;
|
||||
}
|
||||
|
||||
@override
|
||||
Directory getDownloadDir() {
|
||||
return fs.currentDirectory;
|
||||
}
|
||||
|
||||
@override
|
||||
Directory getRoot() {
|
||||
return fs.currentDirectory;
|
||||
}
|
||||
|
||||
@override
|
||||
File getStampFileFor(String artifactName) {
|
||||
throw UnsupportedError('Not supported in the fake Cache');
|
||||
}
|
||||
|
||||
@override
|
||||
String getStampFor(String artifactName) {
|
||||
throw UnsupportedError('Not supported in the fake Cache');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> getThirdPartyFile(String urlStr, String serviceName) {
|
||||
throw UnsupportedError('Not supported in the fake Cache');
|
||||
}
|
||||
|
||||
@override
|
||||
String getVersionFor(String artifactName) {
|
||||
throw UnsupportedError('Not supported in the fake Cache');
|
||||
}
|
||||
|
||||
@override
|
||||
Directory getWebSdkDirectory() {
|
||||
return fs.currentDirectory;
|
||||
}
|
||||
|
||||
@override
|
||||
bool isOlderThanToolsStamp(FileSystemEntity entity) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
bool isUpToDate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
void setStampFor(String artifactName, String version) {
|
||||
throw UnsupportedError('Not supported in the fake Cache');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> updateAll(Set<DevelopmentArtifact> requiredArtifacts) async {
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user