diff --git a/include/vcpkg/tools.h b/include/vcpkg/tools.h index 8572d13117..99c1218851 100644 --- a/include/vcpkg/tools.h +++ b/include/vcpkg/tools.h @@ -22,6 +22,7 @@ namespace vcpkg static const std::string POWERSHELL_CORE = "powershell-core"; static const std::string NUGET = "nuget"; static const std::string ARIA2 = "aria2"; + static const std::string NODE = "node"; static const std::string IFW_INSTALLER_BASE = "ifw_installerbase"; static const std::string IFW_BINARYCREATOR = "ifw_binarycreator"; static const std::string IFW_REPOGEN = "ifw_repogen"; diff --git a/src/vcpkg/base/files.cpp b/src/vcpkg/base/files.cpp index c80aa2d616..3fceb331b8 100644 --- a/src/vcpkg/base/files.cpp +++ b/src/vcpkg/base/files.cpp @@ -432,7 +432,6 @@ namespace else { stdfs::remove(current_entry.path(), ec); - if (err.check_ec(ec, current_entry)) return; } err.check_ec(ec, current_entry); @@ -463,7 +462,23 @@ namespace void vcpkg_remove_all(const Path& base, std::error_code& ec, Path& failure_point) { - stdfs::directory_entry entry(to_stdfs_path(base), ec); + std::wstring wide_path; + const auto& native_base = base.native(); + // Attempt to handle paths that are too long in recursive delete by prefixing absolute ones with + // backslash backslash question backslash + // See https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation + // We are conservative and only accept paths that begin with a drive letter prefix because other forms + // may have more Win32 path normalization that we do not replicate herein. + // (There are still edge cases we don't handle, such as trailing whitespace or nulls, but + // for purposes of remove_all, we never supported such trailing bits) + if (has_drive_letter_prefix(native_base.data(), native_base.data() + native_base.size())) + { + wide_path = L"\\\\?\\"; + } + + wide_path.append(Strings::to_utf16(native_base)); + + stdfs::directory_entry entry(wide_path, ec); translate_not_found_to_success(ec); if (ec) { diff --git a/src/vcpkg/base/system.process.cpp b/src/vcpkg/base/system.process.cpp index 168bb8b267..57bacdb511 100644 --- a/src/vcpkg/base/system.process.cpp +++ b/src/vcpkg/base/system.process.cpp @@ -329,6 +329,9 @@ namespace vcpkg L"IFORT_COMPILER19", L"IFORT_COMPILER20", L"IFORT_COMPILER21", + // Environment variables used by wrapper scripts to allow us to set environment variables in parent shells + L"Z_VCPKG_POSTSCRIPT", + L"Z_VCPKG_UNDO", }; const Optional keep_vars = get_environment_variable("VCPKG_KEEP_ENV_VARS"); diff --git a/src/vcpkg/tools.cpp b/src/vcpkg/tools.cpp index d4e1fa115c..e825a836c2 100644 --- a/src/vcpkg/tools.cpp +++ b/src/vcpkg/tools.cpp @@ -418,6 +418,50 @@ Copyright (C) 2006, 2019 Tatsuhiro Tsujikawa } }; + struct NodeProvider : ToolProvider + { + virtual const std::string& tool_data_name() const override { return Tools::NODE; } + virtual const std::string& exe_stem() const override { return Tools::NODE; } + virtual std::array default_min_version() const override { return {16, 12, 0}; } + + virtual void add_special_paths(std::vector& out_candidate_paths) const override + { +#if defined(_WIN32) + const auto& program_files = get_program_files_platform_bitness(); + if (const auto pf = program_files.get()) out_candidate_paths.push_back(*pf / "nodejs" / "node.exe"); + const auto& program_files_32_bit = get_program_files_32_bit(); + if (const auto pf = program_files_32_bit.get()) out_candidate_paths.push_back(*pf / "nodejs" / "node.exe"); +#else + // TODO: figure out if this should do anything on non-windows + (void)out_candidate_paths; +#endif + } + + virtual ExpectedS get_version(const VcpkgPaths&, const Path& exe_path) const override + { + auto cmd = Command(exe_path).string_arg("--version"); + auto rc = cmd_execute_and_capture_output(cmd); + if (rc.exit_code != 0) + { + return {Strings::concat(std::move(rc.output), "\n\nFailed to get version of ", Tools::NODE, "\n"), + expected_right_tag}; + } + + // Sample output: v16.12.0 + auto start = rc.output.begin(); + if (start == rc.output.end() || *start != 'v') + { + return {Strings::concat(std::move(rc.output), "\n\nUnexpected output of ", Tools::NODE, " --version\n"), + expected_right_tag}; + } + + ++start; + char newlines[] = "\r\n"; + auto end = std::find_first_of(start, rc.output.end(), &newlines[0], &newlines[2]); + return {std::string(start, end), expected_left_tag}; + } + }; + struct GitProvider : ToolProvider { std::string m_exe = "git"; @@ -651,6 +695,7 @@ gsutil version: 4.58 } if (tool == Tools::NUGET) return get_path(paths, NuGetProvider()); if (tool == Tools::ARIA2) return get_path(paths, Aria2Provider()); + if (tool == Tools::NODE) return get_path(paths, NodeProvider()); if (tool == Tools::IFW_INSTALLER_BASE) return get_path(paths, IfwInstallerBaseProvider()); if (tool == Tools::MONO) return get_path(paths, MonoProvider()); if (tool == Tools::GSUTIL)