Node app treats escaped chars in path treated differently when installed globally - node.js

I am very new to this Node stuff so there is probably a really simple answer to this but anyways...
I am building an app that prompts for a file path. This path is supplied by dropping a file into the Terminal window which gives a path with spaces escaped like this:
Users/[username]/Desktop/test\ file.txt
I then use jsonfile to add this path to an array and write out a JSON file. In this file the path now has the escape escaped and looks like this:
Users/[username]/Desktop/test\\ file.txt
Now I want to grab that path from the JSON and reveal it in Finder and this is where I get lost. I am using mac-open to reveal the path by passing the -R option and this works fine while I am testing and running my code using node bin/my-code.js but as soon I install with npm install -g . it breaks. The install works and I can run the app (there are other functions that work fine) but now if I try to reveal the path I get the error:
{ [Error: Command failed: /bin/sh -c open -a "Finder" -R "/Users/[username]/Desktop/test\\\ file.txt"
The file /Users/[username]/Desktop/test\\ file.txt does not exist.
]
killed: false,
code: 1,
signal: null,
cmd: '/bin/sh -c open -a "Finder" -R "/Users/[username]/Desktop/test\\\\\\ file.txt"' }
I have noticed the varying amounts of escapes in the different path references in the error so my questions are:
Why is this different when I test using node bin/my-code.js
and when I install globally and run that way?
Is there a way that I can make the two behave the same as I don't really want to be installing every time I want to test my code?
Is there a more robust way of storing and/or escaping file paths?
Sorry this has got a bit rambling. Any advice welcome :)

So I haven't exactly answered all the questions I posed but I have fixed the issue and learned what I consider a really valuable lesson in Node development.
Trying to find the problem I actually open the source mac-open and in doing so realised that I didn't actually need to be using the additional module at all. Searching the source led me to look into reading about child_process and eventually sacking off the whole mac-open module for a simple:
var exec = require("child_process").exec;
exec("open " +assetsPath +" -R", function(err){
if(err)
console.log(err);
});
The esson here is not to use 3rd party modules just because they are there. In this situation I didn't need the all-situation covereage that it was trying to provide and the extra complexity actually caused the problem.

Related

Nest js failed to execute command: with 'node'

I'm trying to init my first NestJS project but met this fail:
-----------------------------------------
$ nest new testproj
⚡ We will scaffold your app in a few seconds..
'node' is not recognized as an internal or external command,
operable program or batch file.
Failed to execute command: node #nestjs/schematics:application --name=testproj --directory=undefined --no-dry-run --no-skip-git --no-strict --package-manager=undefined --language="ts" --collection="#nestjs/schematics"
------------------------------------------
Tryed to reinstall NodeJS, but no luck.
$ node -v
v16.13.1
$ nest -v
8.1.6
$ npm -v
8.3.0
Any help will be appreciated.
tl;dr:
If your PATH somewhere has a file in it and not a folder (can also be in the middle of a path, with some \other\stuff appended like C:\stuff\somefile.txt\stuff), then this can happen due to an error when Git bash is translating PATH before calling cmd.exe, resulting in part of the PATH not being forwarded and making binaries in that part "not found".
Details:
After some investigation via chat, it turned out that the root cause was a bad GRADLE_HOME environment variable.
Yes, Gradle has nothing to do with node.js or nest, but bear with me, this is one of those moments where a TV episode starts with a totally crazy scene and you wonder what the heck happened that led to this, and then you get "6 hours earlier..." 😁
So, Git bash obviously succeeded in finding node, because it ran the nest CLI (which is a node script). But then, somehow, cmd (which is called by node when executing shell commands) did not find node. This normally should not happen.
Tracing the events with Process Monitor revealed that bash (sh.exe) passed a truncated PATH variable to node.exe. It just ended abruptly somewhere in the middle, and C:\Program Files\nodejs (which was towards the end of it) was not passed along.
The reason for this turned out to be an entry in the PATH that looked like this: C:\foobar\file.zip\bin. The transition into bash worked, as the full path (including this bad entry as /c/foobar/file.zip/bin) could be seen in bash's $PATH, and /c/Program Files/nodejs was there too.
But the transition from bash to node.exe failed. In the process of converting the Linux-style paths to Windows-style paths before passing the variable on to node.exe, bash silently failed in the middle of the string and stopped processing it - as soon as this /c/foobar/file.zip/bin entry was encountered. C:\foobar\file.zip did exist, and it turns out Git bash behaves like this when it unexpectedly encounters a "not a directory" error from the OS when querying the path segment ("file not found" is fine) - as a result of attempting to access a "subdirectory" of a file. Removing this entry from the PATH made everything work normally.
The source of this entry was actually %GRADLE_PATH%\bin in the Windows PATH, and the reason this caused the problem was that GRADLE_PATH itself was incorrectly set to a file (C:\foobar\file.zip) instead of a directory.
There are three ways to resolve this:
Remove %GRADLE_PATH%\bin from the PATH.
Fix GRADLE_PATH to point to a directory.
Delete or rename the C:\foobar\file.zip file.

Bash: app definitely on $path, but not found when run

I'm having a issue with a python app that I installed on a empty server.
The package I installed is invoke using pip3 install invoke
After install if I just run invoke without specifying the abs path, then I
get a error: -bash: /usr/bin/invoke: No such file or directory
Running it with the full path to the app works fine.
So I'm confused why it's ignoring the legit app that is in a location
that is definitely on the $PATH.
See the cli commands below for visual reference:
/# invoke
-bash: /usr/bin/invoke: No such file or directory
/# find -name invoke
./usr/local/bin/invoke
./usr/local/lib/python3.6/dist-packages/invoke
/# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
/# /usr/local/bin/invoke -V
Invoke 1.4.1
Anyone know what's going on here?
As mentioned in the comments of my original post, this was because the command was previously hashed and bash remembered the old path. Running hash -r was suggested, which resets all mappings. I eventually used hash -d invoke which cleared only that single entry. My reasoning was that I wasn't sure if anything else in the mappings were expected to be there by some other app.
Edit: As pointed out in the comments below, there is no harm in using -r since it's just a faster way to look something up and is saved there once it finds it again anyway.

/usr/bin/env: node --harmony: No such file or directory

I have searched online thru this site and others for a solution, so I finally bow my head and ask for help. It looks like most of the answers are identifying the node/nodejs naming conflict and creating symlinks as a solution. I don't have a nodejs anywhere on my system.
I am using a _ n _ as my node version manager. So,
sudo n
displays a list of installed versions and allows me to choose. n simply copies the chosen version into /usr/local/bin/ as node. It has already established a link from /usr/bin/node to the managed version.
I installed a javascript library called 'waigo.' When I run the following:
waigo init
I get the following output...
/usr/bin/env: node --harmony: No such file or directory
arrgghhh..... I'm frustrated. Any help will be appreciated.
It looks like a problem with the shebang line in a shell script which specifies the program used to interpret the file. This might look like:
#!/usr/bin/env node --harmony
The error message in your case suggests that env is attempting to locate "node --harmony" which was probably a problem with the executable file run when you typed waigo. For example, it might have had a shebang line incorrectly formatted like:
#!/usr/bin/env "node --harmony"

how to control where spawnCommand method executes

How can I understand and control from where spawnCommand runs?
I am creating a yo generator and as part of the process I need to call an external tool. The way I am attmepting to do this is by calling a powershell script from spawnCommand. I was having trouble with spawnCommand having spaces in paths, so I just encapsulated that within the powershell file. I saw something about superspawn but couldn't get it to work.
Anyway, my main problem is that I am trying to call powershell and give it the script file as an argument, but it can't find the script file. Here is the code:
signatureKeyFile: function() {
var done = this.async();
this.spawnCommand('powershell', ['sign.ps1'], {
cwd: this.destinationPath('.')
}).on('close', done);
},
I tried using procmon to see what directory it executes from and understand it better. It looks like it tries it in a ton of places, but seemingly all environment paths. It doesn't try the source or destination path for the yo generator, or at least that's how it seemed to me.
So my questions are
1) which working directory does spawnCommand run from by default?
2) How can I contorl that so it can find the this powershell file? spawnCommand won't let me use spaces in paths, so I can't feed it a full path or so it seems to me.
Thanks so much!
spawnCommand won't let me use spaces in paths, so I can't feed it a full path or so it seems to me.
That's usually a well known issues of command line. Arguments are separated by spaces, so it just assume your path is actually multiples arguments.
I'm not 100% for windows, but on OSx, you'd espace spaces as some\ path\ with\ spaces.
Another options is to pass arguments as strings. What if you were to wrap your path in double quotes?
this.spawnCommand('powershell', ['"/home/My Home/sign.ps1"']);
FWIW, Yeoman spawnCommand is just a wrapper for Node spawn command where we help normalize a command so it'll run fine on windows. See
https://github.com/yeoman/generator/blob/master/lib/actions/spawn-command.js#L20
https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options
It'll help you to test the correct syntax to pass path if you can reduce the scope of your problem to only the Node spawn command.
[Edited to fix broken link]
We were able to solve it by setting the current working directory or cwd, with the spaces:
this.spawnCommandSync('sn.exe', ['-k', format("{0}\\{1}.snk", this.destinationPath('.'), this.props.myItemName)], {
cwd: 'C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v10.0A\\bin\\NETFX 4.6 Tools'
});

Modifying $PATH variable

Trying to install node.js.
Did brew install node
It seems to have worked.
However, received this message upon its completion
Homebrew installed npm.
We recommend prepending the following path to your PATH environment
variable to have npm-installed binaries picked up:
/usr/local/share/npm/bin
Ok ... so, I open my bash_profile...
And this is what I have in it:
export PATH="/usr/local/bin:/usr/local/sbin:~/bin:$PATH"
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm" # Load RVM into a shell session *as a function*
Trying to understand how to modify it correctly so I won't ruin it ...
Do I add /usr/local/share/npm/bin like this
export PATH="/usr/local/bin:/usr/local/sbin:~/bin/usr/local/share/npm/bin:$PATH"
If not, what is the correct way to add that path?
Thank you for any help provided!
PS. let me know if there is any additional information I could have provided
EDIT
upon seeing which npm in macedigital's answer, I ran that ...
and got this: /usr/local/bin/npm
and that was before I did the second answer (ie, ThiefMaster's answer).
ran which npm again ...
and got the same answer as before ...
i did echo $PATH and got this:
/Users/name/.rvm/gems/ruby-1.9.3-p374/bin:/Users/name/.rvm/gems/ruby-1.9.3-p374#global/bin:/Users/name/.rvm/rubies/ruby-1.9.3-p374/bin:/Users/name/.rvm/bin:/usr/local/share/npm/bin:/usr/local/bin:/usr/local/sbin:~/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/X11/bin:/usr/local/git/bin
So, it looks like I already had it installed?
Therefore, how do I handle the answers? I hate leaving it unresolved since both of you were so helpful and I feel bad that I asked without providing echo $PATH information since that would have told you that I had it installed ...
EDIT 2
ls -la /usr/local/share/npm/bin gets this:
ls: /usr/local/share/npm/bin: No such file or directory
which -a npm gets this: /usr/local/bin/npm
EDIT 3
ls -a /usr/local/bin/npm gets this: /usr/local/bin/npm
there's no timestamp...
Short answer, do this (notice the additional colon I inserted):
export PATH="/usr/local/share/npm/bin:/usr/local/bin:/usr/local/sbin:~/bin:$PATH"
The $PATH environment variable is colon separated list of directories to look in if you want to run a command without a fully qualified path (e.g. running npm instead of having to type /usr/local/share/npm/bin/npm).
You can try this from a terminal before actually saving the change in bash_profile. If everything is good, which -a npm will show you all fully qualified path(s).
UPDATE
It is not necessary to modify the $PATH variable in order to use npm. What homebrew install recommends instead is to add the directory where npm-installed binaries are stored to the $PATH variables, so its more convenient to use them from the command line later on.
Node modules like phantomjs, phonegap, express, etc. provide binaries which after the change are available on the command prompt without having to type the full path.
The cleanest solution is adding the following between the two lines you posted:
export PATH="/usr/local/share/npm/bin:$PATH"
That way everything stays readable and you prepend it to PATH just like the program suggested it. And if you ever want to undo the change you just remove that line instead of editing a possibly long line.
In PATH ORDER IS IMPORTANT. So anything before desired npm version will still cause problems.
#adding in first place of the path, before anything else
export PATH=/usr/local/bin:otherPathEntries:$PATH
assuming that version of npm You want is in /usr/local/bin, to check all use 'which -a npm'

Resources