mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Reland: Ensure that flutter run/drive/test/update_packages only downloads required artifacts (#30254)
This commit is contained in:
parent
99b4459944
commit
9baffb97ca
@ -65,7 +65,7 @@ class AnalyzeCommand extends FlutterCommand {
|
||||
String get description => "Analyze the project's Dart code.";
|
||||
|
||||
@override
|
||||
Set<DevelopmentArtifact> get requiredArtifacts => const <DevelopmentArtifact>{
|
||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{
|
||||
DevelopmentArtifact.universal,
|
||||
};
|
||||
|
||||
|
@ -16,7 +16,7 @@ import '../resident_runner.dart';
|
||||
import '../runner/flutter_command.dart';
|
||||
import 'build.dart';
|
||||
|
||||
class BuildAotCommand extends BuildSubCommand {
|
||||
class BuildAotCommand extends BuildSubCommand with TargetPlatformBasedDevelopmentArtifacts {
|
||||
BuildAotCommand() {
|
||||
usesTargetOption();
|
||||
addBuildModeFlags();
|
||||
|
@ -6,7 +6,7 @@ import 'dart:async';
|
||||
|
||||
import '../android/apk.dart';
|
||||
import '../project.dart';
|
||||
import '../runner/flutter_command.dart' show FlutterCommandResult;
|
||||
import '../runner/flutter_command.dart' show DevelopmentArtifact, FlutterCommandResult;
|
||||
import 'build.dart';
|
||||
|
||||
class BuildApkCommand extends BuildSubCommand {
|
||||
@ -34,6 +34,12 @@ class BuildApkCommand extends BuildSubCommand {
|
||||
@override
|
||||
final String name = 'apk';
|
||||
|
||||
@override
|
||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{
|
||||
DevelopmentArtifact.universal,
|
||||
DevelopmentArtifact.android,
|
||||
};
|
||||
|
||||
@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 '
|
||||
|
@ -10,7 +10,7 @@ import '../base/utils.dart';
|
||||
import '../build_info.dart';
|
||||
import '../globals.dart';
|
||||
import '../ios/mac.dart';
|
||||
import '../runner/flutter_command.dart' show FlutterCommandResult;
|
||||
import '../runner/flutter_command.dart' show DevelopmentArtifact, FlutterCommandResult;
|
||||
import 'build.dart';
|
||||
|
||||
class BuildIOSCommand extends BuildSubCommand {
|
||||
@ -48,6 +48,12 @@ class BuildIOSCommand extends BuildSubCommand {
|
||||
@override
|
||||
final String description = 'Build an iOS application bundle (Mac OS X host only).';
|
||||
|
||||
@override
|
||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{
|
||||
DevelopmentArtifact.universal,
|
||||
DevelopmentArtifact.iOS,
|
||||
};
|
||||
|
||||
@override
|
||||
Future<FlutterCommandResult> runCommand() async {
|
||||
final bool forSimulator = argResults['simulator'];
|
||||
|
@ -20,7 +20,7 @@ class BuildWebCommand extends BuildSubCommand {
|
||||
}
|
||||
|
||||
@override
|
||||
Set<DevelopmentArtifact> get requiredArtifacts => const <DevelopmentArtifact>{
|
||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{
|
||||
DevelopmentArtifact.universal,
|
||||
DevelopmentArtifact.web,
|
||||
};
|
||||
|
@ -31,6 +31,9 @@ class ChannelCommand extends FlutterCommand {
|
||||
@override
|
||||
String get invocation => '${runner.executableName} $name [<channel-name>]';
|
||||
|
||||
@override
|
||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{};
|
||||
|
||||
@override
|
||||
Future<FlutterCommandResult> runCommand() async {
|
||||
switch (argResults.rest.length) {
|
||||
|
@ -22,6 +22,9 @@ class CleanCommand extends FlutterCommand {
|
||||
@override
|
||||
final String description = 'Delete the build/ and .dart_tool/ directories.';
|
||||
|
||||
@override
|
||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{};
|
||||
|
||||
@override
|
||||
Future<FlutterCommandResult> runCommand() async {
|
||||
final FlutterProject flutterProject = await FlutterProject.current();
|
||||
|
@ -44,6 +44,9 @@ class ConfigCommand extends FlutterCommand {
|
||||
@override
|
||||
bool get shouldUpdateCache => false;
|
||||
|
||||
@override
|
||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{};
|
||||
|
||||
@override
|
||||
String get usageFooter {
|
||||
// List all config settings.
|
||||
|
@ -39,6 +39,11 @@ class FormatCommand extends FlutterCommand {
|
||||
@override
|
||||
final String description = 'Format one or more dart files.';
|
||||
|
||||
@override
|
||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{
|
||||
DevelopmentArtifact.universal,
|
||||
};
|
||||
|
||||
@override
|
||||
String get invocation => '${runner.executableName} $name <one or more paths>';
|
||||
|
||||
|
@ -21,6 +21,11 @@ class GenerateCommand extends FlutterCommand {
|
||||
@override
|
||||
bool get hidden => true;
|
||||
|
||||
@override
|
||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{
|
||||
DevelopmentArtifact.universal,
|
||||
};
|
||||
|
||||
@override
|
||||
Future<FlutterCommandResult> runCommand() async {
|
||||
Cache.releaseLockEarly();
|
||||
|
@ -42,6 +42,9 @@ class IdeConfigCommand extends FlutterCommand {
|
||||
@override
|
||||
final String name = 'ide-config';
|
||||
|
||||
@override
|
||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{};
|
||||
|
||||
@override
|
||||
final String description = 'Configure the IDE for use in the Flutter tree.\n\n'
|
||||
'If run on a Flutter tree that is already configured for the IDE, this '
|
||||
|
@ -23,6 +23,9 @@ class InjectPluginsCommand extends FlutterCommand {
|
||||
@override
|
||||
final bool hidden;
|
||||
|
||||
@override
|
||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{};
|
||||
|
||||
@override
|
||||
Future<FlutterCommandResult> runCommand() async {
|
||||
final FlutterProject project = await FlutterProject.current();
|
||||
|
@ -11,7 +11,7 @@ import '../device.dart';
|
||||
import '../globals.dart';
|
||||
import '../runner/flutter_command.dart';
|
||||
|
||||
class InstallCommand extends FlutterCommand {
|
||||
class InstallCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
|
||||
InstallCommand() {
|
||||
requiresPubspecYaml();
|
||||
}
|
||||
|
@ -26,6 +26,9 @@ class LogsCommand extends FlutterCommand {
|
||||
@override
|
||||
final String description = 'Show log output for running Flutter apps.';
|
||||
|
||||
@override
|
||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{};
|
||||
|
||||
Device device;
|
||||
|
||||
@override
|
||||
|
@ -27,6 +27,11 @@ class PackagesCommand extends FlutterCommand {
|
||||
@override
|
||||
final String description = 'Commands for managing Flutter packages.';
|
||||
|
||||
@override
|
||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{
|
||||
DevelopmentArtifact.universal,
|
||||
};
|
||||
|
||||
@override
|
||||
Future<FlutterCommandResult> runCommand() async => null;
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ import '../runner/flutter_command.dart';
|
||||
import '../tracing.dart';
|
||||
import 'daemon.dart';
|
||||
|
||||
abstract class RunCommandBase extends FlutterCommand {
|
||||
abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
|
||||
// Used by run and drive commands.
|
||||
RunCommandBase({ bool verboseHelp = false }) {
|
||||
addBuildModeFlags(defaultToRelease: false, verboseHelp: verboseHelp);
|
||||
@ -64,6 +64,7 @@ abstract class RunCommandBase extends FlutterCommand {
|
||||
}
|
||||
|
||||
bool get traceStartup => argResults['trace-startup'];
|
||||
|
||||
String get route => argResults['route'];
|
||||
}
|
||||
|
||||
|
@ -86,6 +86,11 @@ class TestCommand extends FastFlutterCommand {
|
||||
valueHelp: 'jobs');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => <DevelopmentArtifact>{
|
||||
DevelopmentArtifact.universal,
|
||||
};
|
||||
|
||||
@override
|
||||
String get name => 'test';
|
||||
|
||||
@ -94,7 +99,7 @@ class TestCommand extends FastFlutterCommand {
|
||||
|
||||
@override
|
||||
Future<FlutterCommandResult> runCommand() async {
|
||||
await cache.updateAll(requiredArtifacts);
|
||||
await cache.updateAll(await requiredArtifacts);
|
||||
if (!fs.isFileSync('pubspec.yaml')) {
|
||||
throwToolExit(
|
||||
'Error: No pubspec.yaml file found in the current working directory.\n'
|
||||
|
@ -84,6 +84,11 @@ class UpdatePackagesCommand extends FlutterCommand {
|
||||
@override
|
||||
final bool hidden;
|
||||
|
||||
@override
|
||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => <DevelopmentArtifact>{
|
||||
DevelopmentArtifact.universal,
|
||||
};
|
||||
|
||||
Future<void> _downloadCoverageData() async {
|
||||
final Status status = logger.startProgress(
|
||||
'Downloading lcov data for package:flutter...',
|
||||
|
@ -36,6 +36,11 @@ class UpgradeCommand extends FlutterCommand {
|
||||
@override
|
||||
bool get shouldUpdateCache => false;
|
||||
|
||||
@override
|
||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => <DevelopmentArtifact>{
|
||||
DevelopmentArtifact.universal,
|
||||
};
|
||||
|
||||
@override
|
||||
Future<FlutterCommandResult> runCommand() async {
|
||||
final UpgradeCommandRunner upgradeCommandRunner = UpgradeCommandRunner();
|
||||
|
@ -540,7 +540,7 @@ abstract class FlutterCommand extends Command<void> {
|
||||
// Populate the cache. We call this before pub get below so that the sky_engine
|
||||
// package is available in the flutter cache for pub to find.
|
||||
if (shouldUpdateCache) {
|
||||
await cache.updateAll(requiredArtifacts);
|
||||
await cache.updateAll(await requiredArtifacts);
|
||||
}
|
||||
|
||||
if (shouldRunPub) {
|
||||
@ -563,7 +563,7 @@ abstract class FlutterCommand extends Command<void> {
|
||||
///
|
||||
/// Defaults to [DevelopmentArtifact.universal],
|
||||
/// [DevelopmentArtifact.android], and [DevelopmentArtifact.iOS].
|
||||
Set<DevelopmentArtifact> get requiredArtifacts => const <DevelopmentArtifact>{
|
||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{
|
||||
DevelopmentArtifact.universal,
|
||||
DevelopmentArtifact.iOS,
|
||||
DevelopmentArtifact.android,
|
||||
@ -689,6 +689,90 @@ abstract class FlutterCommand extends Command<void> {
|
||||
ApplicationPackageStore applicationPackages;
|
||||
}
|
||||
|
||||
/// A mixin which applies an implementation of [requiredArtifacts] that only
|
||||
/// downloads artifacts corresponding to an attached device.
|
||||
mixin DeviceBasedDevelopmentArtifacts on FlutterCommand {
|
||||
@override
|
||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async {
|
||||
// If there are no attached devices, use the default configuration.
|
||||
// Otherwise, only add development artifacts which correspond to a
|
||||
// connected device.
|
||||
final List<Device> devices = await deviceManager.getDevices().toList();
|
||||
if (devices.isEmpty) {
|
||||
return super.requiredArtifacts;
|
||||
}
|
||||
final Set<DevelopmentArtifact> artifacts = <DevelopmentArtifact>{
|
||||
DevelopmentArtifact.universal,
|
||||
};
|
||||
for (Device device in devices) {
|
||||
final TargetPlatform targetPlatform = await device.targetPlatform;
|
||||
switch (targetPlatform) {
|
||||
case TargetPlatform.android_arm:
|
||||
case TargetPlatform.android_arm64:
|
||||
case TargetPlatform.android_x64:
|
||||
case TargetPlatform.android_x86:
|
||||
artifacts.add(DevelopmentArtifact.android);
|
||||
break;
|
||||
case TargetPlatform.web:
|
||||
artifacts.add(DevelopmentArtifact.web);
|
||||
break;
|
||||
case TargetPlatform.ios:
|
||||
artifacts.add(DevelopmentArtifact.iOS);
|
||||
break;
|
||||
case TargetPlatform.darwin_x64:
|
||||
case TargetPlatform.fuchsia:
|
||||
case TargetPlatform.tester:
|
||||
case TargetPlatform.windows_x64:
|
||||
case TargetPlatform.linux_x64:
|
||||
// No artifacts currently supported.
|
||||
break;
|
||||
}
|
||||
}
|
||||
return artifacts;
|
||||
}
|
||||
}
|
||||
|
||||
/// A mixin which applies an implementation of [requiredArtifacts] that only
|
||||
/// downloads artifacts corresponding to a target device.
|
||||
mixin TargetPlatformBasedDevelopmentArtifacts on FlutterCommand {
|
||||
@override
|
||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async {
|
||||
// If there is no specified target device, fallback to the default
|
||||
// confiugration.
|
||||
final String rawTargetPlatform = argResults['target-platform'];
|
||||
final TargetPlatform targetPlatform = getTargetPlatformForName(rawTargetPlatform);
|
||||
if (targetPlatform == null) {
|
||||
return super.requiredArtifacts;
|
||||
}
|
||||
|
||||
final Set<DevelopmentArtifact> artifacts = <DevelopmentArtifact>{
|
||||
DevelopmentArtifact.universal,
|
||||
};
|
||||
switch (targetPlatform) {
|
||||
case TargetPlatform.android_arm:
|
||||
case TargetPlatform.android_arm64:
|
||||
case TargetPlatform.android_x64:
|
||||
case TargetPlatform.android_x86:
|
||||
artifacts.add(DevelopmentArtifact.android);
|
||||
break;
|
||||
case TargetPlatform.web:
|
||||
artifacts.add(DevelopmentArtifact.web);
|
||||
break;
|
||||
case TargetPlatform.ios:
|
||||
artifacts.add(DevelopmentArtifact.iOS);
|
||||
break;
|
||||
case TargetPlatform.darwin_x64:
|
||||
case TargetPlatform.fuchsia:
|
||||
case TargetPlatform.tester:
|
||||
case TargetPlatform.windows_x64:
|
||||
case TargetPlatform.linux_x64:
|
||||
// No artifacts currently supported.
|
||||
break;
|
||||
}
|
||||
return artifacts;
|
||||
}
|
||||
}
|
||||
|
||||
/// A command which runs less analytics and checks to speed up startup time.
|
||||
abstract class FastFlutterCommand extends FlutterCommand {
|
||||
@override
|
||||
|
@ -3,13 +3,19 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter_tools/src/base/common.dart';
|
||||
import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/commands/run.dart';
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:flutter_tools/src/runner/flutter_command.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import '../src/common.dart';
|
||||
import '../src/context.dart';
|
||||
import '../src/mocks.dart';
|
||||
|
||||
void main() {
|
||||
final MockDeviceManager mockDeviceManager = MockDeviceManager();
|
||||
|
||||
group('run', () {
|
||||
testUsingContext('fails when target not found', () async {
|
||||
final RunCommand command = RunCommand();
|
||||
@ -21,5 +27,65 @@ void main() {
|
||||
expect(e.exitCode ?? 1, 1);
|
||||
}
|
||||
});
|
||||
|
||||
testUsingContext('should only request artifacts corresponding to connected devices', () async {
|
||||
when(mockDeviceManager.getDevices()).thenAnswer((Invocation invocation) {
|
||||
return Stream<Device>.fromIterable(<Device>[
|
||||
MockDevice(TargetPlatform.android_arm),
|
||||
]);
|
||||
});
|
||||
|
||||
expect(await RunCommand().requiredArtifacts, unorderedEquals(<DevelopmentArtifact>{
|
||||
DevelopmentArtifact.universal,
|
||||
DevelopmentArtifact.android,
|
||||
}));
|
||||
|
||||
when(mockDeviceManager.getDevices()).thenAnswer((Invocation invocation) {
|
||||
return Stream<Device>.fromIterable(<Device>[
|
||||
MockDevice(TargetPlatform.ios),
|
||||
]);
|
||||
});
|
||||
|
||||
expect(await RunCommand().requiredArtifacts, unorderedEquals(<DevelopmentArtifact>{
|
||||
DevelopmentArtifact.universal,
|
||||
DevelopmentArtifact.iOS,
|
||||
}));
|
||||
|
||||
when(mockDeviceManager.getDevices()).thenAnswer((Invocation invocation) {
|
||||
return Stream<Device>.fromIterable(<Device>[
|
||||
MockDevice(TargetPlatform.ios),
|
||||
MockDevice(TargetPlatform.android_arm),
|
||||
]);
|
||||
});
|
||||
|
||||
expect(await RunCommand().requiredArtifacts, unorderedEquals(<DevelopmentArtifact>{
|
||||
DevelopmentArtifact.universal,
|
||||
DevelopmentArtifact.iOS,
|
||||
DevelopmentArtifact.android,
|
||||
}));
|
||||
|
||||
when(mockDeviceManager.getDevices()).thenAnswer((Invocation invocation) {
|
||||
return Stream<Device>.fromIterable(<Device>[
|
||||
MockDevice(TargetPlatform.web),
|
||||
]);
|
||||
});
|
||||
|
||||
expect(await RunCommand().requiredArtifacts, unorderedEquals(<DevelopmentArtifact>{
|
||||
DevelopmentArtifact.universal,
|
||||
DevelopmentArtifact.web,
|
||||
}));
|
||||
}, overrides: <Type, Generator>{
|
||||
DeviceManager: () => mockDeviceManager,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class MockDeviceManager extends Mock implements DeviceManager {}
|
||||
class MockDevice extends Mock implements Device {
|
||||
MockDevice(this._targetPlatform);
|
||||
|
||||
final TargetPlatform _targetPlatform;
|
||||
|
||||
@override
|
||||
Future<TargetPlatform> get targetPlatform async => _targetPlatform;
|
||||
}
|
@ -14,7 +14,7 @@ typedef CommandFunction = Future<FlutterCommandResult> Function();
|
||||
class DummyFlutterCommand extends FlutterCommand {
|
||||
|
||||
DummyFlutterCommand({
|
||||
this.shouldUpdateCache = false,
|
||||
this.shouldUpdateCache = false,
|
||||
this.noUsagePath = false,
|
||||
this.commandFunction,
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user