Unverified Commit 393f9276 authored by Stanislav Baranov's avatar Stanislav Baranov Committed by GitHub

Reland Flutter tool support for dynamic code #20543 (#20646)

parent bcae4717
......@@ -42,6 +42,8 @@ class FlutterPlugin implements Plugin<Project> {
private File debugFlutterJar
private File profileFlutterJar
private File releaseFlutterJar
private File dynamicProfileFlutterJar
private File dynamicReleaseFlutterJar
private Properties readPropertiesIfExist(File propertiesFile) {
Properties result = new Properties()
......@@ -70,7 +72,7 @@ class FlutterPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
// Add a 'profile' build type
// Add custom build types
project.android.buildTypes {
profile {
initWith debug
......@@ -78,6 +80,18 @@ class FlutterPlugin implements Plugin<Project> {
matchingFallbacks = ['debug', 'release']
}
}
dynamicProfile {
initWith debug
if (it.hasProperty('matchingFallbacks')) {
matchingFallbacks = ['debug', 'release']
}
}
dynamicRelease {
initWith debug
if (it.hasProperty('matchingFallbacks')) {
matchingFallbacks = ['debug', 'release']
}
}
}
String flutterRootPath = resolveProperty(project, "flutter.sdk", System.env.FLUTTER_ROOT)
......@@ -123,6 +137,8 @@ class FlutterPlugin implements Plugin<Project> {
debugFlutterJar = baseEnginePath.resolve("android-${targetArch}").resolve("flutter.jar").toFile()
profileFlutterJar = baseEnginePath.resolve("android-${targetArch}-profile").resolve("flutter.jar").toFile()
releaseFlutterJar = baseEnginePath.resolve("android-${targetArch}-release").resolve("flutter.jar").toFile()
dynamicProfileFlutterJar = baseEnginePath.resolve("android-${targetArch}-dynamic-profile").resolve("flutter.jar").toFile()
dynamicReleaseFlutterJar = baseEnginePath.resolve("android-${targetArch}-dynamic-release").resolve("flutter.jar").toFile()
if (!debugFlutterJar.isFile()) {
project.exec {
executable flutterExecutable.absolutePath
......@@ -217,6 +233,10 @@ class FlutterPlugin implements Plugin<Project> {
[flutterX86Jar, debugFlutterJar]
} else if (buildMode == "profile") {
profileFlutterJar
} else if (buildMode == "dynamicProfile") {
dynamicProfileFlutterJar
} else if (buildMode == "dynamicRelease") {
dynamicReleaseFlutterJar
} else {
releaseFlutterJar
}
......@@ -229,11 +249,15 @@ class FlutterPlugin implements Plugin<Project> {
*
* Note: The BuildType DSL type is not public, and is therefore omitted from the signature.
*
* @return "debug", "profile", or "release" (fall-back).
* @return "debug", "profile", "dynamicProfile", "dynamicRelease", or "release" (fall-back).
*/
private static String buildModeFor(buildType) {
if (buildType.name == "profile") {
return "profile"
} else if (buildType.name == "dynamicProfile") {
return "dynamicProfile"
} else if (buildType.name == "dynamicRelease") {
return "dynamicRelease"
} else if (buildType.debuggable) {
return "debug"
}
......@@ -409,7 +433,7 @@ abstract class BaseFlutterTask extends DefaultTask {
intermediateDir.mkdirs()
if (buildMode != "debug") {
if (buildMode == "profile" || buildMode == "release") {
project.exec {
executable flutterExecutable.absolutePath
workingDir sourceDir
......@@ -488,7 +512,7 @@ abstract class BaseFlutterTask extends DefaultTask {
if (targetPlatform != null) {
args "--target-platform", "${targetPlatform}"
}
if (buildMode != "debug") {
if (buildMode == "release" || buildMode == "profile") {
args "--precompiled"
} else {
args "--depfile", "${intermediateDir}/snapshot_blob.bin.d"
......@@ -497,7 +521,18 @@ abstract class BaseFlutterTask extends DefaultTask {
}
}
args "--asset-dir", "${intermediateDir}/flutter_assets"
args "--${buildMode}"
if (buildMode == "debug") {
args "--debug"
}
if (buildMode == "profile" || buildMode == "dynamicProfile") {
args "--profile"
}
if (buildMode == "release" || buildMode == "dynamicRelease") {
args "--release"
}
if (buildMode == "dynamicProfile" || buildMode == "dynamicRelease") {
args "--dynamic"
}
}
}
}
......
......@@ -415,12 +415,13 @@ File _findApkFile(GradleProject project, BuildInfo buildInfo) {
File apkFile = fs.file(fs.path.join(project.apkDirectory.path, apkFileName));
if (apkFile.existsSync())
return apkFile;
apkFile = fs.file(fs.path.join(project.apkDirectory.path, buildInfo.modeName, apkFileName));
final String modeName = camelCase(buildInfo.modeName);
apkFile = fs.file(fs.path.join(project.apkDirectory.path, modeName, apkFileName));
if (apkFile.existsSync())
return apkFile;
if (buildInfo.flavor != null) {
// Android Studio Gradle plugin v3 adds flavor to path.
apkFile = fs.file(fs.path.join(project.apkDirectory.path, buildInfo.flavor, buildInfo.modeName, apkFileName));
apkFile = fs.file(fs.path.join(project.apkDirectory.path, buildInfo.flavor, modeName, apkFileName));
if (apkFile.existsSync())
return apkFile;
}
......@@ -484,8 +485,9 @@ class GradleProject {
final Directory apkDirectory;
String _buildTypeFor(BuildInfo buildInfo) {
if (buildTypes.contains(buildInfo.modeName))
return buildInfo.modeName;
final String modeName = camelCase(buildInfo.modeName);
if (buildTypes.contains(modeName.toLowerCase()))
return modeName;
return null;
}
......
......@@ -8,6 +8,7 @@ import 'base/context.dart';
import 'base/file_system.dart';
import 'base/platform.dart';
import 'base/process_manager.dart';
import 'base/utils.dart';
import 'build_info.dart';
import 'dart/sdk.dart';
import 'globals.dart';
......@@ -218,7 +219,7 @@ class CachedArtifacts extends Artifacts {
case TargetPlatform.android_x64:
case TargetPlatform.android_x86:
assert(mode != null, 'Need to specify a build mode for platform $platform.');
final String suffix = mode != BuildMode.debug ? '-${getModeName(mode)}' : '';
final String suffix = mode != BuildMode.debug ? '-${snakeCase(getModeName(mode), '-')}' : '';
return fs.path.join(engineDir, platformName + suffix);
}
assert(false, 'Invalid platform $platform.');
......
......@@ -75,6 +75,14 @@ String camelCase(String str) {
return str;
}
final RegExp _upperRegex = new RegExp(r'[A-Z]');
/// Convert `fooBar` to `foo_bar`.
String snakeCase(String str, [String sep = '_']) {
return str.replaceAllMapped(_upperRegex,
(Match m) => '${m.start == 0 ? '' : sep}${m[0].toLowerCase()}');
}
String toTitleCase(String str) {
if (str.isEmpty)
return str;
......
......@@ -74,6 +74,8 @@ class BuildInfo {
static const BuildInfo debug = BuildInfo(BuildMode.debug, null);
static const BuildInfo profile = BuildInfo(BuildMode.profile, null);
static const BuildInfo release = BuildInfo(BuildMode.release, null);
static const BuildInfo dynamicProfile = BuildInfo(BuildMode.dynamicProfile, null);
static const BuildInfo dynamicRelease = BuildInfo(BuildMode.dynamicRelease, null);
/// Returns whether a debug build is requested.
///
......@@ -83,12 +85,12 @@ class BuildInfo {
/// Returns whether a profile build is requested.
///
/// Exactly one of [isDebug], [isProfile], or [isRelease] is true.
bool get isProfile => mode == BuildMode.profile;
bool get isProfile => mode == BuildMode.profile || mode == BuildMode.dynamicProfile;
/// Returns whether a release build is requested.
///
/// Exactly one of [isDebug], [isProfile], or [isRelease] is true.
bool get isRelease => mode == BuildMode.release;
bool get isRelease => mode == BuildMode.release || mode == BuildMode.dynamicRelease;
bool get usesAot => isAotBuildMode(mode);
bool get supportsEmulator => isEmulatorBuildMode(mode);
......@@ -106,25 +108,17 @@ class BuildInfo {
targetPlatform: targetPlatform);
}
/// The type of build - `debug`, `profile`, or `release`.
/// The type of build.
enum BuildMode {
debug,
profile,
release
release,
dynamicProfile,
dynamicRelease
}
String getModeName(BuildMode mode) => getEnumName(mode);
BuildMode getBuildModeForName(String mode) {
if (mode == 'debug')
return BuildMode.debug;
if (mode == 'profile')
return BuildMode.profile;
if (mode == 'release')
return BuildMode.release;
return null;
}
// Returns true if the selected build mode uses ahead-of-time compilation.
bool isAotBuildMode(BuildMode mode) {
return mode == BuildMode.profile || mode == BuildMode.release;
......
......@@ -115,8 +115,7 @@ Future<void> build({
extraGenSnapshotOptions: extraGenSnapshotOptions,
);
if (snapshotExitCode != 0) {
printError('Snapshotting exited with non-zero exit code: $snapshotExitCode');
return;
throwToolExit('Snapshotting exited with non-zero exit code: $snapshotExitCode');
}
}
}
......
......@@ -403,6 +403,10 @@ class FlutterEngine extends CachedArtifact {
<String>['android-arm-release/linux-x64', 'android-arm-release/linux-x64.zip'],
<String>['android-arm64-profile/linux-x64', 'android-arm64-profile/linux-x64.zip'],
<String>['android-arm64-release/linux-x64', 'android-arm64-release/linux-x64.zip'],
<String>['android-arm-dynamic-profile/linux-x64', 'android-arm-dynamic-profile/linux-x64.zip'],
<String>['android-arm-dynamic-release/linux-x64', 'android-arm-dynamic-release/linux-x64.zip'],
<String>['android-arm64-dynamic-profile/linux-x64', 'android-arm64-dynamic-profile/linux-x64.zip'],
<String>['android-arm64-dynamic-release/linux-x64', 'android-arm64-dynamic-release/linux-x64.zip'],
];
List<List<String>> get _windowsBinaryDirs => <List<String>>[
......@@ -422,6 +426,10 @@ class FlutterEngine extends CachedArtifact {
<String>['android-arm64', 'android-arm64/artifacts.zip'],
<String>['android-arm64-profile', 'android-arm64-profile/artifacts.zip'],
<String>['android-arm64-release', 'android-arm64-release/artifacts.zip'],
<String>['android-arm-dynamic-profile', 'android-arm-dynamic-profile/artifacts.zip'],
<String>['android-arm-dynamic-release', 'android-arm-dynamic-release/artifacts.zip'],
<String>['android-arm64-dynamic-profile', 'android-arm64-dynamic-profile/artifacts.zip'],
<String>['android-arm64-dynamic-release', 'android-arm64-dynamic-release/artifacts.zip'],
];
List<List<String>> get _iosBinaryDirs => <List<String>>[
......
......@@ -21,8 +21,8 @@ import 'daemon.dart';
abstract class RunCommandBase extends FlutterCommand {
// Used by run and drive commands.
RunCommandBase() {
addBuildModeFlags(defaultToRelease: false);
RunCommandBase({ bool verboseHelp = false }) {
addBuildModeFlags(defaultToRelease: false, verboseHelp: verboseHelp);
usesFlavorOption();
argParser
..addFlag('trace-startup',
......@@ -78,7 +78,7 @@ class RunCommand extends RunCommandBase {
@override
final String description = 'Run your Flutter app on an attached device.';
RunCommand({ bool verboseHelp = false }) {
RunCommand({ bool verboseHelp = false }) : super(verboseHelp: verboseHelp) {
requiresPubspecYaml();
argParser
......
......@@ -101,6 +101,7 @@ class KernelCompiler {
properties: <String, String>{
'entryPoint': mainPath,
'trackWidgetCreation': trackWidgetCreation.toString(),
'linkPlatformKernelIn': linkPlatformKernelIn.toString(),
},
depfilePaths: <String>[depFilePath],
pathFilter: (String path) => !path.startsWith('/b/build/slave/'),
......
......@@ -141,7 +141,7 @@ abstract class FlutterCommand extends Command<Null> {
valueHelp: 'x.y.z');
}
void addBuildModeFlags({bool defaultToRelease = true}) {
void addBuildModeFlags({bool defaultToRelease = true, bool verboseHelp = false}) {
defaultBuildMode = defaultToRelease ? BuildMode.release : BuildMode.debug;
argParser.addFlag('debug',
......@@ -153,6 +153,11 @@ abstract class FlutterCommand extends Command<Null> {
argParser.addFlag('release',
negatable: false,
help: 'Build a release version of your app${defaultToRelease ? ' (default mode)' : ''}.');
argParser.addFlag('dynamic',
hide: !verboseHelp,
negatable: false,
help: 'Enable dynamic code. This flag is intended for use with\n'
'--release or --profile; --debug always has this enabled.');
}
set defaultBuildMode(BuildMode value) {
......@@ -163,12 +168,15 @@ abstract class FlutterCommand extends Command<Null> {
final List<bool> modeFlags = <bool>[argResults['debug'], argResults['profile'], argResults['release']];
if (modeFlags.where((bool flag) => flag).length > 1)
throw new UsageException('Only one of --debug, --profile, or --release can be specified.', null);
final bool dynamicFlag = argParser.options.containsKey('dynamic')
? argResults['dynamic']
: false;
if (argResults['debug'])
return BuildMode.debug;
if (argResults['profile'])
return BuildMode.profile;
return dynamicFlag ? BuildMode.dynamicProfile : BuildMode.profile;
if (argResults['release'])
return BuildMode.release;
return dynamicFlag ? BuildMode.dynamicRelease : BuildMode.release;
return _defaultBuildMode;
}
......
......@@ -166,4 +166,17 @@ baz=qux
expect(duration, greaterThanOrEqualTo(new Duration(milliseconds: kShortDelay.inMilliseconds * 2)));
});
});
group('Misc', () {
test('snakeCase', () async {
expect(snakeCase('abc'), equals('abc'));
expect(snakeCase('abC'), equals('ab_c'));
expect(snakeCase('aBc'), equals('a_bc'));
expect(snakeCase('aBC'), equals('a_b_c'));
expect(snakeCase('Abc'), equals('abc'));
expect(snakeCase('AbC'), equals('ab_c'));
expect(snakeCase('ABc'), equals('a_bc'));
expect(snakeCase('ABC'), equals('a_b_c'));
});
});
}
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