-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: do not use a shell for git commands #29
Conversation
@wraithgar , @nlf: All tests pass with flying colors in my win32 cmd shell system.
Just to be extra sure, when the |
@ferdinando-ferreira That's awesome to hear! Pretty ironic that this solution came only a short while after we figured out the core problem w/ detecting cmd. Hopefully though you can use that conversation with your attempts to clean up nodejs itself with the same issues. |
@wraithgar : The hardest part was getting node to compile on my Win system, after that I already got the solution on lib/child_process figured out from the beggining. Here is a rough draft. diff --git "a/lib/child_process.js" "b/lib/child_process.js"
index 26e1bb33d0..a01c2dd8a6 100644
--- "a/lib/child_process.js"
+++ "b/lib/child_process.js"
@@ -502,27 +502,39 @@ function normalizeSpawnArguments(file, args, options) {
}
if (options.shell) {
- const command = ArrayPrototypeJoin([file, ...args], ' ');
+ let shell;
+ let useWin32Cmd = false;
// Set the shell, switches, and commands.
if (process.platform === 'win32') {
if (typeof options.shell === 'string')
- file = options.shell;
+ shell = options.shell;
else
- file = process.env.comspec || 'cmd.exe';
- // '/d /s /c' is used only for cmd.exe.
- if (RegExpPrototypeTest(/^(?:.*\\)?cmd(?:\.exe)?$/i, file)) {
- args = ['/d', '/s', '/c', `"${command}"`];
- windowsVerbatimArguments = true;
- } else {
- args = ['-c', command];
+ shell = process.env.comspec || 'cmd.exe';
+ if (RegExpPrototypeTest(/^(?:.*\\)?cmd(?:\.exe)?$/i, shell)) {
+ useWin32Cmd = true;
}
} else {
if (typeof options.shell === 'string')
- file = options.shell;
+ shell = options.shell;
else if (process.platform === 'android')
- file = '/system/bin/sh';
+ shell = '/system/bin/sh';
else
- file = '/bin/sh';
+ shell = '/bin/sh';
+ }
+ // escaping is used only for cmd.exe.
+ const needsEscaping = (arg) => useWin32Cmd && !(/^"/.test(String(arg)));
+ // Unless the argument was explicitly made an ArgFilePath with the
+ // use of escapeFilePath, processArgs is a noop
+ const processArgs = (arg) => (!(arg instanceof ArgFilePath))
+ ? arg
+ : (needsEscaping(arg) ? '"' + arg + '"' : String(arg));
+ const command = ArrayPrototypeJoin([file, ...args.map(processArgs)], ' ');
+ file = shell;
+ // '/d /s /c' is used only for cmd.exe.
+ if (useWin32Cmd) {
+ args = ['/d', '/s', '/c', `"${command}"`];
+ windowsVerbatimArguments = true;
+ } else {
args = ['-c', command];
}
}
@@ -776,6 +788,24 @@ function sanitizeKillSignal(killSignal) {
}
}
+// A wrapper for a filePath whose purpose is to signal that an argument is
+// a filePath to be used by spawn other functions that make use of
+// normalizeSpawnArguments
+class ArgFilePath {
+ constructor(filePath) {
+ this.filePath = filePath;
+ }
+
+ toString() {
+ return `${this.filePath}`;
+ }
+}
+
+function escapeFilePath(filePath) {
+ validateString(filePath, 'filePath');
+ return new ArgFilePath(filePath);
+}
+
module.exports = {
_forkChild,
ChildProcess,
@@ -785,5 +815,6 @@ module.exports = {
execSync,
fork,
spawn,
- spawnSync
+ spawnSync,
+ escapeFilePath
}; Here is the test case (that would only be applicable for WIndows): const { spawnSync, escapeFilePath } = require('child_process');
let dirName = escapeFilePath('c:\\Program Files\\');
console.log('\n****************************************');
console.log('Testing with escapeFilePath');
console.log('****************************************\n');
spawnSync('dir', [dirName], {shell: 'cmd', stdio: 'inherit'});
console.log('\n****************************************');
console.log('Testing without escapeFilePath');
dirName = 'c:\\Program Files\\';
console.log('****************************************\n');
spawnSync('dir', [dirName], {shell: 'cmd', stdio: 'inherit'}); Executing that using the changed node with the patch above, prints
Technically that's a sound solution:
I'll try to polish it a little to ensure no friction and will post a bug report plus a PR on With that said, in the great majority of the projects that can hit this bug the solution is to force But I am digressing and taking your folks valuable brain cycles, I'll present this case in the proper venue and see if they accept the proposed changes. |
this is an alternative to #27
rather than attempting to escape strings to be friendly with the shell, let's not use a shell at all
References