Unverified Commit 09686a04 authored by Christopher Fujino's avatar Christopher Fujino Committed by GitHub

[flutter_tools] add --uninstall-first flag and pipe it through to ios-deploy (#102948)

parent 4bed7675
......@@ -33,7 +33,15 @@ TaskFunction createHotModeTest({String? deviceIdOverride, Map<String, String>? e
final File benchmarkFile = file(path.join(_editedFlutterGalleryDir.path, 'hot_benchmark.json'));
rm(benchmarkFile);
final List<String> options = <String>[
'--hot', '-d', deviceIdOverride!, '--benchmark', '--resident', '--no-android-gradle-daemon', '--no-publish-port', '--verbose',
'--hot',
'-d',
deviceIdOverride!,
'--benchmark',
'--resident',
'--no-android-gradle-daemon',
'--no-publish-port',
'--verbose',
'--uninstall-first',
];
int hotReloadCount = 0;
late Map<String, dynamic> smallReloadData;
......
......@@ -140,6 +140,11 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
'this option multiple times each with one argument to pass '
'multiple arguments to the Dart entrypoint. Currently this is '
'only supported on desktop platforms.',
)
..addFlag('uninstall-first',
hide: !verboseHelp,
help: 'Uninstall previous versions of the app on the device '
'before reinstalling. Currently only supported on iOS.',
);
usesWebOptions(verboseHelp: verboseHelp);
usesTargetOption();
......@@ -166,6 +171,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
bool get runningWithPrebuiltApplication => argResults[FlutterOptions.kUseApplicationBinary] != null;
bool get trackWidgetCreation => boolArg('track-widget-creation');
bool get enableImpeller => boolArg('enable-impeller');
bool get uninstallFirst => boolArg('uninstall-first');
@override
bool get reportNullSafety => true;
......@@ -196,6 +202,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
webRunHeadless: featureFlags.isWebEnabled && boolArg('web-run-headless'),
webBrowserDebugPort: browserDebugPort,
enableImpeller: enableImpeller,
uninstallFirst: uninstallFirst,
);
} else {
return DebuggingOptions.enabled(
......@@ -240,6 +247,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
nullAssertions: boolArg('null-assertions'),
nativeNullAssertions: boolArg('native-null-assertions'),
enableImpeller: enableImpeller,
uninstallFirst: uninstallFirst,
);
}
}
......
......@@ -792,6 +792,7 @@ class DebuggingOptions {
this.nullAssertions = false,
this.nativeNullAssertions = false,
this.enableImpeller = false,
this.uninstallFirst = false,
}) : debuggingEnabled = true;
DebuggingOptions.disabled(this.buildInfo, {
......@@ -808,6 +809,7 @@ class DebuggingOptions {
this.cacheSkSL = false,
this.traceAllowlist,
this.enableImpeller = false,
this.uninstallFirst = false,
}) : debuggingEnabled = false,
useTestFonts = false,
startPaused = false,
......@@ -876,6 +878,7 @@ class DebuggingOptions {
required this.nullAssertions,
required this.nativeNullAssertions,
required this.enableImpeller,
required this.uninstallFirst,
});
final bool debuggingEnabled;
......@@ -912,6 +915,11 @@ class DebuggingOptions {
final bool webUseSseForInjectedClient;
final bool enableImpeller;
/// Whether the tool should try to uninstall a previously installed version of the app.
///
/// This is not implemented for every platform.
final bool uninstallFirst;
/// Whether to run the browser in headless mode.
///
/// Some CI environments do not provide a display and fail to launch the
......@@ -1026,6 +1034,7 @@ class DebuggingOptions {
nullAssertions: (json['nullAssertions'] as bool?)!,
nativeNullAssertions: (json['nativeNullAssertions'] as bool?)!,
enableImpeller: (json['enableImpeller'] as bool?) ?? false,
uninstallFirst: (json['uninstallFirst'] as bool?) ?? false,
);
}
......
......@@ -394,6 +394,7 @@ class IOSDevice extends Device {
appDeltaDirectory: package.appDeltaDirectory,
launchArguments: launchArguments,
interfaceType: interfaceType,
uninstallFirst: debuggingOptions.uninstallFirst,
);
if (deviceLogReader is IOSDeviceLogReader) {
deviceLogReader.debuggerStream = iosDeployDebugger;
......@@ -415,6 +416,7 @@ class IOSDevice extends Device {
appDeltaDirectory: package.appDeltaDirectory,
launchArguments: launchArguments,
interfaceType: interfaceType,
uninstallFirst: debuggingOptions.uninstallFirst,
);
} else {
installationResult = await iosDeployDebugger!.launchAndAttach() ? 0 : 1;
......
......@@ -127,6 +127,7 @@ class IOSDeploy {
required List<String> launchArguments,
required IOSDeviceConnectionInterface interfaceType,
Directory? appDeltaDirectory,
required bool uninstallFirst,
}) {
appDeltaDirectory?.createSync(recursive: true);
// Interactive debug session to support sending the lldb detach command.
......@@ -144,6 +145,8 @@ class IOSDeploy {
'--app_deltas',
appDeltaDirectory.path,
],
if (uninstallFirst)
'--uninstall',
'--debug',
if (interfaceType != IOSDeviceConnectionInterface.network)
'--no-wifi',
......@@ -168,6 +171,7 @@ class IOSDeploy {
required String bundlePath,
required List<String> launchArguments,
required IOSDeviceConnectionInterface interfaceType,
required bool uninstallFirst,
Directory? appDeltaDirectory,
}) async {
appDeltaDirectory?.createSync(recursive: true);
......@@ -183,6 +187,8 @@ class IOSDeploy {
],
if (interfaceType != IOSDeviceConnectionInterface.network)
'--no-wifi',
if (uninstallFirst)
'--uninstall',
'--justlaunch',
if (launchArguments.isNotEmpty) ...<String>[
'--args',
......
......@@ -369,6 +369,42 @@ void main() {
Cache: () => Cache.test(processManager: FakeProcessManager.any()),
});
testUsingContext('forwards --uninstall-only to DebuggingOptions', () async {
final RunCommand command = RunCommand();
final FakeDevice mockDevice = FakeDevice(
sdkNameAndVersion: 'iOS 13',
)..startAppSuccess = false;
mockDeviceManager
..devices = <Device>[
mockDevice,
]
..targetDevices = <Device>[
mockDevice,
];
// Causes swift to be detected in the analytics.
fs.currentDirectory.childDirectory('ios').childFile('AppDelegate.swift').createSync(recursive: true);
await expectToolExitLater(createTestCommandRunner(command).run(<String>[
'run',
'--no-pub',
'--no-hot',
'--uninstall-first',
]), isNull);
final DebuggingOptions options = await command.createDebuggingOptions(false);
expect(options.uninstallFirst, isTrue);
}, overrides: <Type, Generator>{
Artifacts: () => artifacts,
Cache: () => Cache.test(processManager: FakeProcessManager.any()),
DeviceManager: () => mockDeviceManager,
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
Usage: () => usage,
});
testUsingContext('passes device target platform to usage', () async {
final RunCommand command = RunCommand();
final FakeDevice mockDevice = FakeDevice(sdkNameAndVersion: 'iOS 13')
......@@ -407,7 +443,7 @@ void main() {
Usage: () => usage,
});
group('--machine', () {
group('--machine', () {
testUsingContext('enables multidex by default', () async {
final DaemonCapturingRunCommand command = DaemonCapturingRunCommand();
final FakeDevice device = FakeDevice();
......
......@@ -53,6 +53,7 @@ void main () {
'/',
'--app_deltas',
'app-delta',
'--uninstall',
'--debug',
'--args',
<String>[
......@@ -73,6 +74,7 @@ void main () {
appDeltaDirectory: appDeltaDirectory,
launchArguments: <String>['--enable-dart-profiling'],
interfaceType: IOSDeviceConnectionInterface.network,
uninstallFirst: true,
);
expect(iosDeployDebugger.logLines, emits('Did finish launching.'));
......
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