✨ 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.
This commit is contained in:
parent
3ad9998cf0
commit
3e7c388e91
@ -15,6 +15,11 @@ import '../runner/flutter_command_runner.dart';
|
|||||||
|
|
||||||
class ConfigCommand extends FlutterCommand {
|
class ConfigCommand extends FlutterCommand {
|
||||||
ConfigCommand({ bool verboseHelp = false }) {
|
ConfigCommand({ bool verboseHelp = false }) {
|
||||||
|
argParser.addFlag(
|
||||||
|
'list',
|
||||||
|
help: 'List all settings and their current values.',
|
||||||
|
negatable: false,
|
||||||
|
);
|
||||||
argParser.addFlag('analytics',
|
argParser.addFlag('analytics',
|
||||||
hide: !verboseHelp,
|
hide: !verboseHelp,
|
||||||
help: 'Enable or disable reporting anonymously tool usage statistics and crash reports.\n'
|
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;
|
bool get shouldUpdateCache => false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get usageFooter {
|
String get usageFooter => '\n$analyticsUsage';
|
||||||
// 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'}.';
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return null to disable analytics recording of the `config` command.
|
/// Return null to disable analytics recording of the `config` command.
|
||||||
@override
|
@override
|
||||||
@ -121,6 +96,11 @@ class ConfigCommand extends FlutterCommand {
|
|||||||
' flutter config --android-studio-dir "/opt/Android Studio"');
|
' flutter config --android-studio-dir "/opt/Android Studio"');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (boolArg('list')) {
|
||||||
|
globals.printStatus(settingsText);
|
||||||
|
return FlutterCommandResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
if (boolArg('machine')) {
|
if (boolArg('machine')) {
|
||||||
await handleMachine();
|
await handleMachine();
|
||||||
return FlutterCommandResult.success();
|
return FlutterCommandResult.success();
|
||||||
@ -133,6 +113,7 @@ class ConfigCommand extends FlutterCommand {
|
|||||||
globals.config.removeValue(configSetting);
|
globals.config.removeValue(configSetting);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
globals.printStatus(requireReloadTipText);
|
||||||
return FlutterCommandResult.success();
|
return FlutterCommandResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,7 +176,7 @@ class ConfigCommand extends FlutterCommand {
|
|||||||
if (argResults == null || argResults!.arguments.isEmpty) {
|
if (argResults == null || argResults!.arguments.isEmpty) {
|
||||||
globals.printStatus(usage);
|
globals.printStatus(usage);
|
||||||
} else {
|
} else {
|
||||||
globals.printStatus('\nYou may need to restart any open editors for them to read new settings.');
|
globals.printStatus('\n$requireReloadTipText');
|
||||||
}
|
}
|
||||||
|
|
||||||
return FlutterCommandResult.success();
|
return FlutterCommandResult.success();
|
||||||
@ -234,4 +215,50 @@ class ConfigCommand extends FlutterCommand {
|
|||||||
globals.printStatus('Setting "$keyName" value to "$keyValue".');
|
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/build_info.dart';
|
||||||
import 'package:flutter_tools/src/cache.dart';
|
import 'package:flutter_tools/src/cache.dart';
|
||||||
import 'package:flutter_tools/src/commands/config.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/globals.dart' as globals;
|
||||||
import 'package:flutter_tools/src/reporting/reporting.dart';
|
import 'package:flutter_tools/src/reporting/reporting.dart';
|
||||||
import 'package:flutter_tools/src/version.dart';
|
import 'package:flutter_tools/src/version.dart';
|
||||||
@ -48,6 +49,23 @@ void main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group('config', () {
|
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', () {
|
testUsingContext('throws error on excess arguments', () {
|
||||||
final ConfigCommand configCommand = ConfigCommand();
|
final ConfigCommand configCommand = ConfigCommand();
|
||||||
final CommandRunner<void> commandRunner = createTestCommandRunner(configCommand);
|
final CommandRunner<void> commandRunner = createTestCommandRunner(configCommand);
|
||||||
@ -196,6 +214,7 @@ void main() {
|
|||||||
|
|
||||||
await commandRunner.run(<String>[
|
await commandRunner.run(<String>[
|
||||||
'config',
|
'config',
|
||||||
|
'--list'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
@ -270,20 +289,21 @@ void main() {
|
|||||||
Usage: () => testUsage,
|
Usage: () => testUsage,
|
||||||
});
|
});
|
||||||
|
|
||||||
testUsingContext('analytics reported disabled when suppressed', () async {
|
testUsingContext('analytics reported with help usages', () async {
|
||||||
final ConfigCommand configCommand = ConfigCommand();
|
final ConfigCommand configCommand = ConfigCommand();
|
||||||
final CommandRunner<void> commandRunner = createTestCommandRunner(configCommand);
|
createTestCommandRunner(configCommand);
|
||||||
|
|
||||||
testUsage.suppressAnalytics = true;
|
testUsage.suppressAnalytics = true;
|
||||||
|
|
||||||
await commandRunner.run(<String>[
|
|
||||||
'config',
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
testLogger.statusText,
|
configCommand.usage,
|
||||||
containsIgnoringWhitespace('Analytics reporting is currently disabled'),
|
containsIgnoringWhitespace('Analytics reporting is currently disabled'),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
testUsage.suppressAnalytics = false;
|
||||||
|
expect(
|
||||||
|
configCommand.usage,
|
||||||
|
containsIgnoringWhitespace('Analytics reporting is currently enabled'),
|
||||||
|
);
|
||||||
}, overrides: <Type, Generator>{
|
}, overrides: <Type, Generator>{
|
||||||
Usage: () => testUsage,
|
Usage: () => testUsage,
|
||||||
});
|
});
|
||||||
|
@ -71,11 +71,12 @@ void main() {
|
|||||||
expect(result.stdout, contains('Shutdown hooks complete'));
|
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 String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter');
|
||||||
final ProcessResult result = await processManager.run(<String>[
|
final ProcessResult result = await processManager.run(<String>[
|
||||||
flutterBin,
|
flutterBin,
|
||||||
'config',
|
'config',
|
||||||
|
'--list'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// contains all of the experiments in features.dart
|
// contains all of the experiments in features.dart
|
||||||
|
Loading…
x
Reference in New Issue
Block a user