-
Notifications
You must be signed in to change notification settings - Fork 138
Description
In my use of cross-spawn (actually via the cross-env package), I have discovered that there is some special error-emission behavior (apparently for Windows and cmd.exe?) implemented by the enoent.js source file, which is described on the following line:
https://github.com/moxystudio/node-cross-spawn/blob/master/lib/enoent.js#L25
This line also contains a comment which refers the original issue.
Basically, the special behavior is: If the spawned process exits with 1 and the command line cannot be found in file system, emit an Error describing an ENOENT error condition (i.e., "command not found").
(It may be helpful to familiarize yourself with the source code and the details of the original issue before reading on.)
But, there is (and IMO has always been) a problem: The logic in enoent.js assumes that exit code 1 should aways trigger the special ENOENT error-emission behavior... but the assumptions behind that special behavior are only correct in certain cases, wrong in others.
Firstly, cmd.exe may not even be in the picture, so any behavior based on the assumption that it is, is flawed. (Windows has a new shell, now the default, called PowerShell.exe, so the chances that cmd.exe is not being used is actually quite high.)
Secondly, there are many used-cases in which an exit code of 1 does not implicitly mean "command not found". Even with cmd.exe this could easily be the case... any Windows command script, or process launched by the script, could simply choose to exit the script with 1, or any other code, for any purpose.
Thirdly, the command passed to cross-spawn may not be an actual file-system location that can be "verified" exists or not. This is especially true with PowerShell, since the command might refer to a "cmdlet" (callable entities which are named independently of the file system) that ran successfully, but simply chose to exit with 1.
In short, this special hard-coded behavior can easily do the wrong thing. For some cases, it may be desirable to convert exit code 1 + "command not found" into an emission of ENOENT, but in other cases, this logic is wrong, and only creates confusion and annoyance.
Case in point: Unit test frameworks (mocha for example) exit with the number of failed tests (i.e., 0 for success, any other number for failure). When cross-spawn is used in such a case, a confusing ENOENT error occurs whenever 1 test fails, but not when 2 more tests fail.
For real-world cases like this, where the special ENOENT behavior is not appropriate, would you consider adding a flag to allow the caller to opt-out of the special logic? That is, just pass any exit code straight through. (Better yet, IMO, place the current special behavior behind an opt-in flag instead.)
Thanks.