mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
209 lines
6.3 KiB
Dart
209 lines
6.3 KiB
Dart
// 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.
|
|
|
|
import 'package:file/memory.dart';
|
|
import 'package:meta/meta.dart';
|
|
|
|
import '../convert.dart';
|
|
import 'error_handling_io.dart';
|
|
import 'file_system.dart';
|
|
import 'logger.dart';
|
|
import 'platform.dart';
|
|
import 'utils.dart';
|
|
|
|
/// A class to abstract configuration files.
|
|
class Config {
|
|
/// Constructs a new [Config] object from a file called [name] in the
|
|
/// current user's configuration directory as determined by the [Platform]
|
|
/// and [FileSystem].
|
|
///
|
|
/// The configuration directory defaults to $XDG_CONFIG_HOME on Linux and
|
|
/// macOS, but falls back to the home directory if a file named
|
|
/// `.flutter_$name` already exists there. On other platforms the
|
|
/// configuration file will always be a file named `.flutter_$name` in the
|
|
/// home directory.
|
|
///
|
|
/// Uses some good default behaviours:
|
|
/// - deletes the file if it's not valid JSON
|
|
/// - reports an empty config in that case
|
|
/// - logs and catches any exceptions
|
|
factory Config(
|
|
String name, {
|
|
required FileSystem fileSystem,
|
|
required Logger logger,
|
|
required Platform platform
|
|
}) {
|
|
return Config._common(
|
|
name,
|
|
fileSystem: fileSystem,
|
|
logger: logger,
|
|
platform: platform
|
|
);
|
|
}
|
|
|
|
/// Similar to the default config constructor, but with some different
|
|
/// behaviours:
|
|
/// - will not delete the config if it's not valid JSON
|
|
/// - will log but also rethrow any exceptions while loading the JSON, so
|
|
/// you can actually detect whether something went wrong
|
|
///
|
|
/// Useful if you want some more control.
|
|
factory Config.managed(
|
|
String name, {
|
|
required FileSystem fileSystem,
|
|
required Logger logger,
|
|
required Platform platform
|
|
}) {
|
|
return Config._common(
|
|
name,
|
|
fileSystem: fileSystem,
|
|
logger: logger,
|
|
platform: platform,
|
|
managed: true
|
|
);
|
|
}
|
|
|
|
factory Config._common(
|
|
String name, {
|
|
required FileSystem fileSystem,
|
|
required Logger logger,
|
|
required Platform platform,
|
|
bool managed = false
|
|
}) {
|
|
final String filePath = _configPath(platform, fileSystem, name);
|
|
final File file = fileSystem.file(filePath);
|
|
file.parent.createSync(recursive: true);
|
|
return Config.createForTesting(file, logger, managed: managed);
|
|
}
|
|
|
|
/// Constructs a new [Config] object from a file called [name] in
|
|
/// the given [Directory].
|
|
///
|
|
/// Defaults to [BufferLogger], [MemoryFileSystem], and [name]=test.
|
|
factory Config.test({
|
|
String name = 'test',
|
|
Directory? directory,
|
|
Logger? logger,
|
|
bool managed = false
|
|
}) {
|
|
directory ??= MemoryFileSystem.test().directory('/');
|
|
return Config.createForTesting(
|
|
directory.childFile('.${kConfigDir}_$name'),
|
|
logger ?? BufferLogger.test(),
|
|
managed: managed
|
|
);
|
|
}
|
|
|
|
/// Test only access to the Config constructor.
|
|
@visibleForTesting
|
|
Config.createForTesting(File file, Logger logger, {bool managed = false}) : _file = file, _logger = logger {
|
|
if (!_file.existsSync()) {
|
|
return;
|
|
}
|
|
try {
|
|
ErrorHandlingFileSystem.noExitOnFailure(() {
|
|
_values = castStringKeyedMap(json.decode(_file.readAsStringSync())) ?? <String, Object>{};
|
|
});
|
|
} on FormatException {
|
|
_logger
|
|
..printError('Failed to decode preferences in ${_file.path}.')
|
|
..printError(
|
|
'You may need to reapply any previously saved configuration '
|
|
'with the "flutter config" command.',
|
|
);
|
|
|
|
if (managed) {
|
|
rethrow;
|
|
} else {
|
|
_file.deleteSync();
|
|
}
|
|
} on Exception catch (err) {
|
|
_logger
|
|
..printError('Could not read preferences in ${file.path}.\n$err')
|
|
..printError(
|
|
'You may need to resolve the error above and reapply any previously '
|
|
'saved configuration with the "flutter config" command.',
|
|
);
|
|
|
|
if (managed) {
|
|
rethrow;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The default directory name for Flutter's configs.
|
|
|
|
/// Configs will be written to the user's config path. If there is already a
|
|
/// file with the name `.${kConfigDir}_$name` in the user's home path, that
|
|
/// file will be used instead.
|
|
static const String kConfigDir = 'flutter';
|
|
|
|
/// Environment variable specified in the XDG Base Directory
|
|
/// [specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html)
|
|
/// to specify the user's configuration directory.
|
|
static const String kXdgConfigHome = 'XDG_CONFIG_HOME';
|
|
|
|
/// Fallback directory in the user's home directory if `XDG_CONFIG_HOME` is
|
|
/// not defined.
|
|
static const String kXdgConfigFallback = '.config';
|
|
|
|
/// The default name for the Flutter config file.
|
|
static const String kFlutterSettings = 'settings';
|
|
|
|
final Logger _logger;
|
|
|
|
File _file;
|
|
|
|
String get configPath => _file.path;
|
|
|
|
Map<String, dynamic> _values = <String, Object>{};
|
|
|
|
Iterable<String> get keys => _values.keys;
|
|
|
|
bool containsKey(String key) => _values.containsKey(key);
|
|
|
|
Object? getValue(String key) => _values[key];
|
|
|
|
void setValue(String key, Object value) {
|
|
_values[key] = value;
|
|
_flushValues();
|
|
}
|
|
|
|
void removeValue(String key) {
|
|
_values.remove(key);
|
|
_flushValues();
|
|
}
|
|
|
|
void _flushValues() {
|
|
String json = const JsonEncoder.withIndent(' ').convert(_values);
|
|
json = '$json\n';
|
|
_file.writeAsStringSync(json);
|
|
}
|
|
|
|
// Reads the process environment to find the current user's home directory.
|
|
//
|
|
// If the searched environment variables are not set, '.' is returned instead.
|
|
//
|
|
// Note that this is different from FileSystemUtils.homeDirPath.
|
|
static String _userHomePath(Platform platform) {
|
|
final String envKey = platform.isWindows ? 'APPDATA' : 'HOME';
|
|
return platform.environment[envKey] ?? '.';
|
|
}
|
|
|
|
static String _configPath(
|
|
Platform platform, FileSystem fileSystem, String name) {
|
|
final String homeDirFile =
|
|
fileSystem.path.join(_userHomePath(platform), '.${kConfigDir}_$name');
|
|
if (platform.isLinux || platform.isMacOS) {
|
|
if (fileSystem.isFileSync(homeDirFile)) {
|
|
return homeDirFile;
|
|
}
|
|
final String configDir = platform.environment[kXdgConfigHome] ??
|
|
fileSystem.path.join(_userHomePath(platform), '.config', kConfigDir);
|
|
return fileSystem.path.join(configDir, name);
|
|
}
|
|
return homeDirFile;
|
|
}
|
|
}
|