Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 36.4k
src: traverse parent folders while running --run#53154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,36 +1,28 @@ | ||
| #include "node_task_runner.h" | ||
| #include "util.h" | ||
| #include <filesystem> | ||
| #include <regex> // NOLINT(build/c++11) | ||
| namespace node::task_runner { | ||
| #ifdef _WIN32 | ||
| static constexpr const char* bin_path = "\\node_modules\\.bin"; | ||
| static constexpr const char* env_var_separator = ";"; | ||
| #else | ||
| static constexpr const char* bin_path = "/node_modules/.bin"; | ||
| static constexpr const char* env_var_separator = ":"; | ||
| #endif // _WIN32 | ||
| ProcessRunner::ProcessRunner(std::shared_ptr<InitializationResultImpl> result, | ||
| std::string_view package_json_path, | ||
| const std::filesystem::path& package_json_path, | ||
| std::string_view script_name, | ||
| std::string_view command, | ||
| const PositionalArgs& positional_args) { | ||
| std::string_view path_env_var, | ||
| const PositionalArgs& positional_args) | ||
| : init_result(std::move(result)), | ||
| package_json_path_(package_json_path), | ||
| script_name_(script_name), | ||
| path_env_var_(path_env_var) { | ||
| memset(&options_, 0, sizeof(uv_process_options_t)); | ||
| // Get the current working directory. | ||
| char cwd[PATH_MAX_BYTES]; | ||
| size_t cwd_size = PATH_MAX_BYTES; | ||
| CHECK_EQ(uv_cwd(cwd, &cwd_size), 0); | ||
| CHECK_GT(cwd_size, 0); | ||
| #ifdef _WIN32 | ||
| std::string current_bin_path = cwd + std::string(bin_path) + ";"; | ||
| #else | ||
| std::string current_bin_path = cwd + std::string(bin_path) + ":"; | ||
| #endif // _WIN32 | ||
| // Inherit stdin, stdout, and stderr from the parent process. | ||
| options_.stdio_count = 3; | ||
| child_stdio[0].flags = UV_INHERIT_FD; | ||
| @@ -46,18 +38,13 @@ ProcessRunner::ProcessRunner(std::shared_ptr<InitializationResultImpl> result, | ||
| options_.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS; | ||
| #endif | ||
| init_result = std::move(result); | ||
| // Set the process handle data to this class instance. | ||
| // This is used to access the class instance from the OnExit callback. | ||
| // It is required because libuv doesn't allow passing lambda functions as a | ||
| // callback. | ||
| process_.data = this; | ||
| SetEnvironmentVariables(current_bin_path, | ||
| std::string_view(cwd, cwd_size), | ||
| package_json_path, | ||
| script_name); | ||
| SetEnvironmentVariables(); | ||
| std::string command_str(command); | ||
| @@ -73,12 +60,7 @@ ProcessRunner::ProcessRunner(std::shared_ptr<InitializationResultImpl> result, | ||
| } | ||
| #ifdef _WIN32 | ||
| // We check whether file_ ends with cmd.exe in a case-insensitive manner. | ||
| // C++20 provides ends_with, but we roll our own for compatibility. | ||
| const char* cmdexe = "cmd.exe"; | ||
| if (file_.size() >= strlen(cmdexe) && | ||
| StringEqualNoCase(cmdexe, | ||
| file_.c_str() + file_.size() - strlen(cmdexe))) { | ||
| if (file_.ends_with("cmd.exe")) { | ||
| // If the file is cmd.exe, use the following command line arguments: | ||
| // "/c" Carries out the command and exit. | ||
| // "/d" Disables execution of AutoRun commands. | ||
| @@ -106,10 +88,7 @@ ProcessRunner::ProcessRunner(std::shared_ptr<InitializationResultImpl> result, | ||
| options_.args[argc] = nullptr; | ||
| } | ||
| void ProcessRunner::SetEnvironmentVariables(const std::string& current_bin_path, | ||
| std::string_view cwd, | ||
| std::string_view package_json_path, | ||
| std::string_view script_name) { | ||
| void ProcessRunner::SetEnvironmentVariables() { | ||
| uv_env_item_t* env_items; | ||
| int env_count; | ||
| CHECK_EQ(0, uv_os_environ(&env_items, &env_count)); | ||
| @@ -130,28 +109,21 @@ void ProcessRunner::SetEnvironmentVariables(const std::string& current_bin_path, | ||
| #endif // _WIN32 | ||
| if (StringEqualNoCase(name.c_str(), "path")) { | ||
| // Add bin_path to the beginning of the PATH | ||
| value = current_bin_path + value; | ||
| // Add path env variable to the beginning of the PATH | ||
| value = path_env_var_ + value; | ||
| } | ||
| env_vars_.push_back(name + "=" + value); | ||
| } | ||
| uv_os_free_environ(env_items, env_count); | ||
| // Add NODE_RUN_SCRIPT_NAME environment variable to the environment | ||
| // to indicate which script is being run. | ||
| env_vars_.push_back("NODE_RUN_SCRIPT_NAME=" + std::string(script_name)); | ||
| env_vars_.push_back("NODE_RUN_SCRIPT_NAME=" + script_name_); | ||
| // Add NODE_RUN_PACKAGE_JSON_PATH environment variable to the environment to | ||
| // indicate which package.json is being processed. | ||
| if (std::filesystem::path(package_json_path).is_absolute()) { | ||
| // TODO(anonrig): Traverse up the directory tree until we find a | ||
| // package.json | ||
| env_vars_.push_back("NODE_RUN_PACKAGE_JSON_PATH=" + | ||
| std::string(package_json_path)); | ||
| } else { | ||
| auto path = std::filesystem::path(cwd) / std::string(package_json_path); | ||
| env_vars_.push_back("NODE_RUN_PACKAGE_JSON_PATH=" + path.string()); | ||
| } | ||
| env_vars_.push_back("NODE_RUN_PACKAGE_JSON_PATH=" + | ||
| package_json_path_.string()); | ||
| env = std::unique_ptr<char*[]>(new char*[env_vars_.size() + 1]); | ||
| options_.env = env.get(); | ||
| @@ -240,19 +212,58 @@ void ProcessRunner::Run() { | ||
| uv_run(loop_, UV_RUN_DEFAULT); | ||
| } | ||
| std::optional<std::tuple<std::filesystem::path, std::string, std::string>> | ||
| FindPackageJson(const std::filesystem::path& cwd) { | ||
anonrig marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| auto package_json_path = cwd / "package.json"; | ||
| std::string raw_content; | ||
| std::string path_env_var; | ||
| auto root_path = cwd.root_path(); | ||
| for (auto directory_path = cwd; | ||
| !std::filesystem::equivalent(root_path, directory_path); | ||
| directory_path = directory_path.parent_path()) { | ||
| // 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; | ||
| } | ||
| 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. | ||
anonrig marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| std::string contents = package_json_path.string(); | ||
| USE(ReadFileSync(&raw_content, contents.c_str()) > 0); | ||
| } | ||
| } | ||
| // This means that there is no package.json until the root directory. | ||
| // In this case, we just return nullopt, which will terminate the process.. | ||
| if (raw_content.empty()) { | ||
| return std::nullopt; | ||
| } | ||
| return {{package_json_path, raw_content, path_env_var}}; | ||
| } | ||
| void RunTask(std::shared_ptr<InitializationResultImpl> result, | ||
| std::string_view command_id, | ||
| const std::vector<std::string_view>& positional_args) { | ||
| std::string_view path = "package.json"; | ||
| std::string raw_json; | ||
| auto cwd = std::filesystem::current_path(); | ||
| auto package_json = FindPackageJson(cwd); | ||
| // No need to exclude BOM since simdjson will skip it. | ||
| if (ReadFileSync(&raw_json, path.data()) < 0) { | ||
| if (!package_json.has_value()) { | ||
| fprintf(stderr, "Can't read package.json\n"); | ||
| result->exit_code_ = ExitCode::kGenericUserError; | ||
| return; | ||
| } | ||
| // - path: Path to the package.json file. | ||
| // - raw_json: Raw content of the package.json file. | ||
| // - path_env_var: This represents the `PATH` environment variable. | ||
| // It always ends with ";" or ":" depending on the platform. | ||
| auto [path, raw_json, path_env_var] = *package_json; | ||
anonrig marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
anonrig marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| simdjson::ondemand::parser json_parser; | ||
| simdjson::ondemand::document document; | ||
| simdjson::ondemand::object main_object; | ||
| @@ -302,8 +313,8 @@ void RunTask(std::shared_ptr<InitializationResultImpl> result, | ||
| return; | ||
| } | ||
| auto runner = | ||
| ProcessRunner(result, path, command_id, command, positional_args); | ||
| auto runner = ProcessRunner( | ||
| result, path, command_id, command, path_env_var, positional_args); | ||
| runner.Run(); | ||
| } | ||
| @@ -317,10 +328,11 @@ PositionalArgs GetPositionalArgs(const std::vector<std::string>& args) { | ||
| if (auto dash_dash = std::find(args.begin(), args.end(), "--"); | ||
| dash_dash != args.end()) { | ||
| PositionalArgs positional_args{}; | ||
| positional_args.reserve(args.size() - (dash_dash - args.begin())); | ||
| for (auto it = dash_dash + 1; it != args.end(); ++it) { | ||
| // SAFETY: The following code is safe because the lifetime of the | ||
| // arguments is guaranteed to be valid until the end of the task runner. | ||
| positional_args.push_back(std::string_view(it->c_str(), it->size())); | ||
| positional_args.emplace_back(it->c_str(), it->size()); | ||
| } | ||
| return positional_args; | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.