Add Windows portable auto-update from Forgejo continuous releases.
Some checks failed
Windows Release / windows-x86_64 (push) Failing after 1h12m0s

Poll windows-continuous by git SHA, download the matching zip, and apply it in place so friends stay current without manual installs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
copilot 2026-11-12 12:29:49 +01:00
parent 7f34283537
commit cdc4c5cb30
13 changed files with 371 additions and 22 deletions

View file

@ -51,6 +51,8 @@
#endif
#include <Helpers/Logger.hpp>
#include "VersionConstants.hpp"
#include "WindowsPortableUpdater.hpp"
#ifdef __ANDROID__
#define UPDATE_NOTIFICATION_URL "https://infinipaint.com/updateNotificationVersionAndroid.txt"
@ -121,18 +123,95 @@ void MainProgram::update() {
post_callback();
}
void MainProgram::start_windows_portable_update_download() {
#ifdef _WIN32
if(updateCheckerData.downloadingZip || updateCheckerData.downloadUrl.empty())
return;
updateCheckerData.downloadingZip = true;
updateCheckerData.downloadStatus = "Downloading update…";
updateCheckerData.zipDownload = FileDownloader::download_data_from_url(updateCheckerData.downloadUrl);
g.gui.set_to_layout();
#else
(void)0;
#endif
}
void MainProgram::update_notification_check() {
#ifndef __EMSCRIPTEN__
#ifdef _WIN32
// Poll in-flight zip download / apply.
if(updateCheckerData.downloadingZip && updateCheckerData.zipDownload) {
switch(updateCheckerData.zipDownload->status) {
case FileDownloader::DownloadData::Status::IN_PROGRESS: {
float p = updateCheckerData.zipDownload->progress.load();
if(p > 0.f)
updateCheckerData.downloadStatus = "Downloading update… " + std::to_string(int(p * 100.f)) + "%";
break;
}
case FileDownloader::DownloadData::Status::SUCCESS: {
updateCheckerData.downloadStatus = "Installing update…";
g.gui.set_to_layout();
if(!WindowsPortableUpdater::apply_zip_and_restart(updateCheckerData.zipDownload->str)) {
updateCheckerData.downloadStatus = "Update install failed (see log).";
updateCheckerData.downloadingZip = false;
updateCheckerData.zipDownload = nullptr;
g.gui.set_to_layout();
}
break;
}
case FileDownloader::DownloadData::Status::FAILURE:
updateCheckerData.downloadStatus = "Download failed.";
updateCheckerData.downloadingZip = false;
updateCheckerData.zipDownload = nullptr;
g.gui.set_to_layout();
break;
}
}
#endif
if(!updateCheckerData.updateCheckDone) {
if(conf.checkForUpdates) {
if(!updateCheckerData.versionFile)
if(!updateCheckerData.versionFile) {
#ifdef _WIN32
// Fork continuous builds: compare git SHA against Forgejo windows-continuous.
updateCheckerData.forgejoContinuous = true;
updateCheckerData.versionFile = FileDownloader::download_data_from_url(FORGEJO_WINDOWS_CONTINUOUS_API);
#else
updateCheckerData.versionFile = FileDownloader::download_data_from_url(UPDATE_NOTIFICATION_URL);
#endif
}
else {
switch(updateCheckerData.versionFile->status) {
case FileDownloader::DownloadData::Status::IN_PROGRESS:
break;
case FileDownloader::DownloadData::Status::SUCCESS: {
updateCheckerData.updateCheckDone = true;
#ifdef _WIN32
std::string label, commit, zipUrl;
if(WindowsPortableUpdater::parse_continuous_release_json(
updateCheckerData.versionFile->str, label, commit, zipUrl)) {
updateCheckerData.remoteCommit = commit;
updateCheckerData.downloadUrl = zipUrl;
updateCheckerData.newVersionStr = label.empty()
? (VersionConstants::CURRENT_VERSION_STRING + "+" + commit)
: label;
const std::string& local = VersionConstants::build_commit_short();
Logger::get().log(Logger::LogType::INFO,
"Forgejo continuous commit=" + commit + " local=" + local);
if(local != "unknown" && commit != local.substr(0, commit.size())) {
updateCheckerData.showGui = true;
Logger::get().log(Logger::LogType::PHONE_USERINFO,
"Windows update available: " + updateCheckerData.newVersionStr);
g.gui.set_to_layout();
}
else if(local == "unknown")
Logger::get().log(Logger::LogType::INFO, "Local build commit unknown — skip update prompt");
else
Logger::get().log(Logger::LogType::INFO, "Windows portable build is up to date");
}
else
Logger::get().log(Logger::LogType::INFO, "Could not parse Forgejo windows-continuous release");
#else
std::optional<VersionNumber> newVersion = version_str_to_version_numbers(updateCheckerData.versionFile->str);
std::optional<VersionNumber> currentVersion = VersionConstants::CURRENT_VERSION_NUMBER;
if(newVersion.has_value() && currentVersion.has_value()) {
@ -152,6 +231,7 @@ void MainProgram::update_notification_check() {
}
else
Logger::get().log(Logger::LogType::INFO, "Update notification file couldn't be converted to version numbers");
#endif
updateCheckerData.versionFile = nullptr;
break;
}