Skip to content
This repository has been archived by the owner on Jan 6, 2021. It is now read-only.

cross-env, cross-env-shell not working on MacOS.13 #148

Closed
brucejo75 opened this issue Oct 17, 2017 · 11 comments · Fixed by #158
Closed

cross-env, cross-env-shell not working on MacOS.13 #148

brucejo75 opened this issue Oct 17, 2017 · 11 comments · Fixed by #158

Comments

@brucejo75
Copy link

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:

@echo off
echo Argument: %1
echo Environment: %CROSS_ENV_TEST%

MacOS: cross-env-test.sh

#!/bin/bash

echo Argument: $1
echo Environment: $CROSS_ENV_TEST

Results

Windows:

E:\>cross-env CROSS_ENV_TEST=Working cross-env-test.cmd $CROSS_ENV_TEST
Argument: "Working"
Environment: Working

E:\>cross-env-shell CROSS_ENV_TEST=Working cross-env-test.cmd $CROSS_ENV_TEST
Argument: Working
Environment: Working

MacOS:

MacBook:~$ cross-env CROSS_ENV_TEST=Working ./cross-env-test.sh  $CROSS_ENV_TEST
Argument:
Environment: Working
MacBook:~$ cross-env-shell CROSS_ENV_TEST=Working ./cross-env-test.sh  $CROSS_ENV_TEST
Argument:
Environment: Working

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.

@brucejo75 brucejo75 changed the title cross-env, cross-env-shell not working on MacOS cross-env, cross-env-shell not working on MacOS.13 Oct 18, 2017
@brucejo75
Copy link
Author

@kentcdodds, any thoughts on this? Am I expecting the wrong behavior? Thanks!

@kentcdodds
Copy link
Owner

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.

@kentcdodds
Copy link
Owner

Whoops, you my also need to escape the dollar sign:

cross-env-shell CROSS_ENV_TEST=Working "./cross-env-test.sh \$CROSS_ENV_TEST"

@brucejo75
Copy link
Author

@kentcdodds, thanks much! that worked.

@brucejo75
Copy link
Author

@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.

Attempt 1

package.json script command:
"foo": "cross-env-shell CROSS_ENV_TEST=Working \"cross-env-test \$CROSS_ENV_TEST\""

Result

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

Attempt 2: Remove escaping for $

package.json script command:
"foo": "cross-env-shell CROSS_ENV_TEST=Working \"cross-env-test $CROSS_ENV_TEST\""

Result

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

Attempt 3: remove enclosing quotes

package.json script command:
"foo": "cross-env-shell CROSS_ENV_TEST=Working cross-env-test $CROSS_ENV_TEST"

Result

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

@kentcdodds
Copy link
Owner

kentcdodds commented Nov 7, 2017

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/ 👍

@brucejo75
Copy link
Author

@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.

Environment

node - 8.8.1
npm - 5.4.2

More data

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'"

On OSX

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.

On Windows

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.

Proposed Fix

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.

@kentcdodds
Copy link
Owner

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?

@brucejo75
Copy link
Author

brucejo75 commented Nov 9, 2017

I am saying that:

  • on MacOS only single quotes works. Nothing else works.
  • on Windows everything works except for single quotes.

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

@kentcdodds
Copy link
Owner

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.

@mansn
Copy link

mansn commented Dec 18, 2019

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.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants