diff --git a/CHANGELOG.md b/CHANGELOG.md index b0a0dc8..4e0bb6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +#### 3.0.10 + +* Added quoted strings to indicate where the command name ends and the arguments +begin otherwise, the file name is ambiguous on Windows. #### 3.0.9 diff --git a/lib/src/interface/common.dart b/lib/src/interface/common.dart index 7918f1d..481c082 100644 --- a/lib/src/interface/common.dart +++ b/lib/src/interface/common.dart @@ -16,6 +16,24 @@ const Map _osToPathStyle = const { 'windows': 'windows', }; +/// Sanatizes the executable path on Windows. +/// https://github.com/dart-lang/sdk/issues/37751 +String sanitizeExecutablePath(String executable, + {Platform platform = const LocalPlatform()}) { + if (executable.isEmpty) { + return executable; + } + if (!platform.isWindows) { + return executable; + } + if (executable.contains(' ') && !executable.startsWith('"')) { + // Use quoted strings to indicate where the file name ends and the arguments begin; + // otherwise, the file name is ambiguous. + return '"$executable"'; + } + return executable; +} + /// Searches the `PATH` for the executable that [command] is supposed to launch. /// /// This first builds a list of candidate paths where the executable may reside. diff --git a/lib/src/interface/local_process_manager.dart b/lib/src/interface/local_process_manager.dart index a297967..d7f287a 100644 --- a/lib/src/interface/local_process_manager.dart +++ b/lib/src/interface/local_process_manager.dart @@ -12,6 +12,8 @@ import 'dart:io' ProcessStartMode, systemEncoding; +import 'package:platform/platform.dart'; + import 'common.dart'; import 'process_manager.dart'; @@ -38,7 +40,11 @@ class LocalProcessManager implements ProcessManager { ProcessStartMode mode: ProcessStartMode.normal, }) { return Process.start( - _getExecutable(command, workingDirectory, runInShell), + sanitizeExecutablePath(_getExecutable( + command, + workingDirectory, + runInShell, + )), _getArguments(command), workingDirectory: workingDirectory, environment: environment, @@ -59,7 +65,11 @@ class LocalProcessManager implements ProcessManager { Encoding stderrEncoding: systemEncoding, }) { return Process.run( - _getExecutable(command, workingDirectory, runInShell), + sanitizeExecutablePath(_getExecutable( + command, + workingDirectory, + runInShell, + )), _getArguments(command), workingDirectory: workingDirectory, environment: environment, @@ -81,7 +91,11 @@ class LocalProcessManager implements ProcessManager { Encoding stderrEncoding: systemEncoding, }) { return Process.runSync( - _getExecutable(command, workingDirectory, runInShell), + sanitizeExecutablePath(_getExecutable( + command, + workingDirectory, + runInShell, + )), _getArguments(command), workingDirectory: workingDirectory, environment: environment, diff --git a/pubspec.yaml b/pubspec.yaml index 00a4510..c9f5ad2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: process -version: 3.0.9 +version: 3.0.10 authors: - Todd Volkert - Michael Goderbauer diff --git a/test/src/interface/common_test.dart b/test/src/interface/common_test.dart index 77480e5..7f4dfc6 100644 --- a/test/src/interface/common_test.dart +++ b/test/src/interface/common_test.dart @@ -191,6 +191,20 @@ void main() { ); expect(executablePath, isNull); }); + + test('when path has spaces', () { + expect( + sanitizeExecutablePath('Program Files\\bla.exe', + platform: platform), + '"Program Files\\bla.exe"'); + expect( + sanitizeExecutablePath('ProgramFiles\\bla.exe', platform: platform), + 'ProgramFiles\\bla.exe'); + expect( + sanitizeExecutablePath('"Program Files\\bla.exe"', + platform: platform), + '"Program Files\\bla.exe"'); + }); }); group('on Linux', () { @@ -247,6 +261,13 @@ void main() { ); expect(executablePath, isNull); }); + + test('when path has spaces', () { + expect( + sanitizeExecutablePath('/usr/local/bin/foo bar', + platform: platform), + '/usr/local/bin/foo bar'); + }); }); }); }