[flutter_tools] Make Config context-free (#49834)

This commit is contained in:
Zachary Anderson 2020-01-31 12:51:20 -08:00 committed by GitHub
parent 1eb5bb653c
commit 2c51efef29
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 115 additions and 83 deletions

View file

@ -189,7 +189,11 @@ FileSystem crashFileSystem = const LocalFileSystem();
/// Saves the crash report to a local file.
Future<File> _createLocalCrashReport(List<String> args, dynamic error, StackTrace stackTrace, String doctorText) async {
File crashFile = fsUtils.getUniqueFile(crashFileSystem.currentDirectory, 'flutter', 'log');
File crashFile = globals.fsUtils.getUniqueFile(
crashFileSystem.currentDirectory,
'flutter',
'log',
);
final StringBuffer buffer = StringBuffer();
@ -209,7 +213,11 @@ Future<File> _createLocalCrashReport(List<String> args, dynamic error, StackTrac
crashFile.writeAsStringSync(buffer.toString());
} on FileSystemException catch (_) {
// Fallback to the system temporary directory.
crashFile = fsUtils.getUniqueFile(crashFileSystem.systemTempDirectory, 'flutter', 'log');
crashFile = globals.fsUtils.getUniqueFile(
crashFileSystem.systemTempDirectory,
'flutter',
'log',
);
try {
crashFile.writeAsStringSync(buffer.toString());
} on FileSystemException catch (e) {

View file

@ -549,7 +549,7 @@ Future<void> buildGradleAar({
// Copy the local engine repo in the output directory.
try {
fsUtils.copyDirectorySync(
globals.fsUtils.copyDirectorySync(
localEngineRepo,
getRepoDirectory(outputDirectory),
);

View file

@ -97,7 +97,7 @@ class GradleUtils {
/// Injects the Gradle wrapper files if any of these files don't exist in [directory].
void injectGradleWrapperIfNeeded(Directory directory) {
fsUtils.copyDirectorySync(
globals.fsUtils.copyDirectorySync(
globals.cache.getArtifactDirectory('gradle_wrapper'),
directory,
shouldCopyFile: (File sourceFile, File destinationFile) {
@ -266,10 +266,10 @@ void updateLocalProperties({
}
if (androidSdk != null) {
changeIfNecessary('sdk.dir', fsUtils.escapePath(androidSdk.directory));
changeIfNecessary('sdk.dir', globals.fsUtils.escapePath(androidSdk.directory));
}
changeIfNecessary('flutter.sdk', fsUtils.escapePath(Cache.flutterRoot));
changeIfNecessary('flutter.sdk', globals.fsUtils.escapePath(Cache.flutterRoot));
if (buildInfo != null) {
changeIfNecessary('flutter.buildMode', buildInfo.modeName);
final String buildName = validatedBuildNameForPlatform(
@ -295,7 +295,7 @@ void updateLocalProperties({
void writeLocalProperties(File properties) {
final SettingsFile settings = SettingsFile();
if (androidSdk != null) {
settings.values['sdk.dir'] = fsUtils.escapePath(androidSdk.directory);
settings.values['sdk.dir'] = globals.fsUtils.escapePath(androidSdk.directory);
}
settings.writeContents(properties);
}

View file

@ -2,36 +2,40 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:meta/meta.dart';
import '../convert.dart';
import '../globals.dart' as globals;
import 'file_system.dart';
import 'logger.dart';
import 'utils.dart';
class Config {
Config([File configFile, Logger localLogger]) {
final Logger loggerInstance = localLogger ?? globals.logger;
_configFile = configFile ?? globals.fs.file(globals.fs.path.join(
fsUtils.userHomePath,
'.flutter_settings',
));
if (_configFile.existsSync()) {
try {
_values = castStringKeyedMap(json.decode(_configFile.readAsStringSync()));
} on FormatException {
loggerInstance
..printError('Failed to decode preferences in ${_configFile.path}.')
..printError(
'You may need to reapply any previously saved configuration '
'with the "flutter config" command.',
);
_configFile.deleteSync();
}
Config({
@required File file,
@required Logger logger,
}) : _file = file, _logger = logger {
if (!_file.existsSync()) {
return;
}
try {
_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();
}
}
File _configFile;
String get configPath => _configFile.path;
static const String kFlutterSettings = '.flutter_settings';
final File _file;
final Logger _logger;
String get configPath => _file.path;
Map<String, dynamic> _values = <String, dynamic>{};
@ -54,6 +58,6 @@ class Config {
void _flushValues() {
String json = const JsonEncoder.withIndent(' ').convert(_values);
json = '$json\n';
_configFile.writeAsStringSync(json);
_file.writeAsStringSync(json);
}
}

View file

@ -6,9 +6,7 @@ import 'package:file/file.dart';
import 'package:meta/meta.dart';
import 'package:platform/platform.dart';
import '../globals.dart' as globals;
import 'common.dart' show throwToolExit;
import 'context.dart';
export 'package:file/file.dart';
export 'package:file/local.dart';
@ -23,13 +21,6 @@ class FileNotFoundException implements IOException {
String toString() => 'File not found: $path';
}
final FileSystemUtils _defaultFileSystemUtils = FileSystemUtils(
fileSystem: globals.fs,
platform: globals.platform,
);
FileSystemUtils get fsUtils => context.get<FileSystemUtils>() ?? _defaultFileSystemUtils;
/// Various convenience file system methods.
class FileSystemUtils {
FileSystemUtils({

View file

@ -397,7 +397,7 @@ class _ExperimentalResidentWebRunner extends ResidentWebRunner {
}
final String modeName = debuggingOptions.buildInfo.friendlyModeName;
globals.printStatus(
'Launching ${fsUtils.getDisplayPath(target)} '
'Launching ${globals.fsUtils.getDisplayPath(target)} '
'on ${device.device.name} in $modeName mode...',
);
final String effectiveHostname = debuggingOptions.hostname ?? 'localhost';
@ -641,7 +641,7 @@ class _DwdsResidentWebRunner extends ResidentWebRunner {
}
final String modeName = debuggingOptions.buildInfo.friendlyModeName;
globals.printStatus(
'Launching ${fsUtils.getDisplayPath(target)} '
'Launching ${globals.fsUtils.getDisplayPath(target)} '
'on ${device.device.name} in $modeName mode...',
);
Status buildStatus;

View file

@ -87,7 +87,7 @@ class BuildRunnerWebCompilationProxy extends WebCompilationProxy {
'packages',
globals.fs.path.basename(childDirectory.path),
);
fsUtils.copyDirectorySync(
globals.fsUtils.copyDirectorySync(
childDirectory.childDirectory('lib'),
globals.fs.directory(path),
);
@ -95,7 +95,7 @@ class BuildRunnerWebCompilationProxy extends WebCompilationProxy {
final Directory outputDirectory = rootDirectory
.childDirectory(projectName)
.childDirectory('test');
fsUtils.copyDirectorySync(
globals.fsUtils.copyDirectorySync(
outputDirectory,
globals.fs.directory(globals.fs.path.join(testOutputDir)),
);

View file

@ -124,7 +124,7 @@ class FlutterPlugins extends Target {
final FlutterProject project = FlutterProject.fromDirectory(environment.projectDir);
final List<Plugin> plugins = findPlugins(project);
final String pluginManifest = plugins
.map<String>((Plugin p) => '${p.name}=${fsUtils.escapePath(p.path)}')
.map<String>((Plugin p) => '${p.name}=${globals.fsUtils.escapePath(p.path)}')
.join('\n');
final File flutterPluginsFile = environment.projectDir.childFile('.flutter-plugins');
if (!flutterPluginsFile.existsSync() || flutterPluginsFile.readAsStringSync() != pluginManifest) {

View file

@ -106,6 +106,7 @@ class Cache {
// TODO(zra): Move to initializer list once logger and platform parameters
// are required.
_net = Net(logger: _logger, platform: _platform);
_fsUtils = FileSystemUtils(fileSystem: _fileSystem, platform: _platform);
if (artifacts == null) {
_artifacts.add(MaterialFonts(this));
@ -139,6 +140,7 @@ class Cache {
final OperatingSystemUtils _osUtils;
Net _net;
FileSystemUtils _fsUtils;
static const List<String> _hostsBlockedInChina = <String> [
'storage.googleapis.com',
@ -347,9 +349,12 @@ class Cache {
}
String getVersionFor(String artifactName) {
final File versionFile = _fileSystem.file(globals.fs.path.join(
_rootOverride?.path ?? flutterRoot, 'bin', 'internal',
'$artifactName.version'));
final File versionFile = _fileSystem.file(_fileSystem.path.join(
_rootOverride?.path ?? flutterRoot,
'bin',
'internal',
'$artifactName.version',
));
return versionFile.existsSync() ? versionFile.readAsStringSync().trim() : null;
}
@ -370,7 +375,7 @@ class Cache {
/// [entity] doesn't exist.
bool isOlderThanToolsStamp(FileSystemEntity entity) {
final File flutterToolsStamp = getStampFileFor('flutter_tools');
return fsUtils.isOlderThanReference(
return _fsUtils.isOlderThanReference(
entity: entity,
referenceFile: flutterToolsStamp,
);
@ -382,13 +387,19 @@ class Cache {
final Uri url = Uri.parse(urlStr);
final Directory thirdPartyDir = getArtifactDirectory('third_party');
final Directory serviceDir = _fileSystem.directory(_fileSystem.path.join(thirdPartyDir.path, serviceName));
final Directory serviceDir = _fileSystem.directory(_fileSystem.path.join(
thirdPartyDir.path,
serviceName,
));
if (!serviceDir.existsSync()) {
serviceDir.createSync(recursive: true);
_osUtils.chmod(serviceDir, '755');
}
final File cachedFile = _fileSystem.file(_fileSystem.path.join(serviceDir.path, url.pathSegments.last));
final File cachedFile = _fileSystem.file(_fileSystem.path.join(
serviceDir.path,
url.pathSegments.last,
));
if (!cachedFile.existsSync()) {
try {
await downloadFile(url, cachedFile);
@ -452,7 +463,7 @@ class Cache {
}
Future<bool> doesRemoteExist(String message, Uri url) async {
final Status status = globals.logger.startProgress(
final Status status = _logger.startProgress(
message,
timeout: timeoutConfiguration.slowOperation,
);
@ -971,7 +982,7 @@ class AndroidMavenArtifacts extends ArtifactSet {
);
try {
final String gradleExecutable = gradle.absolute.path;
final String flutterSdk = fsUtils.escapePath(Cache.flutterRoot);
final String flutterSdk = globals.fsUtils.escapePath(Cache.flutterRoot);
final RunResult processResult = await processUtils.run(
<String>[
gradleExecutable,

View file

@ -294,7 +294,7 @@ end
try {
// Copy universal engine cache framework to mode directory.
fsUtils.copyDirectorySync(
globals.fsUtils.copyDirectorySync(
globals.fs.directory(engineCacheFlutterFrameworkDirectory),
fatFlutterFrameworkCopy,
);
@ -523,7 +523,7 @@ end
}
final String binaryName = globals.fs.path.basenameWithoutExtension(podFrameworkName);
if (boolArg('universal')) {
fsUtils.copyDirectorySync(
globals.fsUtils.copyDirectorySync(
podProduct as Directory,
modeDirectory.childDirectory(podFrameworkName),
);
@ -637,7 +637,7 @@ end
.childDirectory(frameworkFileName);
final File armFlutterFrameworkBinary = armFlutterFrameworkDirectory
.childFile(frameworkBinaryName);
fsUtils.copyDirectorySync(fatFramework, armFlutterFrameworkDirectory);
globals.fsUtils.copyDirectorySync(fatFramework, armFlutterFrameworkDirectory);
// Create iOS framework.
List<String> lipoCommand = <String>[
@ -664,7 +664,7 @@ end
.childDirectory(frameworkFileName);
final File simulatorFlutterFrameworkBinary = simulatorFlutterFrameworkDirectory
.childFile(frameworkBinaryName);
fsUtils.copyDirectorySync(fatFramework, simulatorFlutterFrameworkDirectory);
globals.fsUtils.copyDirectorySync(fatFramework, simulatorFlutterFrameworkDirectory);
lipoCommand = <String>[
'xcrun',

View file

@ -659,7 +659,7 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi
int _injectGradleWrapper(FlutterProject project) {
int filesCreated = 0;
fsUtils.copyDirectorySync(
globals.fsUtils.copyDirectorySync(
globals.cache.getArtifactDirectory('gradle_wrapper'),
project.android.hostAppGradleRoot,
onFileCopied: (File sourceFile, File destinationFile) {

View file

@ -109,7 +109,7 @@ class ScreenshotCommand extends FlutterCommand {
}
Future<void> runScreenshot(File outputFile) async {
outputFile ??= fsUtils.getUniqueFile(
outputFile ??= globals.fsUtils.getUniqueFile(
globals.fs.currentDirectory,
'flutter',
'png',
@ -124,7 +124,7 @@ class ScreenshotCommand extends FlutterCommand {
Future<void> runSkia(File outputFile) async {
final Map<String, dynamic> skp = await _invokeVmServiceRpc('_flutter.screenshotSkp');
outputFile ??= fsUtils.getUniqueFile(
outputFile ??= globals.fsUtils.getUniqueFile(
globals.fs.currentDirectory,
'flutter',
'skp',
@ -138,7 +138,7 @@ class ScreenshotCommand extends FlutterCommand {
Future<void> runRasterizer(File outputFile) async {
final Map<String, dynamic> response = await _invokeVmServiceRpc('_flutter.screenshot');
outputFile ??= fsUtils.getUniqueFile(
outputFile ??= globals.fsUtils.getUniqueFile(
globals.fs.currentDirectory,
'flutter',
'png',

View file

@ -189,7 +189,7 @@ class ArtifactUnpacker {
final String sourcePath = globals.fs.path.join(sourceDirectory, entityName);
final String targetPath = globals.fs.path.join(targetDirectory, entityName);
if (entityName.endsWith('/')) {
fsUtils.copyDirectorySync(
globals.fsUtils.copyDirectorySync(
globals.fs.directory(sourcePath),
globals.fs.directory(targetPath),
);

View file

@ -87,7 +87,13 @@ Future<T> runInContext<T>(
ChromeLauncher: () => const ChromeLauncher(),
CocoaPods: () => CocoaPods(),
CocoaPodsValidator: () => const CocoaPodsValidator(),
Config: () => Config(),
Config: () => Config(
file: globals.fs.file(globals.fs.path.join(
globals.fsUtils.userHomePath,
Config.kFlutterSettings,
)),
logger: globals.logger,
),
DevFSConfig: () => DevFSConfig(),
DeviceManager: () => DeviceManager(),
Doctor: () => const Doctor(),

View file

@ -35,6 +35,12 @@ FileSystem get fs => ErrorHandlingFileSystem(
context.get<FileSystem>() ?? _kLocalFs,
);
final FileSystemUtils _defaultFileSystemUtils = FileSystemUtils(
fileSystem: fs,
platform: platform,
);
FileSystemUtils get fsUtils => context.get<FileSystemUtils>() ?? _defaultFileSystemUtils;
const ProcessManager _kLocalProcessManager = LocalProcessManager();

View file

@ -547,7 +547,7 @@ Future<XcodeBuildResult> buildXcodeProject({
// (for example, kernel binary files produced from previous run).
globals.fs.directory(outputDir).deleteSync(recursive: true);
}
fsUtils.copyDirectorySync(
globals.fsUtils.copyDirectorySync(
globals.fs.directory(expectedOutputDirectory),
globals.fs.directory(outputDir),
);

View file

@ -25,10 +25,13 @@ abstract class PersistentToolState {
class _DefaultPersistentToolState implements PersistentToolState {
_DefaultPersistentToolState([File configFile]) :
_config = Config(configFile ?? globals.fs.file(globals.fs.path.join(
fsUtils.userHomePath,
_kFileName,
)));
_config = Config(
file: configFile ?? globals.fs.file(globals.fs.path.join(
globals.fsUtils.userHomePath,
_kFileName,
)),
logger: globals.logger,
);
static const String _kFileName = '.flutter_tool_state';
static const String _kRedisplayWelcomeMessage = 'redisplay-welcome-message';

View file

@ -329,7 +329,7 @@ List<Plugin> findPlugins(FlutterProject project) {
for (final Plugin plugin in platformPlugins) {
list.add(<String, dynamic>{
'name': plugin.name,
'path': fsUtils.escapePath(plugin.path),
'path': globals.fsUtils.escapePath(plugin.path),
'dependencies': <String>[...plugin.dependencies.where(pluginNames.contains)],
});
}
@ -468,7 +468,7 @@ bool _writeFlutterPluginsListLegacy(FlutterProject project, List<Plugin> plugins
final StringBuffer flutterPluginsBuffer = StringBuffer('# $info\n');
for (final Plugin plugin in plugins) {
flutterPluginsBuffer.write('${plugin.name}=${fsUtils.escapePath(plugin.path)}\n');
flutterPluginsBuffer.write('${plugin.name}=${globals.fsUtils.escapePath(plugin.path)}\n');
}
final String oldPluginFileContent = _readFileContent(pluginsFile);
final String pluginFileContent = flutterPluginsBuffer.toString();

View file

@ -481,7 +481,7 @@ class IosProject extends FlutterProjectPlatform implements XcodeBasedProject {
if (!isModule) {
return;
}
final bool pubspecChanged = fsUtils.isOlderThanReference(
final bool pubspecChanged = globals.fsUtils.isOlderThanReference(
entity: ephemeralDirectory,
referenceFile: parent.pubspecFile,
);
@ -528,7 +528,7 @@ class IosProject extends FlutterProjectPlatform implements XcodeBasedProject {
.childDirectory('Flutter')
.childDirectory('engine');
final File podspec = framework.parent.childFile('Flutter.podspec');
fsUtils.copyDirectorySync(
globals.fsUtils.copyDirectorySync(
framework,
engineDest.childDirectory('Flutter.framework'),
);
@ -689,7 +689,7 @@ class AndroidProject extends FlutterProjectPlatform {
}
bool _shouldRegenerateFromTemplate() {
return fsUtils.isOlderThanReference(
return globals.fsUtils.isOlderThanReference(
entity: ephemeralDirectory,
referenceFile: parent.pubspecFile,
) || globals.cache.isOlderThanToolsStamp(ephemeralDirectory);

View file

@ -406,7 +406,7 @@ class FlutterDevice {
final bool prebuiltMode = hotRunner.applicationBinary != null;
final String modeName = hotRunner.debuggingOptions.buildInfo.friendlyModeName;
globals.printStatus(
'Launching ${fsUtils.getDisplayPath(hotRunner.mainPath)} '
'Launching ${globals.fsUtils.getDisplayPath(hotRunner.mainPath)} '
'on ${device.name} in $modeName mode...',
);
@ -481,7 +481,7 @@ class FlutterDevice {
);
} else {
globals.printStatus(
'Launching ${fsUtils.getDisplayPath(coldRunner.mainPath)} '
'Launching ${globals.fsUtils.getDisplayPath(coldRunner.mainPath)} '
'on ${device.name} in $modeName mode...',
);
}
@ -862,7 +862,7 @@ abstract class ResidentRunner {
'Taking screenshot for ${device.device.name}...',
timeout: timeoutConfiguration.fastOperation,
);
final File outputFile = fsUtils.getUniqueFile(
final File outputFile = globals.fsUtils.getUniqueFile(
globals.fs.currentDirectory,
'flutter',
'png',

View file

@ -160,7 +160,7 @@ class TestCompiler {
// The idea is to keep the cache file up-to-date and include as
// much as possible in an effort to re-use as many packages as
// possible.
fsUtils.ensureDirectoryExists(testFilePath);
globals.fsUtils.ensureDirectoryExists(testFilePath);
await outputFile.copy(testFilePath);
}
request.result.complete(kernelReadyToRun.path);

View file

@ -7,10 +7,13 @@ import 'package:flutter_tools/src/base/config.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/terminal.dart';
import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import '../src/common.dart';
class MockLogger extends Mock implements Logger {}
void main() {
Config config;
MemoryFileSystem memoryFileSystem;
@ -18,29 +21,29 @@ void main() {
setUp(() {
memoryFileSystem = MemoryFileSystem();
final File file = memoryFileSystem.file('example');
config = Config(file);
config = Config(file: file, logger: MockLogger());
});
test('Config get set value', () async {
testWithoutContext('Config get set value', () async {
expect(config.getValue('foo'), null);
config.setValue('foo', 'bar');
expect(config.getValue('foo'), 'bar');
expect(config.keys, contains('foo'));
});
test('Config get set bool value', () async {
testWithoutContext('Config get set bool value', () async {
expect(config.getValue('foo'), null);
config.setValue('foo', true);
expect(config.getValue('foo'), true);
expect(config.keys, contains('foo'));
});
test('Config containsKey', () async {
testWithoutContext('Config containsKey', () async {
expect(config.containsKey('foo'), false);
config.setValue('foo', 'bar');
expect(config.containsKey('foo'), true);
});
test('Config removeValue', () async {
testWithoutContext('Config removeValue', () async {
expect(config.getValue('foo'), null);
config.setValue('foo', 'bar');
expect(config.getValue('foo'), 'bar');
@ -50,7 +53,7 @@ void main() {
expect(config.keys, isNot(contains('foo')));
});
test('Config parse error', () {
testWithoutContext('Config parse error', () {
final BufferLogger bufferLogger = BufferLogger(
terminal: AnsiTerminal(
stdio: null,
@ -60,7 +63,7 @@ void main() {
);
final File file = memoryFileSystem.file('example')
..writeAsStringSync('{"hello":"bar');
config = Config(file, bufferLogger);
config = Config(file: file, logger: bufferLogger);
expect(file.existsSync(), false);
expect(bufferLogger.errorText, contains('Failed to decode preferences'));

View file

@ -82,7 +82,7 @@ void testUsingContext(
final File settingsFile = globals.fs.file(
globals.fs.path.join(configDir.path, '.flutter_settings')
);
return Config(settingsFile);
return Config(file: settingsFile, logger: globals.logger);
}
PersistentToolState buildPersistentToolState(FileSystem fs) {
configDir ??= globals.fs.systemTempDirectory.createTempSync('flutter_config_dir_test.');