Unverified Commit 3e7c388e authored by Alex Li's avatar Alex Li Committed by GitHub

`flutter config --list` (#135401)

Resolves #81831.

The PR improves the `config` command in below ways:
- Does not print the settings in usages or other options.
- Adds the `--list` flag to print the full settings list.
- Separates usages for settings and analytics.
- Prints the restart tip when clearing features.
parent 3ad9998c
......@@ -15,6 +15,11 @@ import '../runner/flutter_command_runner.dart';
class ConfigCommand extends FlutterCommand {
ConfigCommand({ bool verboseHelp = false }) {
argParser.addFlag(
'list',
help: 'List all settings and their current values.',
negatable: false,
);
argParser.addFlag('analytics',
hide: !verboseHelp,
help: 'Enable or disable reporting anonymously tool usage statistics and crash reports.\n'
......@@ -73,37 +78,7 @@ class ConfigCommand extends FlutterCommand {
bool get shouldUpdateCache => false;
@override
String get usageFooter {
// List all config settings. for feature flags, include whether they
// are available.
final Map<String, Feature> featuresByName = <String, Feature>{};
final String channel = globals.flutterVersion.channel;
for (final Feature feature in allFeatures) {
final String? configSetting = feature.configSetting;
if (configSetting != null) {
featuresByName[configSetting] = feature;
}
}
String values = globals.config.keys
.map<String>((String key) {
String configFooter = '';
if (featuresByName.containsKey(key)) {
final FeatureChannelSetting setting = featuresByName[key]!.getSettingForChannel(channel);
if (!setting.available) {
configFooter = '(Unavailable)';
}
}
return ' $key: ${globals.config.getValue(key)} $configFooter';
}).join('\n');
if (values.isEmpty) {
values = ' No settings have been configured.';
}
final bool analyticsEnabled = globals.flutterUsage.enabled &&
!globals.flutterUsage.suppressAnalytics;
return
'\nSettings:\n$values\n\n'
'Analytics reporting is currently ${analyticsEnabled ? 'enabled' : 'disabled'}.';
}
String get usageFooter => '\n$analyticsUsage';
/// Return null to disable analytics recording of the `config` command.
@override
......@@ -121,6 +96,11 @@ class ConfigCommand extends FlutterCommand {
' flutter config --android-studio-dir "/opt/Android Studio"');
}
if (boolArg('list')) {
globals.printStatus(settingsText);
return FlutterCommandResult.success();
}
if (boolArg('machine')) {
await handleMachine();
return FlutterCommandResult.success();
......@@ -133,6 +113,7 @@ class ConfigCommand extends FlutterCommand {
globals.config.removeValue(configSetting);
}
}
globals.printStatus(requireReloadTipText);
return FlutterCommandResult.success();
}
......@@ -195,7 +176,7 @@ class ConfigCommand extends FlutterCommand {
if (argResults == null || argResults!.arguments.isEmpty) {
globals.printStatus(usage);
} else {
globals.printStatus('\nYou may need to restart any open editors for them to read new settings.');
globals.printStatus('\n$requireReloadTipText');
}
return FlutterCommandResult.success();
......@@ -234,4 +215,50 @@ class ConfigCommand extends FlutterCommand {
globals.printStatus('Setting "$keyName" value to "$keyValue".');
}
}
/// List all config settings. for feature flags, include whether they are available.
String get settingsText {
final Map<String, Feature> featuresByName = <String, Feature>{};
final String channel = globals.flutterVersion.channel;
for (final Feature feature in allFeatures) {
final String? configSetting = feature.configSetting;
if (configSetting != null) {
featuresByName[configSetting] = feature;
}
}
final Set<String> keys = <String>{
...allFeatures.map((Feature e) => e.configSetting).whereType<String>(),
...globals.config.keys,
};
final Iterable<String> settings = keys.map<String>((String key) {
Object? value = globals.config.getValue(key);
value ??= '(Not set)';
final StringBuffer buffer = StringBuffer(' $key: $value');
if (featuresByName.containsKey(key)) {
final FeatureChannelSetting setting = featuresByName[key]!.getSettingForChannel(channel);
if (!setting.available) {
buffer.write(' (Unavailable)');
}
}
return buffer.toString();
});
final StringBuffer buffer = StringBuffer();
buffer.writeln('All Settings:');
if (settings.isEmpty) {
buffer.writeln(' No configs have been configured.');
} else {
buffer.writeln(settings.join('\n'));
}
return buffer.toString();
}
/// List the status of the analytics reporting.
String get analyticsUsage {
final bool analyticsEnabled =
globals.flutterUsage.enabled && !globals.flutterUsage.suppressAnalytics;
return 'Analytics reporting is currently ${analyticsEnabled ? 'enabled' : 'disabled'}.';
}
/// Raising the reload tip for setting changes.
final String requireReloadTipText = 'You may need to restart any open editors for them to read new settings.';
}
......@@ -12,6 +12,7 @@ import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/config.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:flutter_tools/src/version.dart';
......@@ -48,6 +49,23 @@ void main() {
}
group('config', () {
testUsingContext('prints all settings with --list', () async {
final ConfigCommand configCommand = ConfigCommand();
final CommandRunner<void> commandRunner = createTestCommandRunner(configCommand);
await commandRunner.run(<String>['config', '--list']);
expect(
testLogger.statusText,
'All Settings:\n'
'${allFeatures
.where((Feature e) => e.configSetting != null)
.map((Feature e) => ' ${e.configSetting}: (Not set)')
.join('\n')}'
'\n\n',
);
}, overrides: <Type, Generator>{
Usage: () => testUsage,
});
testUsingContext('throws error on excess arguments', () {
final ConfigCommand configCommand = ConfigCommand();
final CommandRunner<void> commandRunner = createTestCommandRunner(configCommand);
......@@ -196,6 +214,7 @@ void main() {
await commandRunner.run(<String>[
'config',
'--list'
]);
expect(
......@@ -270,20 +289,21 @@ void main() {
Usage: () => testUsage,
});
testUsingContext('analytics reported disabled when suppressed', () async {
testUsingContext('analytics reported with help usages', () async {
final ConfigCommand configCommand = ConfigCommand();
final CommandRunner<void> commandRunner = createTestCommandRunner(configCommand);
createTestCommandRunner(configCommand);
testUsage.suppressAnalytics = true;
await commandRunner.run(<String>[
'config',
]);
expect(
testLogger.statusText,
configCommand.usage,
containsIgnoringWhitespace('Analytics reporting is currently disabled'),
);
testUsage.suppressAnalytics = false;
expect(
configCommand.usage,
containsIgnoringWhitespace('Analytics reporting is currently enabled'),
);
}, overrides: <Type, Generator>{
Usage: () => testUsage,
});
......
......@@ -71,11 +71,12 @@ void main() {
expect(result.stdout, contains('Shutdown hooks complete'));
});
testWithoutContext('flutter config contains all features', () async {
testWithoutContext('flutter config --list contains all features', () async {
final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter');
final ProcessResult result = await processManager.run(<String>[
flutterBin,
'config',
'--list'
]);
// contains all of the experiments in features.dart
......
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