diff --git a/.ci.yaml b/.ci.yaml index f1764a4e624c9..6f00385c4c4a6 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -3270,7 +3270,6 @@ targets: - name: Mac_arm64_android run_debug_test_android recipe: devicelab/devicelab_drone - bringup: true presubmit: false runIf: - dev/** @@ -3974,7 +3973,6 @@ targets: - name: Mac_arm64_ios run_debug_test_macos recipe: devicelab/devicelab_drone - bringup: true timeout: 60 properties: tags: > @@ -4303,7 +4301,6 @@ targets: - name: Windows run_debug_test_windows recipe: devicelab/devicelab_drone - bringup: true presubmit: false timeout: 60 properties: diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8e43cc8e5f5dd..f44d1d2b3c30d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -687e3cb0fbe2fd7006d8d0dcd642471c2d3363fe +6256f05db145b2bb8b690901cf128389599e0282 diff --git a/bin/internal/flutter_plugins.version b/bin/internal/flutter_plugins.version index 513c401bb6334..5328797297ae9 100644 --- a/bin/internal/flutter_plugins.version +++ b/bin/internal/flutter_plugins.version @@ -1 +1 @@ -0a0e3d205ca32fdeebe237262e6ac824b3f3d51f +9fdc899b72cac49a4ffade799563c4730c0279a8 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 391920b009eb4..d5422472020e9 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -zC90VpkAGMG1jJ-BKmFqF8gWp4vYu6FGaFAwUXf9QWMC +a9NpYJbjhDRX9P9u4EU-v-v3y5U7jG4VvhvYLzR8a9QC diff --git a/dev/bots/test.dart b/dev/bots/test.dart index e6919b72ab888..48ad19c23fc5b 100644 --- a/dev/bots/test.dart +++ b/dev/bots/test.dart @@ -1236,7 +1236,6 @@ Future _runWebLongRunningTests() async { () => _runWebDebugTest('lib/framework_stack_trace.dart'), () => _runWebDebugTest('lib/web_directory_loading.dart'), () => _runWebDebugTest('test/test.dart'), - () => _runWebDebugTest('lib/null_assert_main.dart', enableNullSafety: true), () => _runWebDebugTest('lib/null_safe_main.dart', enableNullSafety: true), () => _runWebDebugTest('lib/web_define_loading.dart', additionalArguments: [ diff --git a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml index 269023793aa30..2f83c7024a859 100644 --- a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml +++ b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml @@ -9,9 +9,9 @@ dependencies: sdk: flutter camera: 0.10.1 - camera_android: 0.10.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - camera_avfoundation: 0.9.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - camera_platform_interface: 2.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + camera_android: 0.10.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + camera_avfoundation: 0.9.10+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + camera_platform_interface: 2.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_web: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.17.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -31,4 +31,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: eabf +# PUBSPEC CHECKSUM: 7d79 diff --git a/dev/integration_tests/web/lib/null_assert_main.dart b/dev/integration_tests/web/lib/null_assert_main.dart deleted file mode 100644 index e9588628ccdf7..0000000000000 --- a/dev/integration_tests/web/lib/null_assert_main.dart +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// ignore_for_file: enable_null_safety - -// @dart = 2.8 - -import 'null_enabled_api.dart'; - -void main() { - dynamic error; - try { - // Validate that a generated null assertion is thrown. - methodThatAcceptsNonNull(null); - } catch (err) { - error = err; - } - if (error is AssertionError) { - print('--- TEST SUCCEEDED ---'); - } else { - print('--- TEST FAILED ---'); - } -} diff --git a/examples/api/lib/cupertino/picker/cupertino_picker.0.dart b/examples/api/lib/cupertino/picker/cupertino_picker.0.dart index ca626d29c8449..73d57cc11d103 100644 --- a/examples/api/lib/cupertino/picker/cupertino_picker.0.dart +++ b/examples/api/lib/cupertino/picker/cupertino_picker.0.dart @@ -29,6 +29,7 @@ class CupertinoPickerApp extends StatelessWidget { ); } } + class CupertinoPickerExample extends StatefulWidget { const CupertinoPickerExample({super.key}); @@ -57,7 +58,7 @@ class _CupertinoPickerExampleState extends State { top: false, child: child, ), - ) + ), ); } @@ -86,6 +87,10 @@ class _CupertinoPickerExampleState extends State { squeeze: 1.2, useMagnifier: true, itemExtent: _kItemExtent, + // This sets the initial item. + scrollController: FixedExtentScrollController( + initialItem: _selectedFruit, + ), // This is called when selected item is changed. onSelectedItemChanged: (int selectedItem) { setState(() { @@ -93,16 +98,13 @@ class _CupertinoPickerExampleState extends State { }); }, children: List.generate(_fruitNames.length, (int index) { - return Center( - child: Text( - _fruitNames[index], - ), - ); + return Center(child: Text(_fruitNames[index])); }), ), ), // This displays the selected fruit name. - child: Text(_fruitNames[_selectedFruit], + child: Text( + _fruitNames[_selectedFruit], style: const TextStyle( fontSize: 22.0, ), diff --git a/examples/api/test/cupertino/picker/cupertino_picker.0_test.dart b/examples/api/test/cupertino/picker/cupertino_picker.0_test.dart index f2e9a97fa6050..178764ae7c447 100644 --- a/examples/api/test/cupertino/picker/cupertino_picker.0_test.dart +++ b/examples/api/test/cupertino/picker/cupertino_picker.0_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:flutter/cupertino.dart'; import 'package:flutter_api_samples/cupertino/picker/cupertino_picker.0.dart' as example; import 'package:flutter_test/flutter_test.dart'; @@ -14,12 +15,15 @@ void main() { ); // Open the Cupertino picker. - await tester.tap(find.text('Apple')); + await tester.tap(find.widgetWithText(CupertinoButton, 'Apple')); await tester.pumpAndSettle(); + // Test the initial item. + CupertinoPicker picker = tester.widget(find.byType(CupertinoPicker)); + expect(picker.scrollController!.initialItem, 0); + // Drag the wheel to change fruit selection. await tester.drag(find.text('Mango'), _kRowOffset, touchSlopY: 0, warnIfMissed: false); // see top of file - await tester.pump(); await tester.pump(const Duration(milliseconds: 500)); @@ -27,6 +31,13 @@ void main() { await tester.tapAt(const Offset(1.0, 1.0)); await tester.pumpAndSettle(); - expect(find.text('Banana'), findsOneWidget); + expect(find.widgetWithText(CupertinoButton, 'Banana'), findsOneWidget); + + // Test if the initial item has updated. + await tester.tap(find.widgetWithText(CupertinoButton, 'Banana')); + await tester.pumpAndSettle(); + + picker = tester.widget(find.byType(CupertinoPicker)); + expect(picker.scrollController!.initialItem, 2); }); } diff --git a/packages/flutter/lib/src/material/page_transitions_theme.dart b/packages/flutter/lib/src/material/page_transitions_theme.dart index ce9415079897e..168003077cdc5 100644 --- a/packages/flutter/lib/src/material/page_transitions_theme.dart +++ b/packages/flutter/lib/src/material/page_transitions_theme.dart @@ -157,6 +157,7 @@ class _ZoomPageTransition extends StatelessWidget { required this.animation, required this.secondaryAnimation, required this.allowSnapshotting, + required this.allowEnterRouteSnapshotting, this.child, }) : assert(animation != null), assert(secondaryAnimation != null); @@ -207,6 +208,15 @@ class _ZoomPageTransition extends StatelessWidget { /// [secondaryAnimation]. final Widget? child; + /// Whether to enable snapshotting on the entering route during the + /// transition animation. + /// + /// If not specified, defaults to true. + /// If false, the route snapshotting will not be applied to the route being + /// animating into, e.g. when transitioning from route A to route B, B will + /// not be snapshotted. + final bool allowEnterRouteSnapshotting; + @override Widget build(BuildContext context) { return DualTransitionBuilder( @@ -218,7 +228,7 @@ class _ZoomPageTransition extends StatelessWidget { ) { return _ZoomEnterTransition( animation: animation, - allowSnapshotting: allowSnapshotting, + allowSnapshotting: allowSnapshotting && allowEnterRouteSnapshotting, child: child, ); }, @@ -243,7 +253,7 @@ class _ZoomPageTransition extends StatelessWidget { ) { return _ZoomEnterTransition( animation: animation, - allowSnapshotting: allowSnapshotting, + allowSnapshotting: allowSnapshotting && allowEnterRouteSnapshotting , reverse: true, child: child, ); @@ -596,7 +606,18 @@ class OpenUpwardsPageTransitionsBuilder extends PageTransitionsBuilder { class ZoomPageTransitionsBuilder extends PageTransitionsBuilder { /// Constructs a page transition animation that matches the transition used on /// Android Q. - const ZoomPageTransitionsBuilder(); + const ZoomPageTransitionsBuilder({ + this.allowEnterRouteSnapshotting = true, + }); + + /// Whether to enable snapshotting on the entering route during the + /// transition animation. + /// + /// If not specified, defaults to true. + /// If false, the route snapshotting will not be applied to the route being + /// animating into, e.g. when transitioning from route A to route B, B will + /// not be snapshotted. + final bool allowEnterRouteSnapshotting; @override Widget buildTransitions( @@ -610,6 +631,7 @@ class ZoomPageTransitionsBuilder extends PageTransitionsBuilder { animation: animation, secondaryAnimation: secondaryAnimation, allowSnapshotting: route?.allowSnapshotting ?? true, + allowEnterRouteSnapshotting: allowEnterRouteSnapshotting, child: child, ); } diff --git a/packages/flutter/test/material/page_test.dart b/packages/flutter/test/material/page_test.dart index 0296c25bcddde..87d9d6211c625 100644 --- a/packages/flutter/test/material/page_test.dart +++ b/packages/flutter/test/material/page_test.dart @@ -287,6 +287,89 @@ void main() { } }, variant: TargetPlatformVariant.only(TargetPlatform.android), skip: kIsWeb); // [intended] rasterization is not used on the web. + + testWidgets( + 'test page transition (_ZoomPageTransition) with rasterization disables snapshotting for enter route', + (WidgetTester tester) async { + Iterable findLayers(Finder of) { + return tester.layerListOf( + find.ancestor(of: of, matching: find.byType(SnapshotWidget)).first, + ); + } + + bool isTransitioningWithoutSnapshotting(Finder of) { + // When snapshotting is off, the OpacityLayer and TransformLayer will be + // applied directly. + final Iterable layers = findLayers(of); + return layers.whereType().length == 1 && + layers.whereType().length == 1; + } + + bool isSnapshotted(Finder of) { + final Iterable layers = findLayers(of); + // The scrim and the snapshot image are the only two layers. + return layers.length == 2 && + layers.whereType().length == 1 && + layers.whereType().length == 1; + } + + await tester.pumpWidget( + MaterialApp( + routes: { + '/1': (_) => const Material(child: Text('Page 1')), + '/2': (_) => const Material(child: Text('Page 2')), + }, + initialRoute: '/1', + builder: (BuildContext context, Widget? child) { + final ThemeData themeData = Theme.of(context); + return Theme( + data: themeData.copyWith( + pageTransitionsTheme: PageTransitionsTheme( + builders: { + ...themeData.pageTransitionsTheme.builders, + TargetPlatform.android: const ZoomPageTransitionsBuilder( + allowEnterRouteSnapshotting: false, + ), + }, + ), + ), + child: Builder(builder: (_) => child!), + ); + }, + ), + ); + + final Finder page1Finder = find.text('Page 1'); + final Finder page2Finder = find.text('Page 2'); + + // Page 1 on top. + expect(isSnapshotted(page1Finder), isFalse); + + // Transitioning from page 1 to page 2. + tester.state(find.byType(Navigator)).pushNamed('/2'); + await tester.pump(); + await tester.pump(const Duration(milliseconds: 50)); + + expect(isSnapshotted(page1Finder), isTrue); + expect(isTransitioningWithoutSnapshotting(page2Finder), isTrue); + + // Page 2 on top. + await tester.pumpAndSettle(); + expect(isSnapshotted(page2Finder), isFalse); + + // Transitioning back from page 2 to page 1. + tester.state(find.byType(Navigator)).pop(); + await tester.pump(); + await tester.pump(const Duration(milliseconds: 50)); + + expect(isTransitioningWithoutSnapshotting(page1Finder), isTrue); + expect(isSnapshotted(page2Finder), isTrue); + + // Page 1 on top. + await tester.pumpAndSettle(); + expect(isSnapshotted(page1Finder), isFalse); + }, variant: TargetPlatformVariant.only(TargetPlatform.android), skip: kIsWeb); // [intended] rasterization is not used on the web. + testWidgets('test fullscreen dialog transition', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( diff --git a/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart b/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart index f9783e28b1737..1d3f7d9dfab3c 100644 --- a/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart +++ b/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart @@ -13227,7 +13227,7 @@ class MaterialLocalizationFi extends GlobalMaterialLocalizations { String get tabLabelRaw => r'Välilehti $tabIndex/$tabCount'; @override - TimeOfDayFormat get timeOfDayFormatRaw => TimeOfDayFormat.HH_colon_mm; + TimeOfDayFormat get timeOfDayFormatRaw => TimeOfDayFormat.HH_dot_mm; @override String get timePickerDialHelpText => 'VALITSE AIKA'; diff --git a/packages/flutter_localizations/lib/src/l10n/material_fi.arb b/packages/flutter_localizations/lib/src/l10n/material_fi.arb index 5459422ecae89..451d30d8c5e09 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_fi.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_fi.arb @@ -1,6 +1,6 @@ { "scriptCategory": "English-like", - "timeOfDayFormat": "HH:mm", + "timeOfDayFormat": "HH.mm", "openAppDrawerTooltip": "Avaa navigointivalikko", "backButtonTooltip": "Takaisin", "closeButtonTooltip": "Sulje", diff --git a/packages/flutter_localizations/test/material/date_time_test.dart b/packages/flutter_localizations/test/material/date_time_test.dart index 5b544b8a131b0..9b32c582bd78e 100644 --- a/packages/flutter_localizations/test/material/date_time_test.dart +++ b/packages/flutter_localizations/test/material/date_time_test.dart @@ -107,6 +107,11 @@ void main() { expect(await formatTimeOfDay(tester, const Locale('ja'), const TimeOfDay(hour: 20, minute: 32)), '20:32'); }); + testWidgets('formats ${TimeOfDayFormat.HH_dot_mm}', (WidgetTester tester) async { + expect(await formatTimeOfDay(tester, const Locale('fi'), const TimeOfDay(hour: 20, minute: 32)), '20.32'); + expect(await formatTimeOfDay(tester, const Locale('fi'), const TimeOfDay(hour: 9, minute: 32)), '09.32'); + }); + testWidgets('formats ${TimeOfDayFormat.frenchCanadian}', (WidgetTester tester) async { expect(await formatTimeOfDay(tester, const Locale('fr', 'CA'), const TimeOfDay(hour: 9, minute: 32)), '09 h 32'); }); diff --git a/packages/flutter_tools/lib/src/commands/packages.dart b/packages/flutter_tools/lib/src/commands/packages.dart index 14503a03b2f52..b65e3177b1fb6 100644 --- a/packages/flutter_tools/lib/src/commands/packages.dart +++ b/packages/flutter_tools/lib/src/commands/packages.dart @@ -20,10 +20,10 @@ import '../runner/flutter_command.dart'; class PackagesCommand extends FlutterCommand { PackagesCommand() { - addSubcommand(PackagesGetCommand('get', false)); - addSubcommand(PackagesInteractiveGetCommand('upgrade', "Upgrade the current package's dependencies to latest versions.")); - addSubcommand(PackagesInteractiveGetCommand('add', 'Add a dependency to pubspec.yaml.')); - addSubcommand(PackagesInteractiveGetCommand('remove', 'Removes a dependency from the current package.')); + addSubcommand(PackagesGetCommand('get', "Get the current package's dependencies.", PubContext.pubGet)); + addSubcommand(PackagesGetCommand('upgrade', "Upgrade the current package's dependencies to latest versions.", PubContext.pubUpgrade)); + addSubcommand(PackagesGetCommand('add', 'Add a dependency to pubspec.yaml.', PubContext.pubAdd)); + addSubcommand(PackagesGetCommand('remove', 'Removes a dependency from the current package.', PubContext.pubRemove)); addSubcommand(PackagesTestCommand()); addSubcommand(PackagesForwardCommand('publish', 'Publish the current package to pub.dartlang.org.', requiresPubspec: true)); addSubcommand(PackagesForwardCommand('downgrade', 'Downgrade packages in a Flutter project.', requiresPubspec: true)); @@ -56,136 +56,6 @@ class PackagesCommand extends FlutterCommand { Future runCommand() async => FlutterCommandResult.fail(); } -class PackagesGetCommand extends FlutterCommand { - PackagesGetCommand(this.name, this.upgrade) { - argParser.addFlag('offline', - negatable: false, - help: 'Use cached packages instead of accessing the network.', - ); - } - - @override - final String name; - - final bool upgrade; - - @override - String get description { - return '${ upgrade ? "Upgrade" : "Get" } packages in a Flutter project.'; - } - - @override - String get invocation { - return '${runner!.executableName} pub $name []'; - } - - /// The pub packages usage values are incorrect since these are calculated/sent - /// before pub get completes. This needs to be performed after dependency resolution. - @override - Future get usageValues async { - final ArgResults argumentResults = argResults!; - final String? workingDirectory = argumentResults.rest.length == 1 ? argumentResults.rest[0] : null; - final String? target = findProjectRoot(globals.fs, workingDirectory); - if (target == null) { - return const CustomDimensions(); - } - - int numberPlugins; - - final FlutterProject rootProject = FlutterProject.fromDirectory(globals.fs.directory(target)); - // Do not send plugin analytics if pub has not run before. - final bool hasPlugins = rootProject.flutterPluginsDependenciesFile.existsSync() - && rootProject.packageConfigFile.existsSync(); - if (hasPlugins) { - // Do not fail pub get if package config files are invalid before pub has - // had a chance to run. - final List plugins = await findPlugins(rootProject, throwOnError: false); - numberPlugins = plugins.length; - } else { - numberPlugins = 0; - } - - return CustomDimensions( - commandPackagesNumberPlugins: numberPlugins, - commandPackagesProjectModule: rootProject.isModule, - commandPackagesAndroidEmbeddingVersion: rootProject.android.getEmbeddingVersion().toString().split('.').last, - ); - } - - Future _runPubGet(String directory, FlutterProject flutterProject) async { - if (flutterProject.manifest.generateSyntheticPackage) { - final Environment environment = Environment( - artifacts: globals.artifacts!, - logger: globals.logger, - cacheDir: globals.cache.getRoot(), - engineVersion: globals.flutterVersion.engineRevision, - fileSystem: globals.fs, - flutterRootDir: globals.fs.directory(Cache.flutterRoot), - outputDir: globals.fs.directory(getBuildDirectory()), - processManager: globals.processManager, - platform: globals.platform, - usage: globals.flutterUsage, - projectDir: flutterProject.directory, - generateDartPluginRegistry: true, - ); - - await generateLocalizationsSyntheticPackage( - environment: environment, - buildSystem: globals.buildSystem, - ); - } - - final Stopwatch pubGetTimer = Stopwatch()..start(); - try { - await pub.get( - context: PubContext.pubGet, - project: flutterProject, - upgrade: upgrade, - shouldSkipThirdPartyGenerator: false, - offline: boolArgDeprecated('offline'), - ); - pubGetTimer.stop(); - globals.flutterUsage.sendTiming('pub', 'get', pubGetTimer.elapsed, label: 'success'); - // Not limiting to catching Exception because the exception is rethrown. - } catch (_) { // ignore: avoid_catches_without_on_clauses - pubGetTimer.stop(); - globals.flutterUsage.sendTiming('pub', 'get', pubGetTimer.elapsed, label: 'failure'); - rethrow; - } - } - - @override - Future runCommand() async { - final ArgResults argumentResults = argResults!; - if (argumentResults.rest.length > 1) { - throwToolExit('Too many arguments.\n$usage'); - } - - final String? workingDirectory = argumentResults.rest.length == 1 ? argumentResults.rest[0] : null; - final String? target = findProjectRoot(globals.fs, workingDirectory); - if (target == null) { - throwToolExit( - 'Expected to find project root in ' - '${ workingDirectory ?? "current working directory" }.' - ); - } - final FlutterProject rootProject = FlutterProject.fromDirectory(globals.fs.directory(target)); - - // This will also resolve dependencies for the example folder, - await _runPubGet(target, rootProject); - - // We need to regenerate the platform specific tooling for both the project - // itself and example (if present). - await rootProject.regeneratePlatformSpecificTooling(); - if (rootProject.hasExampleApp && rootProject.example.pubspecFile.existsSync()) { - final FlutterProject exampleProject = rootProject.example; - await exampleProject.regeneratePlatformSpecificTooling(); - } - - return FlutterCommandResult.success(); - } -} - class PackagesTestCommand extends FlutterCommand { PackagesTestCommand() { requiresPubspecYaml(); @@ -223,6 +93,8 @@ class PackagesForwardCommand extends FlutterCommand { } } + PubContext context = PubContext.pubForward; + @override ArgParser argParser = ArgParser.allowAnything(); @@ -247,7 +119,11 @@ class PackagesForwardCommand extends FlutterCommand { Future runCommand() async { final List subArgs = argResults!.rest.toList() ..removeWhere((String arg) => arg == '--'); - await pub.interactively([_commandName, ...subArgs], stdio: globals.stdio); + await pub.interactively( + [ _commandName, ...subArgs], + context: context, + command: _commandName, + ); return FlutterCommandResult.success(); } } @@ -270,21 +146,31 @@ class PackagesPassthroughCommand extends FlutterCommand { return '${runner!.executableName} packages pub []'; } + static final PubContext _context = PubContext.pubPassThrough; + @override Future runCommand() async { - await pub.interactively(argResults!.rest, stdio: globals.stdio); + await pub.interactively( + command: 'pub', + argResults!.rest, + context: _context, + ); return FlutterCommandResult.success(); } } -class PackagesInteractiveGetCommand extends FlutterCommand { - PackagesInteractiveGetCommand(this._commandName, this._description); +/// Represents the pub sub-commands that makes package-resolutions. +class PackagesGetCommand extends FlutterCommand { + PackagesGetCommand(this._commandName, this._description, this._context); @override ArgParser argParser = ArgParser.allowAnything(); final String _commandName; final String _description; + final PubContext _context; + + FlutterProject? _rootProject; @override String get name => _commandName; @@ -300,29 +186,89 @@ class PackagesInteractiveGetCommand extends FlutterCommand { return '${runner!.executableName} pub $_commandName []'; } + /// An [ArgParser] that accepts all options and flags that the + /// + /// `pub get` + /// `pub upgrade` + /// `pub downgrade` + /// `pub add` + /// `pub remove` + /// + /// commands accept. + ArgParser get _permissiveArgParser { + final ArgParser argParser = ArgParser(); + argParser.addOption('directory', abbr: 'C'); + argParser.addFlag('offline'); + argParser.addFlag('dry-run', abbr: 'n'); + argParser.addFlag('help', abbr: 'h'); + argParser.addFlag('enforce-lockfile'); + argParser.addFlag('precompile'); + argParser.addFlag('major-versions'); + argParser.addFlag('null-safety'); + argParser.addFlag('example', defaultsTo: true); + argParser.addOption('sdk'); + argParser.addOption('path'); + argParser.addOption('hosted-url'); + argParser.addOption('git-url'); + argParser.addOption('git-ref'); + argParser.addOption('git-path'); + argParser.addFlag('dev'); + return argParser; + } + @override Future runCommand() async { List rest = argResults!.rest; - final bool isHelp = rest.contains('-h') || rest.contains('--help'); - String? target; - if (rest.length == 1 && (rest.single.contains('/') || rest.single.contains(r'\'))) { - // For historical reasons, if there is one argument to the command and it contains - // a multiple-component path (i.e. contains a slash) then we use that to determine - // to which project we're applying the command. - target = findProjectRoot(globals.fs, rest.single); - rest = []; - } else { - target = findProjectRoot(globals.fs); + bool isHelp = false; + bool example = true; + bool exampleWasParsed = false; + String? directoryOption; + bool dryRun = false; + try { + final ArgResults results = _permissiveArgParser.parse(rest); + isHelp = results['help'] as bool; + directoryOption = results['directory'] as String?; + example = results['example'] as bool; + exampleWasParsed = results.wasParsed('example'); + dryRun = results['dry-run'] as bool; + } on ArgParserException { + // Let pub give the error message. } + String? target; + FlutterProject? rootProject; - FlutterProject? flutterProject; if (!isHelp) { - if (target == null) { - throwToolExit('Expected to find project root in current working directory.'); + if (directoryOption == null && rest.length == 1 && + ((rest.single.contains('/') || rest.single.contains(r'\')) || + name == 'get')) { + // For historical reasons, if there is one argument to the command and it contains + // a multiple-component path (i.e. contains a slash) then we use that to determine + // to which project we're applying the command. + target = findProjectRoot(globals.fs, rest.single); + + globals.printWarning(''' + Using a naked argument for directory is deprecated and will stop working in a future Flutter release. + + Use --directory instead.'''); + if (target == null) { + throwToolExit('Expected to find project root in ${rest.single}.'); + } + rest = []; + } else { + target = findProjectRoot(globals.fs, directoryOption); + if (target == null) { + if (directoryOption == null) { + throwToolExit('Expected to find project root in current working directory.'); + } else { + throwToolExit('Expected to find project root in $directoryOption.'); + } + } } - flutterProject = FlutterProject.fromDirectory(globals.fs.directory(target)); - if (flutterProject.manifest.generateSyntheticPackage) { + rootProject = FlutterProject.fromDirectory(globals.fs.directory(target)); + _rootProject = rootProject; + + if (rootProject.manifest.generateSyntheticPackage) { final Environment environment = Environment( artifacts: globals.artifacts!, logger: globals.logger, @@ -334,7 +280,7 @@ class PackagesInteractiveGetCommand extends FlutterCommand { processManager: globals.processManager, platform: globals.platform, usage: globals.flutterUsage, - projectDir: flutterProject.directory, + projectDir: rootProject.directory, generateDartPluginRegistry: true, ); @@ -344,17 +290,70 @@ class PackagesInteractiveGetCommand extends FlutterCommand { ); } } + final String? relativeTarget = target == null ? null : globals.fs.path.relative(target); final List subArgs = rest.toList()..removeWhere((String arg) => arg == '--'); - await pub.interactively( - [name, ...subArgs], - directory: target, - stdio: globals.stdio, - touchesPackageConfig: !isHelp, - generateSyntheticPackage: flutterProject?.manifest.generateSyntheticPackage ?? false, - ); + final Stopwatch timer = Stopwatch()..start(); + try { + await pub.interactively( + [ + name, + ...subArgs, + // `dart pub get` and friends defaults to `--no-example`. + if(!exampleWasParsed && target != null) '--example', + if(directoryOption == null && relativeTarget != null) ...['--directory', relativeTarget], + ], + project: rootProject, + context: _context, + command: name, + touchesPackageConfig: !(isHelp || dryRun), + ); + globals.flutterUsage.sendTiming('pub', 'get', timer.elapsed, label: 'success'); + // Not limiting to catching Exception because the exception is rethrown. + } catch (_) { // ignore: avoid_catches_without_on_clauses + globals.flutterUsage.sendTiming('pub', 'get', timer.elapsed, label: 'failure'); + rethrow; + } + + if (rootProject != null) { + // We need to regenerate the platform specific tooling for both the project + // itself and example(if present). + await rootProject.regeneratePlatformSpecificTooling(); + if (example && rootProject.hasExampleApp && rootProject.example.pubspecFile.existsSync()) { + final FlutterProject exampleProject = rootProject.example; + await exampleProject.regeneratePlatformSpecificTooling(); + } + } - await flutterProject?.regeneratePlatformSpecificTooling(); return FlutterCommandResult.success(); } + + /// The pub packages usage values are incorrect since these are calculated/sent + /// before pub get completes. This needs to be performed after dependency resolution. + @override + Future get usageValues async { + final FlutterProject? rootProject = _rootProject; + if (rootProject == null) { + return const CustomDimensions(); + } + + int numberPlugins; + // Do not send plugin analytics if pub has not run before. + final bool hasPlugins = rootProject.flutterPluginsDependenciesFile.existsSync() + && rootProject.packageConfigFile.existsSync(); + if (hasPlugins) { + // Do not fail pub get if package config files are invalid before pub has + // had a chance to run. + final List plugins = await findPlugins(rootProject, throwOnError: false); + numberPlugins = plugins.length; + } else { + numberPlugins = 0; + } + + return CustomDimensions( + commandPackagesNumberPlugins: numberPlugins, + commandPackagesProjectModule: rootProject.isModule, + commandPackagesAndroidEmbeddingVersion: rootProject.android.getEmbeddingVersion().toString().split('.').last, + ); + } } diff --git a/packages/flutter_tools/lib/src/dart/pub.dart b/packages/flutter_tools/lib/src/dart/pub.dart index fdb97d6a19a29..94c07ea003149 100644 --- a/packages/flutter_tools/lib/src/dart/pub.dart +++ b/packages/flutter_tools/lib/src/dart/pub.dart @@ -120,7 +120,10 @@ class PubContext { static final PubContext interactive = PubContext._(['interactive']); static final PubContext pubGet = PubContext._(['get']); static final PubContext pubUpgrade = PubContext._(['upgrade']); + static final PubContext pubAdd = PubContext._(['add']); + static final PubContext pubRemove = PubContext._(['remove']); static final PubContext pubForward = PubContext._(['forward']); + static final PubContext pubPassThrough = PubContext._(['passthrough']); static final PubContext runTest = PubContext._(['run_test']); static final PubContext flutterTests = PubContext._(['flutter_tests']); static final PubContext updatePackages = PubContext._(['update_packages']); @@ -161,7 +164,7 @@ abstract class Pub { required Stdio stdio, }) = _DefaultPub.test; - /// Runs `pub get` or `pub upgrade` for [project]. + /// Runs `pub get` for [project]. /// /// [context] provides extra information to package server requests to /// understand usage. @@ -173,7 +176,6 @@ abstract class Pub { Future get({ required PubContext context, required FlutterProject project, - bool skipIfAbsent = false, bool upgrade = false, bool offline = false, String? flutterRootOverride, @@ -203,14 +205,23 @@ abstract class Pub { /// Runs pub in 'interactive' mode. /// - /// directly piping the stdin stream of this process to that of pub, and the - /// stdout/stderr stream of pub to the corresponding streams of this process. + /// This will run the pub process with StdioInherited (unless [_stdio] is set + /// for testing). + /// + /// The pub process will be run in current working directory, so `--directory` + /// should be passed appropriately in [arguments]. This ensures output from + /// pub will refer to relative paths correctly. + /// + /// [touchesPackageConfig] should be true if this is a command expexted to + /// create a new `.dart_tool/package_config.json` file. Future interactively( List arguments, { - String? directory, - required io.Stdio stdio, + FlutterProject? project, + required PubContext context, + required String command, bool touchesPackageConfig = false, bool generateSyntheticPackage = false, + bool printProgress = true, }); } @@ -268,7 +279,6 @@ class _DefaultPub implements Pub { Future get({ required PubContext context, required FlutterProject project, - bool skipIfAbsent = false, bool upgrade = false, bool offline = false, bool generateSyntheticPackage = false, @@ -280,8 +290,6 @@ class _DefaultPub implements Pub { }) async { final String directory = project.directory.path; final File packageConfigFile = project.packageConfigFile; - final Directory generatedDirectory = _fileSystem.directory( - _fileSystem.path.join(directory, '.dart_tool', 'flutter_gen')); final File lastVersion = _fileSystem.file( _fileSystem.path.join(directory, '.dart_tool', 'version')); final File currentVersion = _fileSystem.file( @@ -352,25 +360,7 @@ class _DefaultPub implements Pub { flutterRootOverride: flutterRootOverride, printProgress: printProgress ); - - if (!packageConfigFile.existsSync()) { - throwToolExit('$directory: pub did not create .dart_tools/package_config.json file.'); - } - lastVersion.writeAsStringSync(currentVersion.readAsStringSync()); - await _updatePackageConfig( - packageConfigFile, - generatedDirectory, - project.manifest.generateSyntheticPackage, - ); - if (project.hasExampleApp && project.example.pubspecFile.existsSync()) { - final Directory exampleGeneratedDirectory = _fileSystem.directory( - _fileSystem.path.join(project.example.directory.path, '.dart_tool', 'flutter_gen')); - await _updatePackageConfig( - project.example.packageConfigFile, - exampleGeneratedDirectory, - project.example.manifest.generateSyntheticPackage, - ); - } + await _updateVersionAndPackageConfig(project); } /// Runs pub with [arguments] and [ProcessStartMode.inheritStdio] mode. @@ -392,9 +382,6 @@ class _DefaultPub implements Pub { String? flutterRootOverride, }) async { int exitCode; - if (printProgress) { - _logger.printStatus('Running "flutter pub $command" in ${_fileSystem.path.basename(directory)}...'); - } final List pubCommand = _pubCommand(arguments); final Map pubEnvironment = await _createPubEnvironment(context, flutterRootOverride); @@ -567,64 +554,22 @@ class _DefaultPub implements Pub { @override Future interactively( List arguments, { - String? directory, - required io.Stdio stdio, + FlutterProject? project, + required PubContext context, + required String command, bool touchesPackageConfig = false, bool generateSyntheticPackage = false, + bool printProgress = true, }) async { - // Fully resolved pub or pub.bat is calculated based on current platform. - final io.Process process = await _processUtils.start( - _pubCommand([ - if (_logger.supportsColor) '--color', - ...arguments, - ]), - workingDirectory: directory, - environment: await _createPubEnvironment(PubContext.interactive), + await _runWithStdioInherited( + arguments, + command: command, + directory: _fileSystem.currentDirectory.path, + context: context, + printProgress: printProgress, ); - - // Pipe the Flutter tool stdin to the pub stdin. - unawaited(process.stdin.addStream(stdio.stdin) - // If pub exits unexpectedly with an error, that will be reported below - // by the tool exit after the exit code check. - .catchError((dynamic err, StackTrace stack) { - _logger.printTrace('Echoing stdin to the pub subprocess failed:'); - _logger.printTrace('$err\n$stack'); - } - )); - - // Pipe the pub stdout and stderr to the tool stdout and stderr. - try { - await Future.wait(>[ - stdio.addStdoutStream(process.stdout), - stdio.addStderrStream(process.stderr), - ]); - } on Exception catch (err, stack) { - _logger.printTrace('Echoing stdout or stderr from the pub subprocess failed:'); - _logger.printTrace('$err\n$stack'); - } - - // Wait for pub to exit. - final int code = await process.exitCode; - if (code != 0) { - throwToolExit('pub finished with exit code $code', exitCode: code); - } - - if (touchesPackageConfig) { - final String targetDirectory = directory ?? _fileSystem.currentDirectory.path; - final File packageConfigFile = _fileSystem.file( - _fileSystem.path.join(targetDirectory, '.dart_tool', 'package_config.json')); - final Directory generatedDirectory = _fileSystem.directory( - _fileSystem.path.join(targetDirectory, '.dart_tool', 'flutter_gen')); - final File lastVersion = _fileSystem.file( - _fileSystem.path.join(targetDirectory, '.dart_tool', 'version')); - final File currentVersion = _fileSystem.file( - _fileSystem.path.join(Cache.flutterRoot!, 'version')); - lastVersion.writeAsStringSync(currentVersion.readAsStringSync()); - await _updatePackageConfig( - packageConfigFile, - generatedDirectory, - generateSyntheticPackage, - ); + if (touchesPackageConfig && project != null) { + await _updateVersionAndPackageConfig(project); } } @@ -766,23 +711,46 @@ class _DefaultPub implements Pub { return environment; } - /// Update the package configuration file. + /// Updates the .dart_tool/version file to be equal to current Flutter + /// version. + /// + /// Calls [_updatePackageConfig] for [project] and [project.example] (if it + /// exists). + /// + /// This should be called after pub invocations that are expected to update + /// the packageConfig. + Future _updateVersionAndPackageConfig(FlutterProject project) async { + if (!project.packageConfigFile.existsSync()) { + throwToolExit('${project.directory}: pub did not create .dart_tools/package_config.json file.'); + } + final File lastVersion = _fileSystem.file( + _fileSystem.path.join(project.directory.path, '.dart_tool', 'version'), + ); + final File currentVersion = _fileSystem.file( + _fileSystem.path.join(Cache.flutterRoot!, 'version')); + lastVersion.writeAsStringSync(currentVersion.readAsStringSync()); + + await _updatePackageConfig(project); + if (project.hasExampleApp && project.example.pubspecFile.existsSync()) { + await _updatePackageConfig(project.example); + } + } + + /// Update the package configuration file in [project]. /// - /// Creates a corresponding `package_config_subset` file that is used by the build - /// system to avoid rebuilds caused by an updated pub timestamp. + /// Creates a corresponding `package_config_subset` file that is used by the + /// build system to avoid rebuilds caused by an updated pub timestamp. /// - /// if [generateSyntheticPackage] is true then insert flutter_gen synthetic - /// package into the package configuration. This is used by the l10n localization - /// tooling to insert a new reference into the package_config file, allowing the import - /// of a package URI that is not specified in the pubspec.yaml + /// if `project.generateSyntheticPackage` is `true` then insert flutter_gen + /// synthetic package into the package configuration. This is used by the l10n + /// localization tooling to insert a new reference into the package_config + /// file, allowing the import of a package URI that is not specified in the + /// pubspec.yaml /// /// For more information, see: /// * [generateLocalizations], `in lib/src/localizations/gen_l10n.dart` - Future _updatePackageConfig( - File packageConfigFile, - Directory generatedDirectory, - bool generateSyntheticPackage, - ) async { + Future _updatePackageConfig(FlutterProject project) async { + final File packageConfigFile = project.packageConfigFile; final PackageConfig packageConfig = await loadPackageConfigWithLogging(packageConfigFile, logger: _logger); packageConfigFile.parent @@ -792,7 +760,7 @@ class _DefaultPub implements Pub { _fileSystem, )); - if (!generateSyntheticPackage) { + if (!project.manifest.generateSyntheticPackage) { return; } if (packageConfig.packages.any((Package package) => package.name == 'flutter_gen')) { diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index 0ee430397808f..724902683ceb8 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -10,8 +10,8 @@ dependencies: archive: 3.3.2 args: 2.3.1 browser_launcher: 1.1.1 - dds: 2.6.0 - dwds: 16.0.1 + dds: 2.7.0 + dwds: 16.0.2 completion: 1.0.1 coverage: 1.6.1 crypto: 3.0.2 @@ -102,4 +102,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 13f7 +# PUBSPEC CHECKSUM: 02f9 diff --git a/packages/flutter_tools/test/commands.shard/hermetic/create_usage_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/create_usage_test.dart index 9c419c3567f42..4a617ff70e126 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/create_usage_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/create_usage_test.dart @@ -29,7 +29,6 @@ class FakePub extends Fake implements Pub { Future get({ PubContext? context, required FlutterProject project, - bool skipIfAbsent = false, bool upgrade = false, bool offline = false, bool generateSyntheticPackage = false, diff --git a/packages/flutter_tools/test/commands.shard/hermetic/drive_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/drive_test.dart index 6e10ff510afab..a7445131369d8 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/drive_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/drive_test.dart @@ -480,7 +480,6 @@ class FakePub extends Fake implements Pub { Future get({ PubContext? context, required FlutterProject project, - bool skipIfAbsent = false, bool upgrade = false, bool offline = false, bool generateSyntheticPackage = false, diff --git a/packages/flutter_tools/test/commands.shard/hermetic/pub_get_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/pub_get_test.dart index e8b9db01ac265..4ab290199c6d4 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/pub_get_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/pub_get_test.dart @@ -35,7 +35,7 @@ void main() { fileSystem.currentDirectory.childFile('.flutter-plugins').createSync(); fileSystem.currentDirectory.childFile('.flutter-plugins-dependencies').createSync(); - final PackagesGetCommand command = PackagesGetCommand('get', false); + final PackagesGetCommand command = PackagesGetCommand('get', '', PubContext.pubGet); final CommandRunner commandRunner = createTestCommandRunner(command); await commandRunner.run(['get']); @@ -60,7 +60,7 @@ void main() { ..createSync(recursive: true) ..writeAsBytesSync([0]); - final PackagesGetCommand command = PackagesGetCommand('get', false); + final PackagesGetCommand command = PackagesGetCommand('get', '', PubContext.pubGet); final CommandRunner commandRunner = createTestCommandRunner(command); await commandRunner.run(['get']); @@ -81,7 +81,7 @@ void main() { final Directory targetDirectory = fileSystem.currentDirectory.childDirectory('target'); targetDirectory.childFile('pubspec.yaml').createSync(); - final PackagesGetCommand command = PackagesGetCommand('get', false); + final PackagesGetCommand command = PackagesGetCommand('get', '', PubContext.pubGet); final CommandRunner commandRunner = createTestCommandRunner(command); await commandRunner.run(['get', targetDirectory.path]); @@ -98,7 +98,7 @@ void main() { fileSystem.currentDirectory.childFile('pubspec.yaml').createSync(); fileSystem.currentDirectory.childDirectory('example').createSync(recursive: true); - final PackagesGetCommand command = PackagesGetCommand('get', false); + final PackagesGetCommand command = PackagesGetCommand('get', '', PubContext.pubGet); final CommandRunner commandRunner = createTestCommandRunner(command); await commandRunner.run(['get']); @@ -115,7 +115,7 @@ void main() { }); testUsingContext('pub get throws error on missing directory', () async { - final PackagesGetCommand command = PackagesGetCommand('get', false); + final PackagesGetCommand command = PackagesGetCommand('get', '', PubContext.pubGet); final CommandRunner commandRunner = createTestCommandRunner(command); try { @@ -159,7 +159,7 @@ void main() { ''' ); - final PackagesGetCommand command = PackagesGetCommand('get', false); + final PackagesGetCommand command = PackagesGetCommand('get', '', PubContext.pubGet); final CommandRunner commandRunner = createTestCommandRunner(command); await commandRunner.run(['get']); @@ -183,23 +183,21 @@ class FakePub extends Fake implements Pub { final FileSystem fileSystem; @override - Future get({ + Future interactively( + List arguments, { + FlutterProject? project, required PubContext context, - required FlutterProject project, - bool skipIfAbsent = false, - bool upgrade = false, - bool offline = false, + required String command, + bool touchesPackageConfig = false, bool generateSyntheticPackage = false, - bool generateSyntheticPackageForExample = false, - String? flutterRootOverride, - bool checkUpToDate = false, - bool shouldSkipThirdPartyGenerator = true, bool printProgress = true, }) async { - fileSystem.directory(project.directory) - .childDirectory('.dart_tool') - .childFile('package_config.json') - ..createSync(recursive: true) - ..writeAsStringSync('{"configVersion":2,"packages":[]}'); + if (project != null) { + fileSystem.directory(project.directory) + .childDirectory('.dart_tool') + .childFile('package_config.json') + ..createSync(recursive: true) + ..writeAsStringSync('{"configVersion":2,"packages":[]}'); + } } } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/update_packages_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/update_packages_test.dart index 1456bacc1ca1c..56b9fa0d7a120 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/update_packages_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/update_packages_test.dart @@ -275,7 +275,6 @@ class FakePub extends Fake implements Pub { Future get({ required PubContext context, required FlutterProject project, - bool skipIfAbsent = false, bool upgrade = false, bool offline = false, bool generateSyntheticPackage = false, diff --git a/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart b/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart index c96b1474e7c4b..4bd4f811aace3 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart @@ -72,6 +72,7 @@ void main() { 'packages', verb, ...?args, + '--directory', projectPath, ]); return command; diff --git a/packages/flutter_tools/test/general.shard/cache_test.dart b/packages/flutter_tools/test/general.shard/cache_test.dart index 9ae86725b343c..de4229c2d59c0 100644 --- a/packages/flutter_tools/test/general.shard/cache_test.dart +++ b/packages/flutter_tools/test/general.shard/cache_test.dart @@ -1208,7 +1208,6 @@ class FakePub extends Fake implements Pub { Future get({ PubContext? context, required FlutterProject project, - bool skipIfAbsent = false, bool upgrade = false, bool offline = false, bool generateSyntheticPackage = false, diff --git a/packages/flutter_tools/test/general.shard/dart/pub_get_test.dart b/packages/flutter_tools/test/general.shard/dart/pub_get_test.dart index d3a8bc50068c5..173a1a7b50eb8 100644 --- a/packages/flutter_tools/test/general.shard/dart/pub_get_test.dart +++ b/packages/flutter_tools/test/general.shard/dart/pub_get_test.dart @@ -557,7 +557,7 @@ exit code: 66 ), throwsA(isA().having((ToolExit error) => error.message, 'message', toolExitMessage)), ); - expect(logger.statusText, 'Running "flutter pub get" in /...\n'); + expect(logger.statusText, isEmpty); expect( mockStdio.stdout.writes.map(utf8.decode), [ @@ -634,9 +634,7 @@ exit code: 66 ), ), ); - expect(logger.statusText, - 'Running "flutter pub get" in /...\n' - ); + expect(logger.statusText, isEmpty); expect(logger.errorText, isEmpty); expect(processManager, hasNoRemainingExpectations); }); @@ -1074,7 +1072,6 @@ exit code: 66 context: PubContext.flutterTests, ); // pub sets date of .packages to 2002 - expect(logger.statusText, 'Running "flutter pub get" in /...\n'); expect(logger.errorText, isEmpty); expect(fileSystem.file('pubspec.yaml').lastModifiedSync(), DateTime(2001)); // because nothing should touch it logger.clear(); @@ -1089,7 +1086,7 @@ exit code: 66 context: PubContext.flutterTests, ); // pub does nothing - expect(logger.statusText, 'Running "flutter pub get" in /...\n'); + expect(logger.statusText, isEmpty); expect(logger.errorText, isEmpty); expect(fileSystem.file('pubspec.yaml').lastModifiedSync(), DateTime(2001)); // because nothing should touch it logger.clear(); diff --git a/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart b/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart index 765773ed9dd4b..4f5d774a6d429 100644 --- a/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart +++ b/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart @@ -951,7 +951,6 @@ class FakePub extends Fake implements Pub { Future get({ required PubContext context, required FlutterProject project, - bool skipIfAbsent = false, bool upgrade = false, bool offline = false, String? flutterRootOverride, diff --git a/packages/flutter_tools/test/src/fake_process_manager.dart b/packages/flutter_tools/test/src/fake_process_manager.dart index fb87570c873c8..e0fc5102db676 100644 --- a/packages/flutter_tools/test/src/fake_process_manager.dart +++ b/packages/flutter_tools/test/src/fake_process_manager.dart @@ -110,15 +110,8 @@ class FakeCommand { Map? environment, Encoding? encoding, ) { - expect(command.length, this.command.length); - for(int i = 0; i < command.length; i++) { - final Pattern expected = this.command[i]; - if (expected is String) { - expect(command[i], expected); - } else { - expect(command[i], matches(this.command[i])); - } - } + final List matchers = this.command.map((Pattern x) => x is String ? x : matches(x)).toList(); + expect(command, matchers); if (this.workingDirectory != null) { expect(this.workingDirectory, workingDirectory); } diff --git a/packages/flutter_tools/test/src/throwing_pub.dart b/packages/flutter_tools/test/src/throwing_pub.dart index c00a7f12d5d92..a96d13375ab00 100644 --- a/packages/flutter_tools/test/src/throwing_pub.dart +++ b/packages/flutter_tools/test/src/throwing_pub.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/dart/pub.dart'; import 'package:flutter_tools/src/project.dart'; @@ -21,7 +20,6 @@ class ThrowingPub implements Pub { Future get({ PubContext? context, required FlutterProject project, - bool skipIfAbsent = false, bool upgrade = false, bool offline = false, bool checkLastModified = true, @@ -39,10 +37,12 @@ class ThrowingPub implements Pub { @override Future interactively( List arguments, { - String? directory, - required Stdio stdio, + FlutterProject? project, + required PubContext context, + required String command, bool touchesPackageConfig = false, bool generateSyntheticPackage = false, + bool printProgress = true, }) { throw UnsupportedError('Attempted to invoke pub during test.'); }