mirror of
https://github.com/flutter/flutter
synced 2024-10-04 07:19:46 +00:00
Add --use-application-binary to "flutter install" (#101324)
This commit is contained in:
parent
d08f7ab9c9
commit
d745eec051
|
@ -42,7 +42,7 @@ class BuildIOSCommand extends _BuildIOSSubCommand {
|
|||
final String name = 'ios';
|
||||
|
||||
@override
|
||||
final String description = 'Build an iOS application bundle (Mac OS X host only).';
|
||||
final String description = 'Build an iOS application bundle (macOS host only).';
|
||||
|
||||
@override
|
||||
final XcodeBuildAction xcodeBuildAction = XcodeBuildAction.build;
|
||||
|
@ -94,7 +94,7 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
|
|||
final List<String> aliases = <String>['xcarchive'];
|
||||
|
||||
@override
|
||||
final String description = 'Build an iOS archive bundle and IPA for distribution (Mac OS X host only).';
|
||||
final String description = 'Build an iOS archive bundle and IPA for distribution (macOS host only).';
|
||||
|
||||
@override
|
||||
final XcodeBuildAction xcodeBuildAction = XcodeBuildAction.archive;
|
||||
|
|
|
@ -92,7 +92,7 @@ class DriveCommand extends RunCommandBase {
|
|||
)
|
||||
..addFlag('build',
|
||||
defaultsTo: true,
|
||||
help: '(deprecated) Build the app before running. To use an existing app, pass the "--use-application-binary" '
|
||||
help: '(deprecated) Build the app before running. To use an existing app, pass the "--${FlutterOptions.kUseApplicationBinary}" '
|
||||
'flag with an existing APK.',
|
||||
)
|
||||
..addOption('screenshot',
|
||||
|
@ -209,7 +209,8 @@ class DriveCommand extends RunCommandBase {
|
|||
if (await _fileSystem.type(testFile) != FileSystemEntityType.file) {
|
||||
throwToolExit('Test file not found: $testFile');
|
||||
}
|
||||
final Device device = await findTargetDevice(includeUnsupportedDevices: stringArg('use-application-binary') == null);
|
||||
final String applicationBinaryPath = stringArg(FlutterOptions.kUseApplicationBinary);
|
||||
final Device device = await findTargetDevice(includeUnsupportedDevices: applicationBinaryPath == null);
|
||||
if (device == null) {
|
||||
throwToolExit(null);
|
||||
}
|
||||
|
@ -233,9 +234,9 @@ class DriveCommand extends RunCommandBase {
|
|||
final DriverService driverService = _flutterDriverFactory.createDriverService(web);
|
||||
final BuildInfo buildInfo = await getBuildInfo();
|
||||
final DebuggingOptions debuggingOptions = await createDebuggingOptions(web);
|
||||
final File applicationBinary = stringArg('use-application-binary') == null
|
||||
final File applicationBinary = applicationBinaryPath == null
|
||||
? null
|
||||
: _fileSystem.file(stringArg('use-application-binary'));
|
||||
: _fileSystem.file(applicationBinaryPath);
|
||||
|
||||
bool screenshotTaken = false;
|
||||
try {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
import '../android/android_device.dart';
|
||||
import '../application_package.dart';
|
||||
import '../base/common.dart';
|
||||
import '../base/file_system.dart';
|
||||
import '../base/io.dart';
|
||||
import '../device.dart';
|
||||
import '../globals.dart' as globals;
|
||||
|
@ -15,6 +16,7 @@ class InstallCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts
|
|||
requiresPubspecYaml();
|
||||
usesDeviceUserOption();
|
||||
usesDeviceTimeoutOption();
|
||||
usesApplicationBinaryOption();
|
||||
argParser.addFlag('uninstall-only',
|
||||
help: 'Uninstall the app if already on the device. Skip install.',
|
||||
);
|
||||
|
@ -34,6 +36,9 @@ class InstallCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts
|
|||
bool get uninstallOnly => boolArg('uninstall-only');
|
||||
String? get userIdentifier => stringArg(FlutterOptions.kDeviceUser);
|
||||
|
||||
String? get _applicationBinaryPath => stringArg(FlutterOptions.kUseApplicationBinary);
|
||||
File? get _applicationBinary => _applicationBinaryPath == null ? null : globals.fs.file(_applicationBinaryPath);
|
||||
|
||||
@override
|
||||
Future<void> validateCommand() async {
|
||||
await super.validateCommand();
|
||||
|
@ -44,6 +49,9 @@ class InstallCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts
|
|||
if (userIdentifier != null && device is! AndroidDevice) {
|
||||
throwToolExit('--${FlutterOptions.kDeviceUser} is only supported for Android');
|
||||
}
|
||||
if (_applicationBinaryPath != null && !(_applicationBinary?.existsSync() ?? true)) {
|
||||
throwToolExit('Prebuilt binary $_applicationBinaryPath does not exist');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -51,6 +59,7 @@ class InstallCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts
|
|||
final Device targetDevice = device!;
|
||||
final ApplicationPackage? package = await applicationPackages?.getPackageForPlatform(
|
||||
await targetDevice.targetPlatform,
|
||||
applicationBinary: _applicationBinary,
|
||||
);
|
||||
if (package == null) {
|
||||
throwToolExit('Could not find or build package');
|
||||
|
|
|
@ -38,6 +38,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
|
|||
usesWebRendererOption();
|
||||
addNativeNullAssertions(hide: !verboseHelp);
|
||||
addBundleSkSLPathOption(hide: !verboseHelp);
|
||||
usesApplicationBinaryOption();
|
||||
argParser
|
||||
..addFlag('trace-startup',
|
||||
negatable: false,
|
||||
|
@ -87,12 +88,6 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
|
|||
help: '(deprecated) Allow connections to the VM service without using authentication codes. '
|
||||
'(Not recommended! This can open your device to remote code execution attacks!)'
|
||||
)
|
||||
..addOption('use-application-binary',
|
||||
help: 'Specify a pre-built application binary to use when running. For Android applications, '
|
||||
'this must be the path to an APK. For iOS applications, the path to an IPA. Other device types '
|
||||
'do not yet support prebuilt application binaries.',
|
||||
valueHelp: 'path/to/app.apk',
|
||||
)
|
||||
..addFlag('start-paused',
|
||||
defaultsTo: startPausedDefault,
|
||||
help: 'Start in a paused mode and wait for a debugger to connect.',
|
||||
|
@ -168,7 +163,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
|
|||
bool get purgePersistentCache => boolArg('purge-persistent-cache');
|
||||
bool get disableServiceAuthCodes => boolArg('disable-service-auth-codes');
|
||||
bool get cacheStartupProfile => boolArg('cache-startup-profile');
|
||||
bool get runningWithPrebuiltApplication => argResults['use-application-binary'] != null;
|
||||
bool get runningWithPrebuiltApplication => argResults[FlutterOptions.kUseApplicationBinary] != null;
|
||||
bool get trackWidgetCreation => boolArg('track-widget-creation');
|
||||
bool get enableImpeller => boolArg('enable-impeller');
|
||||
|
||||
|
@ -347,7 +342,7 @@ class RunCommand extends RunCommandBase {
|
|||
defaultsTo: false,
|
||||
help: 'Whether to quickly bootstrap applications with a minimal app. '
|
||||
'Currently this is only supported on Android devices. This option '
|
||||
'cannot be paired with "--use-application-binary".',
|
||||
'cannot be paired with "--${FlutterOptions.kUseApplicationBinary}".',
|
||||
hide: !verboseHelp,
|
||||
);
|
||||
}
|
||||
|
@ -484,7 +479,7 @@ class RunCommand extends RunCommandBase {
|
|||
throwToolExit(null);
|
||||
}
|
||||
if (globals.deviceManager.hasSpecifiedAllDevices && runningWithPrebuiltApplication) {
|
||||
throwToolExit('Using "-d all" with "--use-application-binary" is not supported');
|
||||
throwToolExit('Using "-d all" with "--${FlutterOptions.kUseApplicationBinary}" is not supported');
|
||||
}
|
||||
|
||||
if (userIdentifier != null
|
||||
|
@ -562,7 +557,7 @@ class RunCommand extends RunCommandBase {
|
|||
// debug mode.
|
||||
final BuildInfo buildInfo = await getBuildInfo();
|
||||
final bool hotMode = shouldUseHotMode(buildInfo);
|
||||
final String applicationBinaryPath = stringArg('use-application-binary');
|
||||
final String applicationBinaryPath = stringArg(FlutterOptions.kUseApplicationBinary);
|
||||
|
||||
if (boolArg('machine')) {
|
||||
if (devices.length > 1) {
|
||||
|
|
|
@ -117,6 +117,7 @@ class FlutterOptions {
|
|||
static const String kInitializeFromDill = 'initialize-from-dill';
|
||||
static const String kAssumeInitializeFromDillUpToDate = 'assume-initialize-from-dill-up-to-date';
|
||||
static const String kFatalWarnings = 'fatal-warnings';
|
||||
static const String kUseApplicationBinary = 'use-application-binary';
|
||||
}
|
||||
|
||||
/// flutter command categories for usage.
|
||||
|
@ -606,6 +607,16 @@ abstract class FlutterCommand extends Command<void> {
|
|||
);
|
||||
}
|
||||
|
||||
void usesApplicationBinaryOption() {
|
||||
argParser.addOption(
|
||||
FlutterOptions.kUseApplicationBinary,
|
||||
help: 'Specify a pre-built application binary to use when running. For Android applications, '
|
||||
'this must be the path to an APK. For iOS applications, the path to an IPA. Other device types '
|
||||
'do not yet support prebuilt application binaries.',
|
||||
valueHelp: 'path/to/app.apk',
|
||||
);
|
||||
}
|
||||
|
||||
/// Whether it is safe for this command to use a cached pub invocation.
|
||||
bool get cachePubGet => true;
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
// @dart = 2.8
|
||||
|
||||
import 'package:file/file.dart';
|
||||
import 'package:file/memory.dart';
|
||||
import 'package:flutter_tools/src/android/android_device.dart';
|
||||
import 'package:flutter_tools/src/android/application_package.dart';
|
||||
import 'package:flutter_tools/src/application_package.dart';
|
||||
|
@ -18,6 +19,7 @@ import 'package:test/fake.dart';
|
|||
|
||||
import '../../src/common.dart';
|
||||
import '../../src/context.dart';
|
||||
import '../../src/fake_process_manager.dart';
|
||||
import '../../src/test_flutter_command_runner.dart';
|
||||
|
||||
void main() {
|
||||
|
@ -26,6 +28,12 @@ void main() {
|
|||
Cache.disableLocking();
|
||||
});
|
||||
|
||||
FileSystem fileSystem;
|
||||
setUp(() {
|
||||
fileSystem = MemoryFileSystem.test();
|
||||
fileSystem.file('pubspec.yaml').createSync(recursive: true);
|
||||
});
|
||||
|
||||
testUsingContext('returns 0 when Android is connected and ready for an install', () async {
|
||||
final InstallCommand command = InstallCommand();
|
||||
command.applicationPackages = FakeApplicationPackageFactory(FakeAndroidApk());
|
||||
|
@ -36,6 +44,8 @@ void main() {
|
|||
await createTestCommandRunner(command).run(<String>['install']);
|
||||
}, overrides: <Type, Generator>{
|
||||
Cache: () => Cache.test(processManager: FakeProcessManager.any()),
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
});
|
||||
|
||||
testUsingContext('returns 1 when targeted device is not Android with --device-user', () async {
|
||||
|
@ -49,6 +59,8 @@ void main() {
|
|||
throwsToolExit(message: '--device-user is only supported for Android'));
|
||||
}, overrides: <Type, Generator>{
|
||||
Cache: () => Cache.test(processManager: FakeProcessManager.any()),
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
});
|
||||
|
||||
testUsingContext('returns 0 when iOS is connected and ready for an install', () async {
|
||||
|
@ -61,6 +73,38 @@ void main() {
|
|||
await createTestCommandRunner(command).run(<String>['install']);
|
||||
}, overrides: <Type, Generator>{
|
||||
Cache: () => Cache.test(processManager: FakeProcessManager.any()),
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
});
|
||||
|
||||
testUsingContext('fails when prebuilt binary not found', () async {
|
||||
final InstallCommand command = InstallCommand();
|
||||
command.applicationPackages = FakeApplicationPackageFactory(FakeAndroidApk());
|
||||
|
||||
final FakeAndroidDevice device = FakeAndroidDevice();
|
||||
testDeviceManager.addDevice(device);
|
||||
|
||||
expect(() async => createTestCommandRunner(command).run(<String>['install', '--use-application-binary', 'bogus']),
|
||||
throwsToolExit(message: 'Prebuilt binary bogus does not exist'));
|
||||
}, overrides: <Type, Generator>{
|
||||
Cache: () => Cache.test(processManager: FakeProcessManager.any()),
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
});
|
||||
|
||||
testUsingContext('succeeds using prebuilt binary', () async {
|
||||
final InstallCommand command = InstallCommand();
|
||||
command.applicationPackages = FakeApplicationPackageFactory(FakeAndroidApk());
|
||||
|
||||
final FakeAndroidDevice device = FakeAndroidDevice();
|
||||
testDeviceManager.addDevice(device);
|
||||
fileSystem.file('binary').createSync(recursive: true);
|
||||
|
||||
await createTestCommandRunner(command).run(<String>['install', '--use-application-binary', 'binary']);
|
||||
}, overrides: <Type, Generator>{
|
||||
Cache: () => Cache.test(processManager: FakeProcessManager.any()),
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue