Skip to content

Commit 0e4ac1e

Browse files
committed
fix: using execvp now while setting env variables
Hopefully this works now.
1 parent 0ed31c7 commit 0e4ac1e

File tree

4 files changed

+37
-32
lines changed

4 files changed

+37
-32
lines changed

src/exec.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,21 @@ import path from 'path';
88

99
interface Exec {
1010
/**
11-
* This calls the provided command with the provided arguments. The env variable are also provided in the format of
12-
* 'key=value'. If the call fails in any way then it just throws the error code 'Error('number')`. The most common
13-
* would be an `ENOENT` in the form of `Error('2')`.
11+
* This calls the provided command with the provided arguments. The env variable are also provided as a
12+
* `Record<string, string>`. If the call fails in any way then it just throws the error code 'Error('number')`.
13+
* The most common would be an `ENOENT` in the form of `Error('2')`.
1414
*
1515
* This will replace the current process with the provided cmd. From the callers perspective this will seem really odd
1616
* and never return. The call can not return so and code after it is unreachable, hence the `never` return type. So
1717
* treat this function as a termination of the process, much like a `process.exit()` call.
1818
*
19-
* The exec'ed program will not assume the environment of the current process. This can allow isolation but if you
20-
* want to have the current environment then you'll have to pass it in manually through the envp parameter.
19+
* The exec'ed program will assume the current environment while adding the environment variables set by `env` to it.
2120
*
2221
* @param cmd - the command to call, this can be anything in the PATH or a specific file
2322
* @param argv - The args to be passed to the command
24-
* @param envp - env variables that you want to provide. These are formatted as an array of 'key=value'
23+
* @param envp - env variables that you want to provide.
2524
*/
26-
execvpe(cmd: string, argv: Array<string>, envp: Array<string>): never;
25+
execvp(cmd: string, argv: Array<string>, envp: Record<string, string>): never;
2726
}
2827

2928
const projectRoot = path.join(__dirname, '../');

src/napi/lib.rs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ extern crate core;
33
use napi_derive::napi;
44
use napi::bindgen_prelude::{
55
Array,
6+
Object,
67
};
78
use uapi;
89

@@ -16,8 +17,8 @@ fn set_fd_cloexec() -> uapi::Result<()> {
1617
Ok(())
1718
}
1819

19-
#[napi(ts_args_type="cmd: string, argv: Array<string>, envp: Array<string>")]
20-
pub fn execvpe(cmd: String, argv: Array, envp: Array) -> napi::Result<()> {
20+
#[napi(ts_args_type="cmd: string, argv: Array<string>, envp: Record<string, string>")]
21+
pub fn execvp(cmd: String, argv: Array, envp: Object) -> napi::Result<()> {
2122
// Before making the call we need to configure the stdio. This ensures we get the output of the exec'ed program.
2223
set_fd_cloexec().or_else(
2324
|e| Err(napi::Error::from_reason(e.to_string()))
@@ -38,22 +39,23 @@ pub fn execvpe(cmd: String, argv: Array, envp: Array) -> napi::Result<()> {
3839
}
3940

4041
// Setting up the env parameters
41-
let mut envp_ = uapi::UstrPtr::new();
42-
for i in 0..envp.len() {
43-
match envp.get::<String>(i) {
44-
Ok(Some(value)) => {
45-
envp_.push(value);
46-
Ok(())
47-
},
48-
Err(e) => Err(napi::Error::from_reason(e.to_string())),
49-
_ => Ok(()),
50-
}?;
42+
let keys = Object::keys(&envp).or_else(
43+
|e| Err(napi::Error::from_reason(e.to_string()))
44+
)?;
45+
for key in keys.iter() {
46+
let value = match envp.get::<String, String>(key.clone()) {
47+
Ok(Some(value)) => Ok(value),
48+
Ok(None) => panic!("asd"),
49+
Err(e) => Err(e),
50+
}.or_else(
51+
|e| Err(napi::Error::from_reason(e.to_string()))
52+
)?;
53+
std::env::set_var(key, value);
5154
}
5255

53-
uapi::execvpe(
56+
uapi::execvp(
5457
cmd,
5558
&argv_,
56-
&envp_,
5759
).or_else(
5860
|e| Err(napi::Error::from_reason(e.to_string()))
5961
)

tests/Exec.test.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
import child_process from 'child_process';
22
import { exec } from '@';
33

4-
test('execvpe should provide environment variables', async () => {
5-
const output = child_process.execFileSync('./tests/callExecvpe.ts');
6-
const jsonOut = JSON.parse(output.toString());
7-
expect(jsonOut).toMatchObject({
8-
test: 'asd',
9-
best: 'bsd',
4+
describe('execvp', () => {
5+
test('execvp should provide environment variables', async () => {
6+
// Setting envs to check
7+
const output = child_process.execFileSync('./tests/callExecvpe.ts');
8+
const jsonOut = JSON.parse(output.toString());
9+
expect(jsonOut['TEST1']).toBe('value1');
10+
expect(jsonOut['TEST2']).toBe('value2');
11+
});
12+
test('execvp should throw when call fails', async () => {
13+
// Code 2 corresponds to `ENOENT`
14+
expect(() => exec.execvp('invalidCommand', [], {})).toThrow('2');
1015
});
11-
});
12-
test('execvpe should throw when call fails', async () => {
13-
// Code 2 corresponds to `ENOENT`
14-
expect(() => exec.execvpe('invalidCommand', [], [])).toThrow('2');
1516
});

tests/callExecvpe.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,8 @@ import { exec } from '@';
44
// This executes `printEnv.js` while setting environment variables
55
// eslint-disable-next-line no-console
66
console.log(
7-
exec.execvpe('node', ['./tests/printEnv.js'], ['test=asd', 'best=bsd']),
7+
exec.execvp('node', ['./tests/printEnv.js'], {
8+
TEST1: 'value1',
9+
TEST2: 'value2',
10+
}),
811
);

0 commit comments

Comments
 (0)