Skip to content

Commit 5e977d6

Browse files
authored
Fix mixtures of parentheses and spaces in windows command paths (#2138)
1 parent 607340c commit 5e977d6

File tree

6 files changed

+87
-56
lines changed

6 files changed

+87
-56
lines changed

.github/workflows/process.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ defaults:
2222

2323
jobs:
2424
build:
25-
runs-on: ubuntu-latest
25+
runs-on: ${{ matrix.os }}
2626
strategy:
2727
matrix:
28-
os: [ubuntu-latest]
28+
os: [ubuntu-latest, windows-latest]
2929
sdk: [stable, dev]
3030
steps:
3131
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683

pkgs/process/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 5.0.5
2+
3+
* Fix mixtures of parentheses and spaces in windows command paths.
4+
15
## 5.0.4
26

37
* Updates minimum supported SDK version to Flutter 3.22/Dart 3.4.

pkgs/process/lib/src/interface/common.dart

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,6 @@ const Map<String, String> _osToPathStyle = <String, String>{
1818
'windows': 'windows',
1919
};
2020

21-
/// Sanitizes the executable path on Windows.
22-
/// https://github.com/dart-lang/sdk/issues/37751
23-
String sanitizeExecutablePath(String executable,
24-
{Platform platform = const LocalPlatform()}) {
25-
if (executable.isEmpty) {
26-
return executable;
27-
}
28-
if (!platform.isWindows) {
29-
return executable;
30-
}
31-
if (executable.contains(' ') && !executable.contains('"')) {
32-
// Use quoted strings to indicate where the file name ends and the arguments begin;
33-
// otherwise, the file name is ambiguous.
34-
return '"$executable"';
35-
}
36-
return executable;
37-
}
38-
3921
/// Searches the `PATH` for the executable that [executable] is supposed to launch.
4022
///
4123
/// This first builds a list of candidate paths where the executable may reside.

pkgs/process/lib/src/interface/local_process_manager.dart

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ class LocalProcessManager implements ProcessManager {
4040
}) {
4141
try {
4242
return Process.start(
43-
sanitizeExecutablePath(_getExecutable(
43+
_getExecutable(
4444
command,
4545
workingDirectory,
4646
runInShell,
47-
)),
47+
),
4848
_getArguments(command),
4949
workingDirectory: workingDirectory,
5050
environment: environment,
@@ -70,11 +70,11 @@ class LocalProcessManager implements ProcessManager {
7070
}) {
7171
try {
7272
return Process.run(
73-
sanitizeExecutablePath(_getExecutable(
73+
_getExecutable(
7474
command,
7575
workingDirectory,
7676
runInShell,
77-
)),
77+
),
7878
_getArguments(command),
7979
workingDirectory: workingDirectory,
8080
environment: environment,
@@ -101,11 +101,11 @@ class LocalProcessManager implements ProcessManager {
101101
}) {
102102
try {
103103
return Process.runSync(
104-
sanitizeExecutablePath(_getExecutable(
104+
_getExecutable(
105105
command,
106106
workingDirectory,
107107
runInShell,
108-
)),
108+
),
109109
_getArguments(command),
110110
workingDirectory: workingDirectory,
111111
environment: environment,

pkgs/process/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: process
22
description: A pluggable, mockable process invocation abstraction for Dart.
3-
version: 5.0.4
3+
version: 5.0.5
44
repository: https://github.com/dart-lang/tools/tree/main/pkgs/process
55
issue_tracker: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Aprocess
66

pkgs/process/test/src/interface/common_test.dart

Lines changed: 74 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -238,28 +238,6 @@ void main() {
238238
' C:\\.tmp_rand0\\dir2_rand0\n'))));
239239
});
240240

241-
test('when path has spaces', () {
242-
expect(
243-
sanitizeExecutablePath(r'Program Files\bla.exe',
244-
platform: platform),
245-
r'"Program Files\bla.exe"');
246-
expect(
247-
sanitizeExecutablePath(r'ProgramFiles\bla.exe', platform: platform),
248-
r'ProgramFiles\bla.exe');
249-
expect(
250-
sanitizeExecutablePath(r'"Program Files\bla.exe"',
251-
platform: platform),
252-
r'"Program Files\bla.exe"');
253-
expect(
254-
sanitizeExecutablePath(r'"Program Files\bla.exe"',
255-
platform: platform),
256-
r'"Program Files\bla.exe"');
257-
expect(
258-
sanitizeExecutablePath(r'C:\"Program Files"\bla.exe',
259-
platform: platform),
260-
r'C:\"Program Files"\bla.exe');
261-
});
262-
263241
test('with absolute path when currentDirectory getter throws', () {
264242
final FileSystem fsNoCwd = MemoryFileSystemNoCwd(fs);
265243
final String command = fs.path.join(dir3.path, 'bla.exe');
@@ -378,13 +356,6 @@ void main() {
378356
' /.tmp_rand0/dir1_rand0\n'
379357
' /.tmp_rand0/dir2_rand0\n'))));
380358
});
381-
382-
test('when path has spaces', () {
383-
expect(
384-
sanitizeExecutablePath('/usr/local/bin/foo bar',
385-
platform: platform),
386-
'/usr/local/bin/foo bar');
387-
});
388359
});
389360
});
390361
group('Real Filesystem', () {
@@ -571,6 +542,80 @@ void main() {
571542
' ${tmpDir.path}/path4\n'
572543
' ${tmpDir.path}/path5\n'))));
573544
});
545+
546+
group('can actually execute files', () {
547+
void testCompileAndExecute(File mainFile) {
548+
final localProcessManager = LocalProcessManager();
549+
final exePath = '${mainFile.path}.exe';
550+
// Create an executable we can actually run.
551+
expect(
552+
localProcessManager.runSync([
553+
io.Platform.resolvedExecutable,
554+
'compile',
555+
'exe',
556+
mainFile.path,
557+
'-o',
558+
exePath
559+
]).exitCode,
560+
0);
561+
562+
for (final runInShell in const [true, false]) {
563+
final result =
564+
localProcessManager.runSync([exePath], runInShell: runInShell);
565+
expect(result.exitCode, 0,
566+
reason: 'runInShell: $runInShell\nstdout: ${result.stdout}\n'
567+
'stderr: ${result.stderr}');
568+
expect(result.stdout, contains('hello'));
569+
}
570+
}
571+
572+
test('with spaces in the command name', () {
573+
final dir = tmpDir.childDirectory('the path');
574+
final main = dir.childFile('main.dart')
575+
..createSync(recursive: true)
576+
..writeAsStringSync('''
577+
void main() {
578+
print('hello');
579+
}''');
580+
testCompileAndExecute(main);
581+
});
582+
583+
test('with parenthesis in the command name', () async {
584+
final dir = tmpDir.childDirectory('theP()ath');
585+
final main = dir.childFile('main.dart')
586+
..createSync(recursive: true)
587+
..writeAsStringSync('''
588+
void main() {
589+
print('hello');
590+
}''');
591+
testCompileAndExecute(main);
592+
},
593+
skip: io.Platform.isWindows
594+
? 'https://github.com/dart-lang/tools/issues/2139'
595+
: null);
596+
597+
test('with spaces and parenthesis in the command name', () async {
598+
final dir = tmpDir.childDirectory('the P()ath');
599+
final main = dir.childFile('main.dart')
600+
..createSync(recursive: true)
601+
..writeAsStringSync('''
602+
void main() {
603+
print('hello');
604+
}''');
605+
testCompileAndExecute(main);
606+
});
607+
608+
test('with spaces inside parenthesis in the command name', () async {
609+
final dir = tmpDir.childDirectory('the P( )ath');
610+
final main = dir.childFile('main.dart')
611+
..createSync(recursive: true)
612+
..writeAsStringSync('''
613+
void main() {
614+
print('hello');
615+
}''');
616+
testCompileAndExecute(main);
617+
});
618+
});
574619
});
575620
}
576621

0 commit comments

Comments
 (0)