1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// 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.
// @dart = 2.8
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.
factory Config(
String name, {
@required FileSystem fileSystem,
@required Logger logger,
@required Platform platform,
}) {
final String filePath = _configPath(platform, fileSystem, name);
final File file = fileSystem.file(filePath);
file.parent.createSync(recursive: true);
return Config.createForTesting(file, logger);
}
/// 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,
}) {
directory ??= MemoryFileSystem.test().directory('/');
return Config.createForTesting(directory.childFile('.${kConfigDir}_$name'), logger ?? BufferLogger.test());
}
/// Test only access to the Config constructor.
@visibleForTesting
Config.createForTesting(File file, Logger logger) : _file = file, _logger = logger {
if (!_file.existsSync()) {
return;
}
try {
ErrorHandlingFileSystem.noExitOnFailure(() {
_values = castStringKeyedMap(json.decode(_file.readAsStringSync()));
});
} 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.',
);
_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.',
);
}
}
/// 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, dynamic>{};
Iterable<String> get keys => _values.keys;
bool containsKey(String key) => _values.containsKey(key);
dynamic 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;
}
}