From f28043e0e969f5ff5e8ad1e5eea8964ebf6f2523 Mon Sep 17 00:00:00 2001 From: qurious-pixel <62252937+qurious-pixel@users.noreply.github.com> Date: Sat, 4 May 2024 16:34:36 -0700 Subject: [PATCH] Linux/Mac Auto-Updater (#1145) --- .github/workflows/build.yml | 20 ++++++------ src/CMakeLists.txt | 1 + src/gui/CemuUpdateWindow.cpp | 56 +++++++++++++++++++++++++++----- src/gui/GeneralSettings2.cpp | 10 +++--- src/gui/GettingStartedDialog.cpp | 7 ++-- src/gui/MainWindow.cpp | 8 +++-- src/resource/update.sh | 8 +++++ 7 files changed, 82 insertions(+), 28 deletions(-) create mode 100755 src/resource/update.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 58a8508d..d188b4a1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: "Checkout repo" - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: "recursive" fetch-depth: 0 @@ -91,7 +91,7 @@ jobs: run: mv bin/Cemu_release bin/Cemu - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: ${{ inputs.deploymode == 'release' }} with: name: cemu-bin-linux-x64 @@ -102,9 +102,9 @@ jobs: needs: build-ubuntu steps: - name: Checkout Upstream Repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: cemu-bin-linux-x64 path: bin @@ -121,7 +121,7 @@ jobs: dist/linux/appimage.sh - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: cemu-appimage-x64 path: artifacts @@ -130,7 +130,7 @@ jobs: runs-on: windows-2022 steps: - name: "Checkout repo" - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: "recursive" @@ -200,7 +200,7 @@ jobs: run: Rename-Item bin/Cemu_release.exe Cemu.exe - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: ${{ inputs.deploymode == 'release' }} with: name: cemu-bin-windows-x64 @@ -210,7 +210,7 @@ jobs: runs-on: macos-12 steps: - name: "Checkout repo" - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: "recursive" @@ -289,14 +289,14 @@ jobs: mv bin/Cemu_release.app bin/Cemu_app/Cemu.app mv bin/Cemu_app/Cemu.app/Contents/MacOS/Cemu_release bin/Cemu_app/Cemu.app/Contents/MacOS/Cemu sed -i '' 's/Cemu_release/Cemu/g' bin/Cemu_app/Cemu.app/Contents/Info.plist - chmod a+x bin/Cemu_app/Cemu.app/Contents/MacOS/Cemu + chmod a+x bin/Cemu_app/Cemu.app/Contents/MacOS/{Cemu,update.sh} ln -s /Applications bin/Cemu_app/Applications hdiutil create ./bin/tmp.dmg -ov -volname "Cemu" -fs HFS+ -srcfolder "./bin/Cemu_app" hdiutil convert ./bin/tmp.dmg -format UDZO -o bin/Cemu.dmg rm bin/tmp.dmg - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: ${{ inputs.deploymode == 'release' }} with: name: cemu-bin-macos-x64 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7442e37c..1b78b1fb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -98,6 +98,7 @@ if (MACOS_BUNDLE) add_custom_command (TARGET CemuBin POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy "/usr/local/lib/libMoltenVK.dylib" "${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/Frameworks/libMoltenVK.dylib" COMMAND ${CMAKE_COMMAND} ARGS -E copy "${CMAKE_BINARY_DIR}/vcpkg_installed/x64-osx/lib/libusb-1.0.0.dylib" "${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/Frameworks/libusb-1.0.0.dylib" + COMMAND ${CMAKE_COMMAND} ARGS -E copy "${CMAKE_SOURCE_DIR}/src/resource/update.sh" "${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/MacOS/update.sh" COMMAND bash -c "install_name_tool -add_rpath @executable_path/../Frameworks ${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/MacOS/${OUTPUT_NAME}" COMMAND bash -c "install_name_tool -change /usr/local/opt/libusb/lib/libusb-1.0.0.dylib @executable_path/../Frameworks/libusb-1.0.0.dylib ${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/MacOS/${OUTPUT_NAME}") endif() diff --git a/src/gui/CemuUpdateWindow.cpp b/src/gui/CemuUpdateWindow.cpp index 91394ee2..445c7c17 100644 --- a/src/gui/CemuUpdateWindow.cpp +++ b/src/gui/CemuUpdateWindow.cpp @@ -12,6 +12,11 @@ #include #include +#ifndef BOOST_OS_WINDOWS +#include +#include +#endif + #include #include #include @@ -105,11 +110,11 @@ bool CemuUpdateWindow::QueryUpdateInfo(std::string& downloadUrlOut, std::string& auto* curl = curl_easy_init(); urlStr.append(_curlUrlEscape(curl, BUILD_VERSION_STRING)); #if BOOST_OS_LINUX - urlStr.append("&platform=linux"); + urlStr.append("&platform=linux_appimage_x86"); #elif BOOST_OS_WINDOWS urlStr.append("&platform=windows"); #elif BOOST_OS_MACOS - urlStr.append("&platform=macos_x86"); + urlStr.append("&platform=macos_bundle_x86"); #elif #error Name for current platform is missing @@ -407,7 +412,13 @@ void CemuUpdateWindow::WorkerThread() if (!exists(tmppath)) create_directory(tmppath); +#if BOOST_OS_WINDOWS const auto update_file = tmppath / L"update.zip"; +#elif BOOST_OS_LINUX + const auto update_file = tmppath / L"Cemu.AppImage"; +#elif BOOST_OS_MACOS + const auto update_file = tmppath / L"cemu.dmg"; +#endif if (DownloadCemuZip(url, update_file)) { auto* event = new wxCommandEvent(wxEVT_RESULT); @@ -427,6 +438,7 @@ void CemuUpdateWindow::WorkerThread() // extract std::string cemuFolderName; +#if BOOST_OS_WINDOWS if (!ExtractUpdate(update_file, tmppath, cemuFolderName)) { cemuLog_log(LogType::Force, "Extracting Cemu zip failed"); @@ -437,7 +449,7 @@ void CemuUpdateWindow::WorkerThread() cemuLog_log(LogType::Force, "Cemu folder not found in zip"); break; } - +#endif const auto expected_path = tmppath / cemuFolderName; if (exists(expected_path)) { @@ -472,6 +484,7 @@ void CemuUpdateWindow::WorkerThread() // apply update fs::path exePath = ActiveSettings::GetExecutablePath(); +#if BOOST_OS_WINDOWS std::wstring target_directory = exePath.parent_path().generic_wstring(); if (target_directory[target_directory.size() - 1] == '/') target_directory = target_directory.substr(0, target_directory.size() - 1); // remove trailing / @@ -480,8 +493,19 @@ void CemuUpdateWindow::WorkerThread() const auto exec = ActiveSettings::GetExecutablePath(); const auto target_exe = fs::path(exec).replace_extension("exe.backup"); fs::rename(exec, target_exe); - m_restartFile = exec; - + m_restartFile = exec; +#elif BOOST_OS_LINUX + const char* appimage_path = std::getenv("APPIMAGE"); + const auto target_exe = fs::path(appimage_path).replace_extension("AppImage.backup"); + const char* filePath = update_file.c_str(); + mode_t permissions = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; + fs::rename(appimage_path, target_exe); + m_restartFile = appimage_path; + chmod(filePath, permissions); + wxString wxAppPath = wxString::FromUTF8(appimage_path); + wxCopyFile (wxT("/tmp/cemu_update/Cemu.AppImage"), wxAppPath); +#endif +#if BOOST_OS_WINDOWS const auto index = expected_path.wstring().size(); int counter = 0; for (const auto& it : fs::recursive_directory_iterator(expected_path)) @@ -516,7 +540,7 @@ void CemuUpdateWindow::WorkerThread() wxQueueEvent(this, event); } } - +#endif auto* event = new wxCommandEvent(wxEVT_PROGRESS); event->SetInt(m_gaugeMaxValue); wxQueueEvent(this, event); @@ -565,8 +589,24 @@ void CemuUpdateWindow::OnClose(wxCloseEvent& event) exit(0); } -#else - cemuLog_log(LogType::Force, "unimplemented - restart on update"); +#elif BOOST_OS_LINUX + if (m_restartRequired && !m_restartFile.empty() && fs::exists(m_restartFile)) + { + const char* appimage_path = std::getenv("APPIMAGE"); + execlp(appimage_path, appimage_path, (char *)NULL); + + exit(0); + } +#elif BOOST_OS_MACOS + if (m_restartRequired) + { + const auto tmppath = fs::temp_directory_path() / L"cemu_update/Cemu.dmg"; + fs::path exePath = ActiveSettings::GetExecutablePath().parent_path(); + const auto apppath = exePath / L"update.sh"; + execlp("sh", "sh", apppath.c_str(), NULL); + + exit(0); + } #endif } diff --git a/src/gui/GeneralSettings2.cpp b/src/gui/GeneralSettings2.cpp index 27ce37fa..dab30981 100644 --- a/src/gui/GeneralSettings2.cpp +++ b/src/gui/GeneralSettings2.cpp @@ -166,9 +166,11 @@ wxPanel* GeneralSettings2::AddGeneralPage(wxNotebook* notebook) m_auto_update = new wxCheckBox(box, wxID_ANY, _("Automatically check for updates")); m_auto_update->SetToolTip(_("Automatically checks for new cemu versions on startup")); second_row->Add(m_auto_update, 0, botflag, 5); -#if BOOST_OS_LINUX || BOOST_OS_MACOS - m_auto_update->Disable(); -#endif +#if BOOST_OS_LINUX + if (!std::getenv("APPIMAGE")) { + m_auto_update->Disable(); + } +#endif second_row->AddSpacer(10); m_save_screenshot = new wxCheckBox(box, wxID_ANY, _("Save screenshot")); m_save_screenshot->SetToolTip(_("Pressing the screenshot key (F12) will save a screenshot directly to the screenshots folder")); @@ -2055,4 +2057,4 @@ wxString GeneralSettings2::GetOnlineAccountErrorMessage(OnlineAccountError error default: return "no error"; } -} \ No newline at end of file +} diff --git a/src/gui/GettingStartedDialog.cpp b/src/gui/GettingStartedDialog.cpp index 91cc3a11..bfd206b1 100644 --- a/src/gui/GettingStartedDialog.cpp +++ b/src/gui/GettingStartedDialog.cpp @@ -146,10 +146,11 @@ wxPanel* GettingStartedDialog::CreatePage2() m_update = new wxCheckBox(sizer->GetStaticBox(), wxID_ANY, _("Automatically check for updates")); option_sizer->Add(m_update, 0, wxALL, 5); -#if BOOST_OS_LINUX || BOOST_OS_MACOS - m_update->Disable(); +#if BOOST_OS_LINUX + if (!std::getenv("APPIMAGE")) { + m_update->Disable(); + } #endif - sizer->Add(option_sizer, 1, wxEXPAND, 5); page2_sizer->Add(sizer, 0, wxALL | wxEXPAND, 5); } diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index da57870c..e8103f9a 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -2292,9 +2292,11 @@ void MainWindow::RecreateMenu() // help menu wxMenu* helpMenu = new wxMenu(); m_check_update_menu = helpMenu->Append(MAINFRAME_MENU_ID_HELP_UPDATE, _("&Check for updates")); -#if BOOST_OS_LINUX || BOOST_OS_MACOS - m_check_update_menu->Enable(false); -#endif +#if BOOST_OS_LINUX + if (!std::getenv("APPIMAGE")) { + m_check_update_menu->Enable(false); + } +#endif helpMenu->Append(MAINFRAME_MENU_ID_HELP_GETTING_STARTED, _("&Getting started")); helpMenu->AppendSeparator(); helpMenu->Append(MAINFRAME_MENU_ID_HELP_ABOUT, _("&About Cemu")); diff --git a/src/resource/update.sh b/src/resource/update.sh new file mode 100755 index 00000000..5ff22160 --- /dev/null +++ b/src/resource/update.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +APP=$(cd "$(dirname "0")"/;pwd) +hdiutil attach $TMPDIR/cemu_update/cemu.dmg +cp -rf /Volumes/Cemu/Cemu.app "$APP" +hdiutil detach /Volumes/Cemu/ + +open -n -a "$APP/Cemu.app"