Merge pull request #6496 from delroth/updater

Moar auto-updater improvements
This commit is contained in:
Pierre Bourdon 2018-03-23 11:21:18 +01:00 committed by GitHub
commit 733186d48b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 100 additions and 23 deletions

View File

@ -664,33 +664,42 @@ std::string GetBundleDirectory()
}
#endif
std::string& GetExeDirectory()
std::string GetExePath()
{
static std::string DolphinPath;
if (DolphinPath.empty())
static std::string dolphin_path;
if (dolphin_path.empty())
{
#ifdef _WIN32
TCHAR Dolphin_exe_Path[2048];
TCHAR Dolphin_exe_Clean_Path[MAX_PATH];
GetModuleFileName(nullptr, Dolphin_exe_Path, 2048);
if (_tfullpath(Dolphin_exe_Clean_Path, Dolphin_exe_Path, MAX_PATH) != nullptr)
DolphinPath = TStrToUTF8(Dolphin_exe_Clean_Path);
TCHAR dolphin_exe_path[2048];
TCHAR dolphin_exe_expanded_path[MAX_PATH];
GetModuleFileName(nullptr, dolphin_exe_path, ARRAYSIZE(dolphin_exe_path));
if (_tfullpath(dolphin_exe_expanded_path, dolphin_exe_path,
ARRAYSIZE(dolphin_exe_expanded_path)) != nullptr)
dolphin_path = TStrToUTF8(dolphin_exe_expanded_path);
else
DolphinPath = TStrToUTF8(Dolphin_exe_Path);
DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\'));
dolphin_path = TStrToUTF8(dolphin_exe_path);
#else
char Dolphin_exe_Path[PATH_MAX];
ssize_t len = ::readlink("/proc/self/exe", Dolphin_exe_Path, sizeof(Dolphin_exe_Path));
if (len == -1 || len == sizeof(Dolphin_exe_Path))
char dolphin_exe_path[PATH_MAX];
ssize_t len = ::readlink("/proc/self/exe", dolphin_exe_path, sizeof(dolphin_exe_path));
if (len == -1 || len == sizeof(dolphin_exe_path))
{
len = 0;
}
Dolphin_exe_Path[len] = '\0';
DolphinPath = Dolphin_exe_Path;
DolphinPath = DolphinPath.substr(0, DolphinPath.rfind('/'));
dolphin_exe_path[len] = '\0';
dolphin_path = dolphin_exe_path;
#endif
}
return DolphinPath;
return dolphin_path;
}
std::string GetExeDirectory()
{
std::string exe_path = GetExePath();
#ifdef _WIN32
return exe_path.substr(0, exe_path.rfind('\\'));
#else
return exe_path.substr(0, exe_path.rfind('/'));
#endif
}
std::string GetSysDirectory()
@ -882,4 +891,4 @@ bool ReadFileToString(const std::string& filename, std::string& str)
return retval;
}
} // namespace
} // namespace File

View File

@ -191,7 +191,8 @@ void SetSysDirectory(const std::string& path);
std::string GetBundleDirectory();
#endif
std::string& GetExeDirectory();
std::string GetExePath();
std::string GetExeDirectory();
bool WriteStringToFile(const std::string& str, const std::string& filename);
bool ReadFileToString(const std::string& filename, std::string& str);

View File

@ -80,7 +80,8 @@ void Updater::OnUpdateAvailable(const NewVersionInformation& info)
if (choice == QDialog::Accepted)
{
TriggerUpdate(info);
TriggerUpdate(info, later ? AutoUpdateChecker::RestartMode::NO_RESTART_AFTER_UPDATE :
AutoUpdateChecker::RestartMode::RESTART_AFTER_UPDATE);
if (!later)
m_parent->close();

View File

@ -5,6 +5,7 @@
#include "UICommon/AutoUpdate.h"
#include <picojson/picojson.h>
#include <string>
#include "Common/CommonPaths.h"
#include "Common/FileUtil.h"
@ -46,6 +47,48 @@ void CleanupFromPreviousUpdate()
File::Delete(reloc_updater_path);
}
#endif
// This ignores i18n because most of the text in there (change descriptions) is only going to be
// written in english anyway.
std::string GenerateChangelog(const picojson::array& versions)
{
std::string changelog;
for (const auto& ver : versions)
{
if (!ver.is<picojson::object>())
continue;
picojson::object ver_obj = ver.get<picojson::object>();
if (ver_obj["changelog_html"].is<picojson::null>())
{
if (!changelog.empty())
changelog += "<div style=\"margin-top: 0.4em;\"></div>"; // Vertical spacing.
// Try to link to the PR if we have this info. Otherwise just show shortrev.
if (ver_obj["pr_url"].is<std::string>())
{
changelog += "<a href=\"" + ver_obj["pr_url"].get<std::string>() + "\">" +
ver_obj["shortrev"].get<std::string>() + "</a>";
}
else
{
changelog += ver_obj["shortrev"].get<std::string>();
}
changelog += " by <a href = \"" + ver_obj["author_url"].get<std::string>() + "\">" +
ver_obj["author"].get<std::string>() + "</a> &mdash; " +
ver_obj["short_descr"].get<std::string>();
}
else
{
if (!changelog.empty())
changelog += "<hr>";
changelog += "<b>Dolphin " + ver_obj["shortrev"].get<std::string>() + "</b>";
changelog += "<p>" + ver_obj["changelog_html"].get<std::string>() + "</p>";
}
}
return changelog;
}
} // namespace
bool AutoUpdateChecker::SystemSupportsAutoUpdates()
@ -106,12 +149,13 @@ void AutoUpdateChecker::CheckForUpdate()
nvi.new_hash = obj["new"].get<picojson::object>()["hash"].get<std::string>();
// TODO: generate the HTML changelog from the JSON information.
nvi.changelog_html = "<h2>TBD</h2>";
nvi.changelog_html = GenerateChangelog(obj["changelog"].get<picojson::array>());
OnUpdateAvailable(nvi);
}
void AutoUpdateChecker::TriggerUpdate(const AutoUpdateChecker::NewVersionInformation& info)
void AutoUpdateChecker::TriggerUpdate(const AutoUpdateChecker::NewVersionInformation& info,
AutoUpdateChecker::RestartMode restart_mode)
{
#ifdef _WIN32
std::map<std::string, std::string> updater_flags;
@ -122,6 +166,9 @@ void AutoUpdateChecker::TriggerUpdate(const AutoUpdateChecker::NewVersionInforma
updater_flags["install-base-path"] = File::GetExeDirectory();
updater_flags["log-file"] = File::GetExeDirectory() + DIR_SEP + UPDATER_LOG_FILE;
if (restart_mode == RestartMode::RESTART_AFTER_UPDATE)
updater_flags["binary-to-restart"] = File::GetExePath();
// Copy the updater so it can update itself if needed.
std::string updater_path = File::GetExeDirectory() + DIR_SEP + UPDATER_FILENAME;
std::string reloc_updater_path = File::GetExeDirectory() + DIR_SEP + UPDATER_RELOC_FILENAME;
@ -130,6 +177,7 @@ void AutoUpdateChecker::TriggerUpdate(const AutoUpdateChecker::NewVersionInforma
// Run the updater!
std::wstring command_line = MakeUpdaterCommandLine(updater_flags);
STARTUPINFO sinfo = {sizeof(info)};
sinfo.dwFlags = STARTF_FORCEOFFFEEDBACK; // No hourglass cursor after starting the process.
PROCESS_INFORMATION pinfo;
INFO_LOG(COMMON, "Updater command line: %s", UTF16ToUTF8(command_line).c_str());
if (!CreateProcessW(UTF8ToUTF16(reloc_updater_path).c_str(),

View File

@ -33,7 +33,12 @@ public:
};
// Starts the updater process, which will wait in the background until the current process exits.
void TriggerUpdate(const NewVersionInformation& info);
enum class RestartMode
{
NO_RESTART_AFTER_UPDATE = 0,
RESTART_AFTER_UPDATE,
};
void TriggerUpdate(const NewVersionInformation& info, RestartMode restart_mode);
protected:
virtual void OnUpdateAvailable(const NewVersionInformation& info) = 0;

View File

@ -47,6 +47,7 @@ struct Options
std::string next_manifest_url;
std::string content_store_url;
std::string install_base_path;
std::optional<std::string> binary_to_restart;
std::optional<DWORD> parent_pid;
std::optional<std::string> log_file;
};
@ -90,6 +91,10 @@ std::optional<Options> ParseCommandLine(PCWSTR command_line)
.dest("install-base-path")
.help("Base path of the Dolphin install to be updated.")
.metavar("PATH");
parser.add_option("--binary-to-restart")
.dest("binary-to-restart")
.help("Binary to restart after the update is over.")
.metavar("PATH");
parser.add_option("--log-file")
.dest("log-file")
.help("File where to log updater debug output.")
@ -123,6 +128,8 @@ std::optional<Options> ParseCommandLine(PCWSTR command_line)
opts.install_base_path = options["install-base-path"];
// Optional arguments.
if (options.is_set("binary-to-restart"))
opts.binary_to_restart = options["binary-to-restart"];
if (options.is_set("parent-pid"))
opts.parent_pid = (DWORD)options.get("parent-pid");
if (options.is_set("log-file"))
@ -685,5 +692,11 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine
fprintf(log_fp, "Failed to apply the update.\n");
CleanUpTempDir(temp_dir, todo);
if (opts.binary_to_restart)
{
ShellExecuteW(nullptr, L"open", UTF8ToUTF16(*opts.binary_to_restart).c_str(), L"", nullptr,
SW_SHOW);
}
return !ok;
}