diff options
| author | Bob Kast <bob.kast@emc.com> | 2018-11-13 15:48:26 -0500 |
|---|---|---|
| committer | Bob Kast <bob.kast@emc.com> | 2018-11-13 15:48:26 -0500 |
| commit | d9e39bb4056795a70028b228a746da4889ca7c15 (patch) | |
| tree | 4853304e1e71e45becedfba5d83e3f5321e0b9c9 /toolsrc/src | |
| parent | 1a9dadf855ab93ff0803fd1ce4ecceec5bf211f0 (diff) | |
| parent | ffa114aaa43e8bcdf880d6e2c47ee0ed46125070 (diff) | |
| download | vcpkg-d9e39bb4056795a70028b228a746da4889ca7c15.tar.gz vcpkg-d9e39bb4056795a70028b228a746da4889ca7c15.zip | |
Merge branch 'master' of https://github.com/EMCECS/vcpkg
# Conflicts:
# ports/ecsutil/CONTROL
# ports/ecsutil/portfile.cmake
Diffstat (limited to 'toolsrc/src')
| -rw-r--r-- | toolsrc/src/vcpkg.cpp | 26 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/base/checks.cpp | 14 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/base/chrono.cpp | 96 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/base/files.cpp | 8 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/base/system.cpp | 46 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/build.cpp | 46 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/commands.cpp | 1 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/commands.edit.cpp | 22 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/commands.env.cpp | 13 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/commands.exportifw.cpp | 2 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/commands.xvsinstances.cpp | 33 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/export.cpp | 10 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/globalstate.cpp | 44 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/help.cpp | 13 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/install.cpp | 19 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/postbuildlint.cpp | 6 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/remove.cpp | 4 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/visualstudio.cpp | 51 |
18 files changed, 337 insertions, 117 deletions
diff --git a/toolsrc/src/vcpkg.cpp b/toolsrc/src/vcpkg.cpp index 6f10c503d..3589881a7 100644 --- a/toolsrc/src/vcpkg.cpp +++ b/toolsrc/src/vcpkg.cpp @@ -33,6 +33,12 @@ using namespace vcpkg; +// 24 hours/day * 30 days/month * 6 months +static constexpr int SURVEY_INTERVAL_IN_HOURS = 24 * 30 * 6; + +// Initial survey appears after 10 days. Therefore, subtract 24 hours/day * 10 days +static constexpr int SURVEY_INITIAL_OFFSET_IN_HOURS = SURVEY_INTERVAL_IN_HOURS - 24 * 10; + void invalid_command(const std::string& cmd) { System::println(System::Color::error, "invalid command: %s", cmd); @@ -113,19 +119,19 @@ static void inner(const VcpkgCmdArguments& args) #endif Checks::check_exit(VCPKG_LINE_INFO, exit_code == 0, "Changing the working dir failed"); - if (args.command != "autocomplete") + if (args.command == "install" || args.command == "remove" || args.command == "export" || args.command == "update") { Commands::Version::warn_if_vcpkg_version_mismatch(paths); std::string surveydate = *GlobalState::g_surveydate.lock(); auto maybe_surveydate = Chrono::CTime::parse(surveydate); if (auto p_surveydate = maybe_surveydate.get()) { - auto delta = std::chrono::system_clock::now() - p_surveydate->to_time_point(); - // 24 hours/day * 30 days/month - if (std::chrono::duration_cast<std::chrono::hours>(delta).count() > 24 * 30) + const auto now = Chrono::CTime::get_current_date_time().value_or_exit(VCPKG_LINE_INFO); + const auto delta = now.to_time_point() - p_surveydate->to_time_point(); + if (std::chrono::duration_cast<std::chrono::hours>(delta).count() > SURVEY_INTERVAL_IN_HOURS) { std::default_random_engine generator( - static_cast<unsigned int>(std::chrono::system_clock::now().time_since_epoch().count())); + static_cast<unsigned int>(now.to_time_point().time_since_epoch().count())); std::uniform_int_distribution<int> distribution(1, 4); if (distribution(generator) == 1) @@ -214,7 +220,9 @@ static void load_config() if (config.last_completed_survey.empty()) { - config.last_completed_survey = config.user_time; + const auto now = Chrono::CTime::parse(config.user_time).value_or_exit(VCPKG_LINE_INFO); + const Chrono::CTime offset = now.add_hours(-SURVEY_INITIAL_OFFSET_IN_HOURS); + config.last_completed_survey = offset.to_string(); } GlobalState::g_surveydate.lock()->assign(config.last_completed_survey); @@ -261,6 +269,7 @@ int main(const int argc, const char* const* const argv) #if defined(_WIN32) GlobalState::g_init_console_cp = GetConsoleCP(); GlobalState::g_init_console_output_cp = GetConsoleOutputCP(); + GlobalState::g_init_console_initialized = true; SetConsoleCP(CP_UTF8); SetConsoleOutputCP(CP_UTF8); @@ -275,6 +284,9 @@ int main(const int argc, const char* const* const argv) locked_metrics->track_property("cmdline", trimmed_command_line); #endif } + + Checks::register_console_ctrl_handler(); + load_config(); const auto vcpkg_feature_flags_env = System::get_environment_variable("VCPKG_FEATURE_FLAGS"); @@ -293,8 +305,6 @@ int main(const int argc, const char* const* const argv) if (const auto p = args.sendmetrics.get()) Metrics::g_metrics.lock()->set_send_metrics(*p); if (const auto p = args.debug.get()) GlobalState::debugging = *p; - Checks::register_console_ctrl_handler(); - if (GlobalState::debugging) { inner(args); diff --git a/toolsrc/src/vcpkg/base/checks.cpp b/toolsrc/src/vcpkg/base/checks.cpp index 72176e58c..cc439adfe 100644 --- a/toolsrc/src/vcpkg/base/checks.cpp +++ b/toolsrc/src/vcpkg/base/checks.cpp @@ -24,8 +24,11 @@ namespace vcpkg::Checks metrics->flush(); #if defined(_WIN32) - SetConsoleCP(GlobalState::g_init_console_cp); - SetConsoleOutputCP(GlobalState::g_init_console_output_cp); + if (GlobalState::g_init_console_initialized) + { + SetConsoleCP(GlobalState::g_init_console_cp); + SetConsoleOutputCP(GlobalState::g_init_console_output_cp); + } #endif auto elapsed_us = GlobalState::timer.lock()->microseconds(); @@ -46,12 +49,11 @@ namespace vcpkg::Checks #if defined(_WIN32) static BOOL ctrl_handler(DWORD fdw_ctrl_type) { + switch (fdw_ctrl_type) { - auto locked_metrics = Metrics::g_metrics.lock(); - locked_metrics->track_property("CtrlHandler", std::to_string(fdw_ctrl_type)); - locked_metrics->track_property("error", "CtrlHandler was fired."); + case CTRL_C_EVENT: GlobalState::g_ctrl_c_state.transition_handle_ctrl_c(); return TRUE; + default: return FALSE; } - cleanup_and_exit(EXIT_FAILURE); } void register_console_ctrl_handler() diff --git a/toolsrc/src/vcpkg/base/chrono.cpp b/toolsrc/src/vcpkg/base/chrono.cpp index 2a76f5df0..405e76605 100644 --- a/toolsrc/src/vcpkg/base/chrono.cpp +++ b/toolsrc/src/vcpkg/base/chrono.cpp @@ -5,6 +5,61 @@ namespace vcpkg::Chrono { + static std::time_t get_current_time_as_time_since_epoch() + { + using std::chrono::system_clock; + return system_clock::to_time_t(system_clock::now()); + } + + static std::time_t utc_mktime(tm* time_ptr) + { +#if defined(_WIN32) + return _mkgmtime(time_ptr); +#else + return timegm(time_ptr); +#endif + } + + static tm to_local_time(const std::time_t& t) + { + tm parts {}; +#if defined(_WIN32) + localtime_s(&parts, &t); +#else + parts = *localtime(&t); +#endif + return parts; + } + + static Optional<tm> to_utc_time(const std::time_t& t) + { + tm parts {}; +#if defined(_WIN32) + const errno_t err = gmtime_s(&parts, &t); + if (err) + { + return nullopt; + } +#else + auto null_if_failed = gmtime_r(&t, &parts); + if (null_if_failed == nullptr) + { + return nullopt; + } +#endif + return parts; + } + + static tm date_plus_hours(tm* date, const int hours) + { + using namespace std::chrono_literals; + static constexpr std::chrono::seconds SECONDS_IN_ONE_HOUR = + std::chrono::duration_cast<std::chrono::seconds>(1h); + + const std::time_t date_in_seconds = utc_mktime(date) + (hours * SECONDS_IN_ONE_HOUR.count()); + return to_utc_time(date_in_seconds).value_or_exit(VCPKG_LINE_INFO); + } + static std::string format_time_userfriendly(const std::chrono::nanoseconds& nanos) { using std::chrono::duration_cast; @@ -63,30 +118,14 @@ namespace vcpkg::Chrono Optional<CTime> CTime::get_current_date_time() { - CTime ret; - -#if defined(_WIN32) - struct _timeb timebuffer; - - _ftime_s(&timebuffer); - - const errno_t err = gmtime_s(&ret.m_tm, &timebuffer.time); - - if (err) + const std::time_t ct = get_current_time_as_time_since_epoch(); + const Optional<tm> opt = to_utc_time(ct); + if (auto p_tm = opt.get()) { - return nullopt; + return CTime {*p_tm}; } -#else - time_t now = {0}; - time(&now); - auto null_if_failed = gmtime_r(&now, &ret.m_tm); - if (null_if_failed == nullptr) - { - return nullopt; - } -#endif - return ret; + return nullopt; } Optional<CTime> CTime::parse(CStringView str) @@ -111,19 +150,28 @@ namespace vcpkg::Chrono ret.m_tm.tm_year -= 1900; if (ret.m_tm.tm_mon < 1) return nullopt; ret.m_tm.tm_mon -= 1; - mktime(&ret.m_tm); + utc_mktime(&ret.m_tm); + return ret; } + CTime CTime::add_hours(const int hours) const { return CTime {date_plus_hours(&this->m_tm, hours)}; } + std::string CTime::to_string() const { - std::array<char, 80> date{}; + std::array<char, 80> date {}; strftime(&date[0], date.size(), "%Y-%m-%dT%H:%M:%S.0Z", &m_tm); return &date[0]; } std::chrono::system_clock::time_point CTime::to_time_point() const { - const time_t t = mktime(&m_tm); + const time_t t = utc_mktime(&m_tm); return std::chrono::system_clock::from_time_t(t); } + + tm get_current_date_time_local() + { + const std::time_t now_time = get_current_time_as_time_since_epoch(); + return Chrono::to_local_time(now_time); + } } diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index 4ff0912d1..f9bce8631 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -216,11 +216,19 @@ namespace vcpkg::Files { return fs::stdfs::copy_file(oldpath, newpath, opts, ec); } + virtual void copy_symlink(const fs::path& oldpath, const fs::path& newpath, std::error_code& ec) + { + return fs::stdfs::copy_symlink(oldpath, newpath, ec); + } virtual fs::file_status status(const fs::path& path, std::error_code& ec) const override { return fs::stdfs::status(path, ec); } + virtual fs::file_status symlink_status(const fs::path& path, std::error_code& ec) const override + { + return fs::stdfs::symlink_status(path, ec); + } virtual void write_contents(const fs::path& file_path, const std::string& data, std::error_code& ec) override { ec.clear(); diff --git a/toolsrc/src/vcpkg/base/system.cpp b/toolsrc/src/vcpkg/base/system.cpp index d968c6dac..d95752bba 100644 --- a/toolsrc/src/vcpkg/base/system.cpp +++ b/toolsrc/src/vcpkg/base/system.cpp @@ -19,19 +19,6 @@ namespace vcpkg::System { - tm get_current_date_time() - { - using std::chrono::system_clock; - std::time_t now_time = system_clock::to_time_t(system_clock::now()); - tm parts{}; -#if defined(_WIN32) - localtime_s(&parts, &now_time); -#else - parts = *localtime(&now_time); -#endif - return parts; - } - fs::path get_exe_path_of_current_process() { #if defined(_WIN32) @@ -133,7 +120,7 @@ namespace vcpkg::System static void windows_create_clean_process(const CStringView cmd_line, const std::unordered_map<std::string, std::string>& extra_env, PROCESS_INFORMATION& process_info, - DWORD dwCreationFlags) + DWORD dwCreationFlags) noexcept { static const std::string SYSTEM_ROOT = get_environment_variable("SystemRoot").value_or_exit(VCPKG_LINE_INFO); static const std::string SYSTEM_32 = SYSTEM_ROOT + R"(\system32)"; @@ -223,7 +210,7 @@ namespace vcpkg::System memset(&startup_info, 0, sizeof(STARTUPINFOW)); startup_info.cb = sizeof(STARTUPINFOW); - // Basically we are wrapping it in quotes + // Wrapping the command in a single set of quotes causes cmd.exe to correctly execute const std::string actual_cmd_line = Strings::format(R"###(cmd.exe /c "%s")###", cmd_line); Debug::println("CreateProcessW(%s)", actual_cmd_line); bool succeeded = TRUE == CreateProcessW(nullptr, @@ -242,7 +229,7 @@ namespace vcpkg::System #endif #if defined(_WIN32) - void cmd_execute_no_wait(const CStringView cmd_line) + void cmd_execute_no_wait(const CStringView cmd_line) noexcept { auto timer = Chrono::ElapsedTimer::create_started(); @@ -258,7 +245,8 @@ namespace vcpkg::System } #endif - int cmd_execute_clean(const CStringView cmd_line, const std::unordered_map<std::string, std::string>& extra_env) + int cmd_execute_clean(const CStringView cmd_line, + const std::unordered_map<std::string, std::string>& extra_env) noexcept { auto timer = Chrono::ElapsedTimer::create_started(); #if defined(_WIN32) @@ -266,11 +254,13 @@ namespace vcpkg::System PROCESS_INFORMATION process_info; memset(&process_info, 0, sizeof(PROCESS_INFORMATION)); + GlobalState::g_ctrl_c_state.transition_to_spawn_process(); windows_create_clean_process(cmd_line, extra_env, process_info, NULL); CloseHandle(process_info.hThread); const DWORD result = WaitForSingleObject(process_info.hProcess, INFINITE); + GlobalState::g_ctrl_c_state.transition_from_spawn_process(); Checks::check_exit(VCPKG_LINE_INFO, result != WAIT_FAILED, "WaitForSingleObject failed"); DWORD exit_code = 0; @@ -279,6 +269,7 @@ namespace vcpkg::System CloseHandle(process_info.hProcess); Debug::println("CreateProcessW() returned %lu after %d us", exit_code, static_cast<int>(timer.microseconds())); + return static_cast<int>(exit_code); #else Debug::println("system(%s)", cmd_line.c_str()); @@ -289,16 +280,18 @@ namespace vcpkg::System #endif } - int cmd_execute(const CStringView cmd_line) + int cmd_execute(const CStringView cmd_line) noexcept { // Flush stdout before launching external process fflush(nullptr); - // Basically we are wrapping it in quotes #if defined(_WIN32) + // We are wrap the command line in quotes to cause cmd.exe to correctly process it const std::string& actual_cmd_line = Strings::format(R"###("%s")###", cmd_line); Debug::println("_wsystem(%s)", actual_cmd_line); + GlobalState::g_ctrl_c_state.transition_to_spawn_process(); const int exit_code = _wsystem(Strings::to_utf16(actual_cmd_line).c_str()); + GlobalState::g_ctrl_c_state.transition_from_spawn_process(); Debug::println("_wsystem() returned %d", exit_code); #else Debug::println("_system(%s)", cmd_line); @@ -308,11 +301,8 @@ namespace vcpkg::System return exit_code; } - ExitCodeAndOutput cmd_execute_and_capture_output(const CStringView cmd_line) + ExitCodeAndOutput cmd_execute_and_capture_output(const CStringView cmd_line) noexcept { - // Flush stdout before launching external process - fflush(stdout); - auto timer = Chrono::ElapsedTimer::create_started(); #if defined(_WIN32) @@ -321,9 +311,13 @@ namespace vcpkg::System Debug::println("_wpopen(%s)", actual_cmd_line); std::wstring output; wchar_t buf[1024]; + GlobalState::g_ctrl_c_state.transition_to_spawn_process(); + // Flush stdout before launching external process + fflush(stdout); const auto pipe = _wpopen(Strings::to_utf16(actual_cmd_line).c_str(), L"r"); if (pipe == nullptr) { + GlobalState::g_ctrl_c_state.transition_from_spawn_process(); return {1, Strings::to_utf8(output.c_str())}; } while (fgetws(buf, 1024, pipe)) @@ -332,10 +326,12 @@ namespace vcpkg::System } if (!feof(pipe)) { + GlobalState::g_ctrl_c_state.transition_from_spawn_process(); return {1, Strings::to_utf8(output.c_str())}; } const auto ec = _pclose(pipe); + GlobalState::g_ctrl_c_state.transition_from_spawn_process(); // On Win7, output from powershell calls contain a utf-8 byte order mark in the utf-16 stream, so we strip it // out if it is present. 0xEF,0xBB,0xBF is the UTF-8 byte-order mark @@ -354,6 +350,8 @@ namespace vcpkg::System Debug::println("popen(%s)", actual_cmd_line); std::string output; char buf[1024]; + // Flush stdout before launching external process + fflush(stdout); const auto pipe = popen(actual_cmd_line.c_str(), "r"); if (pipe == nullptr) { @@ -391,7 +389,7 @@ namespace vcpkg::System #if defined(_WIN32) const HANDLE console_handle = GetStdHandle(STD_OUTPUT_HANDLE); - CONSOLE_SCREEN_BUFFER_INFO console_screen_buffer_info{}; + CONSOLE_SCREEN_BUFFER_INFO console_screen_buffer_info {}; GetConsoleScreenBufferInfo(console_handle, &console_screen_buffer_info); const auto original_color = console_screen_buffer_info.wAttributes; diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 8e87fe7fe..7569f340f 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -63,7 +63,7 @@ namespace vcpkg::Build::Command spec.name()); const StatusParagraphs status_db = database_load_check(paths); - const Build::BuildPackageOptions build_package_options{ + const Build::BuildPackageOptions build_package_options { Build::UseHeadVersion::NO, Build::AllowDownloads::YES, Build::CleanBuildtrees::NO, @@ -76,8 +76,8 @@ namespace vcpkg::Build::Command std::set<std::string> features_as_set(full_spec.features.begin(), full_spec.features.end()); features_as_set.emplace("core"); - const Build::BuildPackageConfig build_config{ - *scf, spec.triplet(), fs::path{port_dir}, build_package_options, features_as_set}; + const Build::BuildPackageConfig build_config { + *scf, spec.triplet(), fs::path {port_dir}, build_package_options, features_as_set}; const auto build_timer = Chrono::ElapsedTimer::create_started(); const auto result = Build::build_package(paths, build_config, status_db); @@ -245,7 +245,7 @@ namespace vcpkg::Build const auto arch = to_vcvarsall_toolchain(pre_build_info.target_architecture, toolset); const auto target = to_vcvarsall_target(pre_build_info.cmake_system_name); - return Strings::format(R"("%s" %s %s %s %s 2>&1)", + return Strings::format(R"("%s" %s %s %s %s 2>&1 <NUL)", toolset.vcvarsall.u8string(), Strings::join(" ", toolset.vcvarsall_options), arch, @@ -381,9 +381,15 @@ namespace vcpkg::Build }); auto command = make_build_env_cmd(pre_build_info, toolset); - if (!command.empty()) command.append(" && "); + if (!command.empty()) + { +#ifdef _WIN32 + command.append(" & "); +#else + command.append(" && "); +#endif + } command.append(cmd_launch_cmake); - const auto timer = Chrono::ElapsedTimer::create_started(); const int return_code = System::cmd_execute_clean(command); @@ -440,7 +446,7 @@ namespace vcpkg::Build auto buildtree_files = fs.get_files_non_recursive(buildtrees_dir); for (auto&& file : buildtree_files) { - if (fs.is_directory(file) && file.filename() != "src") + if (fs.is_directory(file)) // Will only keep the logs { std::error_code ec; fs.remove_all(file, ec); @@ -464,22 +470,22 @@ namespace vcpkg::Build std::vector<AbiEntry> abi_tag_entries; - abi_tag_entries.emplace_back(AbiEntry{"cmake", paths.get_tool_version(Tools::CMAKE)}); + abi_tag_entries.emplace_back(AbiEntry {"cmake", paths.get_tool_version(Tools::CMAKE)}); abi_tag_entries.insert(abi_tag_entries.end(), dependency_abis.begin(), dependency_abis.end()); abi_tag_entries.emplace_back( - AbiEntry{"portfile", vcpkg::Hash::get_file_hash(fs, config.port_dir / "portfile.cmake", "SHA1")}); + AbiEntry {"portfile", vcpkg::Hash::get_file_hash(fs, config.port_dir / "portfile.cmake", "SHA1")}); abi_tag_entries.emplace_back( - AbiEntry{"control", vcpkg::Hash::get_file_hash(fs, config.port_dir / "CONTROL", "SHA1")}); + AbiEntry {"control", vcpkg::Hash::get_file_hash(fs, config.port_dir / "CONTROL", "SHA1")}); - abi_tag_entries.emplace_back(AbiEntry{"triplet", pre_build_info.triplet_abi_tag}); + abi_tag_entries.emplace_back(AbiEntry {"triplet", pre_build_info.triplet_abi_tag}); const std::string features = Strings::join(";", config.feature_list); - abi_tag_entries.emplace_back(AbiEntry{"features", features}); + abi_tag_entries.emplace_back(AbiEntry {"features", features}); if (config.build_package_options.use_head_version == UseHeadVersion::YES) - abi_tag_entries.emplace_back(AbiEntry{"head", ""}); + abi_tag_entries.emplace_back(AbiEntry {"head", ""}); Util::sort(abi_tag_entries); @@ -506,7 +512,7 @@ namespace vcpkg::Build const auto abi_file_path = paths.buildtrees / name / (triplet.canonical_name() + ".vcpkg_abi_info.txt"); fs.write_contents(abi_file_path, full_abi_info); - return AbiTagAndFile{Hash::get_file_hash(fs, abi_file_path, "SHA1"), abi_file_path}; + return AbiTagAndFile {Hash::get_file_hash(fs, abi_file_path, "SHA1"), abi_file_path}; } System::println( @@ -596,7 +602,7 @@ namespace vcpkg::Build const auto status_it = status_db.find_installed(pspec); Checks::check_exit(VCPKG_LINE_INFO, status_it != status_db.end()); dependency_abis.emplace_back( - AbiEntry{status_it->get()->package.spec.name(), status_it->get()->package.abi}); + AbiEntry {status_it->get()->package.spec.name(), status_it->get()->package.abi}); } const auto pre_build_info = PreBuildInfo::from_triplet_file(paths, triplet); @@ -642,7 +648,7 @@ namespace vcpkg::Build System::println("Could not locate cached archive: %s", archive_path.u8string()); ExtendedBuildResult result = do_build_package_and_clean_buildtrees( - paths, pre_build_info, spec, maybe_abi_tag_and_file.value_or(AbiTagAndFile{}).tag, config); + paths, pre_build_info, spec, maybe_abi_tag_and_file.value_or(AbiTagAndFile {}).tag, config); std::error_code ec; fs.create_directories(paths.package_dir(spec) / "share" / spec.name(), ec); @@ -679,7 +685,7 @@ namespace vcpkg::Build } return do_build_package_and_clean_buildtrees( - paths, pre_build_info, spec, maybe_abi_tag_and_file.value_or(AbiTagAndFile{}).tag, config); + paths, pre_build_info, spec, maybe_abi_tag_and_file.value_or(AbiTagAndFile {}).tag, config); } const std::string& to_string(const BuildResult build_result) @@ -844,21 +850,21 @@ namespace vcpkg::Build if (variable_name == "VCPKG_PLATFORM_TOOLSET") { pre_build_info.platform_toolset = - variable_value.empty() ? nullopt : Optional<std::string>{variable_value}; + variable_value.empty() ? nullopt : Optional<std::string> {variable_value}; continue; } if (variable_name == "VCPKG_VISUAL_STUDIO_PATH") { pre_build_info.visual_studio_path = - variable_value.empty() ? nullopt : Optional<fs::path>{variable_value}; + variable_value.empty() ? nullopt : Optional<fs::path> {variable_value}; continue; } if (variable_name == "VCPKG_CHAINLOAD_TOOLCHAIN_FILE") { pre_build_info.external_toolchain_file = - variable_value.empty() ? nullopt : Optional<std::string>{variable_value}; + variable_value.empty() ? nullopt : Optional<std::string> {variable_value}; continue; } diff --git a/toolsrc/src/vcpkg/commands.cpp b/toolsrc/src/vcpkg/commands.cpp index 7204b6e78..db265514f 100644 --- a/toolsrc/src/vcpkg/commands.cpp +++ b/toolsrc/src/vcpkg/commands.cpp @@ -46,6 +46,7 @@ namespace vcpkg::Commands {"autocomplete", &Autocomplete::perform_and_exit}, {"hash", &Hash::perform_and_exit}, {"fetch", &Fetch::perform_and_exit}, + {"x-vsinstances", &X_VSInstances::perform_and_exit}, }; return t; } diff --git a/toolsrc/src/vcpkg/commands.edit.cpp b/toolsrc/src/vcpkg/commands.edit.cpp index 2569c2cea..237feebdd 100644 --- a/toolsrc/src/vcpkg/commands.edit.cpp +++ b/toolsrc/src/vcpkg/commands.edit.cpp @@ -92,8 +92,8 @@ namespace vcpkg::Commands::Edit void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths) { - static const fs::path VS_CODE_INSIDERS = fs::path{"Microsoft VS Code Insiders"} / "Code - Insiders.exe"; - static const fs::path VS_CODE = fs::path{"Microsoft VS Code"} / "Code.exe"; + static const fs::path VS_CODE_INSIDERS = fs::path {"Microsoft VS Code Insiders"} / "Code - Insiders.exe"; + static const fs::path VS_CODE = fs::path {"Microsoft VS Code"} / "Code.exe"; auto& fs = paths.get_filesystem(); @@ -128,6 +128,14 @@ namespace vcpkg::Commands::Edit candidate_paths.push_back(*pf / VS_CODE); } + const auto& app_data = System::get_environment_variable("APPDATA"); + if (const auto* ad = app_data.get()) + { + const fs::path default_base = fs::path {*ad}.parent_path() / "Local" / "Programs"; + candidate_paths.push_back(default_base / VS_CODE_INSIDERS); + candidate_paths.push_back(default_base / VS_CODE); + } + const std::vector<fs::path> from_registry = find_from_registry(); candidate_paths.insert(candidate_paths.end(), from_registry.cbegin(), from_registry.cend()); @@ -147,6 +155,16 @@ namespace vcpkg::Commands::Edit const std::vector<std::string> arguments = create_editor_arguments(paths, options, ports); const auto args_as_string = Strings::join(" ", arguments); const auto cmd_line = Strings::format(R"("%s" %s -n)", env_editor.u8string(), args_as_string); + + auto editor_exe = env_editor.filename().u8string(); + +#ifdef _WIN32 + if (editor_exe == "Code.exe" || editor_exe == "Code - Insiders.exe") + { + System::cmd_execute_no_wait(cmd_line + " <NUL"); + Checks::exit_success(VCPKG_LINE_INFO); + } +#endif Checks::exit_with_code(VCPKG_LINE_INFO, System::cmd_execute(cmd_line)); } } diff --git a/toolsrc/src/vcpkg/commands.env.cpp b/toolsrc/src/vcpkg/commands.env.cpp index d078baedb..ea00617d4 100644 --- a/toolsrc/src/vcpkg/commands.env.cpp +++ b/toolsrc/src/vcpkg/commands.env.cpp @@ -23,9 +23,9 @@ namespace vcpkg::Commands::Env }}; const CommandStructure COMMAND_STRUCTURE = { - Help::create_example_string("env --triplet x64-windows"), - 0, + Help::create_example_string("env <optional command> --triplet x64-windows"), 0, + 1, {SWITCHES, {}}, nullptr, }; @@ -64,11 +64,12 @@ namespace vcpkg::Commands::Env if (add_python) extra_env.emplace("PYTHONPATH", (paths.installed / triplet.to_string() / "python").u8string()); if (path_vars.size() > 0) extra_env.emplace("PATH", Strings::join(";", path_vars)); - if (env_cmd.empty()) - System::cmd_execute_clean("cmd", extra_env); - else - System::cmd_execute_clean(env_cmd + " && cmd", extra_env); + std::string env_cmd_prefix = env_cmd.empty() ? "" : Strings::format("%s && ", env_cmd); + std::string env_cmd_suffix = + args.command_arguments.empty() ? "cmd" : Strings::format("cmd /c %s", args.command_arguments.at(0)); + const std::string cmd = Strings::format("%s%s", env_cmd_prefix, env_cmd_suffix); + System::cmd_execute_clean(cmd, extra_env); Checks::exit_success(VCPKG_LINE_INFO); } } diff --git a/toolsrc/src/vcpkg/commands.exportifw.cpp b/toolsrc/src/vcpkg/commands.exportifw.cpp index ae106196a..62725a90a 100644 --- a/toolsrc/src/vcpkg/commands.exportifw.cpp +++ b/toolsrc/src/vcpkg/commands.exportifw.cpp @@ -13,7 +13,7 @@ namespace vcpkg::Export::IFW static std::string create_release_date() { - const tm date_time = System::get_current_date_time(); + const tm date_time = Chrono::get_current_date_time_local(); // Format is: YYYY-mm-dd // 10 characters + 1 null terminating character will be written for a total of 11 chars diff --git a/toolsrc/src/vcpkg/commands.xvsinstances.cpp b/toolsrc/src/vcpkg/commands.xvsinstances.cpp new file mode 100644 index 000000000..d748b6b2f --- /dev/null +++ b/toolsrc/src/vcpkg/commands.xvsinstances.cpp @@ -0,0 +1,33 @@ +#include "pch.h"
+
+#include <vcpkg/commands.h>
+#include <vcpkg/help.h>
+#include <vcpkg/visualstudio.h>
+
+namespace vcpkg::Commands::X_VSInstances
+{
+ const CommandStructure COMMAND_STRUCTURE = {
+ Help::create_example_string("x-vsinstances"),
+ 0,
+ 0,
+ {{}, {}},
+ nullptr,
+ };
+
+ void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths)
+ {
+#if defined(_WIN32)
+ const ParsedArguments parsed_args = args.parse_arguments(COMMAND_STRUCTURE);
+
+ const auto instances = vcpkg::VisualStudio::get_visual_studio_instances(paths);
+ for (const std::string& instance : instances)
+ {
+ System::println(instance);
+ }
+
+ Checks::exit_success(VCPKG_LINE_INFO);
+#else
+ Checks::exit_with_message(VCPKG_LINE_INFO, "This command is not supported on non-windows platforms.");
+#endif
+ }
+}
diff --git a/toolsrc/src/vcpkg/export.cpp b/toolsrc/src/vcpkg/export.cpp index 8161c0a62..eec9a39f2 100644 --- a/toolsrc/src/vcpkg/export.cpp +++ b/toolsrc/src/vcpkg/export.cpp @@ -108,7 +108,7 @@ namespace vcpkg::Export static std::string create_export_id() { - const tm date_time = System::get_current_date_time(); + const tm date_time = Chrono::get_current_date_time_local(); // Format is: YYYYmmdd-HHMMSS // 15 characters + 1 null terminating character will be written for a total of 16 chars @@ -227,10 +227,10 @@ namespace vcpkg::Export { const std::vector<fs::path> integration_files_relative_to_root = { {".vcpkg-root"}, - {fs::path{"scripts"} / "buildsystems" / "msbuild" / "applocal.ps1"}, - {fs::path{"scripts"} / "buildsystems" / "msbuild" / "vcpkg.targets"}, - {fs::path{"scripts"} / "buildsystems" / "vcpkg.cmake"}, - {fs::path{"scripts"} / "cmake" / "vcpkg_get_windows_sdk.cmake"}, + {fs::path {"scripts"} / "buildsystems" / "msbuild" / "applocal.ps1"}, + {fs::path {"scripts"} / "buildsystems" / "msbuild" / "vcpkg.targets"}, + {fs::path {"scripts"} / "buildsystems" / "vcpkg.cmake"}, + {fs::path {"scripts"} / "cmake" / "vcpkg_get_windows_sdk.cmake"}, }; for (const fs::path& file : integration_files_relative_to_root) diff --git a/toolsrc/src/vcpkg/globalstate.cpp b/toolsrc/src/vcpkg/globalstate.cpp index a4100acf7..a54c596fb 100644 --- a/toolsrc/src/vcpkg/globalstate.cpp +++ b/toolsrc/src/vcpkg/globalstate.cpp @@ -13,4 +13,48 @@ namespace vcpkg std::atomic<int> GlobalState::g_init_console_cp(0); std::atomic<int> GlobalState::g_init_console_output_cp(0); + std::atomic<bool> GlobalState::g_init_console_initialized(false); + + GlobalState::CtrlCStateMachine GlobalState::g_ctrl_c_state; + + GlobalState::CtrlCStateMachine::CtrlCStateMachine() : m_state(CtrlCState::normal) {} + + void GlobalState::CtrlCStateMachine::transition_to_spawn_process() noexcept + { + auto expected = CtrlCState::normal; + auto transitioned = m_state.compare_exchange_strong(expected, CtrlCState::blocked_on_child); + if (!transitioned) + { + // Ctrl-C was hit and is asynchronously executing on another thread + Checks::exit_fail(VCPKG_LINE_INFO); + } + } + void GlobalState::CtrlCStateMachine::transition_from_spawn_process() noexcept + { + auto expected = CtrlCState::blocked_on_child; + auto transitioned = m_state.compare_exchange_strong(expected, CtrlCState::normal); + if (!transitioned) + { + // Ctrl-C was hit while blocked on the child process + Checks::exit_fail(VCPKG_LINE_INFO); + } + } + void GlobalState::CtrlCStateMachine::transition_handle_ctrl_c() noexcept + { + auto prev_state = m_state.exchange(CtrlCState::exit_requested); + + if (prev_state == CtrlCState::normal) + { + // Not currently blocked on a child process and Ctrl-C has not been hit. + Checks::exit_fail(VCPKG_LINE_INFO); + } + else if (prev_state == CtrlCState::exit_requested) + { + // Ctrl-C was hit previously + } + else + { + // This is the case where we are currently blocked on a child process + } + } } diff --git a/toolsrc/src/vcpkg/help.cpp b/toolsrc/src/vcpkg/help.cpp index 743619937..2b409373d 100644 --- a/toolsrc/src/vcpkg/help.cpp +++ b/toolsrc/src/vcpkg/help.cpp @@ -7,6 +7,13 @@ #include <vcpkg/install.h> #include <vcpkg/remove.h> +// Write environment variable names as %VARIABLE% on Windows and $VARIABLE in *nix +#ifdef _WIN32 +#define ENVVAR(VARNAME) "%%" #VARNAME "%%" +#else +#define ENVVAR(VARNAME) "$" #VARNAME +#endif + namespace vcpkg::Help { struct Topic @@ -93,7 +100,7 @@ namespace vcpkg::Help "%s" // Integration help "\n" " vcpkg export <pkg>... [opt]... Exports a package\n" - " vcpkg edit <pkg> Open up a port for editing (uses %%EDITOR%%, default 'code')\n" + " vcpkg edit <pkg> Open up a port for editing (uses " ENVVAR(EDITOR) ", default 'code')\n" " vcpkg import <pkg> Import a pre-built library\n" " vcpkg create <pkg> <url>\n" " [archivename] Create a new package\n" @@ -104,10 +111,10 @@ namespace vcpkg::Help "\n" "Options:\n" " --triplet <t> Specify the target architecture triplet.\n" - " (default: %%VCPKG_DEFAULT_TRIPLET%%, see 'vcpkg help triplet')\n" + " (default: " ENVVAR(VCPKG_DEFAULT_TRIPLET) ", see 'vcpkg help triplet')\n" "\n" " --vcpkg-root <path> Specify the vcpkg root directory\n" - " (default: %%VCPKG_ROOT%%)\n" + " (default: " ENVVAR(VCPKG_ROOT) ")\n" "\n" "For more help (including examples) see the accompanying README.md.", Commands::Integrate::INTEGRATE_COMMAND_HELPSTRING); diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp index 4bb84831e..1cfa2bf71 100644 --- a/toolsrc/src/vcpkg/install.cpp +++ b/toolsrc/src/vcpkg/install.cpp @@ -62,7 +62,7 @@ namespace vcpkg::Install auto files = fs.get_files_recursive(source_dir); for (auto&& file : files) { - const auto status = fs.status(file, ec); + const auto status = fs.symlink_status(file, ec); if (ec) { System::println(System::Color::error, "failed: %s: %s", file.u8string(), ec.message()); @@ -111,6 +111,23 @@ namespace vcpkg::Install output.push_back(Strings::format(R"(%s/%s)", destination_subdirectory, suffix)); break; } + case fs::file_type::symlink: + { + if (fs.exists(target)) + { + System::println(System::Color::warning, + "File %s was already present and will be overwritten", + target.u8string(), + ec.message()); + } + fs.copy_symlink(file, target, ec); + if (ec) + { + System::println(System::Color::error, "failed: %s: %s", target.u8string(), ec.message()); + } + output.push_back(Strings::format(R"(%s/%s)", destination_subdirectory, suffix)); + break; + } default: System::println(System::Color::error, "failed: %s: cannot handle file type", file.u8string()); break; diff --git a/toolsrc/src/vcpkg/postbuildlint.cpp b/toolsrc/src/vcpkg/postbuildlint.cpp index 6fe11951f..90dcb7d64 100644 --- a/toolsrc/src/vcpkg/postbuildlint.cpp +++ b/toolsrc/src/vcpkg/postbuildlint.cpp @@ -617,7 +617,11 @@ namespace vcpkg::PostBuildLint const std::string cmd_line = Strings::format(R"("%s" /directives "%s")", dumpbin_exe.u8string(), lib.u8string()); System::ExitCodeAndOutput ec_data = System::cmd_execute_and_capture_output(cmd_line); - Checks::check_exit(VCPKG_LINE_INFO, ec_data.exit_code == 0, "Running command:\n %s\n failed", cmd_line); + Checks::check_exit(VCPKG_LINE_INFO, + ec_data.exit_code == 0, + "Running command:\n %s\n failed with message:\n%s", + cmd_line, + ec_data.output); for (const BuildType& bad_build_type : bad_build_types) { diff --git a/toolsrc/src/vcpkg/remove.cpp b/toolsrc/src/vcpkg/remove.cpp index 13cc9325e..921a04c23 100644 --- a/toolsrc/src/vcpkg/remove.cpp +++ b/toolsrc/src/vcpkg/remove.cpp @@ -55,7 +55,7 @@ namespace vcpkg::Remove auto target = paths.installed / suffix; - const auto status = fs.status(target, ec); + const auto status = fs.symlink_status(target, ec); if (ec) { System::println(System::Color::error, "failed: status(%s): %s", target.u8string(), ec.message()); @@ -66,7 +66,7 @@ namespace vcpkg::Remove { dirs_touched.push_back(target); } - else if (fs::is_regular_file(status)) + else if (fs::is_regular_file(status) || fs::is_symlink(status)) { fs.remove(target, ec); if (ec) diff --git a/toolsrc/src/vcpkg/visualstudio.cpp b/toolsrc/src/vcpkg/visualstudio.cpp index 9480a11bf..e3656a7d2 100644 --- a/toolsrc/src/vcpkg/visualstudio.cpp +++ b/toolsrc/src/vcpkg/visualstudio.cpp @@ -22,6 +22,17 @@ namespace vcpkg::VisualStudio LEGACY }; + static std::string release_type_to_string(const ReleaseType& release_type) + { + switch (release_type) + { + case ReleaseType::STABLE: return "STABLE"; + case ReleaseType::PRERELEASE: return "PRERELEASE"; + case ReleaseType::LEGACY: return "LEGACY"; + default: Checks::unreachable(VCPKG_LINE_INFO); + } + } + static bool preferred_first_comparator(const VisualStudioInstance& left, const VisualStudioInstance& right) { const auto get_preference_weight = [](const ReleaseType& type) -> int { @@ -51,10 +62,15 @@ namespace vcpkg::VisualStudio std::string version; ReleaseType release_type; + std::string to_string() const + { + return Strings::format("%s, %s, %s", root_path.u8string(), version, release_type_to_string(release_type)); + } + std::string major_version() const { return version.substr(0, 2); } }; - static std::vector<VisualStudioInstance> get_visual_studio_instances(const VcpkgPaths& paths) + static std::vector<VisualStudioInstance> get_visual_studio_instances_internal(const VcpkgPaths& paths) { const auto& fs = paths.get_filesystem(); std::vector<VisualStudioInstance> instances; @@ -66,7 +82,7 @@ namespace vcpkg::VisualStudio if (fs.exists(vswhere_exe)) { const auto code_and_output = System::cmd_execute_and_capture_output( - Strings::format(R"("%s" -prerelease -legacy -products * -format xml)", vswhere_exe.u8string())); + Strings::format(R"("%s" -all -prerelease -legacy -products * -format xml)", vswhere_exe.u8string())); Checks::check_exit(VCPKG_LINE_INFO, code_and_output.exit_code == 0, "Running vswhere.exe failed with message:\n%s", @@ -114,9 +130,9 @@ namespace vcpkg::VisualStudio { // We want lexically_normal(), but it is not available // Correct root path might be 2 or 3 levels up, depending on if the path has trailing backslash. Try both. - auto common7_tools = fs::path{*path_as_string}; - append_if_has_cl(fs::path{*path_as_string}.parent_path().parent_path()); - append_if_has_cl(fs::path{*path_as_string}.parent_path().parent_path().parent_path()); + auto common7_tools = fs::path {*path_as_string}; + append_if_has_cl(fs::path {*path_as_string}.parent_path().parent_path()); + append_if_has_cl(fs::path {*path_as_string}.parent_path().parent_path().parent_path()); } // VS2015 instance from Program Files @@ -125,6 +141,13 @@ namespace vcpkg::VisualStudio return instances; } + std::vector<std::string> get_visual_studio_instances(const VcpkgPaths& paths) + { + std::vector<VisualStudioInstance> sorted {get_visual_studio_instances_internal(paths)}; + std::sort(sorted.begin(), sorted.end(), VisualStudioInstance::preferred_first_comparator); + return Util::fmap(sorted, [](const VisualStudioInstance& instance) { return instance.to_string(); }); + } + std::vector<Toolset> find_toolset_instances_preferred_first(const VcpkgPaths& paths) { using CPU = System::CPUArchitecture; @@ -137,8 +160,8 @@ namespace vcpkg::VisualStudio std::vector<Toolset> found_toolsets; std::vector<Toolset> excluded_toolsets; - const SortedVector<VisualStudioInstance> sorted{get_visual_studio_instances(paths), - VisualStudioInstance::preferred_first_comparator}; + const SortedVector<VisualStudioInstance> sorted {get_visual_studio_instances_internal(paths), + VisualStudioInstance::preferred_first_comparator}; const bool v140_is_available = Util::find_if(sorted, [&](const VisualStudioInstance& vs_instance) { return vs_instance.major_version() == "14"; @@ -194,7 +217,7 @@ namespace vcpkg::VisualStudio paths_examined.push_back(dumpbin_path); if (fs.exists(dumpbin_path)) { - const Toolset v141_toolset{ + const Toolset v141_toolset { vs_instance.root_path, dumpbin_path, vcvarsall_bat, {}, V_141, supported_architectures}; const auto english_language_pack = dumpbin_path.parent_path() / "1033"; @@ -209,12 +232,12 @@ namespace vcpkg::VisualStudio if (v140_is_available) { - const Toolset v140_toolset{vs_instance.root_path, - dumpbin_path, - vcvarsall_bat, - {"-vcvars_ver=14.0"}, - V_140, - supported_architectures}; + const Toolset v140_toolset {vs_instance.root_path, + dumpbin_path, + vcvarsall_bat, + {"-vcvars_ver=14.0"}, + V_140, + supported_architectures}; found_toolsets.push_back(v140_toolset); } |
