spawn-wrap
Version:
Wrap all spawned Node.js child processes by adding environs and arguments ahead of the main JavaScript file argument.
119 lines (87 loc) • 4.55 kB
Markdown
New approach:
- `spawn('sh', ...)`
Find the `-c` arg.
Parse, and split up by `&&`, `||`, `;`, `&`, and `|`, expanding
each bit.
The parsing doesn't have to be complete, since it's not designed
for security. Just handling quotes and escapes is probably
enough. If someone sneaks in a `$VAR` that expands to a node
shebang, oh well. If we DO want to make it work for security use
cases, then it would perhaps be good to be able to detect these
situations and throw an error or something.
Then spawn the exploded command line. When we explode it, we need
to do the same thing with looking up env and shebang results.
However, if there are multiple parts, we can't change the actual
thing that gets executed (ie, it must still be executed by calling
`sh`, just with the exploded command line).
`cmd` is basically the same, but the escapes are different, and
we're looking for the `/c` argument rather than `-c`. In the
short term, probably we should just explicitly not support
windows, by printing a warning and doing nothing if run in
Windows. This may be a case where explicit non-support is better
than poor or partial support.
Each portion of the sh command line looks like:
`(key=val )*(command)( args)*`
- `spawn('.../node', ...)`
Inject the args before the main, if it has a main file, and call
spawn with that.
- `spawn('other', ...)`
Check if it's a shebang file. If so, explode it to the resulting
cli: `$interpreter $file`. In most cases, this will result in
`env <envpairs> node <nodeoptions> $file`
Note that a shebang is strictly space-delimited arguments. Quotes
and escapes are not allowed here, which makes it much simpler. We
can simply resolve this to `shebangLine.trim().split(/\s+/)`. If
that first item is `env` then handle it just like a `spawn(env)`.
- `spawn('env', ...)`
An env command line is done by looking up the resulting thingy
with `which()`, and then resolving it further if it's a shebangK
- Always treat `bash`, `ksh`, and `zsh` the same as `sh`, since they
have similar cli string behavior.
----
Different ways to spawn things:
1. `spawn('node', ...)`
easiest.
inject the args, add the envPairs
2. `spawn('sh', ['-c', 'X=y /path/to/node blah'])`
Parse '-c' arg just like a exec line.
Windows flavor: `spawn('cmd', ['/s', '/c', '"' + command + '"'])`
replace `('sh', ['-c', '/path/to/node <inject args> blah'])`
I think if we do this right, we don't have to do exec() maybe?
3. `spawn('sh', ['-c', '/usr/bin/env x=y node blah blah'])`
This is the hard one, because the indirection capabilities are
endless. `sh` can spawn `bash` which spawns `env` and so on.
A. replace with `spawn('/usr/bin/env', ['x=y', 'node', '...'])`
WARNING: requires writing a sh-compatible command line parser.
Splitting based on spaces won't work.
Eg: `sh -c 'command "long space"'`
B. Write a node program that wraps cli commands, sort of like the
wrap-main.js file. This will let us the just prepend it to the
`sh -c` arg, and it can interpret the rest.
C. Maybe we just have our own `node` and `iojs` scripts (and
`node.cmd` and `iojs.cmd` for win32 peops), and we put those in a
bin folder that we always prepend to the PATH environ. Then it
almost doesn't *matter* what shebangs or whatever get run, because
`which node` will always return that thing. Something to consider.
(Also, that fakey `node` script cannot be a node program, obviously,
because the shell won't know where to find it!)
**OOPS!** no that won't work because how does the fake node shell
script know what to inject to our wrap-main.js file?
Computers are terrible.
4. `spawn('shebangscript', ['arg'])`
resolve shebangscript using which()
read first line of script
`#!/some/interpreter some=args` ->
`spawn('/some/interpreter', ['some=args', '$file'])`
then handle appropriately
5. `spawn('/usr/bin/env', ['x=y', 'node', '$file'])`
becomes case (1), `spawn('node', ['$file')`, but with the `x=y`
appended to the envPairs list
6. `spawn('sh', ['-c', 'shebangscript arg'])`
7. `exec('/path/to/node blah blah')`
becomes `spawn('sh', ['-c', '/path/to/node blah blah'])`
8. `exec('/usr/bin/env node blah blah')`
becomes `spawn('sh', ['-c', '/usr/bin/env node blah blah'])`
9. `exec('sh -c "shebangscript arg"')`
becomes `spawn('sh', ['-c', 'sh -c "shebangscript arg"'])`
This is a dark pit of oblivion.