Skip to content

Commit 073643e

Browse files
committed
cli: add lifecycle event env to node --run
1 parent 075853e commit 073643e

File tree

7 files changed

+78
-35
lines changed

7 files changed

+78
-35
lines changed

doc/api/cli.md

+11
Original file line numberDiff line numberDiff line change
@@ -1847,6 +1847,10 @@ Modules preloaded with `--require` will run before modules preloaded with `--imp
18471847

18481848
<!-- YAML
18491849
added: v22.0.0
1850+
changes:
1851+
- version: REPLACEME
1852+
pr-url: https://github.com/nodejs/node/pull/53032
1853+
description: NODE_LIFECYCLE_EVENT environment variable is added.
18501854
-->
18511855

18521856
> Stability: 1.1 - Active development
@@ -1887,6 +1891,13 @@ are:
18871891
* Running `pre` or `post` scripts in addition to the specified script.
18881892
* Defining package manager-specific environment variables.
18891893

1894+
#### Environment variables
1895+
1896+
The following environment variables are set when running a script with `--run`:
1897+
1898+
* `NODE_LIFECYCLE_EVENT`: The name of the script being run. For example, if
1899+
`--run` is used to run `test`, the value of this variable will be `test`.
1900+
18901901
### `--secure-heap=n`
18911902

18921903
<!-- YAML

src/node_task_runner.cc

+45-34
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ static constexpr const char* bin_path = "/node_modules/.bin";
1212
#endif // _WIN32
1313

1414
ProcessRunner::ProcessRunner(std::shared_ptr<InitializationResultImpl> result,
15+
const std::string& script_name,
1516
std::string_view command,
1617
const PositionalArgs& positional_args) {
1718
memset(&options_, 0, sizeof(uv_process_options_t));
@@ -51,39 +52,9 @@ ProcessRunner::ProcessRunner(std::shared_ptr<InitializationResultImpl> result,
5152
// callback.
5253
process_.data = this;
5354

54-
std::string command_str(command);
55-
56-
// Set environment variables
57-
uv_env_item_t* env_items;
58-
int env_count;
59-
CHECK_EQ(0, uv_os_environ(&env_items, &env_count));
60-
env = std::unique_ptr<char*[]>(new char*[env_count + 1]);
61-
options_.env = env.get();
62-
63-
// Iterate over environment variables once to store them in the current
64-
// ProcessRunner instance.
65-
for (int i = 0; i < env_count; i++) {
66-
std::string name = env_items[i].name;
67-
auto value = env_items[i].value;
68-
69-
#ifdef _WIN32
70-
// We use comspec environment variable to find cmd.exe path on Windows
71-
// Example: 'C:\\Windows\\system32\\cmd.exe'
72-
// If we don't find it, we fallback to 'cmd.exe' for Windows
73-
if (StringEqualNoCase(name.c_str(), "comspec")) {
74-
file_ = value;
75-
}
76-
#endif // _WIN32
55+
SetEnvironmentVariables(current_bin_path, script_name);
7756

78-
// Check if environment variable key is matching case-insensitive "path"
79-
if (StringEqualNoCase(name.c_str(), "path")) {
80-
env_vars_.push_back(name + "=" + current_bin_path + value);
81-
} else {
82-
// Environment variables should be in "KEY=value" format
83-
env_vars_.push_back(name + "=" + value);
84-
}
85-
}
86-
uv_os_free_environ(env_items, env_count);
57+
std::string command_str(command);
8758

8859
// Use the stored reference on the instance.
8960
options_.file = file_.c_str();
@@ -128,11 +99,50 @@ ProcessRunner::ProcessRunner(std::shared_ptr<InitializationResultImpl> result,
12899
options_.args[i] = const_cast<char*>(command_args_[i].c_str());
129100
}
130101
options_.args[argc] = nullptr;
102+
}
103+
104+
void ProcessRunner::SetEnvironmentVariables(const std::string& bin_path,
105+
const std::string& script_name) {
106+
// Set environment variables
107+
uv_env_item_t* env_items;
108+
int env_count;
109+
CHECK_EQ(0, uv_os_environ(&env_items, &env_count));
110+
env = std::unique_ptr<char*[]>(new char*[env_count + 1]);
111+
options_.env = env.get();
131112

113+
// Iterate over environment variables once to store them in the current
114+
// ProcessRunner instance.
132115
for (int i = 0; i < env_count; i++) {
116+
std::string name = env_items[i].name;
117+
auto value = env_items[i].value;
118+
119+
#ifdef _WIN32
120+
// We use comspec environment variable to find cmd.exe path on Windows
121+
// Example: 'C:\\Windows\\system32\\cmd.exe'
122+
// If we don't find it, we fallback to 'cmd.exe' for Windows
123+
if (StringEqualNoCase(name.c_str(), "comspec")) {
124+
file_ = value;
125+
}
126+
#endif // _WIN32
127+
128+
// Check if environment variable key is matching case-insensitive "path"
129+
if (StringEqualNoCase(name.c_str(), "path")) {
130+
env_vars_.push_back(name + "=" + bin_path + value);
131+
} else {
132+
// Environment variables should be in "KEY=value" format
133+
env_vars_.push_back(name + "=" + value);
134+
}
135+
}
136+
uv_os_free_environ(env_items, env_count);
137+
138+
// Add NODE_LIFECYCLE_EVENT environment variable to the environment
139+
// to indicate which script is being run.
140+
env_vars_.push_back("NODE_LIFECYCLE_EVENT=" + script_name);
141+
142+
for (size_t i = 0; i < env_vars_.size(); i++) {
133143
options_.env[i] = const_cast<char*>(env_vars_[i].c_str());
134144
}
135-
options_.env[env_count] = nullptr;
145+
options_.env[env_vars_.size()] = nullptr;
136146
}
137147

138148
// EscapeShell escapes a string to be used as a command line argument.
@@ -276,7 +286,8 @@ void RunTask(std::shared_ptr<InitializationResultImpl> result,
276286
return;
277287
}
278288

279-
auto runner = ProcessRunner(result, command, positional_args);
289+
auto runner =
290+
ProcessRunner(result, std::string(command_id), command, positional_args);
280291
runner.Run();
281292
}
282293

src/node_task_runner.h

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ using PositionalArgs = std::vector<std::string_view>;
2323
class ProcessRunner {
2424
public:
2525
ProcessRunner(std::shared_ptr<InitializationResultImpl> result,
26+
const std::string& script_name,
2627
std::string_view command_id,
2728
const PositionalArgs& positional_args);
2829
void Run();
@@ -43,6 +44,8 @@ class ProcessRunner {
4344

4445
// OnExit is the callback function that is called when the process exits.
4546
void OnExit(int64_t exit_status, int term_signal);
47+
void SetEnvironmentVariables(const std::string& bin_path,
48+
const std::string& script_name);
4649

4750
#ifdef _WIN32
4851
std::string file_ = "cmd.exe";

test/fixtures/run-script/node_modules/.bin/special-env-variables

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/fixtures/run-script/node_modules/.bin/special-env-variables.bat

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/fixtures/run-script/package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
"custom-env": "custom-env",
99
"custom-env-windows": "custom-env.bat",
1010
"path-env": "path-env",
11-
"path-env-windows": "path-env.bat"
11+
"path-env-windows": "path-env.bat",
12+
"special-env-variables": "special-env-variables",
13+
"special-env-variables-windows": "special-env-variables.bat"
1214
}
1315
}

test/parallel/test-node-run.js

+12
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,16 @@ describe('node run [command]', () => {
8080
assert.strictEqual(child.stderr, '');
8181
assert.strictEqual(child.code, 0);
8282
});
83+
84+
it('should set special environment variables', async () => {
85+
const scriptName = `special-env-variables${envSuffix}`;
86+
const child = await common.spawnPromisified(
87+
process.execPath,
88+
[ '--no-warnings', '--run', scriptName],
89+
{ cwd: fixtures.path('run-script') },
90+
);
91+
assert.ok(child.stdout.includes(scriptName));
92+
assert.strictEqual(child.stderr, '');
93+
assert.strictEqual(child.code, 0);
94+
});
8395
});

0 commit comments

Comments
 (0)