mirror of
https://github.com/Toastconcern/FrameStudio.git
synced 2026-10-29 03:02:30 +01:00
Updates: Frame Studio and Frame Home update themselves from GitHub
CI stamps every Studio build with its commit (FRAME_BUILD) and the release gets latest.json: the commit, Frame Home's identity (a hash of the headset programs in frame/payload) and the files in the release. Frame Studio (studio/updater.h): checks a few seconds after start and every 6 hours (Help > Check for Updates any time). A newer build shows "Update Available" in the top bar; Download and Install fetches this computer's build with the system's curl, unpacks it with tar, and swaps each item in (the old one renamed aside first, so the running copy keeps working and a failure rolls everything back). Restart Now closes through the normal unsaved-changes prompt, then starts the new copy; the next start deletes what was set aside. Local builds never update. New platform calls: systemTool (System32's curl/tar on Windows) and launch. Frame Home (src/switcher.cpp): on the Steam Frame the Environments panel checks a minute after it starts and every 6 hours. When the installed programs' hash isn't the release's, "Update Frame Home" shows beside Restart Frame Home; it downloads FrameHome-installer.zip and runs its install.sh in its own session (which restarts Frame Home and the panel), and the new panel says "Frame Home is updated". Also frame-switcher --check-update / --update from a terminal. frame/payload: frame-switcher rebuilt on the Steam Frame with this. Tested: Studio's full cycle (check, download, unpack, swap, relaunch, cleanup) and its rollback against a local fake release on Windows; the headset's check and update against a fake release on the Frame (old panel and Frame Home replaced, then up to date); Linux compile of Studio; Studio --selftest unchanged (98 passed, same 6 known fails). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
39c8424391
commit
fedadd5ae3
12 files changed
+590
-3
No files matched your search
@@ -27,6 +27,7 @@
|
||||
#include "world_runtime.h"
|
||||
#include "frame_pacer.h"
|
||||
#include "platform.h"
|
||||
#include "updater.h"
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#define STBI_WRITE_NO_STDIO
|
||||
#include "stb_image_write.h"
|
||||
@@ -665,6 +666,10 @@ struct Studio {
|
||||
int undoGroup = 0, nextUndoGroup = 1; // pushUndo tags steps with undoGroup while a batch is open
|
||||
std::vector<std::vector<std::string>> recent; // File > Open Recent: each entry footprint [+ vista]
|
||||
bool showControls = false; // Help > Controls
|
||||
updater::Updater updates; // Frame Studio's own updates (studio/updater.h)
|
||||
bool showUpdate = false; // the update window (Help > Check for Updates, or the top bar's button)
|
||||
bool restartAfterClose = false; // "Restart": start the updated copy once this one has closed
|
||||
std::chrono::steady_clock::time_point nextUpdateCheck = std::chrono::steady_clock::now() + std::chrono::seconds(5);
|
||||
bool testing = false; // --selftest: leave the recent list and edits alone
|
||||
struct TestEye { ImVec2 at; std::vector<size_t> members; };
|
||||
std::vector<TestEye> testEyes; // --selftest: the explorer's eye buttons this frame (folders and rows)
|
||||
@@ -6403,6 +6408,8 @@ struct Studio {
|
||||
if (ImGui::BeginMenu("Help")) {
|
||||
if (ImGui::MenuItem("Controls", "F1", showControls)) showControls = !showControls;
|
||||
if (ImGui::MenuItem("Menu Search", "F3")) openSearch();
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("Check for Updates…")) { showUpdate = true; updates.check(); }
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
// The workspace tabs: the active one raised like Blender's
|
||||
@@ -6423,6 +6430,17 @@ struct Studio {
|
||||
dl->AddText(ImVec2(a.x + (bw - ts.x) * 0.5f, a.y + (bh - ts.y) * 0.5f), col(on ? 0xffffff : kDim), kWorkspaceName[w]);
|
||||
ImGui::SameLine(0, 2 * scale);
|
||||
}
|
||||
const updater::State us = updates.state();
|
||||
if (us == updater::State::Available || us == updater::State::Installing || us == updater::State::Ready) {
|
||||
ImGui::Dummy(ImVec2(10 * scale, 0));
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, hex(kOrange));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, hex(kOrange));
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, hex(0xffffff));
|
||||
const char* label = us == updater::State::Ready ? "Restart to Update###upd" : us == updater::State::Installing ? "Updating…###upd" : "Update Available###upd";
|
||||
if (ImGui::SmallButton(label)) showUpdate = true;
|
||||
ImGui::PopStyleColor(3);
|
||||
}
|
||||
if (scene) { // the open home's name, at the right end as Blender shows its scene
|
||||
const std::string name = shownName() + (dirty ? " *" : "");
|
||||
const float w = ImGui::CalcTextSize(name.c_str()).x;
|
||||
@@ -7354,6 +7372,7 @@ struct Studio {
|
||||
addPopup();
|
||||
searchPopup();
|
||||
controlsWindow();
|
||||
updateWindow();
|
||||
settingsWindow();
|
||||
reportWindow();
|
||||
headsetDebugWindow();
|
||||
@@ -7974,6 +7993,49 @@ struct Studio {
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
// Updates: checked a few seconds after start and every 6 hours (Help > Check for Updates any time); the top bar
|
||||
// shows a button when there is one. Installing happens only when asked, here.
|
||||
void updateWindow() {
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
if (!testing && !g_selfTestRun && updater::Updater::canUpdate() && now >= nextUpdateCheck) {
|
||||
nextUpdateCheck = now + std::chrono::hours(6);
|
||||
updates.check();
|
||||
}
|
||||
if (!showUpdate) return;
|
||||
ImGui::SetNextWindowSize(ImVec2(380 * scale, 0), ImGuiCond_Appearing);
|
||||
ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x * 0.5f, ImGui::GetIO().DisplaySize.y * 0.4f), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
||||
if (!ImGui::Begin("Frame Studio Updates", &showUpdate, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDocking)) { ImGui::End(); return; }
|
||||
ImGui::PushTextWrapPos(360 * scale);
|
||||
if (!updater::Updater::canUpdate()) {
|
||||
ImGui::TextUnformatted("This copy of Frame Studio was built on this computer, not downloaded from GitHub, so it doesn't update itself.");
|
||||
if (ImGui::Button("Open the Downloads Page")) platform::openPath(updater::kPageUrl);
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
const updater::State s = updates.state();
|
||||
ImGui::TextUnformatted(updates.text().c_str());
|
||||
ImGui::TextDisabled("This build: %.7s", updater::kBuild);
|
||||
ImGui::Spacing();
|
||||
if (s == updater::State::Available) {
|
||||
if (ImGui::Button("Download and Install")) updates.install();
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Later")) showUpdate = false;
|
||||
} else if (s == updater::State::Ready) {
|
||||
if (ImGui::Button("Restart Now")) { restartAfterClose = true; if (window.requestClose) window.requestClose(); }
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Later")) showUpdate = false;
|
||||
} else if (s == updater::State::Failed) {
|
||||
if (ImGui::Button("Try Again")) updates.check();
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Open the Downloads Page")) platform::openPath(updater::kPageUrl);
|
||||
} else if (s == updater::State::Current) {
|
||||
if (ImGui::Button("Check Again")) updates.check();
|
||||
}
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::End();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -9416,6 +9478,7 @@ int runStudio(StudioWindow& window, const std::vector<std::string>& args) {
|
||||
const float scale = window.uiScale();
|
||||
platform::setDialogOwner(window.nativeHandle());
|
||||
g_selfTestRun = !args.empty() && args[0] == "--selftest"; // (before anything saves)
|
||||
updater::cleanUp(); // what the last update set aside
|
||||
auto app = std::make_unique<Studio>();
|
||||
g_app = app.get();
|
||||
app->window = window.hooks();
|
||||
@@ -9598,6 +9661,8 @@ int runStudio(StudioWindow& window, const std::vector<std::string>& args) {
|
||||
vkDeviceWaitIdle(r.device());
|
||||
window.stopHangWatchdog();
|
||||
if (app->saver.joinable()) app->saver.join();
|
||||
if (app->restartAfterClose && !platform::launch(updater::updatedProgram())) // Help > updates: Restart Now
|
||||
platform::message("Frame Studio", "The updated Frame Studio didn't start. Open it again from its folder.", platform::Icon::Warning);
|
||||
if (app->loadState == 1 || app->loadAbandoned) { // a home still being read: nothing to lose, and waiting for it is what stalls
|
||||
std::fflush(stderr);
|
||||
std::_Exit(0);
|
||||
|
||||
Reference in new issue
Block a user