diff --git a/dev/devicelab/bin/tasks/technical_debt__cost.dart b/dev/devicelab/bin/tasks/technical_debt__cost.dart index 9345c19760..d45d796759 100644 --- a/dev/devicelab/bin/tasks/technical_debt__cost.dart +++ b/dev/devicelab/bin/tasks/technical_debt__cost.dart @@ -73,8 +73,20 @@ Future countDependencies() async { return count; } +Future countConsumerDependencies() async { + final List lines = (await evalFlutter( + 'update-packages', + options: ['--transitive-closure', '--consumer-only'], + )).split('\n'); + final int count = lines.where((String line) => line.contains('->')).length; + if (count < 2) // we'll always have flutter and flutter_test, at least... + throw Exception('"flutter update-packages --transitive-closure" returned bogus output:\n${lines.join("\n")}'); + return count; +} + const String _kCostBenchmarkKey = 'technical_debt_in_dollars'; const String _kNumberOfDependenciesKey = 'dependencies_count'; +const String _kNumberOfConsumerDependenciesKey = 'consumer_dependencies_count'; Future main() async { await task(() async { @@ -82,10 +94,12 @@ Future main() async { { _kCostBenchmarkKey: await findCostsForRepo(), _kNumberOfDependenciesKey: await countDependencies(), + _kNumberOfConsumerDependenciesKey: await countConsumerDependencies(), }, benchmarkScoreKeys: [ _kCostBenchmarkKey, _kNumberOfDependenciesKey, + _kNumberOfConsumerDependenciesKey, ], ); }); diff --git a/packages/flutter_tools/lib/src/commands/update_packages.dart b/packages/flutter_tools/lib/src/commands/update_packages.dart index 7df36b3fb9..54594dde17 100644 --- a/packages/flutter_tools/lib/src/commands/update_packages.dart +++ b/packages/flutter_tools/lib/src/commands/update_packages.dart @@ -65,6 +65,14 @@ class UpdatePackagesCommand extends FlutterCommand { defaultsTo: false, negatable: false, ) + ..addFlag( + 'consumer-only', + help: 'Only prints the dependency graph that is the transitive closure' + 'that a consumer of the Flutter SDK will observe (When combined ' + 'with transitive-closure)', + defaultsTo: false, + negatable: false, + ) ..addFlag( 'verify-only', help: 'verifies the package checksum without changing or updating deps', @@ -107,6 +115,24 @@ class UpdatePackagesCommand extends FlutterCommand { final bool isPrintPaths = argResults['paths']; final bool isPrintTransitiveClosure = argResults['transitive-closure']; final bool isVerifyOnly = argResults['verify-only']; + final bool isConsumerOnly = argResults['consumer-only']; + + // "consumer" packages are those that constitute our public API (e.g. flutter, flutter_test, flutter_driver, flutter_localizations). + if (isConsumerOnly) { + if (!isPrintTransitiveClosure) { + throwToolExit( + '--consumer-only can only be used with the --transitive-closure flag' + ); + } + // Only retain flutter, flutter_test, flutter_driver, and flutter_localizations. + const List consumerPackages = ['flutter', 'flutter_test', 'flutter_driver', 'flutter_localizations']; + // ensure we only get flutter/packages + packages.retainWhere((Directory directory) { + return consumerPackages.any((String package) { + return directory.path.endsWith('packages${fs.path.separator}$package'); + }); + }); + } // The dev/integration_tests/android_views integration test depends on an assets // package that is in the goldens repository. We need to make sure that the goldens