diff --git a/packages/flutter_tools/lib/runner.dart b/packages/flutter_tools/lib/runner.dart index c2f47c57585..9f2e059b607 100644 --- a/packages/flutter_tools/lib/runner.dart +++ b/packages/flutter_tools/lib/runner.dart @@ -191,7 +191,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 = fsUtils.getUniqueFile(crashFileSystem.currentDirectory, 'flutter', 'log'); + File crashFile = getUniqueFile(crashFileSystem.currentDirectory, 'flutter', 'log'); final StringBuffer buffer = StringBuffer(); @@ -211,7 +211,7 @@ Future _createLocalCrashReport(List 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 = 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 8e71ba00574..8a976650dd7 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) { - fsUtils.copyDirectorySync( + copyDirectorySync( globals.cache.getArtifactDirectory('gradle_wrapper'), directory, shouldCopyFile: (File sourceFile, File destinationFile) { @@ -267,10 +267,10 @@ void updateLocalProperties({ } if (androidSdk != null) { - changeIfNecessary('sdk.dir', fsUtils.escapePath(androidSdk.directory)); + changeIfNecessary('sdk.dir', escapePath(androidSdk.directory)); } - changeIfNecessary('flutter.sdk', fsUtils.escapePath(Cache.flutterRoot)); + changeIfNecessary('flutter.sdk', 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'] = fsUtils.escapePath(androidSdk.directory); + settings.values['sdk.dir'] = 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 3f69bf2ec4e..619116aa5e7 100644 --- a/packages/flutter_tools/lib/src/base/config.dart +++ b/packages/flutter_tools/lib/src/base/config.dart @@ -11,10 +11,7 @@ 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', - )); + _configFile = configFile ?? globals.fs.file(globals.fs.path.join(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 089101a2b8e..6e3ccce7b23 100644 --- a/packages/flutter_tools/lib/src/base/file_system.dart +++ b/packages/flutter_tools/lib/src/base/file_system.dart @@ -4,15 +4,94 @@ 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}'); + } +} + +/// 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'); + } + } +} + +/// 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; + } + 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); @@ -23,130 +102,10 @@ 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() ?? _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; - - /// 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}'); - } - } - - /// 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'); - } - } - } - - /// 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 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; - } - - /// 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; - - /// 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 get userHomePath { - final String envKey = _platform.operatingSystem == 'windows' ? 'APPDATA' : 'HOME'; - return _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 userHomePath() { + final String envKey = globals.platform.operatingSystem == 'windows' ? 'APPDATA' : 'HOME'; + return globals.platform.environment[envKey] ?? '.'; } diff --git a/packages/flutter_tools/lib/src/base/io.dart b/packages/flutter_tools/lib/src/base/io.dart index 3e71f26fc82..40ca323f765 100644 --- a/packages/flutter_tools/lib/src/base/io.dart +++ b/packages/flutter_tools/lib/src/base/io.dart @@ -33,7 +33,6 @@ import 'dart:io' as io InternetAddressType, IOSink, NetworkInterface, - pid, Process, ProcessInfo, ProcessSignal, @@ -253,14 +252,6 @@ 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 cc13356ba6b..8a241210c5a 100644 --- a/packages/flutter_tools/lib/src/base/utils.dart +++ b/packages/flutter_tools/lib/src/base/utils.dart @@ -11,6 +11,7 @@ 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`. @@ -50,10 +51,29 @@ 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(); @@ -66,9 +86,11 @@ String getElapsedAsMilliseconds(Duration duration) { return '${kMillisecondsFormat.format(duration.inMilliseconds)}ms'; } -/// 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'; +/// 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; } /// A class to maintain a list of items, fire events when items are added or @@ -293,6 +315,13 @@ 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 fecf566706d..491046bf72b 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,7 +14,6 @@ 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'; @@ -389,10 +388,7 @@ class _ExperimentalResidentWebRunner extends ResidentWebRunner { return 1; } final String modeName = debuggingOptions.buildInfo.friendlyModeName; - globals.printStatus( - 'Launching ${fsUtils.getDisplayPath(target)} ' - 'on ${device.device.name} in $modeName mode...', - ); + globals.printStatus('Launching ${getDisplayPath(target)} on ${device.device.name} in $modeName mode...'); final String effectiveHostname = debuggingOptions.hostname ?? 'localhost'; final int hostPort = debuggingOptions.port == null ? await os.findFreePort() @@ -591,9 +587,7 @@ class _DwdsResidentWebRunner extends ResidentWebRunner { } final String modeName = debuggingOptions.buildInfo.friendlyModeName; globals.printStatus( - 'Launching ${fsUtils.getDisplayPath(target)} ' - 'on ${device.device.name} in $modeName mode...', - ); + 'Launching ${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 24da1647eab..df9c642a4e8 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,23 +82,14 @@ 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), - ); - fsUtils.copyDirectorySync( - childDirectory.childDirectory('lib'), - globals.fs.directory(path), - ); + final String path = globals.fs.path.join(testOutputDir, 'packages', + globals.fs.path.basename(childDirectory.path)); + copyDirectorySync(childDirectory.childDirectory('lib'), globals.fs.directory(path)); } final Directory outputDirectory = rootDirectory - .childDirectory(projectName) - .childDirectory('test'); - fsUtils.copyDirectorySync( - outputDirectory, - globals.fs.directory(globals.fs.path.join(testOutputDir)), - ); + .childDirectory(projectName) + .childDirectory('test'); + 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 a0d185df9ba..fb3c3dfe32b 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}=${fsUtils.escapePath(p.path)}') - .join('\n'); + .map((Plugin p) => '${p.name}=${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 d7bf786c137..4320f34d81f 100644 --- a/packages/flutter_tools/lib/src/cache.dart +++ b/packages/flutter_tools/lib/src/cache.dart @@ -346,10 +346,7 @@ class Cache { /// [entity] doesn't exist. bool isOlderThanToolsStamp(FileSystemEntity entity) { final File flutterToolsStamp = getStampFileFor('flutter_tools'); - return fsUtils.isOlderThanReference( - entity: entity, - referenceFile: flutterToolsStamp, - ); + return isOlderThanReference(entity: entity, referenceFile: flutterToolsStamp); } bool isUpToDate() => _artifacts.every((ArtifactSet artifact) => artifact.isUpToDate()); @@ -915,7 +912,7 @@ class AndroidMavenArtifacts extends ArtifactSet { ); try { final String gradleExecutable = gradle.absolute.path; - final String flutterSdk = fsUtils.escapePath(Cache.flutterRoot); + final String flutterSdk = 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 54f10e5033d..10e0787ae37 100644 --- a/packages/flutter_tools/lib/src/commands/attach.dart +++ b/packages/flutter_tools/lib/src/commands/attach.dart @@ -11,6 +11,7 @@ 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 f3358eebd68..c2f495634ec 100644 --- a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart +++ b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart @@ -265,35 +265,15 @@ 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. - fsUtils.copyDirectorySync( - globals.fs.directory(engineCacheFlutterFrameworkDirectory), - fatFlutterFrameworkCopy, - ); + copyDirectorySync(globals.fs.directory(engineCacheFlutterFrameworkDirectory), fatFlutterFrameworkCopy); if (mode != BuildMode.debug) { final File fatFlutterFrameworkBinary = fatFlutterFrameworkCopy.childFile('Flutter'); @@ -315,8 +295,7 @@ 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 { @@ -399,18 +378,12 @@ 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, @@ -426,10 +399,7 @@ end ); const String appFrameworkName = 'App.framework'; - fsUtils.copyDirectorySync( - iPhoneBuildOutput.childDirectory(appFrameworkName), - destinationAppFrameworkDirectory, - ); + copyDirectorySync(iPhoneBuildOutput.childDirectory(appFrameworkName), destinationAppFrameworkDirectory); } finally { status.stop(); } @@ -486,96 +456,72 @@ 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'); - final Iterable products = iPhoneBuildConfiguration - .listSync(followLinks: false) - .whereType(); - for (final Directory builtProduct in products) { + for (final Directory builtProduct in iPhoneBuildConfiguration.listSync(followLinks: false).whereType()) { for (final FileSystemEntity podProduct in builtProduct.listSync(followLinks: false)) { final String podFrameworkName = podProduct.basename; - 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 - ]; + 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 (pluginsLipoResult.exitCode != 0) { - throwToolExit( - 'Unable to create universal $binaryName.framework: ${buildPluginsResult.stderr}', + 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 (boolArg('xcframework')) { - final List xcframeworkCommand = [ - 'xcrun', - 'xcodebuild', - '-create-xcframework', - '-framework', - podProduct.path, - if (mode == BuildMode.debug) + if (boolArg('xcframework')) { + final List xcframeworkCommand = [ + 'xcrun', + 'xcodebuild', + '-create-xcframework', '-framework', - if (mode == BuildMode.debug) - simulatorBuildConfiguration - .childDirectory(binaryName) - .childDirectory(podFrameworkName) - .path, - '-output', - modeDirectory.childFile('$binaryName.xcframework').path - ]; + 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 (xcframeworkResult.exitCode != 0) { - throwToolExit( - 'Unable to create $binaryName.xcframework: ${xcframeworkResult.stderr}', + final RunResult xcframeworkResult = processUtils.runSync( + xcframeworkCommand, + workingDirectory: outputDirectory.path, + allowReentrantFlutter: false, ); + + if (xcframeworkResult.exitCode != 0) { + throwToolExit('Unable to create $binaryName.xcframework: ${xcframeworkResult.stderr}'); + } } } } @@ -590,10 +536,7 @@ 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); @@ -613,24 +556,22 @@ 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); - fsUtils.copyDirectorySync(fatFramework, armFlutterFrameworkDirectory); + .childFile(frameworkBinaryName); + copyDirectorySync(fatFramework, armFlutterFrameworkDirectory); // Create iOS framework. List lipoCommand = [ @@ -654,10 +595,10 @@ end // Create simulator framework. final Directory simulatorFlutterFrameworkDirectory = simulatorBuildOutput - .childDirectory(frameworkFileName); + .childDirectory(frameworkFileName); final File simulatorFlutterFrameworkBinary = simulatorFlutterFrameworkDirectory - .childFile(frameworkBinaryName); - fsUtils.copyDirectorySync(fatFramework, simulatorFlutterFrameworkDirectory); + .childFile(frameworkBinaryName); + copyDirectorySync(fatFramework, simulatorFlutterFrameworkDirectory); lipoCommand = [ 'xcrun', @@ -698,19 +639,14 @@ 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 937e8e461a8..1cdf8f0d87e 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; - fsUtils.copyDirectorySync( + 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 006d5210b95..e42857901da 100644 --- a/packages/flutter_tools/lib/src/commands/run.dart +++ b/packages/flutter_tools/lib/src/commands/run.dart @@ -8,7 +8,6 @@ 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 e0a818f7733..cc688a254fe 100644 --- a/packages/flutter_tools/lib/src/commands/screenshot.dart +++ b/packages/flutter_tools/lib/src/commands/screenshot.dart @@ -6,6 +6,7 @@ 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; @@ -109,11 +110,7 @@ class ScreenshotCommand extends FlutterCommand { } Future runScreenshot(File outputFile) async { - outputFile ??= fsUtils.getUniqueFile( - globals.fs.currentDirectory, - 'flutter', - 'png', - ); + outputFile ??= getUniqueFile(globals.fs.currentDirectory, 'flutter', 'png'); try { await device.takeScreenshot(outputFile); } catch (error) { @@ -124,11 +121,7 @@ class ScreenshotCommand extends FlutterCommand { Future runSkia(File outputFile) async { final Map skp = await _invokeVmServiceRpc('_flutter.screenshotSkp'); - outputFile ??= fsUtils.getUniqueFile( - globals.fs.currentDirectory, - 'flutter', - 'skp', - ); + outputFile ??= getUniqueFile(globals.fs.currentDirectory, 'flutter', 'skp'); final IOSink sink = outputFile.openWrite(); sink.add(base64.decode(skp['skp'] as String)); await sink.close(); @@ -138,11 +131,7 @@ class ScreenshotCommand extends FlutterCommand { Future runRasterizer(File outputFile) async { final Map response = await _invokeVmServiceRpc('_flutter.screenshot'); - outputFile ??= fsUtils.getUniqueFile( - globals.fs.currentDirectory, - 'flutter', - 'png', - ); + outputFile ??= 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 c3861e8264a..f6466c2d1c3 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('/')) { - fsUtils.copyDirectorySync( + 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 d5b91f42bcb..a220b42f4a1 100644 --- a/packages/flutter_tools/lib/src/ios/mac.dart +++ b/packages/flutter_tools/lib/src/ios/mac.dart @@ -551,10 +551,7 @@ Future buildXcodeProject({ // (for example, kernel binary files produced from previous run). globals.fs.directory(outputDir).deleteSync(recursive: true); } - fsUtils.copyDirectorySync( - globals.fs.directory(expectedOutputDirectory), - globals.fs.directory(outputDir), - ); + 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 3717ba009a4..181131d2999 100644 --- a/packages/flutter_tools/lib/src/persistent_tool_state.dart +++ b/packages/flutter_tools/lib/src/persistent_tool_state.dart @@ -25,10 +25,7 @@ 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(configFile ?? globals.fs.file(globals.fs.path.join(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 76220a58348..cd7eb4361dc 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}=${fsUtils.escapePath(plugin.path)}\n'); + flutterPluginsBuffer.write('${plugin.name}=${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 fd8a48054fc..6d14011e9c9 100644 --- a/packages/flutter_tools/lib/src/project.dart +++ b/packages/flutter_tools/lib/src/project.dart @@ -467,10 +467,7 @@ class IosProject implements XcodeBasedProject { if (!isModule) { return; } - final bool pubspecChanged = fsUtils.isOlderThanReference( - entity: ephemeralDirectory, - referenceFile: parent.pubspecFile, - ); + final bool pubspecChanged = isOlderThanReference(entity: ephemeralDirectory, referenceFile: parent.pubspecFile); final bool toolingChanged = globals.cache.isOlderThanToolsStamp(ephemeralDirectory); if (!pubspecChanged && !toolingChanged) { return; @@ -481,37 +478,22 @@ 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'); - fsUtils.copyDirectorySync( - framework, - engineDest.childDirectory('Flutter.framework'), - ); + copyDirectorySync(framework, engineDest.childDirectory('Flutter.framework')); podspec.copySync(engineDest.childFile('Flutter.podspec').path); } } @@ -523,36 +505,20 @@ 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); } @@ -666,10 +632,8 @@ class AndroidProject { } bool _shouldRegenerateFromTemplate() { - return fsUtils.isOlderThanReference( - entity: ephemeralDirectory, - referenceFile: parent.pubspecFile, - ) || globals.cache.isOlderThanToolsStamp(ephemeralDirectory); + return 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 e43d377ed92..39f6c98cf4f 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart @@ -405,10 +405,7 @@ class FlutterDevice { }) async { final bool prebuiltMode = hotRunner.applicationBinary != null; final String modeName = hotRunner.debuggingOptions.buildInfo.friendlyModeName; - globals.printStatus( - 'Launching ${fsUtils.getDisplayPath(hotRunner.mainPath)} ' - 'on ${device.name} in $modeName mode...', - ); + globals.printStatus('Launching ${getDisplayPath(hotRunner.mainPath)} on ${device.name} in $modeName mode...'); final TargetPlatform targetPlatform = await device.targetPlatform; package = await ApplicationPackageFactory.instance.getPackageForPlatform( @@ -475,15 +472,9 @@ 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 ${fsUtils.getDisplayPath(coldRunner.mainPath)} ' - 'on ${device.name} in $modeName mode...', - ); + globals.printStatus('Launching ${getDisplayPath(coldRunner.mainPath)} on ${device.name} in $modeName mode...'); } if (package == null) { @@ -858,15 +849,8 @@ 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 = fsUtils.getUniqueFile( - globals.fs.currentDirectory, - 'flutter', - 'png', - ); + final Status status = globals.logger.startProgress('Taking screenshot for ${device.device.name}...', timeout: timeoutConfiguration.fastOperation); + final File outputFile = getUniqueFile(globals.fs.currentDirectory, 'flutter', 'png'); try { if (supportsServiceProtocol && isRunningDebug) { await device.refreshViews(); @@ -897,9 +881,7 @@ 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 30e90970c9e..7d434dcec40 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. - fsUtils.ensureDirectoryExists(testFilePath); + 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 e54b7c996e8..2cb94fdd020 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:mockito/mockito.dart'; +import 'package:flutter_tools/src/globals.dart' as globals; import 'package:platform/platform.dart'; import '../../src/common.dart'; - -class MockPlatform extends Mock implements Platform {} +import '../../src/context.dart'; void main() { group('ensureDirectoryExists', () { MemoryFileSystem fs; - FileSystemUtils fsUtils; setUp(() { fs = MemoryFileSystem(); - fsUtils = FileSystemUtils( - fileSystem: fs, - platform: MockPlatform(), - ); }); - testWithoutContext('recursively creates a directory if it does not exist', () async { - fsUtils.ensureDirectoryExists('foo/bar/baz.flx'); + testUsingContext('recursively creates a directory if it does not exist', () async { + ensureDirectoryExists('foo/bar/baz.flx'); expect(fs.isDirectorySync('foo/bar'), true); + }, overrides: { + FileSystem: () => fs, + ProcessManager: () => FakeProcessManager.any(), }); - testWithoutContext('throws tool exit on failure to create', () async { + testUsingContext('throws tool exit on failure to create', () async { fs.file('foo').createSync(); - expect(() => fsUtils.ensureDirectoryExists('foo/bar.flx'), throwsToolExit()); + expect(() => ensureDirectoryExists('foo/bar.flx'), throwsToolExit()); + }, overrides: { + FileSystem: () => fs, + ProcessManager: () => FakeProcessManager.any(), }); }); group('copyDirectorySync', () { /// Test file_systems.copyDirectorySync() using MemoryFileSystem. /// Copies between 2 instances of file systems which is also supported by copyDirectorySync(). - testWithoutContext('test directory copy', () async { + test('test directory copy', () async { final MemoryFileSystem sourceMemoryFs = MemoryFileSystem(); const String sourcePath = '/some/origin'; final Directory sourceDirectory = await sourceMemoryFs.directory(sourcePath).create(recursive: true); @@ -52,12 +52,7 @@ void main() { final MemoryFileSystem targetMemoryFs = MemoryFileSystem(); const String targetPath = '/some/non-existent/target'; final Directory targetDirectory = targetMemoryFs.directory(targetPath); - - final FileSystemUtils fsUtils = FileSystemUtils( - fileSystem: sourceMemoryFs, - platform: MockPlatform(), - ); - fsUtils.copyDirectorySync(sourceDirectory, targetDirectory); + copyDirectorySync(sourceDirectory, targetDirectory); expect(targetDirectory.existsSync(), true); targetMemoryFs.currentDirectory = targetPath; @@ -71,21 +66,16 @@ void main() { expect(sourceMemoryFs.directory(sourcePath).listSync().length, 3); }); - 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'); + testUsingContext('Skip files if shouldCopyFile returns false', () { + final Directory origin = globals.fs.directory('/origin'); origin.createSync(); - 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'); + 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'); - final Directory destination = fileSystem.directory('/destination'); - fsUtils.copyDirectorySync(origin, destination, shouldCopyFile: (File origin, File dest) { + final Directory destination = globals.fs.directory('/destination'); + copyDirectorySync(origin, destination, shouldCopyFile: (File origin, File dest) { return origin.basename == 'b.txt'; }); @@ -95,30 +85,53 @@ 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', () { - 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 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 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'); + 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'), }); }); }