How to append values to the PATH environment variable in NodeJS? - node.js

Following the answer suggested in the question -
Is it possible to permanently set environment variables?
I was able to set new environment variables permanently with the command -
spawnSync('setx', ['-m', 'MyDownloads', 'H:\\temp\\downloads'])
But now my goal is to append new values to the PATH environment variable.
Is it possible?

Why don't you just get the environment variable and then append to it?
I.e.
const {spawnSync} = require("child_process");
const current_value = process.env.PATH;
const new_path_value = current_value.concat(";", "/some/new/path");
var result = spawnSync('setx', ['-m', 'PATH', new_path_value])
// STDOUT
var stdOut = result.stdout.toString();
console.log(stdOut)
// STDERR
var stdErr = result.stderr.toString();
if(stdErr === '') {
console.log('Successfully set environment variable')
} else {
console.log(`ERROR: ${stderr}`)
}
Update "/some/new/path" and run this as admin as the link you provided suggests and it should work.

Run your script with the admin permission:
Open cmd or PowerShell with admin
Run node your_script.js
To append PATH variable, you can set value is : %PATH%;your_new_value here (%PATH% get old value)
If you run with electron app, you should require admin permission.
Don't forget setx run on window

I don't have rights to modify my registry, and I also would rather not call an OS command such as setx.
The following adds an additional component to the Windows PATH. I then ran Selenium, which uses the new setting.
// Display current value of PATH
const current_value = process.env.PATH;
console.log("PREV VALUE:")
console.log(current_value)
// Add the additional entry
const addl_entry = String.raw`\my\new\path\component`
process.env["PATH"] = addl_entry + ";" + current_value
// Display the new value
console.log("NEW VALUE:")
console.log(process.env.PATH)

Related

Unable to get environment variable in azure batch VM

Here is my Azure batch configuration which I am trying to create from microsoft tutorials here and here
I am trying to get env variables defined here
CloudPool pool = batchClient.PoolOperations.CreatePool(
poolId: PoolId,
targetDedicatedComputeNodes: PoolNodeCount,
virtualMachineSize: PoolVMSize,
virtualMachineConfiguration: vmConfiguration);
// Specify the application and version to install on the compute nodes
pool.ApplicationPackageReferences = new List<ApplicationPackageReference>
{
new ApplicationPackageReference {
ApplicationId = "7Zip",
Version = "19.00" }
};
// Commit the pool so that it's created in the Batch service. As the nodes join
// the pool, the specified application package is installed on each.
await pool.CommitAsync();
CloudJob job = batchClient.JobOperations.CreateJob();
job.Id = JobId;
job.PoolInformation = new PoolInformation { PoolId = PoolId };
await job.CommitAsync();
string taskId = "blendertask01";
string commandLine =
#"cmd /c echo %AZ_BATCH_APP_PACKAGE_7Zip%";
CloudTask blenderTask = new CloudTask(taskId, commandLine);
batchClient.JobOperations.AddTask(JobId, blenderTask);
I am expecting the output of cmd /c echo %AZ_BATCH_APP_PACKAGE_7Zip% to give me the path where I can find my application 7zip so that i can install it however I dont get that.
Instead i get %AZ_BATCH_APP_PACKAGE_7Zip%
Instead of using AZ_BATCH_APP_PACKAGE_7Zip we should specify the version also
thus it would become %AZ_BATCH_APP_PACKAGE_7Zip#19.00%\7z1900-x64.exe
This information is not clearly defined however after few hit and tries I discovered it
Also that the env variables are not visible when we log on using remote account.

Create a persistent bash shell session in Node.js, know when commands finish, and read and modify sourced/exported variables

Imagine this contrived scenario:
./main.sh
source ./config.sh
SOME_CONFIG="${SOME_CONFIG}bar"
./output.sh
./config.sh
export SOME_CONFIG='foo'
./output.sh
echo "Config is: ${SOME_CONFIG}"
I am trying to replace ./main.sh with a Node.js powered ./main.js WITHOUT replacing the other shell files. The exported ./config.sh functions/variables must also be fully available to ./output.sh
Here is a NON working ./main.js. I have written this for the sole purpose to explain what I want the final code to look like:
const terminal = require('child_process').spawn('bash')
terminal.stdin.write('source ./config.sh\n')
process.env.SOME_CONFIG = `${process.env.SOME_CONFIG}bar` // this must be done in JS
terminal.stdin.write('./output.sh\n') // this must be able to access all exported functions/variables in config.sh, including the JS modified SOME_CONFIG
How can I achieve this? Ideally if there's a library that can do this I'd prefer that.
While this doesn't fully answer my question, it solves the contrived problem I had at hand and could help others if need be.
In general, if bash scripts communicate with each other via environment variables (eg. using export/source), this will allow you to start moving bash code to Node.js.
./main.js
const child_process = require("child_process");
const os = require("os");
// Source config.sh and print the environment variables including SOME_CONFIG
const sourcedConfig = child_process
.execSync(". ./config.sh > /dev/null 2>&1 && env")
.toString();
// Convert ALL sourced environment variables into an object
const sourcedEnvVars = sourcedConfig
.split(os.EOL)
.map((line) => ({
env: `${line.substr(0, line.indexOf("="))}`,
val: `${line.substr(line.indexOf("=") + 1)}`,
}))
.reduce((envVarObject, envVarEntry) => {
envVarObject[envVarEntry.env] = envVarEntry.val;
return envVarObject;
}, {});
// Make changes
sourcedEnvVars["SOME_CONFIG"] = `${sourcedEnvVars["SOME_CONFIG"]}bar`;
// Run output.sh and pass in the environment variables we got from the previous command
child_process.execSync("./output.sh", {
env: sourcedEnvVars,
stdio: "inherit",
});

why i am not able to update env variable in node js

I want to update my env variable in node js, but i am not able to update its env variable, i tried with console.log(process.env.DB_HOST) but still i am getting old value, here i have added my whole code, can anyone please look in to it, and help me to resolve this issue,
function exec_api() {
return new Promise(async function (resolve) {
const execSync = require('child_process').exec;
//let child_process_obj = execSync('DB_HOST='+process.env.UNITTEST_DB_HOST+' DB_DATABASE='+process.env.UNITTEST_DB_DATABASE+' DB_USERNAME='+process.env.UNITTEST_DB_USERNAME+' DB_PASSWORD='+process.env.UNITTEST_DB_PASSWORD+' PORT='+process.env.UNITTEST_SERVICE_PORT+' ./node_modules/.bin/nodemon main.js');
await execSync('export DB_HOST=' + process.env.UNITTEST_DB_HOST);
await execSync('export DB_DATABASE=' + process.env.UNITTEST_DB_DATABASE);
await execSync('export DB_USERNAME=' + process.env.UNITTEST_DB_USERNAME);
await execSync('export DB_PASSWORD=' + process.env.UNITTEST_DB_PASSWORD);
await execSync('export PORT=' + process.env.UNITTEST_API_BACKEND_PORT);
let child_process_obj = await execSync('node main.js');
unittest_api_backend_process_id = child_process_obj.pid;
resolve(true);
});
}
TLDR: Just change process.env
To change, add or delete environment variables, use process.env. The following is test code showing how this works:
In main.js:
console.log(process.env.DB_DATABASE);
In exec.js:
const execSync = require ('child_process').execSync;
process.env.DB_DATABASE = 'foo'; // this is ALL you need to do
console.log(execSync('node main.js').toString('utf8'));
With the two files above, if you run node exec.js you will see foo printed out in the console. This is printed from main.js which inherits the environment from exec.js.
So all you need to do in your code is:
I want to update my env variable in node js, but i am not able to update its env variable, i tried with console.log(process.env.DB_HOST) but still i am getting old value, here i have added my whole code, can anyone please look in to it, and help me to resolve this issue,
function exec_api() {
return new Promise(function (resolve) {
const exec = require('child_process').exec;
// The following is node.js equivalent of bash "export":
process.env.DB_HOST = process.env.UNITTEST_DB_HOST;
process.env.DB_DATABASE = process.env.UNITTEST_DB_DATABASE;
process.env.DB_USERNAME = process.env.UNITTEST_DB_USERNAME;
process.env.DB_PASSWORD = process.env.UNITTEST_DB_PASSWORD;
process.env.PORT = process.env.UNITTEST_SERVICE_PORT;
let child_process_obj = exec('node main.js', {
stdio: ['inherit', 'inherit', 'inherit']
});
unittest_api_backend_process_id = child_process_obj.pid;
resolve(true);
});
}
Note that if you want the promise to return when the main.js ends you need to do:
function exec_api() {
return new Promise(function (resolve) {
const exec = require('child_process').exec;
// The following is node.js equivalent of bash "export":
process.env.DB_HOST = process.env.UNITTEST_DB_HOST;
process.env.DB_DATABASE = process.env.UNITTEST_DB_DATABASE;
process.env.DB_USERNAME = process.env.UNITTEST_DB_USERNAME;
process.env.DB_PASSWORD = process.env.UNITTEST_DB_PASSWORD;
process.env.PORT = process.env.UNITTEST_SERVICE_PORT;
let child_process_obj = exec('node main.js', {
stdio: ['inherit', 'inherit', 'inherit']
});
unittest_api_backend_process_id = child_process_obj.pid;
child_process_obj.on('exit', () => resolve(true));
// ^^^ Cannot use `await` as the API is not promise based
// but event based instead.
});
}
Long story: The full explanation of why export doesn't work
On unixen, environment variables, and indeed, the entire environment including current working directory, root directory (which can be changed via chroot) etc. are not features of shells. They are features of processes.
We may be familiar with the export syntax of some shells to set environment variables for child processes but that is the shell's syntax. It has nothing to do with environment variables themselves. C/C++ for example don't use export instead uses the setenv() function do set environment variables (indeed, internally that's what bash/sh/ksh etc do when implementing export).
In node.js, the mechanism for reading and setting environment variables is via process.env.
Why asking a shell to do it don't work
This is not merely a node.js issue. It also won't work in bash:
In exporter.sh:
#! /bin/bash
export DB_DATABASE=$1
In exec.sh:
#! /bin/bash
./exporter.sh foo
echo $DB_DATABASE ;# does not print "foo"
This is a core security feature of unixen: other users should not be allowed to mess with your process. The way this policy is enforced in the case of the environment is that only a parent process can set the environment of the child process. A child process is not allowed to set the environment of the parent process. The assumption is that the child process belongs to the parent process so you should be allowed to do what you want to a program - but since the parent process (you) don't belong to the child process the child is not allowed to mess with the parent's environment.
That's why your attempt to use export doesn't work. It actually works (the variables are indeed created in the subshell) but is not allowed to change the environment of it's parent (the node.js process)
When you use export in a terminal, it instructs the shell to set environment variables.
When you call exec from your code, you are not running such a shell, with the reason being that it would become a challenge to extract the output of every command.
This makes export an ignored command.
You can solve this by passing an option object to execSync:
execSync('node main.js', {
env: {
DB_HOST: 'localhost',
// More envs...
}
}

Can't read file using nodejs fs module when file name is stored in environment variable

I am running a node app in ubuntu server 16.04. I have set up an environment variable:
export FILE_PATH="file-path"
Then I tried to read the file in my node script:
const fs = require('fs');
console.log(process.env.FILE_PATH); // gives correct path.
const data = fs.readFileSync((process.env.FILE_PATH || ""), 'utf8');
But I'm getting "no such file or directory" error in debugger. The file is existing and has required permissions. If I give the path directly instead of taking from env variable, it will work.
I figured out the root cause of this issue. All the environment variables I set has a ‘\r’ in the end.
console.log(process.env) gives the output:
...
FILE_PATH: '/tmp/file.txt\r',
...
As a quick fix I used trim() to remove the extra character:
const data = fs.readFileSync((process.env.FILE_PATH.trim() || ""), 'utf8');
You may need to parse your path with Node.js's path module. Something like:
const data = fs.readFileSync(path.resolve((process.env.FILE_PATH || "")), 'utf8');

Git HOME environment variables not being used with child-process.exec

The second optional argument to child-process's exec() method are an option's object with an env property. This should set the environmental variables for the executable that will run, but in some cases this is not the case.
What I'm trying to do is set the HOME variable for git to use to a different path so that the host alias MY_SSH_HOST_ALIAS reads the $HOME/.ssh/config file and chooses the appropriate key for that alias. I'm trying to do this because my system's default .ssh folder is not in HOME.
However, the below fails and reads the default key from $HOME/.ssh/
const exec = require('child-process').exec
var succeeds = 'echo "my home is $HOME"' // prints my home is ~/mypath/
var fail = 'git clone MY_SSH_HOST_ALIAS:repo.git'
var options = { env: { HOME: '~/mypath/' } }
exec(fail, options, function(e, out, err) {
console.out(e, out, err)
})

Resources