Globally installed package does not execute in Git Bash on Windows

I created a package with bin/mything which is actually just an empty file.

I have a postinstall script that fetches a pre-built binary and replaces bin/mything. This works great on Mac and Linux.

If the target platform is Windows, I write bin/mything.exe, and write a git bash script to bin/mything which calls bin/mything.exe… but it can’t ever be called…

Actual File

The npm-generated sh file is missing the definition of basedir. It looks like this:

"$basedir/node_modules/mything/bin/mything" "$@"
exit $?

Expected File

It’s supposed to look like this:

#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")

case `uname` in
    *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac

"$basedir/node_modules/serviceman/bin/serviceman" "$@"
exit $?

Variations

I tried replacing my empty file with one that has a #!cmd.exe /c, which causes a more verbose, but working npm-generated .cmd file, but the npm-generated sh file still doesn’t work in git bash due to the silly /c prefix, causing /c/Users/... to be uninterpretable by cmd.exe

The solution I’d like to see is to have $basedir set in the windows sh file when no hashbang (#!/blah) is present in the bin fine.

Why this is important

Since pretty much all the various devcamp students are being instructed to use Git Bash, I feel like this is pretty important.

Monkey Patch Workaround

My present workaround is to monkey-patch the generated sh file in the postinstall script in my file:

scripts/install.js:

   var name = "mything";
    try {
      fs.writeFileSync(
        path.join(path.join(__dirname, '../../.bin'), name),
        [
          '#!/bin/sh',
          '# manual bugfix patch for npm on windows',
          'basedir=$(dirname "$(echo "$0" | sed -e \'s,\\\\,/,g\')")',
          '"$basedir/../' + name + '/bin/' + name + '"   "$@"',
          'exit $?'
        ].join('\n')
      );
    } catch (e) {
      // ignore
    }
    try {
      fs.writeFileSync(
        path.join(path.join(__dirname, '../../..'), name),
        [
          '#!/bin/sh',
          '# manual bugfix patch for npm on windows',
          'basedir=$(dirname "$(echo "$0" | sed -e \'s,\\\\,/,g\')")',
          '"$basedir/node_modules/' +
            name +
            '/bin/' +
            name +
            '"   "$@"',
          'exit $?'
        ].join('\n')
      );
    } catch (e) {
      // ignore
    }

Are you referencing bin/mything as a “bin” from your package.json?

I suspect you are into somewhat unsupported territory trying to turn an empty file into a platform specific executable after npm has tried to link it during the install, but it does looks like a bug that you get a broken sh linking file for what presumably is the failure case for detecting the nature of the “executable”.

https://docs.npmjs.com/files/package.json#bin

Please make sure that your file(s) referenced in bin starts with #!/usr/bin/env node , otherwise the scripts are started without the node executable!

You don’t have to use the node hashbang, any hashbang will do:

#!/usr/bin/env node

#!/usr/bin/node  --harmony

#!/usr/bin/env python

#!/usr/bin/env bash

You can even call things fairly directly:

#!cmd.exe /c

I don’t think that this is unsupported territory. I believe it’s a regression. The code is there to handle the case of a binary without a hashbang, but at some point it was updated and left half-baked. It works for Mac, Linux, and Windows cmd.exe as expected - but is now broken for Windows Git Bash (MINGW) and Cygwin.

I suspect that whenever $basedir was added is when the bug / regression occurred.

Hopefully that doesn’t fall on deaf ears. There are PRs to fix windows issues that are years old and now out of date.

node hashbang : Yes, I did not intend to imply that node hashbang was (still) strictly required, more that you might be outside was was originally envisaged (and documented),

In my opinion fresh PR are easier to process than old PR. Thanks! Good luck.

It clearly was intended to be supported, because the code for it is right here:

Looks like it’s been 6 years since the change to the line that likely introduced the bug:

74073629 (ForbesLindesay  2013-03-31 19:09:09 +0100 133)   if (shLongProg) {
74073629 (ForbesLindesay  2013-03-31 19:09:09 +0100 134)     sh = sh
8bee9f6b (Sean Copenhaver 2013-10-28 15:36:26 -0400 135)         + "basedir=$(dirname \"$(echo \"$0\" | sed -e 's,\\\\,/,g')\")\n"
74073629 (ForbesLindesay  2013-03-31 19:09:09 +0100 136)         + "\n"
74073629 (ForbesLindesay  2013-03-31 19:09:09 +0100 137)         + "case `uname` in\n"
74073629 (ForbesLindesay  2013-03-31 19:09:09 +0100 138)         + "    *CYGWIN*) basedir=`cygpath -w \"$basedir\"`;;\n"
74073629 (ForbesLindesay  2013-03-31 19:09:09 +0100 139)         + "esac\n"
74073629 (ForbesLindesay  2013-03-31 19:09:09 +0100 140)         + "\n"
74073629 (ForbesLindesay  2013-03-31 19:09:09 +0100 141)
74073629 (ForbesLindesay  2013-03-31 19:09:09 +0100 142)     sh = sh
74073629 (ForbesLindesay  2013-03-31 19:09:09 +0100 143)        + "if [ -x "+shLongProg+" ]; then\n"
74073629 (ForbesLindesay  2013-03-31 19:09:09 +0100 144)        + "  " + shLongProg + " " + args + " " + shTarget + " \"$@\"\n"
74073629 (ForbesLindesay  2013-03-31 19:09:09 +0100 145)        + "  ret=$?\n"
74073629 (ForbesLindesay  2013-03-31 19:09:09 +0100 146)        + "else \n"
74073629 (ForbesLindesay  2013-03-31 19:09:09 +0100 147)        + "  " + shProg + " " + args + " " + shTarget + " \"$@\"\n"
74073629 (ForbesLindesay  2013-03-31 19:09:09 +0100 148)        + "  ret=$?\n"
74073629 (ForbesLindesay  2013-03-31 19:09:09 +0100 149)        + "fi\n"
74073629 (ForbesLindesay  2013-03-31 19:09:09 +0100 150)        + "exit $ret\n"
74073629 (ForbesLindesay  2013-03-31 19:09:09 +0100 151)   } else {
74073629 (ForbesLindesay  2013-03-31 19:09:09 +0100 152)     sh = shProg + " " + args + " " + shTarget + " \"$@\"\n"
74073629 (ForbesLindesay  2013-03-31 19:09:09 +0100 153)        + "exit $?\n"
74073629 (ForbesLindesay  2013-03-31 19:09:09 +0100 154)   }

Eh, historically node has always been broken really bad on Windows. I’m glad that things are starting to get better, but it’s always been rough.

I’m very adamant about testing my code on Windows (and I mean “very adamant” comparatively - as in I test it on Windows at all, even sometimes), and it typically always fails for one reason or another. Shims upon shims upon shims…

1 Like