Closed brucejo75 closed 6 years ago
@kentcdodds, any thoughts on this? Am I expecting the wrong behavior? Thanks!
Hey @brucejo75, I'm pretty sure what's happening is your shell is evaluating the value of $CROSS_ENV_TEST
before the script is even run. Try putting things in a string:
cross-env-shell CROSS_ENV_TEST=Working "./cross-env-test.sh $CROSS_ENV_TEST"
I think that'll work.
Whoops, you my also need to escape the dollar sign:
cross-env-shell CROSS_ENV_TEST=Working "./cross-env-test.sh \$CROSS_ENV_TEST"
@kentcdodds, thanks much! that worked.
@kentcdodds, errr
When I run on the command line it works. If I put it into a package.json and npm run
I cannot get it to work. Note this works fine on Windows.
package.json
script command:
"foo": "cross-env-shell CROSS_ENV_TEST=Working \"cross-env-test \$CROSS_ENV_TEST\""
Cannot handle escaped $
MacBook:cross-env brucejo$ npm run foo
npm ERR! file /Users/brucejo/test/cross-env/package.json
npm ERR! code EJSONPARSE
npm ERR! Failed to parse json
npm ERR! Unexpected token $ in JSON at position 165 while parsing near '... \"cross-env-test \$CROSS_ENV_TEST\"",
npm ERR! ...'
npm ERR! File: /Users/brucejo/test/cross-env/package.json
npm ERR! Failed to parse package.json data.
npm ERR! package.json must be actual JSON, not just JavaScript.
npm ERR!
npm ERR! Tell the package author to fix their package.json file. JSON.parse
npm ERR! A complete log of this run can be found in:
npm ERR! /Users/brucejo/.npm/_logs/2017-11-07T18_51_13_676Z-debug.log
$
package.json
script command:
"foo": "cross-env-shell CROSS_ENV_TEST=Working \"cross-env-test $CROSS_ENV_TEST\""
Does not substitute the command argument.
MacBook:cross-env brucejo$ npm run foo
> MERIS@1.0.0 foo /Users/brucejo/test/cross-env
> cross-env-shell CROSS_ENV_TEST=Working "cross-env-test $CROSS_ENV_TEST"
Argument:
Environment: Working
package.json
script command:
"foo": "cross-env-shell CROSS_ENV_TEST=Working cross-env-test $CROSS_ENV_TEST"
Does not substitute the command argument.
MacBook:cross-env brucejo$ npm run foo
> MERIS@1.0.0 foo /Users/brucejo/test/cross-env
> cross-env-shell CROSS_ENV_TEST=Working "cross-env-test $CROSS_ENV_TEST"
Argument:
Environment: Working
Hi @brucejo75, I'm afraid I don't have time to help debug this. Anyone else want to help?
Please feel free to dig further by adding some console.logs in node_modules/cross-env/
:+1:
@kentcdodds, I got some more data.
Essentially, what I found was that windows quoting and OSX (bash) quoting were exactly the opposite in terms of what worked.
Expression | Windows | OSX |
---|---|---|
unquoted | works | doesn't work |
" quoted | works | doesn't work |
' quoted | doesn't work | works |
I propose enabling Windows to work with '
quotes. See Proposed Fix.
node - 8.8.1 npm - 5.4.2
OK, a little more research. I created these rules in package.json
:
"greet": "npm run greet0 && npm run greet1 && npm run greet2",
"greet0": "cross-env-shell GREETING=Hi NAME=Joe echo unquoted $GREETING",
"greet1": "cross-env-shell GREETING=Hi NAME=Joe \"echo doubleQuotes $GREETING\"",
"greet2": "cross-env-shell GREETING=Hi NAME=Joe 'echo singleQuotes $GREETING'"
For OSX I also added a console.log to output the return value from commandConvert in command.js.
MacBook:cross-env brucejo$ npm run greet
> MERIS@1.0.0 greet /Users/brucejo/test/cross-env
> npm run greet0 && npm run greet1 && npm run greet2
> MERIS@1.0.0 greet0 /Users/brucejo/test/cross-env
> cross-env-shell GREETING=Hi NAME=Joe echo unquoted $GREETING
commandConvert: echo
commandConvert: unquoted
unquoted
> MERIS@1.0.0 greet1 /Users/brucejo/test/cross-env
> cross-env-shell GREETING=Hi NAME=Joe "echo doubleQuotes $GREETING"
commandConvert: echo doubleQuotes
doubleQuotes
> MERIS@1.0.0 greet2 /Users/brucejo/test/cross-env
> cross-env-shell GREETING=Hi NAME=Joe 'echo singleQuotes $GREETING'
commandConvert: echo singleQuotes $GREETING
singleQuotes Hi
The only one that properly processes the $GREETING
environment variable is the singleQuotes. The others look like they evaluate at it in the calling shell.
For Windows I also added a console.log to output the return value from commandConvert in command.js.
E:\temp\cross-env>npm run greet
> foo@1.0.0 greet E:\temp\cross-env
> npm run greet0 && npm run greet1 && npm run greet2
> foo@1.0.0 greet0 E:\temp\cross-env
> cross-env-shell GREETING=Hi NAME=Joe echo unquoted $GREETING
commandConvert: echo
commandConvert: unquoted
commandConvert: %GREETING%
unquoted Hi
> foo@1.0.0 greet1 E:\temp\cross-env
> cross-env-shell GREETING=Hi NAME=Joe "echo doubleQuotes $GREETING"
commandConvert: echo doubleQuotes %GREETING%
doubleQuotes Hi
> foo@1.0.0 greet2 E:\temp\cross-env
> cross-env-shell GREETING=Hi NAME=Joe 'echo singleQuotes $GREETING'
commandConvert: 'echo
commandConvert: singleQuotes
commandConvert: %GREETING%'
''echo' is not recognized as an internal or external command,
operable program or batch file.
events.js:182
throw er; // Unhandled 'error' event
^
Error: spawn 'echo ENOENT
at notFoundError (E:\temp\cross-env\node_modules\cross-spawn\lib\enoent.js:11:11)
at verifyENOENT (E:\temp\cross-env\node_modules\cross-spawn\lib\enoent.js:46:16)
at ChildProcess.cp.emit (E:\temp\cross-env\node_modules\cross-spawn\lib\enoent.js:33:19)
at Process.ChildProcess._handle.onexit (internal/child_process.js:200:12)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! foo@1.0.0 greet2: `cross-env-shell GREETING=Hi NAME=Joe 'echo singleQuotes $GREETING'`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the foo@1.0.0 greet2 script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\Bruce\AppData\Roaming\npm-cache\_logs\2017-11-09T05_44_12_699Z-debug.log
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! foo@1.0.0 greet: `npm run greet0 && npm run greet1 && npm run greet2`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the foo@1.0.0 greet script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\Bruce\AppData\Roaming\npm-cache\_logs\2017-11-09T05_44_12_720Z-debug.log
Essentially, Windows works with all forms but using the single quotes fails it.
If I look at the Windows output, essentially Windows treats '
like any other character. And what commandConvert finds is commandConvert: 'echo
.
Then it tries to spawn 'echo
.
I propose adding code to look at each argument to parseCommand
and remove any leading or trailing '
character. Here is the code:
function parseCommand(_args) {
// Windows does not support nested quotes via ''
// *nix does. So ignore any found ' at the
// beginning or end of an argument.
var args = _args.map(function (_a) {
var a = _a;
if(a[0] === "'") a = a.slice(1, a.length);
if(a[a.length - 1] === "'") a = a.slice(0, a.length - 1);
return a;
});
@kentcdodds, let me know if this looks good to you and I can gin up a PR.
Thanks for all that work @brucejo75! So, to be clear, you're saying that if someone has a script with single quotes that wont work?
If that's correct, this is a known issue and has nothing to do with cross-env. People should only use double quotes for scripts if they want to support multiple platforms. Am I missing something?
I am saying that:
I have a fix that will make single quotes work on Windows.
Try it yourself:
Put these rules into a package.json file with the cross-env
node module installed.
"greet": "npm run greet0 && npm run greet1 && npm run greet2",
"greet0": "cross-env-shell GREETING=Hi NAME=Joe echo unquoted $GREETING",
"greet1": "cross-env-shell GREETING=Hi NAME=Joe \"echo doubleQuotes $GREETING\"",
"greet2": "cross-env-shell GREETING=Hi NAME=Joe 'echo singleQuotes $GREETING'"
npm run greet
see what gets echoed.
This is what I see:
Expected | Windows | OSX |
---|---|---|
unquoted Hi |
unquoted Hi |
unquoted |
doubleQuotes Hi |
doubleQuotes Hi |
doubleQuotes |
singleQuotes Hi |
singleQuotes |
singleQuotes Hi |
Ah, I see. Ok, so of those, the only one that should work on both platforms is the double quotes one:
"greet1": "cross-env-shell GREETING=Hi NAME=Joe \"echo doubleQuotes $GREETING\"",
If you have a fix for that I'd definitely welcome it!
Thank you for your patience with this! My time to work on this project is extremely limited.
I can reproduce this issue in MacOS 10.15.2 (Catalina). So I guess something has changed since MacOS 10.13 (High Sierra).
I.e, the example @brucejo75 gave:
Put these rules into a package.json file with the
cross-env
node module installed."greet": "npm run greet0 && npm run greet1 && npm run greet2", "greet0": "cross-env-shell GREETING=Hi NAME=Joe echo unquoted $GREETING", "greet1": "cross-env-shell GREETING=Hi NAME=Joe \"echo doubleQuotes $GREETING\"", "greet2": "cross-env-shell GREETING=Hi NAME=Joe 'echo singleQuotes $GREETING'"
npm run greet
see what gets echoed.
This is what I see.
Expected | OSX |
---|---|
unquoted Hi | unquoted |
doubleQuotes Hi | doubleQuotes |
singleQuotes Hi | singleQuotes Hi |
Unfortunately I cannot verify the behavior on Windows.
Ran across this tool. Seems to be very useful in its description. But when I first ran the tool it did not act in a way that I expected. I expected running the tool in both environments to be exactly the same and they were not.
Environment
cross-env version: 5.1.0 node version: 8.7.0 npm version: 5.4.2 Windows version: 10 1703 (OS Build 15063.674) MacOS: 10.13
Test code
I created 2 simple test scripts and ran them, one for windows the other for MacOS. Then I ran them
Windows:
cross-env-test.cmd
:MacOS:
cross-env-test.sh
Results
Windows:
MacOS:
Expected
I expected the results of both operations to be exactly the same.
Suggestion
As a verification I cloned the project on my MacOS and ran all your tests and they passed. But all of the tests were unit tests you had no full integration tests. Recommend you add full integration tests, feel free to use the tests I supplied.