diff --git a/packages/flutter_tools/lib/runner.dart b/packages/flutter_tools/lib/runner.dart index 9f2e059b607ea..aed661d4f534b 100644 --- a/packages/flutter_tools/lib/runner.dart +++ b/packages/flutter_tools/lib/runner.dart @@ -17,7 +17,6 @@ import 'src/base/io.dart'; import 'src/base/logger.dart'; import 'src/base/process.dart'; import 'src/base/terminal.dart'; -import 'src/base/utils.dart'; import 'src/context_runner.dart'; import 'src/doctor.dart'; import 'src/globals.dart' as globals; @@ -191,7 +190,7 @@ FileSystem crashFileSystem = const LocalFileSystem(); /// Saves the crash report to a local file. Future _createLocalCrashReport(List args, dynamic error, StackTrace stackTrace, String doctorText) async { - File crashFile = getUniqueFile(crashFileSystem.currentDirectory, 'flutter', 'log'); + File crashFile = fsUtils.getUniqueFile(crashFileSystem.currentDirectory, 'flutter', 'log'); final StringBuffer buffer = StringBuffer(); @@ -211,7 +210,7 @@ Future _createLocalCrashReport(List args, dynamic error, StackTrac crashFile.writeAsStringSync(buffer.toString()); } on FileSystemException catch (_) { // Fallback to the system temporary directory. - crashFile = getUniqueFile(crashFileSystem.systemTempDirectory, 'flutter', 'log'); + crashFile = fsUtils.getUniqueFile(crashFileSystem.systemTempDirectory, 'flutter', 'log'); try { crashFile.writeAsStringSync(buffer.toString()); } on FileSystemException catch (e) { diff --git a/packages/flutter_tools/lib/src/android/gradle_utils.dart b/packages/flutter_tools/lib/src/android/gradle_utils.dart index 8a976650dd7f4..8e71ba005745a 100644 --- a/packages/flutter_tools/lib/src/android/gradle_utils.dart +++ b/packages/flutter_tools/lib/src/android/gradle_utils.dart @@ -98,7 +98,7 @@ class GradleUtils { /// Injects the Gradle wrapper files if any of these files don't exist in [directory]. void injectGradleWrapperIfNeeded(Directory directory) { - copyDirectorySync( + fsUtils.copyDirectorySync( globals.cache.getArtifactDirectory('gradle_wrapper'), directory, shouldCopyFile: (File sourceFile, File destinationFile) { @@ -267,10 +267,10 @@ void updateLocalProperties({ } if (androidSdk != null) { - changeIfNecessary('sdk.dir', escapePath(androidSdk.directory)); + changeIfNecessary('sdk.dir', fsUtils.escapePath(androidSdk.directory)); } - changeIfNecessary('flutter.sdk', escapePath(Cache.flutterRoot)); + changeIfNecessary('flutter.sdk', fsUtils.escapePath(Cache.flutterRoot)); if (buildInfo != null) { changeIfNecessary('flutter.buildMode', buildInfo.modeName); final String buildName = validatedBuildNameForPlatform( @@ -296,7 +296,7 @@ void updateLocalProperties({ void writeLocalProperties(File properties) { final SettingsFile settings = SettingsFile(); if (androidSdk != null) { - settings.values['sdk.dir'] = escapePath(androidSdk.directory); + settings.values['sdk.dir'] = fsUtils.escapePath(androidSdk.directory); } settings.writeContents(properties); } diff --git a/packages/flutter_tools/lib/src/base/config.dart b/packages/flutter_tools/lib/src/base/config.dart index 619116aa5e7bf..3f69bf2ec4e5e 100644 --- a/packages/flutter_tools/lib/src/base/config.dart +++ b/packages/flutter_tools/lib/src/base/config.dart @@ -11,7 +11,10 @@ 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(userHomePath(), '.flutter_settings')); + _configFile = configFile ?? globals.fs.file(globals.fs.path.join( + fsUtils.userHomePath, + '.flutter_settings', + )); if (_configFile.existsSync()) { try { _values = castStringKeyedMap(json.decode(_configFile.readAsStringSync())); diff --git a/packages/flutter_tools/lib/src/base/file_system.dart b/packages/flutter_tools/lib/src/base/file_system.dart index 6e3ccce7b23cf..089101a2b8ebf 100644 --- a/packages/flutter_tools/lib/src/base/file_system.dart +++ b/packages/flutter_tools/lib/src/base/file_system.dart @@ -4,108 +4,149 @@ 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'; -/// Create the ancestor directories of a file path if they do not already exist. -void ensureDirectoryExists(String filePath) { - final String dirPath = globals.fs.path.dirname(filePath); - if (globals.fs.isDirectorySync(dirPath)) { - return; - } - try { - globals.fs.directory(dirPath).createSync(recursive: true); - } on FileSystemException catch (e) { - throwToolExit('Failed to create directory "$dirPath": ${e.osError.message}'); - } +/// Exception indicating that a file that was expected to exist was not found. +class FileNotFoundException implements IOException { + const FileNotFoundException(this.path); + + final String path; + + @override + String toString() => 'File not found: $path'; } -/// Creates `destDir` if needed, then recursively copies `srcDir` to `destDir`, -/// invoking [onFileCopied], if specified, for each source/destination file pair. -/// -/// Skips files if [shouldCopyFile] returns `false`. -void copyDirectorySync( - Directory srcDir, - Directory destDir, { - bool shouldCopyFile(File srcFile, File destFile), - void onFileCopied(File srcFile, File destFile), -}) { - if (!srcDir.existsSync()) { - throw Exception('Source directory "${srcDir.path}" does not exist, nothing to copy'); - } +final FileSystemUtils _defaultFileSystemUtils = FileSystemUtils( + fileSystem: globals.fs, + platform: globals.platform, +); + +FileSystemUtils get fsUtils => context.get() ?? _defaultFileSystemUtils; + +/// Various convenience file system methods. +class FileSystemUtils { + FileSystemUtils({ + @required FileSystem fileSystem, + @required Platform platform, + }) : _fileSystem = fileSystem, + _platform = platform; + + final FileSystem _fileSystem; + + final Platform _platform; - if (!destDir.existsSync()) { - destDir.createSync(recursive: true); + /// Create the ancestor directories of a file path if they do not already exist. + void ensureDirectoryExists(String filePath) { + final String dirPath = _fileSystem.path.dirname(filePath); + if (_fileSystem.isDirectorySync(dirPath)) { + return; + } + try { + _fileSystem.directory(dirPath).createSync(recursive: true); + } on FileSystemException catch (e) { + throwToolExit('Failed to create directory "$dirPath": ${e.osError.message}'); + } } - for (final FileSystemEntity entity in srcDir.listSync()) { - final String newPath = destDir.fileSystem.path.join(destDir.path, entity.basename); - if (entity is File) { - final File newFile = destDir.fileSystem.file(newPath); - if (shouldCopyFile != null && !shouldCopyFile(entity, newFile)) { - continue; + /// Creates `destDir` if needed, then recursively copies `srcDir` to + /// `destDir`, invoking [onFileCopied], if specified, for each + /// source/destination file pair. + /// + /// Skips files if [shouldCopyFile] returns `false`. + void copyDirectorySync( + Directory srcDir, + Directory destDir, { + bool shouldCopyFile(File srcFile, File destFile), + void onFileCopied(File srcFile, File destFile), + }) { + if (!srcDir.existsSync()) { + throw Exception('Source directory "${srcDir.path}" does not exist, nothing to copy'); + } + + if (!destDir.existsSync()) { + destDir.createSync(recursive: true); + } + + for (final FileSystemEntity entity in srcDir.listSync()) { + final String newPath = destDir.fileSystem.path.join(destDir.path, entity.basename); + if (entity is File) { + final File newFile = destDir.fileSystem.file(newPath); + if (shouldCopyFile != null && !shouldCopyFile(entity, newFile)) { + continue; + } + newFile.writeAsBytesSync(entity.readAsBytesSync()); + onFileCopied?.call(entity, newFile); + } else if (entity is Directory) { + copyDirectorySync( + entity, + destDir.fileSystem.directory(newPath), + shouldCopyFile: shouldCopyFile, + onFileCopied: onFileCopied, + ); + } else { + throw Exception('${entity.path} is neither File nor Directory'); } - newFile.writeAsBytesSync(entity.readAsBytesSync()); - onFileCopied?.call(entity, newFile); - } else if (entity is Directory) { - copyDirectorySync( - entity, - destDir.fileSystem.directory(newPath), - shouldCopyFile: shouldCopyFile, - onFileCopied: onFileCopied, - ); - } else { - throw Exception('${entity.path} is neither File nor Directory'); } } -} -/// Canonicalizes [path]. -/// -/// This function implements the behavior of `canonicalize` from -/// `package:path`. However, unlike the original, it does not change the ASCII -/// case of the path. Changing the case can break hot reload in some situations, -/// for an example see: https://github.com/flutter/flutter/issues/9539. -String canonicalizePath(String path) => globals.fs.path.normalize(globals.fs.path.absolute(path)); - -/// Escapes [path]. -/// -/// On Windows it replaces all '\' with '\\'. On other platforms, it returns the -/// path unchanged. -String escapePath(String path) => globals.platform.isWindows ? path.replaceAll('\\', '\\\\') : path; - -/// Returns true if the file system [entity] has not been modified since the -/// latest modification to [referenceFile]. -/// -/// Returns true, if [entity] does not exist. -/// -/// Returns false, if [entity] exists, but [referenceFile] does not. -bool isOlderThanReference({ @required FileSystemEntity entity, @required File referenceFile }) { - if (!entity.existsSync()) { - return true; + /// Appends a number to a filename in order to make it unique under a + /// directory. + File getUniqueFile(Directory dir, String baseName, String ext) { + final FileSystem fs = dir.fileSystem; + int i = 1; + + while (true) { + final String name = '${baseName}_${i.toString().padLeft(2, '0')}.$ext'; + final File file = fs.file(_fileSystem.path.join(dir.path, name)); + if (!file.existsSync()) { + return file; + } + i++; + } } - return referenceFile.existsSync() - && referenceFile.statSync().modified.isAfter(entity.statSync().modified); -} -/// Exception indicating that a file that was expected to exist was not found. -class FileNotFoundException implements IOException { - const FileNotFoundException(this.path); + /// Return a relative path if [fullPath] is contained by the cwd, else return an + /// absolute path. + String getDisplayPath(String fullPath) { + final String cwd = _fileSystem.currentDirectory.path + _fileSystem.path.separator; + return fullPath.startsWith(cwd) ? fullPath.substring(cwd.length) : fullPath; + } - final String path; + /// Escapes [path]. + /// + /// On Windows it replaces all '\' with '\\'. On other platforms, it returns the + /// path unchanged. + String escapePath(String path) => _platform.isWindows ? path.replaceAll('\\', '\\\\') : path; - @override - String toString() => 'File not found: $path'; -} + /// Returns true if the file system [entity] has not been modified since the + /// latest modification to [referenceFile]. + /// + /// Returns true, if [entity] does not exist. + /// + /// Returns false, if [entity] exists, but [referenceFile] does not. + bool isOlderThanReference({ + @required FileSystemEntity entity, + @required File referenceFile, + }) { + if (!entity.existsSync()) { + return true; + } + return referenceFile.existsSync() + && referenceFile.statSync().modified.isAfter(entity.statSync().modified); + } -/// Reads the process environment to find the current user's home directory. -/// -/// If the searched environment variables are not set, '.' is returned instead. -String userHomePath() { - final String envKey = globals.platform.operatingSystem == 'windows' ? 'APPDATA' : 'HOME'; - return globals.platform.environment[envKey] ?? '.'; + /// Reads the process environment to find the current user's home directory. + /// + /// If the searched environment variables are not set, '.' is returned instead. + String get userHomePath { + final String envKey = _platform.operatingSystem == 'windows' ? 'APPDATA' : 'HOME'; + return _platform.environment[envKey] ?? '.'; + } } diff --git a/packages/flutter_tools/lib/src/base/io.dart b/packages/flutter_tools/lib/src/base/io.dart index 40ca323f7656a..3e71f26fc82b1 100644 --- a/packages/flutter_tools/lib/src/base/io.dart +++ b/packages/flutter_tools/lib/src/base/io.dart @@ -33,6 +33,7 @@ import 'dart:io' as io InternetAddressType, IOSink, NetworkInterface, + pid, Process, ProcessInfo, ProcessSignal, @@ -252,6 +253,14 @@ Stream> get stdin => globals.stdio.stdin; io.IOSink get stderr => globals.stdio.stderr; bool get stdinHasTerminal => globals.stdio.stdinHasTerminal; +// TODO(zra): Move pid and writePidFile into `ProcessInfo`. +void writePidFile(String pidFile) { + if (pidFile != null) { + // Write our pid to the file. + globals.fs.file(pidFile).writeAsStringSync(io.pid.toString()); + } +} + /// An overridable version of io.ProcessInfo. abstract class ProcessInfo { factory ProcessInfo() => _DefaultProcessInfo(); diff --git a/packages/flutter_tools/lib/src/base/utils.dart b/packages/flutter_tools/lib/src/base/utils.dart index 8a241210c5aab..8e60b51560003 100644 --- a/packages/flutter_tools/lib/src/base/utils.dart +++ b/packages/flutter_tools/lib/src/base/utils.dart @@ -9,9 +9,7 @@ import 'package:intl/intl.dart'; import 'package:meta/meta.dart'; import '../convert.dart'; -import '../globals.dart' as globals; import 'file_system.dart'; -import 'io.dart' as io; import 'terminal.dart'; /// Convert `foo_bar` to `fooBar`. @@ -51,29 +49,10 @@ String getEnumName(dynamic enumItem) { return index == -1 ? name : name.substring(index + 1); } -File getUniqueFile(Directory dir, String baseName, String ext) { - final FileSystem fs = dir.fileSystem; - int i = 1; - - while (true) { - final String name = '${baseName}_${i.toString().padLeft(2, '0')}.$ext'; - final File file = fs.file(globals.fs.path.join(dir.path, name)); - if (!file.existsSync()) { - return file; - } - i++; - } -} - String toPrettyJson(Object jsonable) { return const JsonEncoder.withIndent(' ').convert(jsonable) + '\n'; } -/// Return a String - with units - for the size in MB of the given number of bytes. -String getSizeAsMB(int bytesLength) { - return '${(bytesLength / (1024 * 1024)).toStringAsFixed(1)}MB'; -} - final NumberFormat kSecondsFormat = NumberFormat('0.0'); final NumberFormat kMillisecondsFormat = NumberFormat.decimalPattern(); @@ -86,11 +65,9 @@ String getElapsedAsMilliseconds(Duration duration) { return '${kMillisecondsFormat.format(duration.inMilliseconds)}ms'; } -/// Return a relative path if [fullPath] is contained by the cwd, else return an -/// absolute path. -String getDisplayPath(String fullPath) { - final String cwd = globals.fs.currentDirectory.path + globals.fs.path.separator; - return fullPath.startsWith(cwd) ? fullPath.substring(cwd.length) : fullPath; +/// Return a String - with units - for the size in MB of the given number of bytes. +String getSizeAsMB(int bytesLength) { + return '${(bytesLength / (1024 * 1024)).toStringAsFixed(1)}MB'; } /// A class to maintain a list of items, fire events when items are added or @@ -315,13 +292,6 @@ String wrapText(String text, { int columnWidth, int hangingIndent, int indent, b return result.join('\n'); } -void writePidFile(String pidFile) { - if (pidFile != null) { - // Write our pid to the file. - globals.fs.file(pidFile).writeAsStringSync(io.pid.toString()); - } -} - // Used to represent a run of ANSI control sequences next to a visible // character. class _AnsiRun { diff --git a/packages/flutter_tools/lib/src/build_runner/resident_web_runner.dart b/packages/flutter_tools/lib/src/build_runner/resident_web_runner.dart index 491046bf72bdd..fecf566706d3b 100644 --- a/packages/flutter_tools/lib/src/build_runner/resident_web_runner.dart +++ b/packages/flutter_tools/lib/src/build_runner/resident_web_runner.dart @@ -14,6 +14,7 @@ import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart' import '../application_package.dart'; import '../base/async_guard.dart'; import '../base/common.dart'; +import '../base/file_system.dart'; import '../base/io.dart'; import '../base/logger.dart'; import '../base/net.dart'; @@ -388,7 +389,10 @@ class _ExperimentalResidentWebRunner extends ResidentWebRunner { return 1; } final String modeName = debuggingOptions.buildInfo.friendlyModeName; - globals.printStatus('Launching ${getDisplayPath(target)} on ${device.device.name} in $modeName mode...'); + globals.printStatus( + 'Launching ${fsUtils.getDisplayPath(target)} ' + 'on ${device.device.name} in $modeName mode...', + ); final String effectiveHostname = debuggingOptions.hostname ?? 'localhost'; final int hostPort = debuggingOptions.port == null ? await os.findFreePort() @@ -587,7 +591,9 @@ class _DwdsResidentWebRunner extends ResidentWebRunner { } final String modeName = debuggingOptions.buildInfo.friendlyModeName; globals.printStatus( - 'Launching ${getDisplayPath(target)} on ${device.device.name} in $modeName mode...'); + 'Launching ${fsUtils.getDisplayPath(target)} ' + 'on ${device.device.name} in $modeName mode...', + ); Status buildStatus; bool statusActive = false; try { diff --git a/packages/flutter_tools/lib/src/build_runner/web_compilation_delegate.dart b/packages/flutter_tools/lib/src/build_runner/web_compilation_delegate.dart index df9c642a4e87d..24da1647eab25 100644 --- a/packages/flutter_tools/lib/src/build_runner/web_compilation_delegate.dart +++ b/packages/flutter_tools/lib/src/build_runner/web_compilation_delegate.dart @@ -82,14 +82,23 @@ class BuildRunnerWebCompilationProxy extends WebCompilationProxy { .listSync() .whereType(); for (final Directory childDirectory in childDirectories) { - final String path = globals.fs.path.join(testOutputDir, 'packages', - globals.fs.path.basename(childDirectory.path)); - copyDirectorySync(childDirectory.childDirectory('lib'), globals.fs.directory(path)); + final String path = globals.fs.path.join( + testOutputDir, + 'packages', + globals.fs.path.basename(childDirectory.path), + ); + fsUtils.copyDirectorySync( + childDirectory.childDirectory('lib'), + globals.fs.directory(path), + ); } final Directory outputDirectory = rootDirectory - .childDirectory(projectName) - .childDirectory('test'); - copyDirectorySync(outputDirectory, globals.fs.directory(globals.fs.path.join(testOutputDir))); + .childDirectory(projectName) + .childDirectory('test'); + fsUtils.copyDirectorySync( + outputDirectory, + globals.fs.directory(globals.fs.path.join(testOutputDir)), + ); } return success; } diff --git a/packages/flutter_tools/lib/src/build_system/targets/assets.dart b/packages/flutter_tools/lib/src/build_system/targets/assets.dart index fb3c3dfe32b42..a0d185df9bae1 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/assets.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/assets.dart @@ -124,8 +124,8 @@ class FlutterPlugins extends Target { final FlutterProject project = FlutterProject.fromDirectory(environment.projectDir); final List plugins = findPlugins(project); final String pluginManifest = plugins - .map((Plugin p) => '${p.name}=${escapePath(p.path)}') - .join('\n'); + .map((Plugin p) => '${p.name}=${fsUtils.escapePath(p.path)}') + .join('\n'); final File flutterPluginsFile = environment.projectDir.childFile('.flutter-plugins'); if (!flutterPluginsFile.existsSync() || flutterPluginsFile.readAsStringSync() != pluginManifest) { flutterPluginsFile.writeAsStringSync(pluginManifest); diff --git a/packages/flutter_tools/lib/src/cache.dart b/packages/flutter_tools/lib/src/cache.dart index 4320f34d81f20..d7bf786c13799 100644 --- a/packages/flutter_tools/lib/src/cache.dart +++ b/packages/flutter_tools/lib/src/cache.dart @@ -346,7 +346,10 @@ class Cache { /// [entity] doesn't exist. bool isOlderThanToolsStamp(FileSystemEntity entity) { final File flutterToolsStamp = getStampFileFor('flutter_tools'); - return isOlderThanReference(entity: entity, referenceFile: flutterToolsStamp); + return fsUtils.isOlderThanReference( + entity: entity, + referenceFile: flutterToolsStamp, + ); } bool isUpToDate() => _artifacts.every((ArtifactSet artifact) => artifact.isUpToDate()); @@ -912,7 +915,7 @@ class AndroidMavenArtifacts extends ArtifactSet { ); try { final String gradleExecutable = gradle.absolute.path; - final String flutterSdk = escapePath(Cache.flutterRoot); + final String flutterSdk = fsUtils.escapePath(Cache.flutterRoot); final RunResult processResult = await processUtils.run( [ gradleExecutable, diff --git a/packages/flutter_tools/lib/src/commands/attach.dart b/packages/flutter_tools/lib/src/commands/attach.dart index 10e0787ae374d..54f10e5033d1a 100644 --- a/packages/flutter_tools/lib/src/commands/attach.dart +++ b/packages/flutter_tools/lib/src/commands/attach.dart @@ -11,7 +11,6 @@ import '../base/common.dart'; import '../base/context.dart'; import '../base/file_system.dart'; import '../base/io.dart'; -import '../base/utils.dart'; import '../cache.dart'; import '../commands/daemon.dart'; import '../compile.dart'; diff --git a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart index c2f495634ec16..f3358eebd68cd 100644 --- a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart +++ b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart @@ -265,15 +265,35 @@ end } } - Future _produceFlutterFramework(Directory outputDirectory, BuildMode mode, Directory iPhoneBuildOutput, Directory simulatorBuildOutput, Directory modeDirectory) async { - final Status status = globals.logger.startProgress(' ├─Populating Flutter.framework...', timeout: timeoutConfiguration.slowOperation); - final String engineCacheFlutterFrameworkDirectory = globals.artifacts.getArtifactPath(Artifact.flutterFramework, platform: TargetPlatform.ios, mode: mode); - final String flutterFrameworkFileName = globals.fs.path.basename(engineCacheFlutterFrameworkDirectory); - final Directory fatFlutterFrameworkCopy = modeDirectory.childDirectory(flutterFrameworkFileName); + Future _produceFlutterFramework( + Directory outputDirectory, + BuildMode mode, + Directory iPhoneBuildOutput, + Directory simulatorBuildOutput, + Directory modeDirectory, + ) async { + final Status status = globals.logger.startProgress( + ' ├─Populating Flutter.framework...', + timeout: timeoutConfiguration.slowOperation, + ); + final String engineCacheFlutterFrameworkDirectory = globals.artifacts.getArtifactPath( + Artifact.flutterFramework, + platform: TargetPlatform.ios, + mode: mode, + ); + final String flutterFrameworkFileName = globals.fs.path.basename( + engineCacheFlutterFrameworkDirectory, + ); + final Directory fatFlutterFrameworkCopy = modeDirectory.childDirectory( + flutterFrameworkFileName, + ); try { // Copy universal engine cache framework to mode directory. - copyDirectorySync(globals.fs.directory(engineCacheFlutterFrameworkDirectory), fatFlutterFrameworkCopy); + fsUtils.copyDirectorySync( + globals.fs.directory(engineCacheFlutterFrameworkDirectory), + fatFlutterFrameworkCopy, + ); if (mode != BuildMode.debug) { final File fatFlutterFrameworkBinary = fatFlutterFrameworkCopy.childFile('Flutter'); @@ -295,7 +315,8 @@ end if (lipoResult.exitCode != 0) { throwToolExit( - 'Unable to remove simulator architecture in $mode: ${lipoResult.stderr}'); + 'Unable to remove simulator architecture in $mode: ${lipoResult.stderr}', + ); } } } finally { @@ -378,12 +399,18 @@ end } } - Future _produceAotAppFrameworkIfNeeded(BuildMode mode, Directory iPhoneBuildOutput, Directory destinationAppFrameworkDirectory) async { + Future _produceAotAppFrameworkIfNeeded( + BuildMode mode, + Directory iPhoneBuildOutput, + Directory destinationAppFrameworkDirectory, + ) async { if (mode == BuildMode.debug) { return; } final Status status = globals.logger.startProgress( - ' ├─Building Dart AOT for App.framework...', timeout: timeoutConfiguration.slowOperation); + ' ├─Building Dart AOT for App.framework...', + timeout: timeoutConfiguration.slowOperation, + ); try { await aotBuilder.build( platform: TargetPlatform.ios, @@ -399,7 +426,10 @@ end ); const String appFrameworkName = 'App.framework'; - copyDirectorySync(iPhoneBuildOutput.childDirectory(appFrameworkName), destinationAppFrameworkDirectory); + fsUtils.copyDirectorySync( + iPhoneBuildOutput.childDirectory(appFrameworkName), + destinationAppFrameworkDirectory, + ); } finally { status.stop(); } @@ -456,72 +486,96 @@ end buildPluginsResult = processUtils.runSync( pluginsBuildCommand, workingDirectory: _project.ios.hostAppRoot - .childDirectory('Pods') - .path, + .childDirectory('Pods') + .path, allowReentrantFlutter: false, ); if (buildPluginsResult.exitCode != 0) { - throwToolExit('Unable to build plugin frameworks for simulator: ${buildPluginsResult.stderr}'); + throwToolExit( + 'Unable to build plugin frameworks for simulator: ${buildPluginsResult.stderr}', + ); } } - final Directory iPhoneBuildConfiguration = iPhoneBuildOutput.childDirectory('$xcodeBuildConfiguration-iphoneos'); - final Directory simulatorBuildConfiguration = simulatorBuildOutput.childDirectory('$xcodeBuildConfiguration-iphonesimulator'); + final Directory iPhoneBuildConfiguration = iPhoneBuildOutput.childDirectory( + '$xcodeBuildConfiguration-iphoneos', + ); + final Directory simulatorBuildConfiguration = simulatorBuildOutput.childDirectory( + '$xcodeBuildConfiguration-iphonesimulator', + ); - for (final Directory builtProduct in iPhoneBuildConfiguration.listSync(followLinks: false).whereType()) { + final Iterable products = iPhoneBuildConfiguration + .listSync(followLinks: false) + .whereType(); + for (final Directory builtProduct in products) { for (final FileSystemEntity podProduct in builtProduct.listSync(followLinks: false)) { final String podFrameworkName = podProduct.basename; - if (globals.fs.path.extension(podFrameworkName) == '.framework') { - final String binaryName = globals.fs.path.basenameWithoutExtension(podFrameworkName); - if (boolArg('universal')) { - copyDirectorySync(podProduct as Directory, modeDirectory.childDirectory(podFrameworkName)); - final List lipoCommand = [ - 'xcrun', - 'lipo', - '-create', - globals.fs.path.join(podProduct.path, binaryName), - if (mode == BuildMode.debug) - simulatorBuildConfiguration.childDirectory(binaryName).childDirectory(podFrameworkName).childFile(binaryName).path, - '-output', - modeDirectory.childDirectory(podFrameworkName).childFile(binaryName).path - ]; - - final RunResult pluginsLipoResult = processUtils.runSync( - lipoCommand, - workingDirectory: outputDirectory.path, - allowReentrantFlutter: false, + if (globals.fs.path.extension(podFrameworkName) != '.framework') { + continue; + } + final String binaryName = globals.fs.path.basenameWithoutExtension(podFrameworkName); + if (boolArg('universal')) { + fsUtils.copyDirectorySync( + podProduct as Directory, + modeDirectory.childDirectory(podFrameworkName), + ); + final List lipoCommand = [ + 'xcrun', + 'lipo', + '-create', + globals.fs.path.join(podProduct.path, binaryName), + if (mode == BuildMode.debug) + simulatorBuildConfiguration + .childDirectory(binaryName) + .childDirectory(podFrameworkName) + .childFile(binaryName) + .path, + '-output', + modeDirectory.childDirectory(podFrameworkName).childFile(binaryName).path + ]; + + final RunResult pluginsLipoResult = processUtils.runSync( + lipoCommand, + workingDirectory: outputDirectory.path, + allowReentrantFlutter: false, + ); + + if (pluginsLipoResult.exitCode != 0) { + throwToolExit( + 'Unable to create universal $binaryName.framework: ${buildPluginsResult.stderr}', ); - - if (pluginsLipoResult.exitCode != 0) { - throwToolExit('Unable to create universal $binaryName.framework: ${buildPluginsResult.stderr}'); - } } + } - if (boolArg('xcframework')) { - final List xcframeworkCommand = [ - 'xcrun', - 'xcodebuild', - '-create-xcframework', + if (boolArg('xcframework')) { + final List xcframeworkCommand = [ + 'xcrun', + 'xcodebuild', + '-create-xcframework', + '-framework', + podProduct.path, + if (mode == BuildMode.debug) '-framework', - podProduct.path, - if (mode == BuildMode.debug) - '-framework', - if (mode == BuildMode.debug) - simulatorBuildConfiguration.childDirectory(binaryName).childDirectory(podFrameworkName).path, - '-output', - modeDirectory.childFile('$binaryName.xcframework').path - ]; - - final RunResult xcframeworkResult = processUtils.runSync( - xcframeworkCommand, - workingDirectory: outputDirectory.path, - allowReentrantFlutter: false, + if (mode == BuildMode.debug) + simulatorBuildConfiguration + .childDirectory(binaryName) + .childDirectory(podFrameworkName) + .path, + '-output', + modeDirectory.childFile('$binaryName.xcframework').path + ]; + + final RunResult xcframeworkResult = processUtils.runSync( + xcframeworkCommand, + workingDirectory: outputDirectory.path, + allowReentrantFlutter: false, + ); + + if (xcframeworkResult.exitCode != 0) { + throwToolExit( + 'Unable to create $binaryName.xcframework: ${xcframeworkResult.stderr}', ); - - if (xcframeworkResult.exitCode != 0) { - throwToolExit('Unable to create $binaryName.xcframework: ${xcframeworkResult.stderr}'); - } } } } @@ -536,7 +590,10 @@ end final String frameworkBinaryName = globals.fs.path.basenameWithoutExtension( fatFramework.basename); - final Status status = globals.logger.startProgress(' ├─Creating $frameworkBinaryName.xcframework...', timeout: timeoutConfiguration.fastOperation); + final Status status = globals.logger.startProgress( + ' ├─Creating $frameworkBinaryName.xcframework...', + timeout: timeoutConfiguration.fastOperation, + ); try { if (mode == BuildMode.debug) { _produceDebugXCFramework(fatFramework, frameworkBinaryName); @@ -556,22 +613,24 @@ end void _produceDebugXCFramework(Directory fatFramework, String frameworkBinaryName) { final String frameworkFileName = fatFramework.basename; final File fatFlutterFrameworkBinary = fatFramework.childFile( - frameworkBinaryName); + frameworkBinaryName, + ); final Directory temporaryOutput = globals.fs.systemTempDirectory.createTempSync( - 'flutter_tool_build_ios_framework.'); + 'flutter_tool_build_ios_framework.', + ); try { // Copy universal framework to variant directory. final Directory iPhoneBuildOutput = temporaryOutput.childDirectory( - 'ios') - ..createSync(recursive: true); + 'ios', + )..createSync(recursive: true); final Directory simulatorBuildOutput = temporaryOutput.childDirectory( - 'simulator') - ..createSync(recursive: true); + 'simulator', + )..createSync(recursive: true); final Directory armFlutterFrameworkDirectory = iPhoneBuildOutput - .childDirectory(frameworkFileName); + .childDirectory(frameworkFileName); final File armFlutterFrameworkBinary = armFlutterFrameworkDirectory - .childFile(frameworkBinaryName); - copyDirectorySync(fatFramework, armFlutterFrameworkDirectory); + .childFile(frameworkBinaryName); + fsUtils.copyDirectorySync(fatFramework, armFlutterFrameworkDirectory); // Create iOS framework. List lipoCommand = [ @@ -595,10 +654,10 @@ end // Create simulator framework. final Directory simulatorFlutterFrameworkDirectory = simulatorBuildOutput - .childDirectory(frameworkFileName); + .childDirectory(frameworkFileName); final File simulatorFlutterFrameworkBinary = simulatorFlutterFrameworkDirectory - .childFile(frameworkBinaryName); - copyDirectorySync(fatFramework, simulatorFlutterFrameworkDirectory); + .childFile(frameworkBinaryName); + fsUtils.copyDirectorySync(fatFramework, simulatorFlutterFrameworkDirectory); lipoCommand = [ 'xcrun', @@ -639,14 +698,19 @@ end if (xcframeworkResult.exitCode != 0) { throwToolExit( - 'Unable to create XCFramework: ${xcframeworkResult.stderr}'); + 'Unable to create XCFramework: ${xcframeworkResult.stderr}', + ); } } finally { temporaryOutput.deleteSync(recursive: true); } } - void _produceNonDebugXCFramework(BuildMode mode, Directory fatFramework, String frameworkBinaryName) { + void _produceNonDebugXCFramework( + BuildMode mode, + Directory fatFramework, + String frameworkBinaryName, + ) { // Simulator is only supported in Debug mode. // "Fat" framework here must only contain arm. final List xcframeworkCommand = [ diff --git a/packages/flutter_tools/lib/src/commands/create.dart b/packages/flutter_tools/lib/src/commands/create.dart index 1cdf8f0d87e3d..937e8e461a899 100644 --- a/packages/flutter_tools/lib/src/commands/create.dart +++ b/packages/flutter_tools/lib/src/commands/create.dart @@ -650,7 +650,7 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi int _injectGradleWrapper(FlutterProject project) { int filesCreated = 0; - copyDirectorySync( + fsUtils.copyDirectorySync( globals.cache.getArtifactDirectory('gradle_wrapper'), project.android.hostAppGradleRoot, onFileCopied: (File sourceFile, File destinationFile) { diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart index e42857901da01..006d5210b9507 100644 --- a/packages/flutter_tools/lib/src/commands/run.dart +++ b/packages/flutter_tools/lib/src/commands/run.dart @@ -8,6 +8,7 @@ import 'package:args/command_runner.dart'; import '../base/common.dart'; import '../base/file_system.dart'; +import '../base/io.dart'; import '../base/time.dart'; import '../base/utils.dart'; import '../build_info.dart'; diff --git a/packages/flutter_tools/lib/src/commands/screenshot.dart b/packages/flutter_tools/lib/src/commands/screenshot.dart index cc688a254fed7..e0a818f773391 100644 --- a/packages/flutter_tools/lib/src/commands/screenshot.dart +++ b/packages/flutter_tools/lib/src/commands/screenshot.dart @@ -6,7 +6,6 @@ import 'dart:async'; import '../base/common.dart'; import '../base/file_system.dart'; -import '../base/utils.dart'; import '../convert.dart'; import '../device.dart'; import '../globals.dart' as globals; @@ -110,7 +109,11 @@ class ScreenshotCommand extends FlutterCommand { } Future runScreenshot(File outputFile) async { - outputFile ??= getUniqueFile(globals.fs.currentDirectory, 'flutter', 'png'); + outputFile ??= fsUtils.getUniqueFile( + globals.fs.currentDirectory, + 'flutter', + 'png', + ); try { await device.takeScreenshot(outputFile); } catch (error) { @@ -121,7 +124,11 @@ class ScreenshotCommand extends FlutterCommand { Future runSkia(File outputFile) async { final Map skp = await _invokeVmServiceRpc('_flutter.screenshotSkp'); - outputFile ??= getUniqueFile(globals.fs.currentDirectory, 'flutter', 'skp'); + outputFile ??= fsUtils.getUniqueFile( + globals.fs.currentDirectory, + 'flutter', + 'skp', + ); final IOSink sink = outputFile.openWrite(); sink.add(base64.decode(skp['skp'] as String)); await sink.close(); @@ -131,7 +138,11 @@ class ScreenshotCommand extends FlutterCommand { Future runRasterizer(File outputFile) async { final Map response = await _invokeVmServiceRpc('_flutter.screenshot'); - outputFile ??= getUniqueFile(globals.fs.currentDirectory, 'flutter', 'png'); + outputFile ??= fsUtils.getUniqueFile( + globals.fs.currentDirectory, + 'flutter', + 'png', + ); final IOSink sink = outputFile.openWrite(); sink.add(base64.decode(response['screenshot'] as String)); await sink.close(); diff --git a/packages/flutter_tools/lib/src/commands/unpack.dart b/packages/flutter_tools/lib/src/commands/unpack.dart index f6466c2d1c3f5..c3861e8264a7a 100644 --- a/packages/flutter_tools/lib/src/commands/unpack.dart +++ b/packages/flutter_tools/lib/src/commands/unpack.dart @@ -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('/')) { - copyDirectorySync( + fsUtils.copyDirectorySync( globals.fs.directory(sourcePath), globals.fs.directory(targetPath), ); diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart index a220b42f4a1ad..d5b91f42bcb80 100644 --- a/packages/flutter_tools/lib/src/ios/mac.dart +++ b/packages/flutter_tools/lib/src/ios/mac.dart @@ -551,7 +551,10 @@ Future buildXcodeProject({ // (for example, kernel binary files produced from previous run). globals.fs.directory(outputDir).deleteSync(recursive: true); } - copyDirectorySync(globals.fs.directory(expectedOutputDirectory), globals.fs.directory(outputDir)); + fsUtils.copyDirectorySync( + globals.fs.directory(expectedOutputDirectory), + globals.fs.directory(outputDir), + ); } else { globals.printError('Build succeeded but the expected app at $expectedOutputDirectory not found'); } diff --git a/packages/flutter_tools/lib/src/persistent_tool_state.dart b/packages/flutter_tools/lib/src/persistent_tool_state.dart index 181131d29990f..3717ba009a49b 100644 --- a/packages/flutter_tools/lib/src/persistent_tool_state.dart +++ b/packages/flutter_tools/lib/src/persistent_tool_state.dart @@ -25,7 +25,10 @@ abstract class PersistentToolState { class _DefaultPersistentToolState implements PersistentToolState { _DefaultPersistentToolState([File configFile]) : - _config = Config(configFile ?? globals.fs.file(globals.fs.path.join(userHomePath(), _kFileName))); + _config = Config(configFile ?? globals.fs.file(globals.fs.path.join( + fsUtils.userHomePath, + _kFileName, + ))); static const String _kFileName = '.flutter_tool_state'; static const String _kRedisplayWelcomeMessage = 'redisplay-welcome-message'; diff --git a/packages/flutter_tools/lib/src/plugins.dart b/packages/flutter_tools/lib/src/plugins.dart index cd7eb4361dc1a..76220a58348a1 100644 --- a/packages/flutter_tools/lib/src/plugins.dart +++ b/packages/flutter_tools/lib/src/plugins.dart @@ -325,7 +325,7 @@ bool _writeFlutterPluginsList(FlutterProject project, List plugins) { pluginNames.add(plugin.name); } for (final Plugin plugin in plugins) { - flutterPluginsBuffer.write('${plugin.name}=${escapePath(plugin.path)}\n'); + flutterPluginsBuffer.write('${plugin.name}=${fsUtils.escapePath(plugin.path)}\n'); directAppDependencies.add({ 'name': plugin.name, // Extract the plugin dependencies which happen to be plugins. diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart index 6d14011e9c99b..fd8a48054fc5e 100644 --- a/packages/flutter_tools/lib/src/project.dart +++ b/packages/flutter_tools/lib/src/project.dart @@ -467,7 +467,10 @@ class IosProject implements XcodeBasedProject { if (!isModule) { return; } - final bool pubspecChanged = isOlderThanReference(entity: ephemeralDirectory, referenceFile: parent.pubspecFile); + final bool pubspecChanged = fsUtils.isOlderThanReference( + entity: ephemeralDirectory, + referenceFile: parent.pubspecFile, + ); final bool toolingChanged = globals.cache.isOlderThanToolsStamp(ephemeralDirectory); if (!pubspecChanged && !toolingChanged) { return; @@ -478,22 +481,37 @@ class IosProject implements XcodeBasedProject { .childDirectory('engine'); _deleteIfExistsSync(ephemeralDirectory); - _overwriteFromTemplate(globals.fs.path.join('module', 'ios', 'library'), ephemeralDirectory); + _overwriteFromTemplate( + globals.fs.path.join('module', 'ios', 'library'), + ephemeralDirectory, + ); // Add ephemeral host app, if a editable host app does not already exist. if (!_editableDirectory.existsSync()) { - _overwriteFromTemplate(globals.fs.path.join('module', 'ios', 'host_app_ephemeral'), ephemeralDirectory); + _overwriteFromTemplate( + globals.fs.path.join('module', 'ios', 'host_app_ephemeral'), + ephemeralDirectory, + ); if (hasPlugins(parent)) { - _overwriteFromTemplate(globals.fs.path.join('module', 'ios', 'host_app_ephemeral_cocoapods'), ephemeralDirectory); + _overwriteFromTemplate( + globals.fs.path.join('module', 'ios', 'host_app_ephemeral_cocoapods'), + ephemeralDirectory, + ); } // Copy podspec and framework from engine cache. The actual build mode // doesn't actually matter as it will be overwritten by xcode_backend.sh. // However, cocoapods will run before that script and requires something // to be in this location. - final Directory framework = globals.fs.directory(globals.artifacts.getArtifactPath(Artifact.flutterFramework, - platform: TargetPlatform.ios, mode: BuildMode.debug)); + final Directory framework = globals.fs.directory( + globals.artifacts.getArtifactPath(Artifact.flutterFramework, + platform: TargetPlatform.ios, + mode: BuildMode.debug, + )); if (framework.existsSync()) { final File podspec = framework.parent.childFile('Flutter.podspec'); - copyDirectorySync(framework, engineDest.childDirectory('Flutter.framework')); + fsUtils.copyDirectorySync( + framework, + engineDest.childDirectory('Flutter.framework'), + ); podspec.copySync(engineDest.childFile('Flutter.podspec').path); } } @@ -505,20 +523,36 @@ class IosProject implements XcodeBasedProject { throwToolExit('iOS host app is already editable. To start fresh, delete the ios/ folder.'); } _deleteIfExistsSync(ephemeralDirectory); - _overwriteFromTemplate(globals.fs.path.join('module', 'ios', 'library'), ephemeralDirectory); - _overwriteFromTemplate(globals.fs.path.join('module', 'ios', 'host_app_ephemeral'), _editableDirectory); - _overwriteFromTemplate(globals.fs.path.join('module', 'ios', 'host_app_ephemeral_cocoapods'), _editableDirectory); - _overwriteFromTemplate(globals.fs.path.join('module', 'ios', 'host_app_editable_cocoapods'), _editableDirectory); + _overwriteFromTemplate( + globals.fs.path.join('module', 'ios', 'library'), + ephemeralDirectory, + ); + _overwriteFromTemplate( + globals.fs.path.join('module', 'ios', 'host_app_ephemeral'), + _editableDirectory, + ); + _overwriteFromTemplate( + globals.fs.path.join('module', 'ios', 'host_app_ephemeral_cocoapods'), + _editableDirectory, + ); + _overwriteFromTemplate( + globals.fs.path.join('module', 'ios', 'host_app_editable_cocoapods'), + _editableDirectory, + ); await _updateGeneratedXcodeConfigIfNeeded(); await injectPlugins(parent); } @override - File get generatedXcodePropertiesFile => _flutterLibRoot.childDirectory('Flutter').childFile('Generated.xcconfig'); + File get generatedXcodePropertiesFile => _flutterLibRoot + .childDirectory('Flutter') + .childFile('Generated.xcconfig'); Directory get pluginRegistrantHost { return isModule - ? _flutterLibRoot.childDirectory('Flutter').childDirectory('FlutterPluginRegistrant') + ? _flutterLibRoot + .childDirectory('Flutter') + .childDirectory('FlutterPluginRegistrant') : hostAppRoot.childDirectory(_hostAppBundleName); } @@ -632,8 +666,10 @@ class AndroidProject { } bool _shouldRegenerateFromTemplate() { - return isOlderThanReference(entity: ephemeralDirectory, referenceFile: parent.pubspecFile) - || globals.cache.isOlderThanToolsStamp(ephemeralDirectory); + return fsUtils.isOlderThanReference( + entity: ephemeralDirectory, + referenceFile: parent.pubspecFile, + ) || globals.cache.isOlderThanToolsStamp(ephemeralDirectory); } Future makeHostAppEditable() async { diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index 39f6c98cf4fe2..e43d377ed9272 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart @@ -405,7 +405,10 @@ class FlutterDevice { }) async { final bool prebuiltMode = hotRunner.applicationBinary != null; final String modeName = hotRunner.debuggingOptions.buildInfo.friendlyModeName; - globals.printStatus('Launching ${getDisplayPath(hotRunner.mainPath)} on ${device.name} in $modeName mode...'); + globals.printStatus( + 'Launching ${fsUtils.getDisplayPath(hotRunner.mainPath)} ' + 'on ${device.name} in $modeName mode...', + ); final TargetPlatform targetPlatform = await device.targetPlatform; package = await ApplicationPackageFactory.instance.getPackageForPlatform( @@ -472,9 +475,15 @@ class FlutterDevice { final bool prebuiltMode = coldRunner.applicationBinary != null; if (coldRunner.mainPath == null) { assert(prebuiltMode); - globals.printStatus('Launching ${package.displayName} on ${device.name} in $modeName mode...'); + globals.printStatus( + 'Launching ${package.displayName} ' + 'on ${device.name} in $modeName mode...', + ); } else { - globals.printStatus('Launching ${getDisplayPath(coldRunner.mainPath)} on ${device.name} in $modeName mode...'); + globals.printStatus( + 'Launching ${fsUtils.getDisplayPath(coldRunner.mainPath)} ' + 'on ${device.name} in $modeName mode...', + ); } if (package == null) { @@ -849,8 +858,15 @@ abstract class ResidentRunner { Future screenshot(FlutterDevice device) async { assert(device.device.supportsScreenshot); - final Status status = globals.logger.startProgress('Taking screenshot for ${device.device.name}...', timeout: timeoutConfiguration.fastOperation); - final File outputFile = getUniqueFile(globals.fs.currentDirectory, 'flutter', 'png'); + final Status status = globals.logger.startProgress( + 'Taking screenshot for ${device.device.name}...', + timeout: timeoutConfiguration.fastOperation, + ); + final File outputFile = fsUtils.getUniqueFile( + globals.fs.currentDirectory, + 'flutter', + 'png', + ); try { if (supportsServiceProtocol && isRunningDebug) { await device.refreshViews(); @@ -881,7 +897,9 @@ abstract class ResidentRunner { } final int sizeKB = outputFile.lengthSync() ~/ 1024; status.stop(); - globals.printStatus('Screenshot written to ${globals.fs.path.relative(outputFile.path)} (${sizeKB}kB).'); + globals.printStatus( + 'Screenshot written to ${globals.fs.path.relative(outputFile.path)} (${sizeKB}kB).', + ); } catch (error) { status.cancel(); globals.printError('Error taking screenshot: $error'); diff --git a/packages/flutter_tools/lib/src/test/test_compiler.dart b/packages/flutter_tools/lib/src/test/test_compiler.dart index 7d434dcec40fa..30e90970c9ede 100644 --- a/packages/flutter_tools/lib/src/test/test_compiler.dart +++ b/packages/flutter_tools/lib/src/test/test_compiler.dart @@ -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. - ensureDirectoryExists(testFilePath); + fsUtils.ensureDirectoryExists(testFilePath); await outputFile.copy(testFilePath); } request.result.complete(kernelReadyToRun.path); diff --git a/packages/flutter_tools/test/general.shard/base/file_system_test.dart b/packages/flutter_tools/test/general.shard/base/file_system_test.dart index 2cb94fdd02053..e54b7c996e8d3 100644 --- a/packages/flutter_tools/test/general.shard/base/file_system_test.dart +++ b/packages/flutter_tools/test/general.shard/base/file_system_test.dart @@ -4,41 +4,41 @@ import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/file_system.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:mockito/mockito.dart'; import 'package:platform/platform.dart'; import '../../src/common.dart'; -import '../../src/context.dart'; + +class MockPlatform extends Mock implements Platform {} void main() { group('ensureDirectoryExists', () { MemoryFileSystem fs; + FileSystemUtils fsUtils; setUp(() { fs = MemoryFileSystem(); + fsUtils = FileSystemUtils( + fileSystem: fs, + platform: MockPlatform(), + ); }); - testUsingContext('recursively creates a directory if it does not exist', () async { - ensureDirectoryExists('foo/bar/baz.flx'); + testWithoutContext('recursively creates a directory if it does not exist', () async { + fsUtils.ensureDirectoryExists('foo/bar/baz.flx'); expect(fs.isDirectorySync('foo/bar'), true); - }, overrides: { - FileSystem: () => fs, - ProcessManager: () => FakeProcessManager.any(), }); - testUsingContext('throws tool exit on failure to create', () async { + testWithoutContext('throws tool exit on failure to create', () async { fs.file('foo').createSync(); - expect(() => ensureDirectoryExists('foo/bar.flx'), throwsToolExit()); - }, overrides: { - FileSystem: () => fs, - ProcessManager: () => FakeProcessManager.any(), + expect(() => fsUtils.ensureDirectoryExists('foo/bar.flx'), throwsToolExit()); }); }); group('copyDirectorySync', () { /// Test file_systems.copyDirectorySync() using MemoryFileSystem. /// Copies between 2 instances of file systems which is also supported by copyDirectorySync(). - test('test directory copy', () async { + testWithoutContext('test directory copy', () async { final MemoryFileSystem sourceMemoryFs = MemoryFileSystem(); const String sourcePath = '/some/origin'; final Directory sourceDirectory = await sourceMemoryFs.directory(sourcePath).create(recursive: true); @@ -52,7 +52,12 @@ void main() { final MemoryFileSystem targetMemoryFs = MemoryFileSystem(); const String targetPath = '/some/non-existent/target'; final Directory targetDirectory = targetMemoryFs.directory(targetPath); - copyDirectorySync(sourceDirectory, targetDirectory); + + final FileSystemUtils fsUtils = FileSystemUtils( + fileSystem: sourceMemoryFs, + platform: MockPlatform(), + ); + fsUtils.copyDirectorySync(sourceDirectory, targetDirectory); expect(targetDirectory.existsSync(), true); targetMemoryFs.currentDirectory = targetPath; @@ -66,16 +71,21 @@ void main() { expect(sourceMemoryFs.directory(sourcePath).listSync().length, 3); }); - testUsingContext('Skip files if shouldCopyFile returns false', () { - final Directory origin = globals.fs.directory('/origin'); + testWithoutContext('Skip files if shouldCopyFile returns false', () { + final MemoryFileSystem fileSystem = MemoryFileSystem(); + final FileSystemUtils fsUtils = FileSystemUtils( + fileSystem: fileSystem, + platform: MockPlatform(), + ); + final Directory origin = fileSystem.directory('/origin'); origin.createSync(); - globals.fs.file(globals.fs.path.join('origin', 'a.txt')).writeAsStringSync('irrelevant'); - globals.fs.directory('/origin/nested').createSync(); - globals.fs.file(globals.fs.path.join('origin', 'nested', 'a.txt')).writeAsStringSync('irrelevant'); - globals.fs.file(globals.fs.path.join('origin', 'nested', 'b.txt')).writeAsStringSync('irrelevant'); + fileSystem.file(fileSystem.path.join('origin', 'a.txt')).writeAsStringSync('irrelevant'); + fileSystem.directory('/origin/nested').createSync(); + fileSystem.file(fileSystem.path.join('origin', 'nested', 'a.txt')).writeAsStringSync('irrelevant'); + fileSystem.file(fileSystem.path.join('origin', 'nested', 'b.txt')).writeAsStringSync('irrelevant'); - final Directory destination = globals.fs.directory('/destination'); - copyDirectorySync(origin, destination, shouldCopyFile: (File origin, File dest) { + final Directory destination = fileSystem.directory('/destination'); + fsUtils.copyDirectorySync(origin, destination, shouldCopyFile: (File origin, File dest) { return origin.basename == 'b.txt'; }); @@ -85,53 +95,30 @@ void main() { expect(destination.childFile('a.txt').existsSync(), isFalse); expect(destination.childDirectory('nested').childFile('a.txt').existsSync(), isFalse); - }, overrides: { - FileSystem: () => MemoryFileSystem(), - ProcessManager: () => FakeProcessManager.any(), }); }); - group('canonicalizePath', () { - test('does not lowercase on Windows', () { - String path = 'C:\\Foo\\bAr\\cOOL.dart'; - expect(canonicalizePath(path), path); - // globals.fs.path.canonicalize does lowercase on Windows - expect(globals.fs.path.canonicalize(path), isNot(path)); - - path = '..\\bar\\.\\\\Foo'; - final String expected = globals.fs.path.join(globals.fs.currentDirectory.parent.absolute.path, 'bar', 'Foo'); - expect(canonicalizePath(path), expected); - // globals.fs.path.canonicalize should return the same result (modulo casing) - expect(globals.fs.path.canonicalize(path), expected.toLowerCase()); - }, testOn: 'windows'); - - test('does not lowercase on posix', () { - String path = '/Foo/bAr/cOOL.dart'; - expect(canonicalizePath(path), path); - // globals.fs.path.canonicalize and canonicalizePath should be the same on Posix - expect(globals.fs.path.canonicalize(path), path); - - path = '../bar/.//Foo'; - final String expected = globals.fs.path.join(globals.fs.currentDirectory.parent.absolute.path, 'bar', 'Foo'); - expect(canonicalizePath(path), expected); - }, testOn: 'posix'); - }); - group('escapePath', () { - testUsingContext('on Windows', () { - expect(escapePath('C:\\foo\\bar\\cool.dart'), 'C:\\\\foo\\\\bar\\\\cool.dart'); - expect(escapePath('foo\\bar\\cool.dart'), 'foo\\\\bar\\\\cool.dart'); - expect(escapePath('C:/foo/bar/cool.dart'), 'C:/foo/bar/cool.dart'); - }, overrides: { - Platform: () => FakePlatform(operatingSystem: 'windows'), + testWithoutContext('on Windows', () { + final MemoryFileSystem fileSystem = MemoryFileSystem(); + final FileSystemUtils fsUtils = FileSystemUtils( + fileSystem: fileSystem, + platform: FakePlatform(operatingSystem: 'windows'), + ); + expect(fsUtils.escapePath('C:\\foo\\bar\\cool.dart'), 'C:\\\\foo\\\\bar\\\\cool.dart'); + expect(fsUtils.escapePath('foo\\bar\\cool.dart'), 'foo\\\\bar\\\\cool.dart'); + expect(fsUtils.escapePath('C:/foo/bar/cool.dart'), 'C:/foo/bar/cool.dart'); }); - testUsingContext('on Linux', () { - expect(escapePath('/foo/bar/cool.dart'), '/foo/bar/cool.dart'); - expect(escapePath('foo/bar/cool.dart'), 'foo/bar/cool.dart'); - expect(escapePath('foo\\cool.dart'), 'foo\\cool.dart'); - }, overrides: { - Platform: () => FakePlatform(operatingSystem: 'linux'), + testWithoutContext('on Linux', () { + final MemoryFileSystem fileSystem = MemoryFileSystem(); + final FileSystemUtils fsUtils = FileSystemUtils( + fileSystem: fileSystem, + platform: FakePlatform(operatingSystem: 'linux'), + ); + expect(fsUtils.escapePath('/foo/bar/cool.dart'), '/foo/bar/cool.dart'); + expect(fsUtils.escapePath('foo/bar/cool.dart'), 'foo/bar/cool.dart'); + expect(fsUtils.escapePath('foo\\cool.dart'), 'foo\\cool.dart'); }); }); }