[Windows,MacOS] Auto-updater refactoring. (#639)

Create and enable auto-updater for MacOS using `Sparkle=1.23`. We need
to sign our app using an `Apple Developer Key` for it to work properly,
since we are not going to sign updates with the Sparkle key.

Add all auto-updater files to `gettext`'s pot.

Use `str_split` to always get related stable version. We do not want
to check for nightly builds.

For Windows, we create the flag `-DHTTPS` to select between using an
HTTPS or HTTP URL for the auto-updater checks. We use this to keep
support for Windows XP (HTTP only) while all others should be HTTPS.

Also, use `::FreeLibrary` to allow us to remove the temporary file
that stores the `WinSparkle.dll`. Previously, we could not get it to
work with `wine`.
This commit is contained in:
Edênis Freindorfer Azevedo 2020-05-07 23:06:00 -03:00 committed by GitHub
parent 8024c87832
commit 07064c8714
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 300 additions and 129 deletions

View File

@ -176,11 +176,15 @@ option(ENABLE_FFMPEG "Enable ffmpeg A/V recording" ${FFMPEG_DEFAULT})
set(ONLINEUPDATES_DEFAULT OFF)
if(WIN32 AND (X64 OR X86))
set(ONLINEUPDATES_DEFAULT ON) # use winsparkle
if((WIN32 AND (X64 OR X86)) OR APPLE) # winsparkle/sparkle
set(ONLINEUPDATES_DEFAULT ON)
endif()
option(ENABLE_ONLINEUPDATES "Enable online update checks" ${ONLINEUPDATES_DEFAULT})
option(HTTPS "Use https URL for winsparkle" ON)
if(NOT HTTPS)
add_definitions(-DNO_HTTPS)
endif()
set(LTO_DEFAULT ON)

View File

@ -50,7 +50,7 @@ Ignore the following cmake error.
execute_process(
COMMAND ${GIT_EXECUTABLE} clone git@github.com:visualboyadvance-m/visualboyadvance-m.github.io web-data
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
# Rewrite appcast.xml.

View File

@ -784,13 +784,32 @@ set(
)
set(ALL_HDR_WX ${HDR_WX})
list(APPEND ALL_SRC_WX winsparkle-wrapper.cpp)
list(APPEND ALL_HDR_WX winsparkle-wrapper.h winsparkle-rc.h)
# make files included for gettext pot generation
list(APPEND ALL_SRC_WX autoupdater/wxmsw/autoupdater.cpp)
list(APPEND ALL_HDR_WX autoupdater/autoupdater.h)
list(APPEND ALL_SRC_WX autoupdater/wxmsw/winsparkle-wrapper.cpp)
list(APPEND ALL_HDR_WX autoupdater/wxmsw/winsparkle-wrapper.h)
list(APPEND ALL_HDR_WX autoupdater/wxmsw/winsparkle-rc.h)
if(WIN32 AND (AMD64 OR X86_32) AND ENABLE_ONLINEUPDATES)
list(APPEND SRC_WX winsparkle-wrapper.cpp)
list(APPEND HDR_WX winsparkle-wrapper.h winsparkle-rc.h)
list(APPEND SRC_WX autoupdater/wxmsw/autoupdater.cpp)
list(APPEND HDR_WX autoupdater/autoupdater.h)
list(APPEND SRC_WX autoupdater/wxmsw/winsparkle-wrapper.cpp)
list(APPEND HDR_WX autoupdater/wxmsw/winsparkle-wrapper.h)
list(APPEND HDR_WX autoupdater/wxmsw/winsparkle-rc.h)
endif()
# make files included for gettext pot generation
list(APPEND ALL_HDR_WX autoupdater/autoupdater.h)
list(APPEND ALL_SRC_WX autoupdater/macos/autoupdater.cpp)
list(APPEND ALL_SRC_WX autoupdater/macos/sparkle-wrapper.mm)
list(APPEND ALL_HDR_WX autoupdater/macos/sparkle-wrapper.h)
if(APPLE AND ENABLE_ONLINEUPDATES)
list(APPEND HDR_WX autoupdater/autoupdater.h)
list(APPEND SRC_WX autoupdater/macos/autoupdater.cpp)
list(APPEND SRC_WX autoupdater/macos/sparkle-wrapper.mm)
list(APPEND HDR_WX autoupdater/macos/sparkle-wrapper.h)
endif()
set(
@ -881,7 +900,47 @@ if(WIN32 AND (AMD64 OR X86_32) AND ENABLE_ONLINEUPDATES)
set(WINSPARKLE_DLL ${CMAKE_SOURCE_DIR}/dependencies/WinSparkle-0.6.0/Release/WinSparkle.dll)
endif()
configure_file(winsparkle-path.h.in ${CMAKE_BINARY_DIR}/winsparkle-path.h)
configure_file(autoupdater/wxmsw/winsparkle-path.h.in ${CMAKE_BINARY_DIR}/winsparkle-path.h)
endif()
if(APPLE AND ENABLE_ONLINEUPDATES)
include(FetchContent)
FetchContent_Declare(Sparkle
URL "https://github.com/sparkle-project/Sparkle/releases/download/1.23.0/Sparkle-1.23.0.tar.bz2"
URL_HASH SHA512=fa7e9736d4319bf839cd5e11177d1ddac78c38048be7e59b5c94ea76c9ffc02919dd17890295d21b7f0e35afe0ec9aba9ba36912caed6e5017420345f9f66682
)
FetchContent_MakeAvailable(Sparkle)
find_library(SPARKLE_FRAMEWORK
NAMES Sparkle
HINTS ${sparkle_SOURCE_DIR}
)
find_path(SPARKLE_INCLUDE_DIR Sparkle.h HINTS ${SPARKLE_FRAMEWORK}/Headers)
target_include_directories(
visualboyadvance-m
PRIVATE ${SPARKLE_INCLUDE_DIR}
)
set(APPCAST_URL "https://data.vba-m.com/appcast.xml")
set(CCS1 mkdir -p ${CMAKE_BINARY_DIR}/visualboyadvance-m.app/Contents/Frameworks)
# The following commands *should* be run to make sure Sparkle is not going
# to bug randomly (version=1.23)
set(CCS2 cp -a ${SPARKLE_FRAMEWORK} ${CMAKE_BINARY_DIR}/visualboyadvance-m.app/Contents/Frameworks/Sparkle.framework)
set(CCS3 defaults write ${CMAKE_BINARY_DIR}/visualboyadvance-m.app/Contents/Info.plist CFBundleVersion -string "${VERSION}")
set(CCS4 defaults write ${CMAKE_BINARY_DIR}/visualboyadvance-m.app/Contents/Info.plist SUEnableAutomaticChecks -bool YES)
#set(CCS5 defaults write ${CMAKE_BINARY_DIR}/visualboyadvance-m.app/Contents/Info.plist SUPublicEDKey -string "${PUBLIC_KEY}")
set(CCS6 defaults write ${CMAKE_BINARY_DIR}/visualboyadvance-m.app/Contents/Info.plist SUFeedURL -string "${APPCAST_URL}")
add_custom_command(TARGET visualboyadvance-m POST_BUILD
COMMAND ${CCS1}
COMMAND ${CCS2}
COMMAND ${CCS3}
COMMAND ${CCS4}
#COMMAND ${CCS5}
COMMAND ${CCS6}
)
TARGET_LINK_LIBRARIES(visualboyadvance-m ${SPARKLE_FRAMEWORK})
endif()
target_link_libraries(
@ -1139,7 +1198,7 @@ if(APPLE)
endif()
endif()
if(UPSTREAM_RELEASE AND APPLE)
if(APPLE AND (UPSTREAM_RELEASE OR ENABLE_ONLINEUPDATES))
if(NOT CMAKE_BUILD_TYPE MATCHES Debug)
find_program(STRIP_PROGRAM strip)
@ -1163,32 +1222,48 @@ if(UPSTREAM_RELEASE AND APPLE)
add_custom_command(
TARGET visualboyadvance-m
POST_BUILD
COMMAND codesign -s "Developer ID Application" --deep ./visualboyadvance-m.app
COMMAND codesign --sign "Developer ID Application" --force ./visualboyadvance-m.app
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
if(EXISTS ${CMAKE_BINARY_DIR}/visualboyadvance-m.app/Contents/Frameworks)
# Sign frameworks individually, like Xcode.
file(GLOB frameworks ${CMAKE_BINARY_DIR}/visualboyadvance-m.app/Contents/Frameworks/*)
foreach(framework ${frameworks})
message(STATUS "Signing framework: " ${framework})
add_custom_command(
TARGET visualboyadvance-m
POST_BUILD
COMMAND codesign --sign "Developer ID Application" --force ${framework}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
endforeach()
endif()
else()
message(WARNING "Set the environment variable LOGIN_KEYCHAIN_PASSWORD to your login keychain password to codesign.")
endif()
set(appzip visualboyadvance-m-Mac-${BITS}bit${ZIP_SUFFIX}.zip)
if(UPSTREAM_RELEASE)
set(appzip visualboyadvance-m-Mac-${BITS}bit${ZIP_SUFFIX}.zip)
add_custom_command(
TARGET visualboyadvance-m
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E remove ${appzip}
COMMAND ${ZIP_PROGRAM} -9r ${appzip} ./visualboyadvance-m.app
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
if(GPG_KEYS)
add_custom_command(
TARGET visualboyadvance-m
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E remove ${appzip}.asc
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/interactive-pause.cmake
COMMAND ${GPG_PROGRAM} --detach-sign -a ${appzip}
COMMAND ${CMAKE_COMMAND} -E remove ${appzip}
COMMAND ${ZIP_PROGRAM} -9r ${appzip} ./visualboyadvance-m.app
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
if(GPG_KEYS)
add_custom_command(
TARGET visualboyadvance-m
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E remove ${appzip}.asc
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/interactive-pause.cmake
COMMAND ${GPG_PROGRAM} --detach-sign -a ${appzip}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
endif()
endif()
endif()

View File

@ -0,0 +1,8 @@
#ifndef AUTOUPDATER_H
#define AUTOUPDATER_H
void initAutoupdater();
void checkUpdatesUi();
void shutdownAutoupdater();
#endif // AUTOUPDATER_H

View File

@ -0,0 +1,22 @@
#include "../autoupdater.h"
#include "../../../common/version_cpp.h"
#include "../../strutils.h"
#include "sparkle-wrapper.h"
SparkleWrapper autoupdater;
void initAutoupdater()
{
autoupdater.addAppcastURL("https://data.vba-m.com/appcast.xml");
}
void checkUpdatesUi()
{
autoupdater.checkForUpdatesUi();
}
void shutdownAutoupdater()
{
}

View File

@ -0,0 +1,17 @@
#ifndef SPARKLE_WRAPPER_H
#define SPARKLE_WRAPPER_H
class SparkleWrapper
{
public:
void checkForUpdatesUi();
void addAppcastURL(const char *appcastUrl);
SparkleWrapper();
~SparkleWrapper();
private:
class Private;
Private* d;
};
#endif // SPARKLE_WRAPPER_H

View File

@ -0,0 +1,40 @@
#include "sparkle-wrapper.h"
#include <AppKit/AppKit.h>
#include <Cocoa/Cocoa.h>
#include <Sparkle/Sparkle.h>
class SparkleWrapper::Private
{
public:
SUUpdater* updater;
};
void SparkleWrapper::addAppcastURL(const char *appcastUrl)
{
NSURL* url = [NSURL URLWithString: [NSString stringWithUTF8String: appcastUrl]];
[d->updater setFeedURL: url];
}
SparkleWrapper::SparkleWrapper()
{
d = new Private;
d->updater = [SUUpdater sharedUpdater];
[d->updater retain];
}
SparkleWrapper::~SparkleWrapper()
{
[d->updater release];
delete d;
}
void SparkleWrapper::checkForUpdatesUi()
{
[d->updater checkForUpdates: nullptr];
}

View File

@ -0,0 +1,30 @@
#include "../autoupdater.h"
#include "../../../common/version_cpp.h"
#include "../../strutils.h"
#include "winsparkle-wrapper.h"
void initAutoupdater()
{
// even if we are a nightly, only check latest stable version
wxString version = str_split(vbam_version, '-')[0];
#ifndef NO_HTTPS
win_sparkle_set_appcast_url("https://data.vba-m.com/appcast.xml");
#else
win_sparkle_set_appcast_url("http://data.vba-m.com/appcast.xml");
#endif // NO_HTTPS
win_sparkle_set_app_details(L"visualboyadvance-m", L"VisualBoyAdvance-M", version.wc_str());
win_sparkle_init();
}
void checkUpdatesUi()
{
win_sparkle_check_update_with_ui();
}
void shutdownAutoupdater()
{
win_sparkle_cleanup();
}

View File

@ -7,6 +7,7 @@
#include "winsparkle-wrapper.h"
#include "wx/msw/private.h"
WinSparkleDllWrapper *WinSparkleDllWrapper::GetInstance()
{
static WinSparkleDllWrapper instance;
@ -14,6 +15,7 @@ WinSparkleDllWrapper *WinSparkleDllWrapper::GetInstance()
return &instance;
}
WinSparkleDllWrapper::WinSparkleDllWrapper()
{
wxFile temp_file;
@ -46,32 +48,24 @@ WinSparkleDllWrapper::WinSparkleDllWrapper()
winsparkle_cleanup = reinterpret_cast<func_win_sparkle_cleanup>(winsparkle_dll->GetSymbol("win_sparkle_cleanup"));
}
WinSparkleDllWrapper::~WinSparkleDllWrapper()
{
HMODULE hMod = winsparkle_dll->Detach();
while(::FreeLibrary(hMod)) {
wxMilliSleep(50);
}
delete winsparkle_dll;
// Wait for the program to exit and release the DLL before deleting the temp file, otherwise access is denied.
char executable[] = "cmd.exe";
char cmd_switch[] = "/c";
char shell_cmd[500];
snprintf(shell_cmd, 500, "ping -n 3 127.0.0.1 > nul&set _file=%s&call del %%^_file%%", temp_file_name.mb_str().data());
char* cmd[]{
executable,
cmd_switch,
shell_cmd,
NULL
};
wxExecute(cmd, wxEXEC_ASYNC | wxEXEC_HIDE_CONSOLE);
wxRemoveFile(temp_file_name);
}
void win_sparkle_init()
{
WinSparkleDllWrapper::GetInstance()->winsparkle_init();
}
void win_sparkle_check_update_with_ui()
{
WinSparkleDllWrapper::GetInstance()->winsparkle_check_update_with_ui();

View File

@ -2714,18 +2714,14 @@ EVT_HANDLER(Customize, "Customize UI...")
}
#ifndef NO_ONLINEUPDATES
#ifdef __WXMSW__
#include "winsparkle-wrapper.h"
#endif
#endif
#include "autoupdater/autoupdater.h"
#endif // NO_ONLINEUPDATES
EVT_HANDLER(UpdateEmu, "Check for updates...")
{
#ifndef NO_ONLINEUPDATES
#ifdef __WXMSW__
win_sparkle_check_update_with_ui();
#endif
#endif
checkUpdatesUi();
#endif // NO_ONLINEUPDATES
}
EVT_HANDLER(FactoryReset, "Factory Reset...")

View File

@ -2819,7 +2819,7 @@ bool MainFrame::BindControls()
continue;
}
#endif
#if defined(NO_ONLINEUPDATES) || !defined(__WXMSW__)
#if defined(NO_ONLINEUPDATES)
if (cmdtab[i].cmd_id == XRCID("UpdateEmu"))
{
if (mi)

View File

@ -41,6 +41,10 @@ int main(int argc, char** argv)
}
#endif
#ifndef NO_ONLINEUPDATES
#include "autoupdater/autoupdater.h"
#endif // NO_ONLINEUPDATES
// Initializer for struct cmditem
cmditem new_cmditem(const wxString cmd, const wxString name, int cmd_id,
int mask_flags, wxMenuItem* mi)
@ -194,24 +198,6 @@ wxString wxvbamApp::GetAbsolutePath(wxString path)
return path;
}
#ifndef NO_ONLINEUPDATES
#include "../common/version_cpp.h"
#ifdef __WXMSW__
#include "winsparkle-wrapper.h"
#endif // __WXMSW__
static void init_check_for_updates()
{
#ifdef __WXMSW__
wxString version(vbam_version);
win_sparkle_set_appcast_url("http://data.vba-m.com/appcast.xml");
win_sparkle_set_app_details(L"visualboyadvance-m", L"VisualBoyAdvance-M", version.wc_str());
win_sparkle_init();
#endif // __WXMSW__
}
#endif // NO_ONLINEUPDATES
#ifdef __WXMSW__
#include <wx/msw/private.h>
#include <windows.h>
@ -470,9 +456,8 @@ bool wxvbamApp::OnInit()
frame->Show(true);
#ifndef NO_ONLINEUPDATES
init_check_for_updates();
initAutoupdater();
#endif
return true;
}
@ -723,8 +708,8 @@ wxvbamApp::~wxvbamApp() {
}
delete overrides;
#if defined(__WXMSW__) && !defined(NO_ONLINEUPDATES)
win_sparkle_cleanup();
#ifndef NO_ONLINEUPDATES
shutdownAutoupdater();
#endif
}

View File

@ -1,58 +1,58 @@
#pragma code_page(65001)
AAAAA_MAINICON ICON "icons/visualboyadvance-m.ico"
#include "wx/msw/wx.rc"
#include "version.h"
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
#define VER_PRODUCTVERSION VER_FILEVERSION
#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR
#ifndef NO_ONLINEUPDATES
#include "winsparkle-rc.h"
#include "winsparkle-path.h"
WINSPARKLE_DLL_RC RCDATA WINSPARKLE_DLL_PATH
#endif /* NO_ONLINEUPDATES */
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION
PRODUCTVERSION VER_PRODUCTVERSION
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "Comments", "VisualBoyAdvance-M comes with NO WARRANTY. Use it at your own risk."
VALUE "CompanyName", "http://vba-m.com/"
VALUE "FileDescription", "VisualBoyAdvance-M"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "wxvbam"
VALUE "LegalCopyright", "Copyright © 2008-2019 VisualBoyAdvance-M development team"
VALUE "OriginalFilename", "VisualBoyAdvance-M.exe"
VALUE "ProductName", "VisualBoyAdvance-M"
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#pragma code_page(65001)
AAAAA_MAINICON ICON "icons/visualboyadvance-m.ico"
#include "wx/msw/wx.rc"
#include "version.h"
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
#define VER_PRODUCTVERSION VER_FILEVERSION
#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR
#ifndef NO_ONLINEUPDATES
#include "autoupdater/wxmsw/winsparkle-rc.h"
#include "winsparkle-path.h"
WINSPARKLE_DLL_RC RCDATA WINSPARKLE_DLL_PATH
#endif /* NO_ONLINEUPDATES */
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION
PRODUCTVERSION VER_PRODUCTVERSION
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "Comments", "VisualBoyAdvance-M comes with NO WARRANTY. Use it at your own risk."
VALUE "CompanyName", "http://vba-m.com/"
VALUE "FileDescription", "VisualBoyAdvance-M"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "wxvbam"
VALUE "LegalCopyright", "Copyright © 2008-2019 VisualBoyAdvance-M development team"
VALUE "OriginalFilename", "VisualBoyAdvance-M.exe"
VALUE "ProductName", "VisualBoyAdvance-M"
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END