Skip to content

Conversation

@MatthieuLemoine
Copy link

Handling stdin inputs

Fix #424.

Well not really..
It will not work with npm init. It seems that npm init improperly returns after execution. Node's exec callback is never called.

I tested it using Node v5.11.0 with the following script waiting for input :

'use strict';

const through2 = require('through2');

process.stdin.setEncoding('utf8');

process.stdin
  .pipe(through2({ decodeStrings : false }, function onChunk(chunk, _, next) {
    if (chunk === 'exit\n') {
      process.exit();
    }
    this.push(chunk);
    next();
  }))
  .pipe(process.stdout);

Exec refactoring

After diving in node child_process, it seems that creating & executing a script file is the only solution.

Synchronous versions of spawn and exec only allow to get the full output if you didn't set the opts.stdio option. But then you can't have the live output. Wontfix (BTW : opened for shelljs)

Then I tried to create a custom stream to intercept the output but opts.stdio only accepts a small set of streams (see waiting for merge doc update) :

  • fs.ReadStream
  • fs.WriteStream
  • net.Socket
  • tty.ReadStream
  • tty.WriteStream
    None of them can be used for our case.

@nfischer
Copy link
Member

Is there a way to add tests for this? If not, that's fine.

@nfischer
Copy link
Member

@MatthieuLemoine Seems like the exec() function is frozen for Windows. Any idea why this might be?

@MatthieuLemoine
Copy link
Author

@nfischer I will look into it.

About the tests, I think that we can't simulate stdin input during execSync as it blocks the event loop.

@MatthieuLemoine
Copy link
Author

@nfischer It seems that on Windows the process wont quit sometimes even when ending process.stdin.
I fixed it calling process.exit() after childProcess return. I'm not very proud of this fix but it works.

I have run the tests on Windows using Node v4.4.3.

@nfischer
Copy link
Member

I'll take a look later. Thanks!

@nfischer nfischer added the fix Bug/defect, or a fix for such a problem label Apr 27, 2016
@nfischer nfischer self-assigned this Apr 27, 2016
@nfischer
Copy link
Member

nfischer commented May 3, 2016

Just tried this out on node v6 Ubuntu 15.10. I noticed that it does accept input, but won't show my user input (which might make this non intuitive). I also noticed that npm init seems to hang at the end (after it asks "is this ok?").

@MatthieuLemoine Any idea on how we might be able to work around these issues?

@MatthieuLemoine
Copy link
Author

@nfischer As I said, npm init does not work but it has nothing to do with our implementation of exec.

npm init does not work with Node child_process exec. The following script hang also at the end :

'use strict';

const childProcess = require('child_process');

const npm = childProcess.exec('npm init', (err, stdout, stderr) => {
        console.log(err, stdout, stderr);
});
npm.stdout.pipe(process.stdout);
npm.stderr.pipe(process.stderr);
process.stdin.pipe(npm.stdin);

I am able to see my input using Node 4 & Node 5. I will try using Node6

@nfischer
Copy link
Member

nfischer commented May 4, 2016

I am able to see my input using Node 4 & Node 5. I will try using Node6

Ok good to know. I can try node v4 and 5 later today. I'd just like to get a solution that fixes the issue entirely, instead of just a partial fix.

@MatthieuLemoine
Copy link
Author

I noticed that it does accept input, but won't show my user input

@nfischer With which command did you have this ?
I tried npm init with Node 6 and I'm able to see my inputs.

@nfischer
Copy link
Member

$ node
> require('shelljs/global')
{}
> exec('npm init')
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg> --save` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
name: (PR_432) version: (1.0.0) description: entry point: (index.js) test command: git repository: keywords: author: license: (ISC) About to write to /home/nate/PR_432/package.json:

{
  "name": "lkjlkj",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "dependencies": {
    "shelljs": "^0.7.0"
  },
  "devDependencies": {},
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}


Is this ok? (yes) [1]    11300 terminated  node
Terminated

It gets terminated because I run killall node in another shell.

node v6.0.0, Ubuntu 15.10, running from within zsh and tmux.

@dowglaz
Copy link

dowglaz commented Jan 19, 2017

Hello guys! I'd like to know how's going with this fix? Do you need some help?

Analyzing this issue, we can see there's a misconception with the nodejs child_process.exec function. Since it's buffered oriented, it's not meant for use with interactive commands, like npm init for instance.

The spawn fits better here, since it's stream oriented and then we can pipe these streams and all work well. I just made a test here and the npm init command work very well with the spawn function when I do the same way it's done in this PR.

Piping the processes using exec does not seem to be appropriate, since it will wait for the buffer to reach its capacity to flush. On the other hand, with spawn it'll send the input as they come, then it gives the user a "interactive" behavior.

I understand shelljs is a wrapper to shell, made to provide a "shell-ish" interface to node.js programs. Hence, create a spawn method on shelljs doesn't seem semantically right. Thus, I suggest you to create an option on shelljs' exec method called { interactive: <boolean> } which uses child_process' spawn function instead of exec, setting up the pipe the same way it's being done in this PR.

What do you think about it? 😄

@nfischer
Copy link
Member

@dowglaz thanks for the follow-up. That info is very helpful!

This is something I was working on addressing in #524. I think for backwards compatibility, we should just leave exec as it is and work toward a new alternative. Would you be able to try that branch and let me know how it works? I'd be eager to get it working to fix all the limitations of exec.

@dowglaz
Copy link

dowglaz commented Jan 19, 2017

Wow, perfect! I didn't see this PR!
I did't tested or tried it out but it seems to do exactly what I suggested here.
I'll try that branch as soon as I can!
Thanks for fast replying!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix Bug/defect, or a fix for such a problem

Projects

None yet

Development

Successfully merging this pull request may close these issues.

processes started via exec are unable to accept input

3 participants