mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 06:09:50 -06:00
MacUpdater: check os version
This commit is contained in:
@ -4,6 +4,7 @@
|
||||
#include <map>
|
||||
#include <optional>
|
||||
|
||||
#include "Common/CommonPaths.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/HttpRequest.h"
|
||||
#include "Common/IOFile.h"
|
||||
@ -12,17 +13,106 @@
|
||||
|
||||
#include "UpdaterCommon/Platform.h"
|
||||
#include "UpdaterCommon/UI.h"
|
||||
#include "UpdaterCommon/UpdaterCommon.h"
|
||||
|
||||
namespace Platform
|
||||
{
|
||||
BuildInfo::BuildInfo(const std::string& content)
|
||||
struct BuildVersion
|
||||
{
|
||||
map = {{"OSMinimumVersionWin10", ""},
|
||||
{"OSMinimumVersionWin11", ""},
|
||||
{"VCToolsVersion", ""},
|
||||
{"VCToolsUpdateURL", ""}};
|
||||
Parse(content);
|
||||
}
|
||||
u32 major{};
|
||||
u32 minor{};
|
||||
u32 build{};
|
||||
auto operator<=>(BuildVersion const& rhs) const = default;
|
||||
static std::optional<BuildVersion> from_string(const std::string& str)
|
||||
{
|
||||
auto components = SplitString(str, '.');
|
||||
// Allow variable number of components (truncating after "build"), but not
|
||||
// empty.
|
||||
if (components.size() == 0)
|
||||
return {};
|
||||
BuildVersion version;
|
||||
if (!TryParse(components[0], &version.major, 10))
|
||||
return {};
|
||||
if (components.size() > 1 && !TryParse(components[1], &version.minor, 10))
|
||||
return {};
|
||||
if (components.size() > 2 && !TryParse(components[2], &version.build, 10))
|
||||
return {};
|
||||
return version;
|
||||
}
|
||||
};
|
||||
|
||||
enum class VersionCheckStatus
|
||||
{
|
||||
NothingToDo,
|
||||
UpdateOptional,
|
||||
UpdateRequired,
|
||||
};
|
||||
|
||||
struct VersionCheckResult
|
||||
{
|
||||
VersionCheckStatus status{VersionCheckStatus::NothingToDo};
|
||||
std::optional<BuildVersion> current_version{};
|
||||
std::optional<BuildVersion> target_version{};
|
||||
};
|
||||
|
||||
class BuildInfo
|
||||
{
|
||||
using Map = std::map<std::string, std::string>;
|
||||
|
||||
public:
|
||||
BuildInfo() = default;
|
||||
BuildInfo(const std::string& content)
|
||||
{
|
||||
map = {{"OSMinimumVersionWin10", ""},
|
||||
{"OSMinimumVersionWin11", ""},
|
||||
{"VCToolsVersion", ""},
|
||||
{"VCToolsUpdateURL", ""}};
|
||||
Parse(content);
|
||||
}
|
||||
|
||||
std::optional<std::string> GetString(const std::string& name) const
|
||||
{
|
||||
auto it = map.find(name);
|
||||
if (it == map.end() || it->second.size() == 0)
|
||||
return {};
|
||||
return it->second;
|
||||
}
|
||||
|
||||
std::optional<BuildVersion> GetVersion(const std::string& name) const
|
||||
{
|
||||
auto str = GetString(name);
|
||||
if (!str.has_value())
|
||||
return {};
|
||||
return BuildVersion::from_string(str.value());
|
||||
}
|
||||
|
||||
private:
|
||||
void Parse(const std::string& content)
|
||||
{
|
||||
std::stringstream content_stream(content);
|
||||
std::string line;
|
||||
while (std::getline(content_stream, line))
|
||||
{
|
||||
if (line.starts_with("//"))
|
||||
continue;
|
||||
const size_t equals_index = line.find('=');
|
||||
if (equals_index == line.npos)
|
||||
continue;
|
||||
auto key = line.substr(0, equals_index);
|
||||
auto key_it = map.find(key);
|
||||
if (key_it == map.end())
|
||||
continue;
|
||||
key_it->second = line.substr(equals_index + 1);
|
||||
}
|
||||
}
|
||||
Map map;
|
||||
};
|
||||
|
||||
struct BuildInfos
|
||||
{
|
||||
BuildInfo current;
|
||||
BuildInfo next;
|
||||
};
|
||||
|
||||
// This default value should be kept in sync with the value of VCToolsUpdateURL in
|
||||
// build_info.txt.in
|
||||
@ -63,14 +153,13 @@ static std::optional<BuildVersion> GetInstalledVCRuntimeVersion()
|
||||
return version;
|
||||
}
|
||||
|
||||
static VersionCheckResult VCRuntimeVersionCheck(const BuildInfo& this_build_info,
|
||||
const BuildInfo& next_build_info)
|
||||
static VersionCheckResult VCRuntimeVersionCheck(const BuildInfos& build_infos)
|
||||
{
|
||||
VersionCheckResult result;
|
||||
result.current_version = GetInstalledVCRuntimeVersion();
|
||||
result.target_version = next_build_info.GetVersion("VCToolsVersion");
|
||||
result.target_version = build_infos.next.GetVersion("VCToolsVersion");
|
||||
|
||||
auto existing_version = this_build_info.GetVersion("VCToolsVersion");
|
||||
auto existing_version = build_infos.current.GetVersion("VCToolsVersion");
|
||||
|
||||
if (!result.target_version.has_value())
|
||||
result.status = VersionCheckStatus::UpdateOptional;
|
||||
@ -155,10 +244,45 @@ static VersionCheckResult OSVersionCheck(const BuildInfo& build_info)
|
||||
return result;
|
||||
}
|
||||
|
||||
bool VersionCheck(const BuildInfo& this_build_info, const BuildInfo& next_build_info)
|
||||
std::optional<BuildInfos> InitBuildInfos(const std::vector<TodoList::UpdateOp>& to_update,
|
||||
const std::string& install_base_path,
|
||||
const std::string& temp_dir, FILE* log_fp)
|
||||
{
|
||||
const auto op_it = std::find_if(to_update.cbegin(), to_update.cend(),
|
||||
[&](const auto& op) { return op.filename == "build_info.txt"; });
|
||||
if (op_it == to_update.cend())
|
||||
return {};
|
||||
|
||||
const auto op = *op_it;
|
||||
std::string build_info_path =
|
||||
temp_dir + DIR_SEP + HexEncode(op.new_hash.data(), op.new_hash.size());
|
||||
std::string build_info_content;
|
||||
if (!File::ReadFileToString(build_info_path, build_info_content) ||
|
||||
op.new_hash != ComputeHash(build_info_content))
|
||||
{
|
||||
fprintf(log_fp, "Failed to read %s\n.", build_info_path.c_str());
|
||||
return {};
|
||||
}
|
||||
BuildInfos build_infos;
|
||||
build_infos.next = Platform::BuildInfo(build_info_content);
|
||||
|
||||
build_info_path = install_base_path + DIR_SEP + "build_info.txt";
|
||||
build_infos.current = Platform::BuildInfo();
|
||||
if (File::ReadFileToString(build_info_path, build_info_content))
|
||||
{
|
||||
if (op.old_hash != ComputeHash(build_info_content))
|
||||
fprintf(log_fp, "Using modified existing BuildInfo %s.\n", build_info_path.c_str());
|
||||
build_infos.current = Platform::BuildInfo(build_info_content);
|
||||
}
|
||||
return build_infos;
|
||||
}
|
||||
|
||||
bool CheckBuildInfo(const BuildInfos& build_infos)
|
||||
{
|
||||
// The existing BuildInfo may have been modified. Be careful not to overly trust its contents!
|
||||
|
||||
// If the binary requires more recent OS, inform the user.
|
||||
auto os_check = OSVersionCheck(next_build_info);
|
||||
auto os_check = OSVersionCheck(build_infos.next);
|
||||
if (os_check.status == VersionCheckStatus::UpdateRequired)
|
||||
{
|
||||
UI::Error("Please update Windows in order to update Dolphin.");
|
||||
@ -167,13 +291,13 @@ bool VersionCheck(const BuildInfo& this_build_info, const BuildInfo& next_build_
|
||||
|
||||
// Check if application being launched needs more recent version of VC Redist. If so, download
|
||||
// latest updater and execute it.
|
||||
auto vc_check = VCRuntimeVersionCheck(this_build_info, next_build_info);
|
||||
auto vc_check = VCRuntimeVersionCheck(build_infos);
|
||||
if (vc_check.status != VersionCheckStatus::NothingToDo)
|
||||
{
|
||||
// Don't bother checking status of the install itself, just check if we actually see the new
|
||||
// version.
|
||||
VCRuntimeUpdate(next_build_info);
|
||||
vc_check = VCRuntimeVersionCheck(this_build_info, next_build_info);
|
||||
VCRuntimeUpdate(build_infos.next);
|
||||
vc_check = VCRuntimeVersionCheck(build_infos);
|
||||
if (vc_check.status == VersionCheckStatus::UpdateRequired)
|
||||
{
|
||||
// The update is required and the install failed for some reason.
|
||||
@ -184,4 +308,17 @@ bool VersionCheck(const BuildInfo& this_build_info, const BuildInfo& next_build_
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VersionCheck(const std::vector<TodoList::UpdateOp>& to_update,
|
||||
const std::string& install_base_path, const std::string& temp_dir, FILE* log_fp)
|
||||
{
|
||||
auto build_infos = InitBuildInfos(to_update, install_base_path, temp_dir, log_fp);
|
||||
// If there's no build info, it means the check should be skipped.
|
||||
if (!build_infos.has_value())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return CheckBuildInfo(build_infos.value());
|
||||
}
|
||||
|
||||
} // namespace Platform
|
||||
|
Reference in New Issue
Block a user