Unverified Commit e2a3c2ee authored by Stanislav Baranov's avatar Stanislav Baranov Committed by GitHub

Remove support for building dynamic patches on Android. (#31359)

parent 0fb6a050
...@@ -4,12 +4,9 @@ ...@@ -4,12 +4,9 @@
import 'dart:async'; import 'dart:async';
import 'package:archive/archive.dart';
import 'package:bsdiff/bsdiff.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import '../android/android_sdk.dart'; import '../android/android_sdk.dart';
import '../application_package.dart';
import '../artifacts.dart'; import '../artifacts.dart';
import '../base/common.dart'; import '../base/common.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
...@@ -20,7 +17,6 @@ import '../base/process.dart'; ...@@ -20,7 +17,6 @@ import '../base/process.dart';
import '../base/utils.dart'; import '../base/utils.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../cache.dart'; import '../cache.dart';
import '../convert.dart';
import '../flutter_manifest.dart'; import '../flutter_manifest.dart';
import '../globals.dart'; import '../globals.dart';
import '../project.dart'; import '../project.dart';
...@@ -425,8 +421,6 @@ Future<void> _buildGradleProjectV2( ...@@ -425,8 +421,6 @@ Future<void> _buildGradleProjectV2(
command.add('-Ptrack-widget-creation=${buildInfo.trackWidgetCreation}'); command.add('-Ptrack-widget-creation=${buildInfo.trackWidgetCreation}');
if (buildInfo.compilationTraceFilePath != null) if (buildInfo.compilationTraceFilePath != null)
command.add('-Pcompilation-trace-file=${buildInfo.compilationTraceFilePath}'); command.add('-Pcompilation-trace-file=${buildInfo.compilationTraceFilePath}');
if (buildInfo.createPatch)
command.add('-Ppatch=true');
if (buildInfo.extraFrontEndOptions != null) if (buildInfo.extraFrontEndOptions != null)
command.add('-Pextra-front-end-options=${buildInfo.extraFrontEndOptions}'); command.add('-Pextra-front-end-options=${buildInfo.extraFrontEndOptions}');
if (buildInfo.extraGenSnapshotOptions != null) if (buildInfo.extraGenSnapshotOptions != null)
...@@ -497,105 +491,6 @@ Future<void> _buildGradleProjectV2( ...@@ -497,105 +491,6 @@ Future<void> _buildGradleProjectV2(
} }
printStatus('Built ${fs.path.relative(apkFile.path)}$appSize.'); printStatus('Built ${fs.path.relative(apkFile.path)}$appSize.');
if (buildInfo.createBaseline) {
// Save baseline apk for generating dynamic patches in later builds.
final AndroidApk package = AndroidApk.fromApk(apkFile);
final Directory baselineDir = fs.directory(buildInfo.baselineDir);
final File baselineApkFile = baselineDir.childFile('${package.versionCode}.apk');
baselineApkFile.parent.createSync(recursive: true);
apkFile.copySync(baselineApkFile.path);
printStatus('Saved baseline package ${baselineApkFile.path}.');
}
if (buildInfo.createPatch) {
final AndroidApk package = AndroidApk.fromApk(apkFile);
final Directory baselineDir = fs.directory(buildInfo.baselineDir);
final File baselineApkFile = baselineDir.childFile('${package.versionCode}.apk');
if (!baselineApkFile.existsSync())
throwToolExit('Error: Could not find baseline package ${baselineApkFile.path}.');
printStatus('Found baseline package ${baselineApkFile.path}.');
printStatus('Creating dynamic patch...');
final Archive newApk = ZipDecoder().decodeBytes(apkFile.readAsBytesSync());
final Archive oldApk = ZipDecoder().decodeBytes(baselineApkFile.readAsBytesSync());
final Archive update = Archive();
for (ArchiveFile newFile in newApk) {
if (!newFile.isFile)
continue;
// Ignore changes to signature manifests.
if (newFile.name.startsWith('META-INF/'))
continue;
final ArchiveFile oldFile = oldApk.findFile(newFile.name);
if (oldFile != null && oldFile.crc32 == newFile.crc32)
continue;
// Only allow certain changes.
if (!newFile.name.startsWith('assets/') &&
!(buildInfo.usesAot && newFile.name.endsWith('.so')))
throwToolExit("Error: Dynamic patching doesn't support changes to ${newFile.name}.");
final String name = newFile.name;
if (name.contains('_snapshot_') || name.endsWith('.so')) {
final List<int> diff = bsdiff(oldFile.content, newFile.content);
final int ratio = 100 * diff.length ~/ newFile.content.length;
printStatus('Deflated $name by ${ratio == 0 ? 99 : 100 - ratio}%');
update.addFile(ArchiveFile(name + '.bzdiff40', diff.length, diff));
} else {
update.addFile(ArchiveFile(name, newFile.content.length, newFile.content));
}
}
File updateFile;
if (buildInfo.patchNumber != null) {
updateFile = fs.directory(buildInfo.patchDir)
.childFile('${package.versionCode}-${buildInfo.patchNumber}.zip');
} else {
updateFile = fs.directory(buildInfo.patchDir)
.childFile('${package.versionCode}.zip');
}
if (update.files.isEmpty) {
printStatus('No changes detected, creating rollback patch.');
}
final List<String> checksumFiles = <String>[
'assets/isolate_snapshot_data',
'assets/isolate_snapshot_instr',
'assets/flutter_assets/isolate_snapshot_data',
];
int baselineChecksum = 0;
for (String fn in checksumFiles) {
final ArchiveFile oldFile = oldApk.findFile(fn);
if (oldFile != null)
baselineChecksum = getCrc32(oldFile.content, baselineChecksum);
}
if (baselineChecksum == 0)
throwToolExit('Error: Could not find baseline VM snapshot.');
final Map<String, dynamic> manifest = <String, dynamic>{
'baselineChecksum': baselineChecksum,
'buildNumber': package.versionCode,
};
if (buildInfo.patchNumber != null) {
manifest.addAll(<String, dynamic>{
'patchNumber': buildInfo.patchNumber,
});
}
const JsonEncoder encoder = JsonEncoder.withIndent(' ');
final String manifestJson = encoder.convert(manifest);
update.addFile(ArchiveFile('manifest.json', manifestJson.length, manifestJson.codeUnits));
updateFile.parent.createSync(recursive: true);
updateFile.writeAsBytesSync(ZipEncoder().encode(update), flush: true);
final String patchSize = getSizeAsMB(updateFile.lengthSync());
printStatus('Created dynamic patch ${updateFile.path} ($patchSize).');
}
} else { } else {
final File bundleFile = _findBundleFile(project, buildInfo); final File bundleFile = _findBundleFile(project, buildInfo);
if (bundleFile == null) if (bundleFile == null)
......
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
import 'dart:async'; import 'dart:async';
import 'package:archive/archive.dart';
import 'package:collection/collection.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import '../android/android_sdk.dart'; import '../android/android_sdk.dart';
...@@ -378,9 +376,6 @@ class JITSnapshotter { ...@@ -378,9 +376,6 @@ class JITSnapshotter {
@required String packagesPath, @required String packagesPath,
@required String outputPath, @required String outputPath,
@required String compilationTraceFilePath, @required String compilationTraceFilePath,
@required bool createPatch,
String buildNumber,
String baselineDir,
List<String> extraGenSnapshotOptions = const <String>[], List<String> extraGenSnapshotOptions = const <String>[],
}) async { }) async {
if (!_isValidJitPlatform(platform)) { if (!_isValidJitPlatform(platform)) {
...@@ -400,83 +395,6 @@ class JITSnapshotter { ...@@ -400,83 +395,6 @@ class JITSnapshotter {
mainPath, compilationTraceFilePath, engineVmSnapshotData, engineIsolateSnapshotData, mainPath, compilationTraceFilePath, engineVmSnapshotData, engineIsolateSnapshotData,
]; ];
if (createPatch) {
inputPaths.add(isolateSnapshotInstructions);
if (buildNumber == null) {
printError('Error: Dynamic patching requires --build-number specified');
return 1;
}
if (baselineDir == null) {
printError('Error: Dynamic patching requires --baseline-dir specified');
return 1;
}
final File baselineApk = fs.directory(baselineDir).childFile('$buildNumber.apk');
if (!baselineApk.existsSync()) {
printError('Error: Could not find baseline package ${baselineApk.path}.');
return 1;
}
final Archive baselinePkg = ZipDecoder().decodeBytes(baselineApk.readAsBytesSync());
{
final File f = fs.file(isolateSnapshotInstructions);
final ArchiveFile af = baselinePkg.findFile(
fs.path.join('assets/flutter_assets/isolate_snapshot_instr'));
if (af == null) {
printError('Error: Invalid baseline package ${baselineApk.path}.');
return 1;
}
// When building an update, gen_snapshot expects to find the original isolate
// snapshot instructions from the previous full build, so we need to extract
// it from saves baseline APK.
if (!f.existsSync()) {
f.writeAsBytesSync(af.content, flush: true);
} else {
// But if this file is already extracted, we make sure that it's identical.
final Function contentEquals = const ListEquality<int>().equals;
if (!contentEquals(f.readAsBytesSync(), af.content)) {
printError('Error: Detected changes unsupported by dynamic patching.');
return 1;
}
}
}
{
final File f = fs.file(engineVmSnapshotData);
final ArchiveFile af = baselinePkg.findFile(
fs.path.join('assets/flutter_assets/vm_snapshot_data'));
if (af == null) {
printError('Error: Invalid baseline package ${baselineApk.path}.');
return 1;
}
// If engine snapshot artifact doesn't exist, gen_snapshot below will fail
// with a friendly error, so we don't need to handle this case here too.
if (f.existsSync()) {
// But if engine snapshot exists, its content must match the engine snapshot
// in baseline APK. Otherwise, we're trying to build an update at an engine
// version that might be binary incompatible with baseline APK.
final Function contentEquals = const ListEquality<int>().equals;
if (!contentEquals(f.readAsBytesSync(), af.content)) {
printError('Error: Detected engine changes unsupported by dynamic patching.');
return 1;
}
}
}
{
final ArchiveFile af = baselinePkg.findFile(
fs.path.join('assets/flutter_assets/vm_snapshot_instr'));
if (af != null) {
printError('Error: Invalid baseline package ${baselineApk.path}.');
return 1;
}
}
}
final String depfilePath = fs.path.join(outputDir.path, 'snapshot.d'); final String depfilePath = fs.path.join(outputDir.path, 'snapshot.d');
final List<String> genSnapshotArgs = <String>[ final List<String> genSnapshotArgs = <String>[
'--deterministic', '--deterministic',
...@@ -490,10 +408,7 @@ class JITSnapshotter { ...@@ -490,10 +408,7 @@ class JITSnapshotter {
} }
final Set<String> outputPaths = <String>{}; final Set<String> outputPaths = <String>{};
outputPaths.addAll(<String>[isolateSnapshotData]); outputPaths.addAll(<String>[isolateSnapshotData, isolateSnapshotInstructions]);
if (!createPatch) {
outputPaths.add(isolateSnapshotInstructions);
}
// There are a couple special cases below where we create a snapshot // There are a couple special cases below where we create a snapshot
// with only the data section, which only contains interpreted code. // with only the data section, which only contains interpreted code.
...@@ -520,11 +435,7 @@ class JITSnapshotter { ...@@ -520,11 +435,7 @@ class JITSnapshotter {
'--isolate_snapshot_data=$isolateSnapshotData', '--isolate_snapshot_data=$isolateSnapshotData',
]); ]);
if (!createPatch) {
genSnapshotArgs.add('--isolate_snapshot_instructions=$isolateSnapshotInstructions'); genSnapshotArgs.add('--isolate_snapshot_instructions=$isolateSnapshotInstructions');
} else {
genSnapshotArgs.add('--reused_instructions=$isolateSnapshotInstructions');
}
if (platform == TargetPlatform.android_arm) { if (platform == TargetPlatform.android_arm) {
// Use softfp for Android armv7 devices. // Use softfp for Android armv7 devices.
...@@ -552,7 +463,6 @@ class JITSnapshotter { ...@@ -552,7 +463,6 @@ class JITSnapshotter {
'buildMode': buildMode.toString(), 'buildMode': buildMode.toString(),
'targetPlatform': platform.toString(), 'targetPlatform': platform.toString(),
'entryPoint': mainPath, 'entryPoint': mainPath,
'createPatch': createPatch.toString(),
'extraGenSnapshotOptions': extraGenSnapshotOptions.join(' '), 'extraGenSnapshotOptions': extraGenSnapshotOptions.join(' '),
}, },
depfilePaths: <String>[], depfilePaths: <String>[],
......
...@@ -15,11 +15,6 @@ class BuildInfo { ...@@ -15,11 +15,6 @@ class BuildInfo {
this.flavor, { this.flavor, {
this.trackWidgetCreation = false, this.trackWidgetCreation = false,
this.compilationTraceFilePath, this.compilationTraceFilePath,
this.createBaseline = false,
this.createPatch = false,
this.patchNumber,
this.patchDir,
this.baselineDir,
this.extraFrontEndOptions, this.extraFrontEndOptions,
this.extraGenSnapshotOptions, this.extraGenSnapshotOptions,
this.buildSharedLibrary, this.buildSharedLibrary,
...@@ -49,25 +44,6 @@ class BuildInfo { ...@@ -49,25 +44,6 @@ class BuildInfo {
/// Dart compilation trace file to use for JIT VM snapshot. /// Dart compilation trace file to use for JIT VM snapshot.
final String compilationTraceFilePath; final String compilationTraceFilePath;
/// Save baseline package.
final bool createBaseline;
/// Build differential snapshot.
final bool createPatch;
/// Internal version number of dynamic patch (not displayed to users).
/// Each patch may have a unique number to differentiate from previous
/// patches for the same versionCode on Android or CFBundleVersion on iOS.
final int patchNumber;
/// The directory where to store generated dynamic patches.
final String patchDir;
/// The directory where to store generated baseline packages.
/// Built packages, such as APK files on Android, are saved and can be used
/// to generate dynamic patches in later builds.
final String baselineDir;
/// Extra command-line options for front-end. /// Extra command-line options for front-end.
final String extraFrontEndOptions; final String extraFrontEndOptions;
...@@ -127,7 +103,6 @@ class BuildInfo { ...@@ -127,7 +103,6 @@ class BuildInfo {
BuildInfo(mode, flavor, BuildInfo(mode, flavor,
trackWidgetCreation: trackWidgetCreation, trackWidgetCreation: trackWidgetCreation,
compilationTraceFilePath: compilationTraceFilePath, compilationTraceFilePath: compilationTraceFilePath,
createPatch: createPatch,
extraFrontEndOptions: extraFrontEndOptions, extraFrontEndOptions: extraFrontEndOptions,
extraGenSnapshotOptions: extraGenSnapshotOptions, extraGenSnapshotOptions: extraGenSnapshotOptions,
buildSharedLibrary: buildSharedLibrary, buildSharedLibrary: buildSharedLibrary,
......
...@@ -61,9 +61,6 @@ Future<void> build({ ...@@ -61,9 +61,6 @@ Future<void> build({
bool reportLicensedPackages = false, bool reportLicensedPackages = false,
bool trackWidgetCreation = false, bool trackWidgetCreation = false,
String compilationTraceFilePath, String compilationTraceFilePath,
bool createPatch = false,
String buildNumber,
String baselineDir,
List<String> extraFrontEndOptions = const <String>[], List<String> extraFrontEndOptions = const <String>[],
List<String> extraGenSnapshotOptions = const <String>[], List<String> extraGenSnapshotOptions = const <String>[],
List<String> fileSystemRoots, List<String> fileSystemRoots,
...@@ -134,9 +131,6 @@ Future<void> build({ ...@@ -134,9 +131,6 @@ Future<void> build({
packagesPath: packagesPath, packagesPath: packagesPath,
compilationTraceFilePath: compilationTraceFilePath, compilationTraceFilePath: compilationTraceFilePath,
extraGenSnapshotOptions: extraGenSnapshotOptions, extraGenSnapshotOptions: extraGenSnapshotOptions,
createPatch: createPatch,
buildNumber: buildNumber,
baselineDir: baselineDir,
); );
if (snapshotExitCode != 0) { if (snapshotExitCode != 0) {
throwToolExit('Snapshotting exited with non-zero exit code: $snapshotExitCode'); throwToolExit('Snapshotting exited with non-zero exit code: $snapshotExitCode');
......
...@@ -14,7 +14,6 @@ class BuildApkCommand extends BuildSubCommand { ...@@ -14,7 +14,6 @@ class BuildApkCommand extends BuildSubCommand {
usesTargetOption(); usesTargetOption();
addBuildModeFlags(verboseHelp: verboseHelp); addBuildModeFlags(verboseHelp: verboseHelp);
addDynamicModeFlags(verboseHelp: verboseHelp); addDynamicModeFlags(verboseHelp: verboseHelp);
addDynamicPatchingFlags(verboseHelp: verboseHelp);
usesFlavorOption(); usesFlavorOption();
usesPubOption(); usesPubOption();
usesBuildNumberOption(); usesBuildNumberOption();
......
...@@ -17,7 +17,6 @@ class BuildBundleCommand extends BuildSubCommand { ...@@ -17,7 +17,6 @@ class BuildBundleCommand extends BuildSubCommand {
usesBuildNumberOption(); usesBuildNumberOption();
addBuildModeFlags(verboseHelp: verboseHelp); addBuildModeFlags(verboseHelp: verboseHelp);
addDynamicModeFlags(verboseHelp: verboseHelp); addDynamicModeFlags(verboseHelp: verboseHelp);
addDynamicBaselineFlags(verboseHelp: verboseHelp);
argParser argParser
..addFlag('precompiled', negatable: false) ..addFlag('precompiled', negatable: false)
// This option is still referenced by the iOS build scripts. We should // This option is still referenced by the iOS build scripts. We should
...@@ -70,8 +69,6 @@ class BuildBundleCommand extends BuildSubCommand { ...@@ -70,8 +69,6 @@ class BuildBundleCommand extends BuildSubCommand {
final BuildMode buildMode = getBuildMode(); final BuildMode buildMode = getBuildMode();
final String buildNumber = argResults['build-number'] != null ? argResults['build-number'] : null;
await build( await build(
platform: platform, platform: platform,
buildMode: buildMode, buildMode: buildMode,
...@@ -84,9 +81,6 @@ class BuildBundleCommand extends BuildSubCommand { ...@@ -84,9 +81,6 @@ class BuildBundleCommand extends BuildSubCommand {
reportLicensedPackages: argResults['report-licensed-packages'], reportLicensedPackages: argResults['report-licensed-packages'],
trackWidgetCreation: argResults['track-widget-creation'], trackWidgetCreation: argResults['track-widget-creation'],
compilationTraceFilePath: argResults['compilation-trace-file'], compilationTraceFilePath: argResults['compilation-trace-file'],
createPatch: argResults['patch'],
buildNumber: buildNumber,
baselineDir: argResults['baseline-dir'],
extraFrontEndOptions: argResults[FlutterOptions.kExtraFrontEndOptions], extraFrontEndOptions: argResults[FlutterOptions.kExtraFrontEndOptions],
extraGenSnapshotOptions: argResults[FlutterOptions.kExtraGenSnapshotOptions], extraGenSnapshotOptions: argResults[FlutterOptions.kExtraGenSnapshotOptions],
fileSystemScheme: argResults['filesystem-scheme'], fileSystemScheme: argResults['filesystem-scheme'],
......
...@@ -25,7 +25,6 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment ...@@ -25,7 +25,6 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
RunCommandBase({ bool verboseHelp = false }) { RunCommandBase({ bool verboseHelp = false }) {
addBuildModeFlags(defaultToRelease: false, verboseHelp: verboseHelp); addBuildModeFlags(defaultToRelease: false, verboseHelp: verboseHelp);
addDynamicModeFlags(verboseHelp: verboseHelp); addDynamicModeFlags(verboseHelp: verboseHelp);
addDynamicPatchingFlags(verboseHelp: verboseHelp);
usesFlavorOption(); usesFlavorOption();
argParser argParser
..addFlag('trace-startup', ..addFlag('trace-startup',
......
...@@ -259,54 +259,6 @@ abstract class FlutterCommand extends Command<void> { ...@@ -259,54 +259,6 @@ abstract class FlutterCommand extends Command<void> {
'--dynamic builds such as \'flutter build apk --dynamic\' to precompile\n' '--dynamic builds such as \'flutter build apk --dynamic\' to precompile\n'
'some code by the offline compiler.', 'some code by the offline compiler.',
); );
argParser.addFlag('patch',
hide: !verboseHelp,
negatable: false,
help: 'Generate dynamic patch for current changes from baseline.\n'
'Dynamic patch is generated relative to baseline package.\n'
'This flag is only allowed when using --dynamic.\n',
);
}
void addDynamicPatchingFlags({ bool verboseHelp = false }) {
argParser.addOption('patch-number',
hide: !verboseHelp,
help: 'An integer used as an internal version number for dynamic patch.\n'
'Each update may have a unique number to differentiate from previous\n'
'patches for same \'versionCode\' on Android or \'CFBundleVersion\' on iOS.\n'
'This optional setting allows several dynamic patches to coexist\n'
'for same baseline build, and is useful for canary and A-B testing\n'
'of dynamic patches.\n'
'This flag is only used when --dynamic --patch is specified.\n',
);
argParser.addOption('patch-dir',
defaultsTo: 'public',
hide: !verboseHelp,
help: 'The directory where to store generated dynamic patches.\n'
'This directory can be deployed to a CDN such as Firebase Hosting.\n'
'It is recommended to store this directory in version control.\n'
'This flag is only used when --dynamic --patch is specified.\n',
);
argParser.addFlag('baseline',
hide: !verboseHelp,
negatable: false,
help: 'Save built package as baseline for future dynamic patching.\n'
'Built package, such as APK file on Android, is saved and '
'can be used to generate dynamic patches in later builds.\n'
'This flag is only allowed when using --dynamic.\n',
);
addDynamicBaselineFlags(verboseHelp: verboseHelp);
}
void addDynamicBaselineFlags({ bool verboseHelp = false }) {
argParser.addOption('baseline-dir',
defaultsTo: '.baseline',
hide: !verboseHelp,
help: 'The directory where to store and find generated baseline packages.\n'
'It is recommended to store this directory in version control.\n'
'This flag is only used when --dynamic --baseline is specified.\n',
);
} }
void usesFuchsiaOptions({ bool hide = false }) { void usesFuchsiaOptions({ bool hide = false }) {
...@@ -382,16 +334,6 @@ abstract class FlutterCommand extends Command<void> { ...@@ -382,16 +334,6 @@ abstract class FlutterCommand extends Command<void> {
? argResults['build-number'] ? argResults['build-number']
: null; : null;
int patchNumber;
try {
patchNumber = argParser.options.containsKey('patch-number') && argResults['patch-number'] != null
? int.parse(argResults['patch-number'])
: null;
} catch (e) {
throw UsageException(
'--patch-number (${argResults['patch-number']}) must be an int.', null);
}
String extraFrontEndOptions = String extraFrontEndOptions =
argParser.options.containsKey(FlutterOptions.kExtraFrontEndOptions) argParser.options.containsKey(FlutterOptions.kExtraFrontEndOptions)
? argResults[FlutterOptions.kExtraFrontEndOptions] ? argResults[FlutterOptions.kExtraFrontEndOptions]
...@@ -416,19 +358,6 @@ abstract class FlutterCommand extends Command<void> { ...@@ -416,19 +358,6 @@ abstract class FlutterCommand extends Command<void> {
compilationTraceFilePath: argParser.options.containsKey('compilation-trace-file') compilationTraceFilePath: argParser.options.containsKey('compilation-trace-file')
? argResults['compilation-trace-file'] ? argResults['compilation-trace-file']
: null, : null,
createBaseline: argParser.options.containsKey('baseline')
? argResults['baseline']
: false,
createPatch: argParser.options.containsKey('patch')
? argResults['patch']
: false,
patchNumber: patchNumber,
patchDir: argParser.options.containsKey('patch-dir')
? argResults['patch-dir']
: null,
baselineDir: argParser.options.containsKey('baseline-dir')
? argResults['baseline-dir']
: null,
extraFrontEndOptions: extraFrontEndOptions, extraFrontEndOptions: extraFrontEndOptions,
extraGenSnapshotOptions: argParser.options.containsKey(FlutterOptions.kExtraGenSnapshotOptions) extraGenSnapshotOptions: argParser.options.containsKey(FlutterOptions.kExtraGenSnapshotOptions)
? argResults[FlutterOptions.kExtraGenSnapshotOptions] ? argResults[FlutterOptions.kExtraGenSnapshotOptions]
...@@ -670,20 +599,6 @@ abstract class FlutterCommand extends Command<void> { ...@@ -670,20 +599,6 @@ abstract class FlutterCommand extends Command<void> {
if (!fs.isFileSync(targetPath)) if (!fs.isFileSync(targetPath))
throw ToolExit(userMessages.flutterTargetFileMissing(targetPath)); throw ToolExit(userMessages.flutterTargetFileMissing(targetPath));
} }
final String compilationTraceFilePath = argParser.options.containsKey('compilation-trace-file')
? argResults['compilation-trace-file'] : null;
final bool createBaseline = argParser.options.containsKey('baseline')
? argResults['baseline'] : false;
final bool createPatch = argParser.options.containsKey('patch')
? argResults['patch'] : false;
if (createBaseline && createPatch)
throw ToolExit(userMessages.flutterBasePatchFlagsExclusive);
if (createBaseline && compilationTraceFilePath == null)
throw ToolExit(userMessages.flutterBaselineRequiresTraceFile);
if (createPatch && compilationTraceFilePath == null)
throw ToolExit(userMessages.flutterPatchRequiresTraceFile);
} }
ApplicationPackageStore applicationPackages; ApplicationPackageStore applicationPackages;
......
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