mirror of
https://github.com/microsoft/vcpkg.git
synced 2025-06-07 12:17:05 +08:00
[fetch] Refactor to allow getting the version along with the path
This commit is contained in:
parent
31374871f2
commit
6b7b82c58a
@ -140,6 +140,7 @@ namespace vcpkg::Commands
|
||||
namespace Fetch
|
||||
{
|
||||
fs::path get_tool_path(const VcpkgPaths& paths, const std::string& tool);
|
||||
std::string get_tool_version(const VcpkgPaths& paths, const std::string& tool);
|
||||
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths);
|
||||
}
|
||||
|
||||
|
@ -114,46 +114,56 @@ namespace vcpkg::Commands::Fetch
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool exists_and_has_equal_or_greater_version(const std::string& version_cmd,
|
||||
struct PathAndVersion
|
||||
{
|
||||
fs::path path;
|
||||
std::string version;
|
||||
};
|
||||
|
||||
static Optional<PathAndVersion> find_first_with_sufficient_version(const std::vector<PathAndVersion>& candidates,
|
||||
const std::array<int, 3>& expected_version)
|
||||
{
|
||||
const auto rc = System::cmd_execute_and_capture_output(Strings::format(R"(%s)", version_cmd));
|
||||
if (rc.exit_code != 0)
|
||||
const auto it = Util::find_if(candidates, [&](const PathAndVersion& candidate) {
|
||||
const auto parsed_version = parse_version_string(candidate.version);
|
||||
if (!parsed_version.has_value())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const Optional<std::array<int, 3>> v = parse_version_string(rc.output);
|
||||
if (!v.has_value())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::array<int, 3> actual_version = *v.get();
|
||||
return (actual_version[0] > expected_version[0] ||
|
||||
const std::array<int, 3> actual_version = *parsed_version.get();
|
||||
return actual_version[0] > expected_version[0] ||
|
||||
(actual_version[0] == expected_version[0] && actual_version[1] > expected_version[1]) ||
|
||||
(actual_version[0] == expected_version[0] && actual_version[1] == expected_version[1] &&
|
||||
actual_version[2] >= expected_version[2]));
|
||||
}
|
||||
|
||||
static Optional<fs::path> find_if_has_equal_or_greater_version(Files::Filesystem& fs,
|
||||
const std::vector<fs::path>& candidate_paths,
|
||||
const std::string& version_check_arguments,
|
||||
const std::array<int, 3>& expected_version)
|
||||
{
|
||||
const auto it = Util::find_if(candidate_paths, [&](const fs::path& p) {
|
||||
if (!fs.exists(p)) return false;
|
||||
const std::string cmd = Strings::format(R"("%s" %s)", p.u8string(), version_check_arguments);
|
||||
return exists_and_has_equal_or_greater_version(cmd, expected_version);
|
||||
actual_version[2] >= expected_version[2]);
|
||||
});
|
||||
|
||||
if (it != candidate_paths.cend())
|
||||
if (it == candidates.cend())
|
||||
{
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
return *it;
|
||||
}
|
||||
|
||||
return nullopt;
|
||||
struct VersionProvider
|
||||
{
|
||||
virtual Optional<std::string> get_version(const fs::path& path_to_exe) const = 0;
|
||||
|
||||
std::vector<PathAndVersion> get_versions(const std::vector<fs::path>& candidate_paths) const
|
||||
{
|
||||
std::vector<PathAndVersion> output;
|
||||
for (auto&& p : candidate_paths)
|
||||
{
|
||||
auto maybe_version = this->get_version(p);
|
||||
if (const auto version = maybe_version.get())
|
||||
{
|
||||
output.emplace_back(PathAndVersion{p, *version});
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
};
|
||||
|
||||
static fs::path fetch_tool(const VcpkgPaths& paths, const std::string& tool_name, const ToolData& tool_data)
|
||||
{
|
||||
const std::array<int, 3>& version = tool_data.version;
|
||||
@ -203,7 +213,39 @@ namespace vcpkg::Commands::Fetch
|
||||
return tool_data.exe_path;
|
||||
}
|
||||
|
||||
static fs::path get_cmake_path(const VcpkgPaths& paths)
|
||||
static PathAndVersion fetch_tool(const VcpkgPaths& paths,
|
||||
const std::string& tool_name,
|
||||
const ToolData& tool_data,
|
||||
const VersionProvider& version_provider)
|
||||
{
|
||||
const auto downloaded_path = fetch_tool(paths, tool_name, tool_data);
|
||||
const auto downloaded_version = version_provider.get_version(downloaded_path).value_or_exit(VCPKG_LINE_INFO);
|
||||
return {downloaded_path, downloaded_version};
|
||||
}
|
||||
|
||||
namespace CMake
|
||||
{
|
||||
struct CmakeVersionProvider : VersionProvider
|
||||
{
|
||||
Optional<std::string> get_version(const fs::path& path_to_exe) const override
|
||||
{
|
||||
const std::string cmd = Strings::format(R"("%s" --version)", path_to_exe.u8string());
|
||||
const auto rc = System::cmd_execute_and_capture_output(cmd);
|
||||
if (rc.exit_code != 0)
|
||||
{
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
/* Sample output:
|
||||
cmake version 3.10.2
|
||||
|
||||
CMake suite maintained and supported by Kitware (kitware.com/cmake).
|
||||
*/
|
||||
return StringRange::find_exactly_one_enclosed(rc.output, "cmake version ", "\n").to_string();
|
||||
}
|
||||
};
|
||||
|
||||
static PathAndVersion get_path(const VcpkgPaths& paths)
|
||||
{
|
||||
std::vector<fs::path> candidate_paths;
|
||||
#if defined(_WIN32) || defined(__APPLE__) || defined(__linux__)
|
||||
@ -212,24 +254,25 @@ namespace vcpkg::Commands::Fetch
|
||||
#else
|
||||
static const ToolData TOOL_DATA = ToolData{{3, 5, 1}, ""};
|
||||
#endif
|
||||
static const std::string VERSION_CHECK_ARGUMENTS = "--version";
|
||||
|
||||
const std::vector<fs::path> from_path = Files::find_from_PATH("cmake");
|
||||
candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
|
||||
|
||||
const auto& program_files = System::get_program_files_platform_bitness();
|
||||
if (const auto pf = program_files.get()) candidate_paths.push_back(*pf / "CMake" / "bin" / "cmake.exe");
|
||||
const auto& program_files_32_bit = System::get_program_files_32_bit();
|
||||
if (const auto pf = program_files_32_bit.get()) candidate_paths.push_back(*pf / "CMake" / "bin" / "cmake.exe");
|
||||
if (const auto pf = program_files_32_bit.get())
|
||||
candidate_paths.push_back(*pf / "CMake" / "bin" / "cmake.exe");
|
||||
|
||||
const Optional<fs::path> path = find_if_has_equal_or_greater_version(
|
||||
paths.get_filesystem(), candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.version);
|
||||
if (const auto p = path.get())
|
||||
const CmakeVersionProvider version_provider{};
|
||||
const std::vector<PathAndVersion> candidates_with_versions = version_provider.get_versions(candidate_paths);
|
||||
const auto maybe_path = find_first_with_sufficient_version(candidates_with_versions, TOOL_DATA.version);
|
||||
if (const auto p = maybe_path.get())
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
return fetch_tool(paths, "cmake", TOOL_DATA);
|
||||
return fetch_tool(paths, Tools::CMAKE, TOOL_DATA, version_provider);
|
||||
}
|
||||
}
|
||||
|
||||
static fs::path get_7za_path(const VcpkgPaths& paths)
|
||||
@ -246,7 +289,27 @@ namespace vcpkg::Commands::Fetch
|
||||
#endif
|
||||
}
|
||||
|
||||
static fs::path get_ninja_path(const VcpkgPaths& paths)
|
||||
namespace Ninja
|
||||
{
|
||||
struct NinjaVersionProvider : VersionProvider
|
||||
{
|
||||
Optional<std::string> get_version(const fs::path& path_to_exe) const override
|
||||
{
|
||||
const std::string cmd = Strings::format(R"("%s" --version)", path_to_exe.u8string());
|
||||
const auto rc = System::cmd_execute_and_capture_output(cmd);
|
||||
if (rc.exit_code != 0)
|
||||
{
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
/* Sample output:
|
||||
1.8.2
|
||||
*/
|
||||
return rc.output;
|
||||
}
|
||||
};
|
||||
|
||||
static PathAndVersion get_path(const VcpkgPaths& paths)
|
||||
{
|
||||
static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "ninja");
|
||||
|
||||
@ -255,17 +318,43 @@ namespace vcpkg::Commands::Fetch
|
||||
const std::vector<fs::path> from_path = Files::find_from_PATH("ninja");
|
||||
candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
|
||||
|
||||
auto path = find_if_has_equal_or_greater_version(
|
||||
paths.get_filesystem(), candidate_paths, "--version", TOOL_DATA.version);
|
||||
if (const auto p = path.get())
|
||||
const NinjaVersionProvider version_provider{};
|
||||
const std::vector<PathAndVersion> candidates_with_versions = version_provider.get_versions(candidate_paths);
|
||||
const auto maybe_path = find_first_with_sufficient_version(candidates_with_versions, TOOL_DATA.version);
|
||||
if (const auto p = maybe_path.get())
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
return fetch_tool(paths, "ninja", TOOL_DATA);
|
||||
return fetch_tool(paths, Tools::NINJA, TOOL_DATA, version_provider);
|
||||
}
|
||||
}
|
||||
|
||||
static fs::path get_nuget_path(const VcpkgPaths& paths)
|
||||
namespace Nuget
|
||||
{
|
||||
struct NugetVersionProvider : VersionProvider
|
||||
{
|
||||
Optional<std::string> get_version(const fs::path& path_to_exe) const override
|
||||
{
|
||||
const std::string cmd = Strings::format(R"("%s")", path_to_exe.u8string());
|
||||
const auto rc = System::cmd_execute_and_capture_output(cmd);
|
||||
if (rc.exit_code != 0)
|
||||
{
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
/* Sample output:
|
||||
NuGet Version: 4.6.2.5055
|
||||
usage: NuGet <command> [args] [options]
|
||||
Type 'NuGet help <command>' for help on a specific command.
|
||||
|
||||
[[[List of available commands follows]]]
|
||||
*/
|
||||
return StringRange::find_exactly_one_enclosed(rc.output, "NuGet Version: ", "\n").to_string();
|
||||
}
|
||||
};
|
||||
|
||||
static PathAndVersion get_path(const VcpkgPaths& paths)
|
||||
{
|
||||
static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "nuget");
|
||||
|
||||
@ -274,20 +363,46 @@ namespace vcpkg::Commands::Fetch
|
||||
const std::vector<fs::path> from_path = Files::find_from_PATH("nuget");
|
||||
candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
|
||||
|
||||
auto path =
|
||||
find_if_has_equal_or_greater_version(paths.get_filesystem(), candidate_paths, "", TOOL_DATA.version);
|
||||
if (const auto p = path.get())
|
||||
const NugetVersionProvider version_provider{};
|
||||
const std::vector<PathAndVersion> candidates_with_versions = version_provider.get_versions(candidate_paths);
|
||||
const auto maybe_path = find_first_with_sufficient_version(candidates_with_versions, TOOL_DATA.version);
|
||||
if (const auto p = maybe_path.get())
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
return fetch_tool(paths, "nuget", TOOL_DATA);
|
||||
return fetch_tool(paths, Tools::NUGET, TOOL_DATA, version_provider);
|
||||
}
|
||||
}
|
||||
|
||||
static fs::path get_git_path(const VcpkgPaths& paths)
|
||||
namespace Git
|
||||
{
|
||||
struct GitVersionProvider : VersionProvider
|
||||
{
|
||||
Optional<std::string> get_version(const fs::path& path_to_exe) const override
|
||||
{
|
||||
const std::string cmd = Strings::format(R"("%s" --version)", path_to_exe.u8string());
|
||||
const auto rc = System::cmd_execute_and_capture_output(cmd);
|
||||
if (rc.exit_code != 0)
|
||||
{
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
/* Sample output:
|
||||
git version 2.17.1.windows.2
|
||||
*/
|
||||
const auto idx = rc.output.find("git version ");
|
||||
Checks::check_exit(VCPKG_LINE_INFO,
|
||||
idx != std::string::npos,
|
||||
"Unexpected format of git version string: %s",
|
||||
rc.output);
|
||||
return rc.output.substr(idx);
|
||||
}
|
||||
};
|
||||
|
||||
static PathAndVersion get_path(const VcpkgPaths& paths)
|
||||
{
|
||||
static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "git");
|
||||
static const std::string VERSION_CHECK_ARGUMENTS = "--version";
|
||||
|
||||
std::vector<fs::path> candidate_paths;
|
||||
#if defined(_WIN32)
|
||||
@ -301,22 +416,42 @@ namespace vcpkg::Commands::Fetch
|
||||
const auto& program_files_32_bit = System::get_program_files_32_bit();
|
||||
if (const auto pf = program_files_32_bit.get()) candidate_paths.push_back(*pf / "git" / "cmd" / "git.exe");
|
||||
|
||||
const Optional<fs::path> path = find_if_has_equal_or_greater_version(
|
||||
paths.get_filesystem(), candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.version);
|
||||
if (const auto p = path.get())
|
||||
const GitVersionProvider version_provider{};
|
||||
const std::vector<PathAndVersion> candidates_with_versions = version_provider.get_versions(candidate_paths);
|
||||
const auto maybe_path = find_first_with_sufficient_version(candidates_with_versions, TOOL_DATA.version);
|
||||
if (const auto p = maybe_path.get())
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
return fetch_tool(paths, "git", TOOL_DATA);
|
||||
return fetch_tool(paths, Tools::GIT, TOOL_DATA, version_provider);
|
||||
}
|
||||
}
|
||||
|
||||
static fs::path get_ifw_installerbase_path(const VcpkgPaths& paths)
|
||||
namespace IfwInstallerBase
|
||||
{
|
||||
struct IfwInstallerBaseVersionProvider : VersionProvider
|
||||
{
|
||||
Optional<std::string> get_version(const fs::path& path_to_exe) const override
|
||||
{
|
||||
const std::string cmd = Strings::format(R"("%s" --framework-version)", path_to_exe.u8string());
|
||||
const auto rc = System::cmd_execute_and_capture_output(cmd);
|
||||
if (rc.exit_code != 0)
|
||||
{
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
/* Sample output:
|
||||
3.1.81
|
||||
*/
|
||||
return rc.output;
|
||||
}
|
||||
};
|
||||
|
||||
static PathAndVersion get_path(const VcpkgPaths& paths)
|
||||
{
|
||||
static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "installerbase");
|
||||
|
||||
static const std::string VERSION_CHECK_ARGUMENTS = "--framework-version";
|
||||
|
||||
std::vector<fs::path> candidate_paths;
|
||||
candidate_paths.push_back(TOOL_DATA.exe_path);
|
||||
// TODO: Uncomment later
|
||||
@ -327,14 +462,16 @@ namespace vcpkg::Commands::Fetch
|
||||
// candidate_paths.push_back(fs::path(System::get_environment_variable("HOMEDRIVE").value_or("C:")) / "Qt" /
|
||||
// "QtIFW-3.1.0" / "bin" / "installerbase.exe");
|
||||
|
||||
const Optional<fs::path> path = find_if_has_equal_or_greater_version(
|
||||
paths.get_filesystem(), candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.version);
|
||||
if (const auto p = path.get())
|
||||
const IfwInstallerBaseVersionProvider version_provider{};
|
||||
const std::vector<PathAndVersion> candidates_with_versions = version_provider.get_versions(candidate_paths);
|
||||
const auto maybe_path = find_first_with_sufficient_version(candidates_with_versions, TOOL_DATA.version);
|
||||
if (const auto p = maybe_path.get())
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
return fetch_tool(paths, "installerbase", TOOL_DATA);
|
||||
return fetch_tool(paths, Tools::IFW_INSTALLER_BASE, TOOL_DATA, version_provider);
|
||||
}
|
||||
}
|
||||
|
||||
fs::path get_tool_path(const VcpkgPaths& paths, const std::string& tool)
|
||||
@ -342,14 +479,14 @@ namespace vcpkg::Commands::Fetch
|
||||
// First deal with specially handled tools.
|
||||
// For these we may look in locations like Program Files, the PATH etc as well as the auto-downloaded location.
|
||||
if (tool == Tools::SEVEN_ZIP) return get_7za_path(paths);
|
||||
if (tool == Tools::CMAKE) return get_cmake_path(paths);
|
||||
if (tool == Tools::GIT) return get_git_path(paths);
|
||||
if (tool == Tools::NINJA) return get_ninja_path(paths);
|
||||
if (tool == Tools::NUGET) return get_nuget_path(paths);
|
||||
if (tool == Tools::IFW_INSTALLER_BASE) return get_ifw_installerbase_path(paths);
|
||||
if (tool == Tools::CMAKE) return CMake::get_path(paths).path;
|
||||
if (tool == Tools::GIT) return Git::get_path(paths).path;
|
||||
if (tool == Tools::NINJA) return Ninja::get_path(paths).path;
|
||||
if (tool == Tools::NUGET) return Nuget::get_path(paths).path;
|
||||
if (tool == Tools::IFW_INSTALLER_BASE) return IfwInstallerBase::get_path(paths).path;
|
||||
if (tool == Tools::IFW_BINARYCREATOR)
|
||||
return get_ifw_installerbase_path(paths).parent_path() / "binarycreator.exe";
|
||||
if (tool == Tools::IFW_REPOGEN) return get_ifw_installerbase_path(paths).parent_path() / "repogen.exe";
|
||||
return IfwInstallerBase::get_path(paths).path.parent_path() / "binarycreator.exe";
|
||||
if (tool == Tools::IFW_REPOGEN) return IfwInstallerBase::get_path(paths).path.parent_path() / "repogen.exe";
|
||||
|
||||
// For other tools, we simply always auto-download them.
|
||||
const ToolData tool_data = parse_tool_data_from_xml(paths, tool);
|
||||
@ -360,6 +497,17 @@ namespace vcpkg::Commands::Fetch
|
||||
return fetch_tool(paths, tool, tool_data);
|
||||
}
|
||||
|
||||
std::string get_tool_version(const VcpkgPaths& paths, const std::string& tool)
|
||||
{
|
||||
if (tool == Tools::CMAKE) return CMake::get_path(paths).version;
|
||||
if (tool == Tools::GIT) return Git::get_path(paths).version;
|
||||
if (tool == Tools::NINJA) return Ninja::get_path(paths).version;
|
||||
if (tool == Tools::NUGET) return Nuget::get_path(paths).version;
|
||||
if (tool == Tools::IFW_INSTALLER_BASE) return IfwInstallerBase::get_path(paths).version;
|
||||
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO, "Finding version for %s is not implemented yet.", tool);
|
||||
}
|
||||
|
||||
const CommandStructure COMMAND_STRUCTURE = {
|
||||
Strings::format("The argument should be tool name\n%s", Help::create_example_string("fetch cmake")),
|
||||
1,
|
||||
|
Loading…
Reference in New Issue
Block a user