#include #include #include #include #include #include #include // used to get the implementation specific compiler flags (i.e., __cpp_lib_filesystem) #include #include #include #if defined(_WIN32) #include #endif #define FILESYSTEM_SYMLINK_STD 0 #define FILESYSTEM_SYMLINK_UNIX 1 #define FILESYSTEM_SYMLINK_NONE 2 #if VCPKG_USE_STD_FILESYSTEM #define FILESYSTEM_SYMLINK FILESYSTEM_SYMLINK_STD #elif !defined(_MSC_VER) #define FILESYSTEM_SYMLINK FILESYSTEM_SYMLINK_UNIX #else #define FILESYSTEM_SYMLINK FILESYSTEM_SYMLINK_NONE #endif namespace vcpkg::Test { const Triplet X86_WINDOWS = Triplet::from_canonical_name("x86-windows"); const Triplet X64_WINDOWS = Triplet::from_canonical_name("x64-windows"); const Triplet X86_UWP = Triplet::from_canonical_name("x86-uwp"); const Triplet ARM_UWP = Triplet::from_canonical_name("arm-uwp"); const Triplet X64_ANDROID = Triplet::from_canonical_name("x64-android"); std::unique_ptr make_control_file( const char* name, const char* depends, const std::vector>& features, const std::vector& default_features) { using Pgh = std::unordered_map; std::vector scf_pghs; scf_pghs.push_back(Pgh{{"Source", name}, {"Version", "0"}, {"Build-Depends", depends}, {"Default-Features", Strings::join(", ", default_features)}}); for (auto&& feature : features) { scf_pghs.push_back(Pgh{ {"Feature", feature.first}, {"Description", "feature"}, {"Build-Depends", feature.second}, }); } auto m_pgh = test_parse_control_file(std::move(scf_pghs)); REQUIRE(m_pgh.has_value()); return std::move(*m_pgh.get()); } std::unique_ptr make_status_pgh(const char* name, const char* depends, const char* default_features, const char* triplet) { return std::make_unique(Parse::Paragraph{{"Package", {name, {}}}, {"Version", {"1", {}}}, {"Architecture", {triplet, {}}}, {"Multi-Arch", {"same", {}}}, {"Depends", {depends, {}}}, {"Default-Features", {default_features, {}}}, {"Status", {"install ok installed", {}}}}); } std::unique_ptr make_status_feature_pgh(const char* name, const char* feature, const char* depends, const char* triplet) { return std::make_unique(Parse::Paragraph{{"Package", {name, {}}}, {"Feature", {feature, {}}}, {"Architecture", {triplet, {}}}, {"Multi-Arch", {"same", {}}}, {"Depends", {depends, {}}}, {"Status", {"install ok installed", {}}}}); } PackageSpec PackageSpecMap::emplace(const char* name, const char* depends, const std::vector>& features, const std::vector& default_features) { auto scfl = SourceControlFileLocation{make_control_file(name, depends, features, default_features), ""}; return emplace(std::move(scfl)); } PackageSpec PackageSpecMap::emplace(vcpkg::SourceControlFileLocation&& scfl) { map.emplace(scfl.source_control_file->core_paragraph->name, std::move(scfl)); return {scfl.source_control_file->core_paragraph->name, triplet}; } static AllowSymlinks internal_can_create_symlinks() noexcept { #if FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_NONE return AllowSymlinks::No; #elif FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_UNIX return AllowSymlinks::Yes; #elif !defined(_WIN32) // FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_STD return AllowSymlinks::Yes; #else constexpr static const wchar_t regkey[] = LR"(SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock)"; constexpr static const wchar_t regkey_member[] = LR"(AllowDevelopmentWithoutDevLicense)"; DWORD data; DWORD dataSize = sizeof(data); const auto status = RegGetValueW(HKEY_LOCAL_MACHINE, regkey, regkey_member, RRF_RT_DWORD, nullptr, &data, &dataSize); if (status == ERROR_SUCCESS && data == 1) { return AllowSymlinks::Yes; } else { std::cout << "Symlinks are not allowed on this system\n"; return AllowSymlinks::No; } #endif } const static AllowSymlinks CAN_CREATE_SYMLINKS = internal_can_create_symlinks(); AllowSymlinks can_create_symlinks() noexcept { return CAN_CREATE_SYMLINKS; } static fs::path internal_base_temporary_directory() { #if defined(_WIN32) wchar_t* tmp = static_cast(std::calloc(32'767, 2)); if (!GetEnvironmentVariableW(L"TEMP", tmp, 32'767)) { std::cerr << "No temporary directory found.\n"; std::abort(); } fs::path result = tmp; std::free(tmp); return result / L"vcpkg-test"; #else return "/tmp/vcpkg-test"; #endif } const fs::path& base_temporary_directory() noexcept { const static fs::path BASE_TEMPORARY_DIRECTORY = internal_base_temporary_directory(); return BASE_TEMPORARY_DIRECTORY; } #if FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_NONE constexpr char no_filesystem_message[] = " doesn't exist; on windows, we don't attempt to use the win32 calls to create symlinks"; #endif void create_symlink(const fs::path& target, const fs::path& file, std::error_code& ec) { #if FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_STD if (can_create_symlinks()) { fs::path targetp = target.native(); fs::path filep = file.native(); fs::stdfs::create_symlink(targetp, filep, ec); } else { vcpkg::Checks::exit_with_message(VCPKG_LINE_INFO, "Symlinks are not allowed on this system"); } #elif FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_UNIX if (symlink(target.c_str(), file.c_str()) != 0) { ec.assign(errno, std::system_category()); } #else (void)target; (void)file; (void)ec; vcpkg::Checks::exit_with_message(VCPKG_LINE_INFO, no_filesystem_message); #endif } void create_directory_symlink(const fs::path& target, const fs::path& file, std::error_code& ec) { #if FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_STD if (can_create_symlinks()) { std::filesystem::path targetp = target.native(); std::filesystem::path filep = file.native(); std::filesystem::create_directory_symlink(targetp, filep, ec); } else { vcpkg::Checks::exit_with_message(VCPKG_LINE_INFO, "Symlinks are not allowed on this system"); } #elif FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_UNIX ::vcpkg::Test::create_symlink(target, file, ec); #else (void)target; (void)file; (void)ec; vcpkg::Checks::exit_with_message(VCPKG_LINE_INFO, no_filesystem_message); #endif } }