mirror of
https://github.com/flutter/packages.git
synced 2025-06-30 14:47:22 +08:00
[xdg_directories] Remove process
dependency (#4460)
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
This commit is contained in:
@ -1,5 +1,6 @@
|
|||||||
## NEXT
|
## 1.0.1
|
||||||
|
|
||||||
|
* Removes `process` dependency.
|
||||||
* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18.
|
* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18.
|
||||||
|
|
||||||
## 1.0.0
|
## 1.0.0
|
||||||
|
@ -9,7 +9,9 @@ import 'dart:io';
|
|||||||
|
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
import 'package:path/path.dart' as path;
|
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
|
/// An override function used by the tests to override the environment variable
|
||||||
/// lookups using [xdgEnvironmentOverride].
|
/// lookups using [xdgEnvironmentOverride].
|
||||||
@ -36,16 +38,44 @@ EnvironmentAccessor? _xdgEnvironmentOverride;
|
|||||||
EnvironmentAccessor _getenv = _productionGetEnv;
|
EnvironmentAccessor _getenv = _productionGetEnv;
|
||||||
String? _productionGetEnv(String value) => Platform.environment[value];
|
String? _productionGetEnv(String value) => Platform.environment[value];
|
||||||
|
|
||||||
/// A testing function that replaces the process manager used to run xdg-user-path
|
/// A wrapper around Process.runSync to allow injection of a fake in tests.
|
||||||
/// with the one supplied.
|
@visibleForTesting
|
||||||
|
abstract class XdgProcessRunner {
|
||||||
|
/// Runs the given command synchronously.
|
||||||
|
ProcessResult runSync(
|
||||||
|
String executable,
|
||||||
|
List<String> arguments, {
|
||||||
|
Encoding? stdoutEncoding = systemEncoding,
|
||||||
|
Encoding? stderrEncoding = systemEncoding,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DefaultProcessRunner implements XdgProcessRunner {
|
||||||
|
const _DefaultProcessRunner();
|
||||||
|
|
||||||
|
@override
|
||||||
|
ProcessResult runSync(String executable, List<String> 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.
|
/// Only available to tests.
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
set xdgProcessManager(ProcessManager processManager) {
|
set xdgProcessRunner(XdgProcessRunner processRunner) {
|
||||||
_processManager = processManager;
|
_processRunner = processRunner;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessManager _processManager = const LocalProcessManager();
|
XdgProcessRunner _processRunner = const _DefaultProcessRunner();
|
||||||
|
|
||||||
List<Directory> _directoryListFromEnvironment(
|
List<Directory> _directoryListFromEnvironment(
|
||||||
String envVar, List<Directory> fallback) {
|
String envVar, List<Directory> fallback) {
|
||||||
@ -152,13 +182,20 @@ Directory? get runtimeDir => _directoryFromEnvironment('XDG_RUNTIME_DIR');
|
|||||||
///
|
///
|
||||||
/// If the `xdg-user-dir` executable is not present this returns null.
|
/// If the `xdg-user-dir` executable is not present this returns null.
|
||||||
Directory? getUserDirectory(String dirName) {
|
Directory? getUserDirectory(String dirName) {
|
||||||
if (!_processManager.canRun('xdg-user-dir')) {
|
final ProcessResult result;
|
||||||
return null;
|
try {
|
||||||
|
result = _processRunner.runSync(
|
||||||
|
'xdg-user-dir',
|
||||||
|
<String>[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(
|
|
||||||
<String>['xdg-user-dir', dirName],
|
|
||||||
stdoutEncoding: utf8,
|
|
||||||
);
|
|
||||||
final String path = (result.stdout as String).split('\n')[0];
|
final String path = (result.stdout as String).split('\n')[0];
|
||||||
return Directory(path);
|
return Directory(path);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ name: xdg_directories
|
|||||||
description: A Dart package for reading XDG directory configuration information on Linux.
|
description: A Dart package for reading XDG directory configuration information on Linux.
|
||||||
repository: https://github.com/flutter/packages/tree/main/packages/xdg_directories
|
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
|
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:
|
environment:
|
||||||
sdk: ">=2.18.0 <4.0.0"
|
sdk: ">=2.18.0 <4.0.0"
|
||||||
@ -13,7 +13,6 @@ platforms:
|
|||||||
dependencies:
|
dependencies:
|
||||||
meta: ^1.3.0
|
meta: ^1.3.0
|
||||||
path: ^1.8.0
|
path: ^1.8.0
|
||||||
process: ^4.0.0
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
test: ^1.16.0
|
test: ^1.16.0
|
||||||
|
@ -6,7 +6,6 @@ import 'dart:convert';
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:path/path.dart' as path;
|
import 'package:path/path.dart' as path;
|
||||||
import 'package:process/process.dart';
|
|
||||||
import 'package:test/fake.dart';
|
import 'package:test/fake.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
import 'package:xdg_directories/xdg_directories.dart' as xdg;
|
import 'package:xdg_directories/xdg_directories.dart' as xdg;
|
||||||
@ -27,6 +26,8 @@ void main() {
|
|||||||
String testPath(String subdir) => path.join(testRootPath(), subdir);
|
String testPath(String subdir) => path.join(testRootPath(), subdir);
|
||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
|
xdg.xdgProcessRunner =
|
||||||
|
FakeProcessRunner(<String, String>{}, canRunExecutable: false);
|
||||||
tmpDir = Directory.systemTemp.createTempSync('xdg_test');
|
tmpDir = Directory.systemTemp.createTempSync('xdg_test');
|
||||||
fakeEnv.clear();
|
fakeEnv.clear();
|
||||||
fakeEnv['HOME'] = testRootPath();
|
fakeEnv['HOME'] = testRootPath();
|
||||||
@ -103,24 +104,22 @@ XDG_VIDEOS_DIR="$HOME/Videos"
|
|||||||
'TEMPLATES': testPath('Templates'),
|
'TEMPLATES': testPath('Templates'),
|
||||||
'VIDEOS': testPath('Videos'),
|
'VIDEOS': testPath('Videos'),
|
||||||
};
|
};
|
||||||
xdg.xdgProcessManager = FakeProcessManager(expected);
|
xdg.xdgProcessRunner = FakeProcessRunner(expected);
|
||||||
final Set<String> userDirs = xdg.getUserDirectoryNames();
|
final Set<String> userDirs = xdg.getUserDirectoryNames();
|
||||||
expect(userDirs, equals(expected.keys.toSet()));
|
expect(userDirs, equals(expected.keys.toSet()));
|
||||||
for (final String key in userDirs) {
|
for (final String key in userDirs) {
|
||||||
expect(xdg.getUserDirectory(key)!.path, equals(expected[key]),
|
expect(xdg.getUserDirectory(key)!.path, equals(expected[key]),
|
||||||
reason: 'Path $key value not correct');
|
reason: 'Path $key value not correct');
|
||||||
}
|
}
|
||||||
xdg.xdgProcessManager = const LocalProcessManager();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Returns null when xdg-user-dir executable is not present', () {
|
test('Returns null when xdg-user-dir executable is not present', () {
|
||||||
xdg.xdgProcessManager = FakeProcessManager(
|
xdg.xdgProcessRunner = FakeProcessRunner(
|
||||||
<String, String>{},
|
<String, String>{},
|
||||||
canRunExecutable: false,
|
canRunExecutable: false,
|
||||||
);
|
);
|
||||||
expect(xdg.getUserDirectory('DESKTOP'), isNull,
|
expect(xdg.getUserDirectory('DESKTOP'), isNull,
|
||||||
reason: 'Found xdg user directory without access to xdg-user-dir');
|
reason: 'Found xdg user directory without access to xdg-user-dir');
|
||||||
xdg.xdgProcessManager = const LocalProcessManager();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Throws StateError when HOME not set', () {
|
test('Throws StateError when HOME not set', () {
|
||||||
@ -131,27 +130,22 @@ XDG_VIDEOS_DIR="$HOME/Videos"
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class FakeProcessManager extends Fake implements ProcessManager {
|
class FakeProcessRunner extends Fake implements xdg.XdgProcessRunner {
|
||||||
FakeProcessManager(this.expected, {this.canRunExecutable = true});
|
FakeProcessRunner(this.expected, {this.canRunExecutable = true});
|
||||||
|
|
||||||
Map<String, String> expected;
|
Map<String, String> expected;
|
||||||
final bool canRunExecutable;
|
final bool canRunExecutable;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ProcessResult runSync(
|
ProcessResult runSync(
|
||||||
List<dynamic> command, {
|
String executable,
|
||||||
String? workingDirectory,
|
List<String> arguments, {
|
||||||
Map<String, String>? environment,
|
Encoding? stdoutEncoding = systemEncoding,
|
||||||
bool includeParentEnvironment = true,
|
Encoding? stderrEncoding = systemEncoding,
|
||||||
bool runInShell = false,
|
|
||||||
Encoding stdoutEncoding = systemEncoding,
|
|
||||||
Encoding stderrEncoding = systemEncoding,
|
|
||||||
}) {
|
}) {
|
||||||
return ProcessResult(0, 0, expected[command[1]], '');
|
if (!canRunExecutable) {
|
||||||
}
|
throw ProcessException(executable, arguments, 'No such executable', 2);
|
||||||
|
}
|
||||||
@override
|
return ProcessResult(0, 0, expected[arguments.first], '');
|
||||||
bool canRun(dynamic executable, {String? workingDirectory}) {
|
|
||||||
return canRunExecutable;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user