Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 13 additions & 12 deletions src/node_task_runner.cc
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ void ProcessRunner::SetEnvironmentVariables() {
// Add NODE_RUN_PACKAGE_JSON_PATH environment variable to the environment to
// indicate which package.json is being processed.
env_vars_.push_back("NODE_RUN_PACKAGE_JSON_PATH=" +
package_json_path_.string());
ConvertPathToUTF8(package_json_path_));

env_ = std::unique_ptr<char*[]>(new char*[env_vars_.size() + 1]);
options_.env = env_.get();
Expand Down Expand Up @@ -206,7 +206,7 @@ void ProcessRunner::OnExit(int64_t exit_status, int term_signal) {

void ProcessRunner::Run() {
// keeps the string alive until destructor
cwd_ = package_json_path_.parent_path().string();
cwd_ = ConvertPathToUTF8(package_json_path_.parent_path());
options_.cwd = cwd_.c_str();
if (int r = uv_spawn(loop_, &process_, &options_)) {
fprintf(stderr, "Error: %s\n", uv_strerror(r));
Expand All @@ -228,14 +228,14 @@ FindPackageJson(const std::filesystem::path& cwd) {
// Append "path/node_modules/.bin" to the env var, if it is a directory.
auto node_modules_bin = directory_path / "node_modules" / ".bin";
if (std::filesystem::is_directory(node_modules_bin)) {
path_env_var += node_modules_bin.string() + env_var_separator;
path_env_var += ConvertPathToUTF8(node_modules_bin) + env_var_separator;
}

if (raw_content.empty()) {
package_json_path = directory_path / "package.json";
// This is required for Windows because std::filesystem::path::c_str()
// returns wchar_t* on Windows, and char* on other platforms.
std::string contents = package_json_path.string();
std::string contents = ConvertPathToUTF8(package_json_path);
USE(ReadFileSync(&raw_content, contents.c_str()) > 0);
}
}
Expand All @@ -258,7 +258,7 @@ void RunTask(const std::shared_ptr<InitializationResultImpl>& result,
if (!package_json.has_value()) {
fprintf(stderr,
"Can't find package.json for directory %s\n",
cwd.string().c_str());
ConvertPathToUTF8(cwd).c_str());
result->exit_code_ = ExitCode::kGenericUserError;
return;
}
Expand All @@ -274,7 +274,7 @@ void RunTask(const std::shared_ptr<InitializationResultImpl>& result,
simdjson::ondemand::object main_object;

if (json_parser.iterate(raw_json).get(document)) {
fprintf(stderr, "Can't parse %s\n", path.string().c_str());
fprintf(stderr, "Can't parse %s\n", ConvertPathToUTF8(path).c_str());
result->exit_code_ = ExitCode::kGenericUserError;
return;
}
Expand All @@ -283,9 +283,9 @@ void RunTask(const std::shared_ptr<InitializationResultImpl>& result,
if (root_error == simdjson::error_code::INCORRECT_TYPE) {
fprintf(stderr,
"Root value unexpected not an object for %s\n\n",
path.string().c_str());
ConvertPathToUTF8(path).c_str());
} else {
fprintf(stderr, "Can't parse %s\n", path.string().c_str());
fprintf(stderr, "Can't parse %s\n", ConvertPathToUTF8(path).c_str());
}
result->exit_code_ = ExitCode::kGenericUserError;
return;
Expand All @@ -294,8 +294,9 @@ void RunTask(const std::shared_ptr<InitializationResultImpl>& result,
// If package_json object doesn't have "scripts" field, throw an error.
simdjson::ondemand::object scripts_object;
if (main_object["scripts"].get_object().get(scripts_object)) {
fprintf(
stderr, "Can't find \"scripts\" field in %s\n", path.string().c_str());
fprintf(stderr,
"Can't find \"scripts\" field in %s\n",
ConvertPathToUTF8(path).c_str());
result->exit_code_ = ExitCode::kGenericUserError;
return;
}
Expand All @@ -309,13 +310,13 @@ void RunTask(const std::shared_ptr<InitializationResultImpl>& result,
"Script \"%.*s\" is unexpectedly not a string for %s\n\n",
static_cast<int>(command_id.size()),
command_id.data(),
path.string().c_str());
ConvertPathToUTF8(path).c_str());
} else {
fprintf(stderr,
"Missing script: \"%.*s\" for %s\n\n",
static_cast<int>(command_id.size()),
command_id.data(),
path.string().c_str());
ConvertPathToUTF8(path).c_str());
fprintf(stderr, "Available scripts are:\n");

// Reset the object to iterate over it again
Expand Down
42 changes: 42 additions & 0 deletions test/parallel/test-node-run.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ common.requireNoPackageJSONAbove();

const { it, describe } = require('node:test');
const assert = require('node:assert');
const fs = require('node:fs');
const path = require('node:path');

const fixtures = require('../common/fixtures');
const tmpdir = require('../common/tmpdir');
const envSuffix = common.isWindows ? '-windows' : '';

describe('node --run [command]', () => {
Expand Down Expand Up @@ -201,6 +204,45 @@ describe('node --run [command]', () => {
assert.strictEqual(child.code, 0);
});

it('handles package paths outside the active Windows code page',
{ skip: !common.isWindows }, async () => {
tmpdir.refresh();

const projectDir = path.join(tmpdir.path, 'node-run-\u{20BB7}');
const packageJsonPath = path.join(projectDir, 'package.json');
const nodeModulesBin = path.join(projectDir, 'node_modules', '.bin');
const checkScript = path.join(projectDir, 'check.js');

fs.mkdirSync(nodeModulesBin, { recursive: true });
fs.writeFileSync(packageJsonPath, JSON.stringify({
scripts: {
unicode: `"${process.execPath}" check.js`,
},
}));
fs.writeFileSync(checkScript, `
'use strict';
console.log(JSON.stringify({
cwd: process.cwd(),
packageJsonPath: process.env.NODE_RUN_PACKAGE_JSON_PATH,
path: process.env.PATH,
}));
`);

const child = await common.spawnPromisified(
process.execPath,
[ '--run', 'unicode'],
{ cwd: projectDir },
);

assert.strictEqual(child.stderr, '');
assert.strictEqual(child.code, 0);

const output = JSON.parse(child.stdout);
assert.strictEqual(output.cwd, projectDir);
assert.strictEqual(output.packageJsonPath, packageJsonPath);
assert.strictEqual(output.path.split(path.delimiter)[0], nodeModulesBin);
});

it('returns error on unparsable file', async () => {
const child = await common.spawnPromisified(
process.execPath,
Expand Down
Loading