From adfb789edb122444f9336a12c7c05a9d4a12a6fa Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 13 Jul 2023 12:15:35 -0400 Subject: [PATCH] [xdg_directories] Remove `process` dependency Replaces the `process` dependency with direct use of `io.Process`, to reduce external dependencies, since this is a `path_provider` dependency and thus a core package. Fixes https://github.com/flutter/flutter/issues/129787 --- packages/xdg_directories/CHANGELOG.md | 3 +- .../xdg_directories/lib/xdg_directories.dart | 61 +++++++++++++++---- packages/xdg_directories/pubspec.yaml | 3 +- .../test/xdg_directories_test.dart | 34 +++++------ 4 files changed, 66 insertions(+), 35 deletions(-) diff --git a/packages/xdg_directories/CHANGELOG.md b/packages/xdg_directories/CHANGELOG.md index 5c63413ed555..ff8640df04d1 100644 --- a/packages/xdg_directories/CHANGELOG.md +++ b/packages/xdg_directories/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 1.0.1 +* Removes `process` dependency. * Updates minimum supported SDK version to Flutter 3.3/Dart 2.18. ## 1.0.0 diff --git a/packages/xdg_directories/lib/xdg_directories.dart b/packages/xdg_directories/lib/xdg_directories.dart index bf6de2d31292..7e115a5aab25 100644 --- a/packages/xdg_directories/lib/xdg_directories.dart +++ b/packages/xdg_directories/lib/xdg_directories.dart @@ -9,7 +9,9 @@ import 'dart:io'; import 'package:meta/meta.dart'; import 'package:path/path.dart' as path; -import 'package:process/process.dart'; + +// From errno definitions. +const int _noSuchFileError = 2; /// An override function used by the tests to override the environment variable /// lookups using [xdgEnvironmentOverride]. @@ -36,16 +38,44 @@ EnvironmentAccessor? _xdgEnvironmentOverride; EnvironmentAccessor _getenv = _productionGetEnv; String? _productionGetEnv(String value) => Platform.environment[value]; -/// A testing function that replaces the process manager used to run xdg-user-path -/// with the one supplied. +/// A wrapper around Process.runSync to allow injection of a fake in tests. +@visibleForTesting +abstract class XdgProcessRunner { + /// Runs the given command synchronously. + ProcessResult runSync( + String executable, + List arguments, { + Encoding? stdoutEncoding = systemEncoding, + Encoding? stderrEncoding = systemEncoding, + }); +} + +class _DefaultProcessRunner implements XdgProcessRunner { + const _DefaultProcessRunner(); + + @override + ProcessResult runSync(String executable, List arguments, + {Encoding? stdoutEncoding = systemEncoding, + Encoding? stderrEncoding = systemEncoding}) { + return Process.runSync( + executable, + arguments, + stdoutEncoding: stdoutEncoding, + stderrEncoding: stderrEncoding, + ); + } +} + +/// A testing function that replaces the process runner used to run +/// xdg-user-path with the one supplied. /// /// Only available to tests. @visibleForTesting -set xdgProcessManager(ProcessManager processManager) { - _processManager = processManager; +set xdgProcessRunner(XdgProcessRunner processRunner) { + _processRunner = processRunner; } -ProcessManager _processManager = const LocalProcessManager(); +XdgProcessRunner _processRunner = const _DefaultProcessRunner(); List _directoryListFromEnvironment( String envVar, List fallback) { @@ -152,13 +182,20 @@ Directory? get runtimeDir => _directoryFromEnvironment('XDG_RUNTIME_DIR'); /// /// If the `xdg-user-dir` executable is not present this returns null. Directory? getUserDirectory(String dirName) { - if (!_processManager.canRun('xdg-user-dir')) { - return null; + final ProcessResult result; + try { + result = _processRunner.runSync( + 'xdg-user-dir', + [dirName], + stdoutEncoding: utf8, + ); + } on ProcessException catch (e) { + // Silently return null if it's missing, otherwise pass the exception up. + if (e.errorCode == _noSuchFileError) { + return null; + } + rethrow; } - final ProcessResult result = _processManager.runSync( - ['xdg-user-dir', dirName], - stdoutEncoding: utf8, - ); final String path = (result.stdout as String).split('\n')[0]; return Directory(path); } diff --git a/packages/xdg_directories/pubspec.yaml b/packages/xdg_directories/pubspec.yaml index edf6517739ff..e9c46285da84 100644 --- a/packages/xdg_directories/pubspec.yaml +++ b/packages/xdg_directories/pubspec.yaml @@ -2,7 +2,7 @@ name: xdg_directories description: A Dart package for reading XDG directory configuration information on Linux. repository: https://github.com/flutter/packages/tree/main/packages/xdg_directories issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+xdg_directories%22 -version: 1.0.0 +version: 1.0.1 environment: sdk: ">=2.18.0 <4.0.0" @@ -13,7 +13,6 @@ platforms: dependencies: meta: ^1.3.0 path: ^1.8.0 - process: ^4.0.0 dev_dependencies: test: ^1.16.0 diff --git a/packages/xdg_directories/test/xdg_directories_test.dart b/packages/xdg_directories/test/xdg_directories_test.dart index b3c95d3df7f8..9c99afdaf8d9 100644 --- a/packages/xdg_directories/test/xdg_directories_test.dart +++ b/packages/xdg_directories/test/xdg_directories_test.dart @@ -6,7 +6,6 @@ import 'dart:convert'; import 'dart:io'; import 'package:path/path.dart' as path; -import 'package:process/process.dart'; import 'package:test/fake.dart'; import 'package:test/test.dart'; import 'package:xdg_directories/xdg_directories.dart' as xdg; @@ -27,6 +26,8 @@ void main() { String testPath(String subdir) => path.join(testRootPath(), subdir); setUp(() { + xdg.xdgProcessRunner = + FakeProcessRunner({}, canRunExecutable: false); tmpDir = Directory.systemTemp.createTempSync('xdg_test'); fakeEnv.clear(); fakeEnv['HOME'] = testRootPath(); @@ -103,24 +104,22 @@ XDG_VIDEOS_DIR="$HOME/Videos" 'TEMPLATES': testPath('Templates'), 'VIDEOS': testPath('Videos'), }; - xdg.xdgProcessManager = FakeProcessManager(expected); + xdg.xdgProcessRunner = FakeProcessRunner(expected); final Set userDirs = xdg.getUserDirectoryNames(); expect(userDirs, equals(expected.keys.toSet())); for (final String key in userDirs) { expect(xdg.getUserDirectory(key)!.path, equals(expected[key]), reason: 'Path $key value not correct'); } - xdg.xdgProcessManager = const LocalProcessManager(); }); test('Returns null when xdg-user-dir executable is not present', () { - xdg.xdgProcessManager = FakeProcessManager( + xdg.xdgProcessRunner = FakeProcessRunner( {}, canRunExecutable: false, ); expect(xdg.getUserDirectory('DESKTOP'), isNull, reason: 'Found xdg user directory without access to xdg-user-dir'); - xdg.xdgProcessManager = const LocalProcessManager(); }); test('Throws StateError when HOME not set', () { @@ -131,27 +130,22 @@ XDG_VIDEOS_DIR="$HOME/Videos" }); } -class FakeProcessManager extends Fake implements ProcessManager { - FakeProcessManager(this.expected, {this.canRunExecutable = true}); +class FakeProcessRunner extends Fake implements xdg.XdgProcessRunner { + FakeProcessRunner(this.expected, {this.canRunExecutable = true}); Map expected; final bool canRunExecutable; @override ProcessResult runSync( - List command, { - String? workingDirectory, - Map? environment, - bool includeParentEnvironment = true, - bool runInShell = false, - Encoding stdoutEncoding = systemEncoding, - Encoding stderrEncoding = systemEncoding, + String executable, + List arguments, { + Encoding? stdoutEncoding = systemEncoding, + Encoding? stderrEncoding = systemEncoding, }) { - return ProcessResult(0, 0, expected[command[1]], ''); - } - - @override - bool canRun(dynamic executable, {String? workingDirectory}) { - return canRunExecutable; + if (!canRunExecutable) { + throw ProcessException(executable, arguments, 'No such executable', 2); + } + return ProcessResult(0, 0, expected[arguments.first], ''); } }