Removed junk updater, switched to NSIS.

This commit is contained in:
Martin Rotter 2014-08-25 07:52:48 +02:00
parent 959f4e04af
commit 89193d06cb
14 changed files with 336 additions and 714 deletions

View File

@ -69,14 +69,6 @@
# Setup basic variables.
project(rssguard)
if(WIN32 OR OS2)
# Setup "rssguard_updater" project.
project(rssguard_updater)
set(UPDATER_SUBFOLDER "updater")
set(UPDATER_EXE_NAME "rssguard_updater")
endif(WIN32 OR OS2)
set(APP_NAME "RSS Guard")
set(APP_LOW_NAME "rssguard")
set(APP_VERSION "2.0.0.0")
@ -98,6 +90,10 @@ option(USE_QT_5 "Use Qt 5 for building" OFF)
option(ENABLE_OS2_RC "Compile application icon on OS/2" OFF)
option(BUNDLE_ICON_THEMES "Equip installation with custom icon themes" ON)
if(WIN32)
option(USE_NSIS "Use NSIS generator to produce installer" OFF)
endif(WIN32)
# Set appropriate CMake policies.
if(POLICY CMP0012)
cmake_policy(SET CMP0012 NEW)
@ -118,6 +114,11 @@ message(STATUS "[${APP_LOW_NAME}] ==== Options summary ====")
message(STATUS "[${APP_LOW_NAME}] Use Qt 5 for building -> ${USE_QT_5}")
message(STATUS "[${APP_LOW_NAME}] Equip installation with custom icon themes -> ${BUNDLE_ICON_THEMES}")
message(STATUS "[${APP_LOW_NAME}] Compile application icon on OS/2 -> ${ENABLE_OS2_RC}")
if(WIN32)
message(STATUS "[${APP_LOW_NAME}] Use NSIS generator to produce installer -> ${USE_NSIS}")
endif(WIN32)
message(STATUS "[${APP_LOW_NAME}] ==== Options summary ====")
message(STATUS "")
@ -126,6 +127,9 @@ message(STATUS "[${APP_LOW_NAME}] Compilation process begins right now.")
# Setup misc options.
set(CMAKE_COLOR_MAKEFILE ON)
set(CMAKE_MODULE_PATH
${PROJECT_SOURCE_DIR}/resources/nsis
${CMAKE_MODULE_PATH})
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# Eliminate a warning when building in Windows that relates
@ -538,29 +542,6 @@ if(WIN32)
)
endif(WIN32)
# Setup source & header files for "rssguard_updater".
if(WIN32 OR OS2)
set(UPDATER_SOURCES
# QTSINGLEAPPLICATION sources.
src/qtsingleapplication/qtlocalpeer.cpp
src/qtsingleapplication/qtsingleapplication.cpp
# MAIN sources.
src/miscellaneous/iofactory.cpp
src/updater/formupdater.cpp
src/updater/main.cpp
)
set(UPDATER_HEADERS
# QTSINGLEAPPLICATION headers.
src/qtsingleapplication/qtlocalpeer.h
src/qtsingleapplication/qtsingleapplication.h
# MAIN headers.
src/updater/formupdater.h
)
endif(WIN32 OR OS2)
# Add custom icon on Mac OS X.
if(APPLE)
SET (APP_SOURCES ${APP_SOURCES} resources/macosx/rssguard.icns)
@ -596,45 +577,9 @@ include_directories (
${CMAKE_SOURCE_DIR}/src/gui
${CMAKE_SOURCE_DIR}/src/network-web
${CMAKE_SOURCE_DIR}/src/dynamic-shortcuts
${CMAKE_SOURCE_DIR}/src/updater
${CMAKE_BINARY_DIR}/src
)
# Compile "rssguard_updater" utility on supported platforms.
if(WIN32 OR OS2)
message(STATUS "[${APP_LOW_NAME}] RSS Guard updater will be compiled.")
if(${USE_QT_5})
add_executable(${UPDATER_EXE_NAME} WIN32
${UPDATER_SOURCES}
)
if(WIN32)
target_link_libraries(${UPDATER_EXE_NAME} Qt5::WinMain)
endif(WIN32)
# Use modules from Qt.
qt5_use_modules(rssguard_updater
Core
Widgets
Network
)
else(${USE_QT_5})
add_executable(${UPDATER_EXE_NAME} WIN32
${UPDATER_SOURCES}
${UPDATER_MOC}
)
# Link modules from Qt.
target_link_libraries(${UPDATER_EXE_NAME}
${QT_QTCORE_LIBRARY}
${QT_QTGUI_LIBRARY}
${QT_QTNETWORK_LIBRARY}
${QT_QTMAIN_LIBRARY}
)
endif(${USE_QT_5})
endif(WIN32 OR OS2)
# Compile "rssguard"
if(${USE_QT_5})
add_executable(${EXE_NAME} WIN32 MACOSX_BUNDLE
@ -689,24 +634,17 @@ if(WIN32 OR OS2)
RUNTIME DESTINATION ./${UPDATER_SUBFOLDER})
# Copy DLLs and other binary files for main installation and updater.
if(WIN32)
# Copy "7za" utility on Windows, OS/2 uses built-in "7za".
install(FILES resources/binaries/windows/7za/7za.exe
resources/binaries/windows/7za/7za_license.txt
if(WIN32 AND NOT ${USE_QT_5})
install(FILES ${APP_DLLS_QT4_MSVC2010}
DESTINATION ./)
install(FILES ${APP_DLLS_QT4_MSVC2010_IMAGEFORMATS}
DESTINATION ./imageformats)
install(FILES ${APP_DLLS_QT4_MSVC2010_SQLDRIVERS}
DESTINATION ./sqldrivers)
install(FILES ${APP_DLLS_QT4_MSVC2010}
DESTINATION ./${UPDATER_SUBFOLDER})
if(NOT ${USE_QT_5})
install(FILES ${APP_DLLS_QT4_MSVC2010}
DESTINATION ./)
install(FILES ${APP_DLLS_QT4_MSVC2010_IMAGEFORMATS}
DESTINATION ./imageformats)
install(FILES ${APP_DLLS_QT4_MSVC2010_SQLDRIVERS}
DESTINATION ./sqldrivers)
install(FILES ${APP_DLLS_QT4_MSVC2010}
DESTINATION ./${UPDATER_SUBFOLDER})
endif(NOT ${USE_QT_5})
endif(WIN32)
endif(WIN32 AND NOT ${USE_QT_5})
if(BUNDLE_ICON_THEMES)
install(DIRECTORY resources/graphics/icons/mini-kfaenza
@ -802,17 +740,40 @@ elseif(UNIX)
endif(WIN32 OR OS2)
# Custom target for packaging.
set(CPACK_GENERATOR "ZIP")
if(WIN32)
if(USE_NSIS)
set(CPACK_GENERATOR "NSIS")
else(USE_NSIS)
set(CPACK_GENERATOR "ZIP")
endif(USE_NSIS)
else(WIN32)
set(CPACK_GENERATOR "ZIP")
endif(WIN32)
set(CPACK_PACKAGE_NAME ${APP_LOW_NAME})
set(CPACK_PACKAGE_VERSION ${APP_VERSION})
set(CPACK_PACKAGE_VERSION_PATCH "0")
set(CPACK_PACKAGE_VENDOR ${APP_AUTHOR})
set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY ${APP_NAME})
set(CPACK_IGNORE_FILES "/resources/aur/;\\\\.psd$;/resources/deployment;/CVS/;/\\\\.svn/;/\\\\.git/;\\\\.swp$;/CMakeLists.txt.user;\\\\.#;/#;\\\\.tar.gz$;/CMakeFiles/;CMakeCache.txt;\\\\.qm$;/build/;\\\\.diff$;.DS_Store'")
set(CPACK_SOURCE_GENERATOR "TGZ")
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
set(CPACK_SOURCE_IGNORE_FILES ${CPACK_IGNORE_FILES})
set(CPACK_NSIS_INSTALLED_ICON_NAME "${APP_LOW_NAME}.ico")
set(CPACK_NSIS_HELP_LINK ${APP_URL})
set(CPACK_NSIS_URL_INFO_ABOUT ${APP_URL})
set(CPACK_NSIS_CONTACT ${APP_EMAIL})
# Load packaging facilities.
include(CPack)
# Configure file with custom definitions for NSIS.
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/resources/nsis/NSIS.definitions.nsh.in
${CMAKE_CURRENT_BINARY_DIR}/resources/nsis/NSIS.definitions.nsh
)
# make dist implementation.
add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source)

View File

@ -1,29 +0,0 @@
7-Zip Command line version
~~~~~~~~~~~~~~~~~~~~~~~~~~
License for use and distribution
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7-Zip Copyright (C) 1999-2010 Igor Pavlov.
7za.exe is distributed under the GNU LGPL license
Notes:
You can use 7-Zip on any computer, including a computer in a commercial
organization. You don't need to register or pay for 7-Zip.
GNU LGPL information
--------------------
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You can receive a copy of the GNU Lesser General Public License from
http://www.gnu.org/

View File

View File

@ -0,0 +1,27 @@
; This file is part of RSS Guard.
;
; Copyright (C) 2011-2014 by Martin Rotter <rotter.martinos@gmail.com>
;
; RSS Guard is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; RSS Guard is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with RSS Guard. If not, see <http:;www.gnu.org/licenses/>.
!define VERSION "@APP_VERSION@"
!define APP_VERSION "@APP_VERSION@"
!define APP_NAME "@APP_NAME@"
!define EXE_NAME "@EXE_NAME@"
!define README_FILE "README"
!define LICENSE_FILE "@PROJECT_SOURCE_DIR@\resources\text\COPYING_GNU_GPL"
!define MUI_ICON "@PROJECT_SOURCE_DIR@\resources\graphics\@APP_LOW_NAME@.ico"
!define MUI_UNICON "@PROJECT_SOURCE_DIR@\resources\graphics\@APP_LOW_NAME@.ico"
!define PATCH "0"

246
resources/nsis/NSIS.template.in Executable file
View File

@ -0,0 +1,246 @@
; This file is part of RSS Guard.
;
; Copyright (C) 2011-2014 by Martin Rotter <rotter.martinos@gmail.com>
;
; RSS Guard is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; RSS Guard is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with RSS Guard. If not, see <http:;www.gnu.org/licenses/>.
;--------------------------------
; Do necessary inclusions.
!include ..\..\..\resources\nsis\NSIS.definitions.nsh
!include MUI2.nsh
;--------------------------------
; Basic values definitions.
!define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@"
; Name and file.
Name "${APP_NAME}"
OutFile "@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@"
; Set custom branding text.
BrandingText "${APP_NAME}"
; Set compression.
SetCompressor /SOLID /FINAL lzma
; Default installation folder.
InstallDir "@CPACK_NSIS_INSTALL_ROOT@\${APP_NAME}"
InstallDirRegKey HKCU "Software\${APP_NAME}" "Install Directory"
; Require administrator access.
RequestExecutionLevel admin
;--------------------------------
; Interface Settings
; Show "are you sure" dialog when cancelling installation.
!define MUI_ABORTWARNING
;--------------------------------
; Pages
; Pages for installator.
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_LICENSE "${LICENSE_FILE}"
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_COMPONENTS
; Start menu folder page configuration.
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKCU"
!define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\${APP_NAME}"
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
!insertmacro MUI_PAGE_INSTFILES
; Offer user to launch the application right when it is installed.
!define MUI_FINISHPAGE_RUN "$INSTDIR\${EXE_NAME}"
!insertmacro MUI_PAGE_FINISH
; Pages for uninstallator.
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_UNPAGE_FINISH
;--------------------------------
; Languages.
!insertmacro MUI_LANGUAGE "English"
;--------------------------------
; Helper macros.
!macro ExecWaitJob _exec
StrCpy $9 0
System::Call 'kernel32::CreateIoCompletionPort(i -1,i0,i0,i0)i.r1'
${IfThen} $1 != 0 ${|} IntOp $9 $9 + 1 ${|}
System::Call 'kernel32::CreateJobObject(i0,i0)i.r2'
${IfThen} $2 != 0 ${|} IntOp $9 $9 + 1 ${|}
System::Call '*(i 0,i $1)i.r0'
System::Call 'kernel32::SetInformationJobObject(i $2,i 7,i $0,i 8)i.r3'
${IfThen} $3 != 0 ${|} IntOp $9 $9 + 1 ${|}
System::Free $0
System::Call '*(i,i,i,i)i.r0'
System::Alloc 72
pop $4
System::Call "*$4(i 72)"
System::Call 'kernel32::CreateProcess(i0,t ${_exec},i0,i0,i0,i 0x01000004,i0,i0,i $4,i $0)i.r3'
${IfThen} $3 != 0 ${|} IntOp $9 $9 + 1 ${|}
System::Free $4
System::Call "*$0(i.r3,i.r4,i,i)"
System::Free $0
System::Call 'kernel32::AssignProcessToJobObject(i $2,i $3)i.r0'
${IfThen} $0 != 0 ${|} IntOp $9 $9 + 1 ${|}
System::Call 'kernel32::ResumeThread(i $4)i.r0'
${IfThen} $0 != -1 ${|} IntOp $9 $9 + 1 ${|}
System::Call 'kernel32::CloseHandle(i $3)'
System::Call 'kernel32::CloseHandle(i $4)'
!define __ExecWaitJob__ ExecWaitJob${__LINE__}
${__ExecWaitJob__}ioportwait:
System::Call 'kernel32::GetQueuedCompletionStatus(i $1,*i.r3,*i,*i.r4,i -1)i.r0'
${IfThen} $0 = 0 ${|} StrCpy $9 0 ${|}
${IfThen} $3 != 4 ${|} goto ${__ExecWaitJob__}ioportwait ${|}
System::Call 'kernel32::CloseHandle(i $2)'
System::Call 'kernel32::CloseHandle(i $1)'
!undef __ExecWaitJob__
${IfThen} $9 < 6 ${|} MessageBox mb_iconstop `ExecWaitJob "${_exec}" failed!` ${|}
!macroend
; If you are using solid compression, files that are required before
; the actual installation should be stored first in the data block,
; because this will make your installer start faster.
!insertmacro MUI_RESERVEFILE_LANGDLL
;--------------------------------
; Sections.
; Installer sections.
Section "!Core" Core
ReadRegStr $R0 SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "UninstallString"
IfFileExists $R0 +1 NotInstalled
MessageBox MB_OK|MB_ICONEXCLAMATION "${APP_NAME} is already installed. $\n$\nClick 'OK' to uninstall it then continue with current installation." IDOK Uninstall
Uninstall:
!insertmacro ExecWaitJob '"$R0 /S"'
NotInstalled:
SetOutPath "$INSTDIR"
; Install core application files.
@CPACK_NSIS_FULL_INSTALL@
; Store installation folder.
WriteRegStr HKCU "Software\${APP_NAME}" "Install Directory" $INSTDIR
; Create uninstaller.
WriteUninstaller "$INSTDIR\Uninstall.exe"
; Create entry in Windows "Add/Remove programs" panel.
Push "DisplayName"
Push "${APP_NAME}"
Call ConditionalAddToRegisty
Push "DisplayVersion"
Push "${APP_VERSION}"
Call ConditionalAddToRegisty
Push "Publisher"
Push "@CPACK_PACKAGE_VENDOR@"
Call ConditionalAddToRegisty
Push "UninstallString"
Push "$INSTDIR\Uninstall.exe"
Call ConditionalAddToRegisty
Push "NoRepair"
Push "1"
Call ConditionalAddToRegisty
Push "NoModify"
Push "1"
Call ConditionalAddToRegisty
Push "DisplayIcon"
Push "$INSTDIR\@CPACK_NSIS_INSTALLED_ICON_NAME@"
Call ConditionalAddToRegisty
Push "HelpLink"
Push "@CPACK_NSIS_HELP_LINK@"
Call ConditionalAddToRegisty
Push "URLInfoAbout"
Push "@CPACK_NSIS_URL_INFO_ABOUT@"
Call ConditionalAddToRegisty
Push "Contact"
Push "@CPACK_NSIS_CONTACT@"
Call ConditionalAddToRegisty
SectionEnd
Section "Desktop Icon" DesktopIcon
CreateShortCut "$DESKTOP\${APP_NAME}.lnk" "$INSTDIR\${EXE_NAME}"
SectionEnd
Section "Start Menu Shortcuts" StartMenuShortcuts
CreateDirectory "$SMPROGRAMS\${APP_NAME}"
CreateShortCut "$SMPROGRAMS\${APP_NAME}\${APP_NAME}.lnk" "$INSTDIR\${EXE_NAME}"
CreateShortCut "$SMPROGRAMS\${APP_NAME}\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
SectionEnd
LangString DESC_Core ${LANG_ENGLISH} "Core installation files for ${APP_NAME}."
LangString DESC_DesktopIcon ${LANG_ENGLISH} "Desktop icon for ${APP_NAME}."
LangString DESC_QuickLaunchIcon ${LANG_ENGLISH} "Quick launch icon for ${APP_NAME}."
LangString DESC_StartMenuShortcuts ${LANG_ENGLISH} "Start Menu Shortcuts for ${APP_NAME}."
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${Core} $(DESC_Core)
!insertmacro MUI_DESCRIPTION_TEXT ${DesktopIcon} $(DESC_DesktopIcon)
!insertmacro MUI_DESCRIPTION_TEXT ${QuickLaunchIcon} $(DESC_QuickLaunchIcon)
!insertmacro MUI_DESCRIPTION_TEXT ${StartMenuShortcuts} $(DESC_StartMenuShortcuts)
!insertmacro MUI_FUNCTION_DESCRIPTION_END
; Uninstaller section.
Section "Uninstall"
; Remove core application files & directories.
@CPACK_NSIS_DELETE_FILES@
@CPACK_NSIS_DELETE_DIRECTORIES@
; Remove uninstaller.
Delete "$INSTDIR\Uninstall.exe"
; Remove entry from Windows "Add/Remove programs" panel.
DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}"
; Remove rest of installed files.
; Custom files are left intact.
RMDir "$INSTDIR"
Delete "$SMPROGRAMS\${APP_NAME}\${APP_NAME}.lnk"
Delete "$SMPROGRAMS\${APP_NAME}\Uninstall.lnk"
RMDir "$SMPROGRAMS\${APP_NAME}"
Delete "$DESKTOP\${APP_NAME}.lnk"
DeleteRegKey /ifempty HKCU "Software\${APP_NAME}"
SectionEnd
;--------------------------------
; Custom functions.
; Executed when installer starts.
Function .onInit
IntOp $0 ${SF_SELECTED} | ${SF_RO}
SectionSetFlags ${Core} $0
FunctionEnd
; Conditional saving to registry.
Function ConditionalAddToRegisty
Pop $0
Pop $1
StrCmp "$0" "" ConditionalAddToRegisty_EmptyString
WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "$1" "$0"
ConditionalAddToRegisty_EmptyString:
FunctionEnd

View File

@ -8,7 +8,7 @@ Fixed:
Added:
<ul>
<li></li>
<li>Added NSIS-based "portable" installer for Windows and restructured update process.</li>
</ul>
Changed:

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<releases>
<release version="1.9.9.9" type="feature">
<url platform="x86" os="Windows">https://bitbucket.org/skunkos/rssguard/downloads/rssguard-1.9.9.9-win32.7z</url>
<url platform="x86" os="Windows">https://bitbucket.org/skunkos/rssguard/downloads/rssguard-2.0.0.0-win32-test.exe</url>
<url platform="x86" os="OS2">https://bitbucket.org/skunkos/rssguard/downloads/rssguard-1.9.9.9-os2.7z</url>
<changes>
<![CDATA[<body>

View File

@ -35,10 +35,6 @@
#define APP_VERSION "@APP_VERSION@"
#define APP_USERAGENT QString("@APP_NAME@/@APP_VERSION@ (@APP_URL@) on @CMAKE_SYSTEM@")
#define APP_UPDATER_SUBFOLDER "updater"
#define APP_UPDATER_EXECUTABLE "rssguard_updater.exe"
#define APP_7ZA_EXECUTABLE "7za.exe"
#define RELEASES_LIST "https://bitbucket.org/skunkos/rssguard/raw/master/resources/text/UPDATES?at=master"
#define DEFAULT_LOCALE "en_GB"
#define DEFAULT_FEED_ENCODING "UTF-8"

View File

@ -148,7 +148,7 @@ void FormUpdate::saveUpdateFile(const QByteArray &file_contents) {
qDebug("Update file contents was successfuly saved.");
m_updateFilePath = output_file.fileName();
m_updateFilePath = QDir::toNativeSeparators(output_file.fileName());
m_readyToInstall = true;
}
else {
@ -199,47 +199,17 @@ void FormUpdate::startUpdate() {
// via self-update feature.
close();
// Now we need to copy updater to temporary path and launch it
// with correct arguments from there.
#if QT_VERSION >= 0x050000
QString temp_directory = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
#else
QString temp_directory = QDesktopServices::storageLocation(QDesktopServices::TempLocation);
#endif
qDebug("Preparing to launch external installer '%s'.", qPrintable(m_updateFilePath));
QString source_updater_directory = QDir::toNativeSeparators(qApp->applicationDirPath() + QDir::separator() +
APP_UPDATER_SUBFOLDER);
QString target_updater_directory = QDir::toNativeSeparators(temp_directory + QDir::separator() +
APP_UPDATER_SUBFOLDER);
if (QDir(temp_directory).exists(APP_UPDATER_SUBFOLDER)) {
IOFactory::removeDirectory(target_updater_directory);
}
IOFactory::copyDirectory(source_updater_directory, target_updater_directory);
qDebug("Preparing to launch external updater '%s'.",
qPrintable(target_updater_directory + QDir::separator() + APP_UPDATER_EXECUTABLE));
if (!QProcess::startDetached(target_updater_directory + QDir::separator() + APP_UPDATER_EXECUTABLE,
QStringList() <<
APP_VERSION <<
m_updateInfo.m_availableVersion <<
QDir::toNativeSeparators(qApp->applicationFilePath()) <<
QDir::toNativeSeparators(m_updateFilePath))) {
if (!QProcess::startDetached(m_updateFilePath)) {
qDebug("External updater was not launched due to error.");
if (SystemTrayIcon::isSystemTrayActivated()) {
qApp->trayIcon()->showMessage(tr("Cannot update application"),
tr("Cannot launch external updater. Update application manually."),
QSystemTrayIcon::Warning);
}
else {
MessageBox::show(this,
QMessageBox::Warning,
tr("Cannot update application"),
tr("Cannot launch external updater. Update application manually."));
}
qApp->showGuiMessage(tr("Cannot update application"),
tr("Cannot launch external updater. Update application manually."),
QSystemTrayIcon::Warning, this);
}
else {
qApp->quit();
}
}
else if (update_for_this_system && isSelfUpdateSupported()) {
@ -264,19 +234,10 @@ void FormUpdate::startUpdate() {
} else {
// Self-update and package are not available.
if (!WebFactory::instance()->openUrlInExternalBrowser(url_file)) {
if (SystemTrayIcon::isSystemTrayActivated()) {
qApp->trayIcon()->showMessage(tr("Cannot update application"),
tr("Cannot navigate to installation file. Check new installation downloads "
"manually on project website."),
QSystemTrayIcon::Warning);
}
else {
MessageBox::show(this,
QMessageBox::Warning,
tr("Cannot update application"),
tr("Cannot navigate to installation file. Check new installation downloads "
"manually on project website."));
}
qApp->showGuiMessage(tr("Cannot update application"),
tr("Cannot navigate to installation file. Check new installation downloads "
"manually on project website."),
QSystemTrayIcon::Warning, this);
}
}
}

View File

@ -49,6 +49,8 @@ void Downloader::downloadFile(const QString &url, int timeout, bool protected_co
request.setOriginatingObject(&originatingObject);
// Set url for this request and fire it up.
m_timer->setInterval(timeout);
request.setUrl(url);
runGetRequest(request);
}

View File

@ -1,382 +0,0 @@
// This file is part of RSS Guard.
//
// Copyright (C) 2011-2014 by Martin Rotter <rotter.martinos@gmail.com>
//
// RSS Guard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// RSS Guard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with RSS Guard. If not, see <http://www.gnu.org/licenses/>.
#include "updater/formupdater.h"
#include "definitions/definitions.h"
#include "miscellaneous/iofactory.h"
#include "qtsingleapplication/qtsingleapplication.h"
#include <QDesktopWidget>
#include <QIcon>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QTextEdit>
#include <QVBoxLayout>
#include <QKeyEvent>
#include <QProcess>
#include <QProcessEnvironment>
#include <QScrollBar>
#include <QEventLoop>
#include <QTimer>
FormUpdater *FormUpdater::s_instance;
FormUpdater::FormUpdater(QWidget *parent)
: QMainWindow(parent, Qt::Dialog | Qt::WindowStaysOnTopHint),
m_state(NoState),
m_txtOutput(new QTextEdit(this)),
m_parsedArguments(QHash<QString, QString>()) {
// Initialize singleton.
s_instance = this;
m_txtOutput->setAutoFormatting(QTextEdit::AutoNone);
m_txtOutput->setAcceptRichText(true);
m_txtOutput->setFontPointSize(10.0);
m_txtOutput->setReadOnly(true);
m_txtOutput->setFocusPolicy(Qt::StrongFocus);
m_txtOutput->setContextMenuPolicy(Qt::DefaultContextMenu);
m_txtOutput->setTextInteractionFlags(Qt::TextSelectableByMouse |
Qt::TextSelectableByKeyboard |
Qt::LinksAccessibleByKeyboard |
Qt::LinksAccessibleByMouse);
setCentralWidget(m_txtOutput);
setWindowTitle("RSS Guard updater");
setWindowIcon(QIcon(APP_ICON_PATH));
moveToCenterAndResize();
connect(this, SIGNAL(debugMessageProduced(QtMsgType,QString)),
this, SLOT(consumeDebugMessage(QtMsgType,QString)));
}
FormUpdater::~FormUpdater() {
}
void FormUpdater::startUpgrade() {
qDebug("Started...");
printHeading("Welcome to RSS Guard updater");
printText("Analyzing updater arguments.");
if (QtSingleApplication::arguments().size() != 5) {
printText("Insufficient arguments passed. Update process cannot proceed.");
printText("\nPress any key to exit updater...");
m_state = ExitError;
return;
}
// Process arguments.
saveArguments();
printArguments();
if (!printUpdateInformation() || !doPreparationCleanup() || !doExtractionAndCopying()) {
printText("\nPress any key to exit updater...");
m_state = ExitError;
return;
}
doFinalCleanup();
executeMainApplication();
printText("\nPress any key to exit updater...");
}
void FormUpdater::saveArguments() {
// Obtain parameters.
QStringList arguments = QtSingleApplication::arguments();
m_parsedArguments["updater_path"] = QDir::toNativeSeparators(qApp->applicationFilePath());
m_parsedArguments["current_version"] = arguments.at(1);
m_parsedArguments["next_version"] = arguments.at(2);
m_parsedArguments["rssguard_executable_path"] = QDir::toNativeSeparators(arguments.at(3));
m_parsedArguments["rssguard_path"] = QDir::toNativeSeparators(QFileInfo(m_parsedArguments["rssguard_executable_path"]).absolutePath());
m_parsedArguments["update_file_path"] = QDir::toNativeSeparators(arguments.at(4));
m_parsedArguments["temp_path"] = QDir::toNativeSeparators(QFileInfo(m_parsedArguments["update_file_path"]).absolutePath());
m_parsedArguments["output_temp_path"] = m_parsedArguments["temp_path"] + QDir::separator() + APP_LOW_NAME;
}
void FormUpdater::executeMainApplication() {
printText("\nApplication was upgraded without serious errors.");
if (!QProcess::startDetached(m_parsedArguments["rssguard_executable_path"])) {
printText("RSS Guard was not started successfully. Start it manually.");
m_state = ExitError;
}
else {
m_state = ExitNormal;
}
}
void FormUpdater::triggerDebugMessageConsumption(QtMsgType type, const QString &message) {
emit debugMessageProduced(type, message);
}
void FormUpdater::consumeDebugMessage(QtMsgType type, const QString &message) {
switch (type) {
case QtDebugMsg:
printText(message);
break;
case QtWarningMsg:
printText(QString("WARNING: %1").arg(message));
break;
case QtCriticalMsg:
printText(QString("CRITICAL: %1").arg(message));
break;
case QtFatalMsg:
printText(QString("FATAL: %1").arg(message));
qApp->exit(EXIT_FAILURE);
default:
break;
}
}
#if QT_VERSION >= 0x050000
void FormUpdater::debugHandler(QtMsgType type,
const QMessageLogContext &placement,
const QString &message) {
#ifndef QT_NO_DEBUG_OUTPUT
Q_UNUSED(placement)
s_instance->triggerDebugMessageConsumption(type, message);
#else
Q_UNUSED(type)
Q_UNUSED(placement)
Q_UNUSED(message)
#endif
}
#else
void FormUpdater::debugHandler(QtMsgType type, const char *message) {
#ifndef QT_NO_DEBUG_OUTPUT
s_instance->triggerDebugMessageConsumption(type, QString(message));
#else
Q_UNUSED(type)
Q_UNUSED(message)
#endif
}
#endif
void FormUpdater::printArguments() {
printNewline();
printHeading("Arguments");
printText(QString("Updater executable file:\n -> %1").arg(m_parsedArguments["updater_path"]));
printText(QString("Application executable file:\n -> %1").arg(m_parsedArguments["rssguard_executable_path"]));
printText(QString("Temp folder:\n -> %1").arg(m_parsedArguments["temp_path"]));
printText(QString("Application temp folder:\n -> %1").arg(m_parsedArguments["output_temp_path"]));
}
bool FormUpdater::printUpdateInformation() {
qApp->processEvents();
bool update_file_exists = QFile::exists(m_parsedArguments["update_file_path"]);
printNewline();
printHeading("Update information");
printText(QString("Version change:\n -> %1 --> %2").arg(m_parsedArguments["current_version"], m_parsedArguments["next_version"]));
printText(QString("Update file:\n -> %1").arg(m_parsedArguments["update_file_path"]));
printText(QString("Update file exists:\n -> %1").arg(update_file_exists ? "yes" : "no"));
printText(QString("Update file size:\n -> %1 bytes").arg(QFileInfo(m_parsedArguments["update_file_path"]).size()));
if (!update_file_exists) {
printText("\nUpdate file does not exist or is corrupted.");
}
return update_file_exists;
}
bool FormUpdater::doPreparationCleanup() {
qApp->processEvents();
printNewline();
printHeading("Initial cleanup");
// Check if main RSS Guard instance is running.
for (int i = 1; i <= 4; i++) {
qApp->processEvents();
if (i == 4) {
printText("Updater made 3 attempts to exit RSS Guard and it failed. Update cannot continue.");
return false;
}
printText(QString("Check for running instances of RSS Guard, attempt %1.").arg(i));
if (static_cast<QtSingleApplication*>(QCoreApplication::instance())->sendMessage(APP_QUIT_INSTANCE)) {
printText("The main application is running. Quitting it.");
printText("Waiting for 6000 ms for main application to finish.");
QEventLoop blocker(this);
QTimer::singleShot(6000, &blocker, SLOT(quit()));
blocker.exec();
}
else {
printText("The main application is not running.");
break;
}
}
// Remove old folders.
if (QDir(m_parsedArguments["output_temp_path"]).exists()) {
if (!IOFactory::removeDirectory(m_parsedArguments["output_temp_path"])) {
printText("Cleanup of old temporary files failed.");
return false;
}
else {
printText("Cleanup of old temporary files is done.");
}
}
if (!IOFactory::removeDirectory(m_parsedArguments["rssguard_path"],
QStringList(),
// Keep the folder with settings.
QStringList() << "data")) {
printText("Full cleanup of actual RSS Guard installation failed.");
printText("Some files from old installation may persist.");
}
return true;
}
bool FormUpdater::doExtractionAndCopying() {
qApp->processEvents();
printNewline();
printHeading("Extraction of update package");
QStringList extractor_arguments;
QProcess process_extractor(this);
extractor_arguments << "x" << "-r" << "-y" <<
QString("-o%1").arg(m_parsedArguments["output_temp_path"]) <<
m_parsedArguments["update_file_path"];
printText(QString("Calling extractor \'%1\' with these arguments:").arg(APP_7ZA_EXECUTABLE));
foreach(const QString &argument, extractor_arguments) {
printText(QString(" -> '%1'").arg(argument));
}
process_extractor.setEnvironment(QProcessEnvironment::systemEnvironment().toStringList());
process_extractor.setWorkingDirectory(qApp->applicationDirPath());
process_extractor.start(APP_7ZA_EXECUTABLE, extractor_arguments);
if (!process_extractor.waitForFinished()) {
process_extractor.close();
}
printText(process_extractor.readAll());
printText(QString("Extractor finished with exit code \'%1\'.").arg(process_extractor.exitCode()));
if (process_extractor.exitCode() != 0 || process_extractor.exitStatus() != QProcess::NormalExit) {
printText("Extraction failed due errors. Update cannot continue.");
return false;
}
// Find "rssguard" subfolder path in
QFileInfoList rssguard_temp_root = QDir(m_parsedArguments["output_temp_path"]).entryInfoList(QDir::Dirs |
QDir::NoDotAndDotDot |
QDir::NoSymLinks);
if (rssguard_temp_root.size() != 1) {
printText("Could not find root of downloaded application data.");
return false;
}
printNewline();
QString rssguard_single_temp_root = rssguard_temp_root.at(0).absoluteFilePath();
if (!IOFactory::copyDirectory(rssguard_single_temp_root, m_parsedArguments["rssguard_path"])) {
printText("Critical error appeared during copying of application files.");
return false;
}
return true;
}
bool FormUpdater::doFinalCleanup() {
bool result_file;
bool result_path;
qApp->processEvents();
printNewline();
printHeading("Final cleanup");
result_path = IOFactory::removeDirectory(m_parsedArguments["output_temp_path"]);
result_file = QFile::remove(m_parsedArguments["update_file_path"]);
printText(QString("Removing temporary files\n -> %1 -> %2\n -> %3 -> %4").arg(
m_parsedArguments["output_temp_path"], result_path ? "success" : "failure",
m_parsedArguments["update_file_path"], result_file ? "success" : "failure"));
return result_file && result_path;
}
void FormUpdater::keyPressEvent(QKeyEvent* event) {
if (event->matches(QKeySequence::Copy)) {
event->accept();
return;
}
else {
event->ignore();
}
switch (m_state) {
case NoState:
break;
case ExitNormal:
case ExitError:
qApp->quit();
break;
default:
break;
}
}
void FormUpdater::printHeading(const QString &header) {
m_txtOutput->setAlignment(Qt::AlignCenter);
m_txtOutput->append(QString("****** %1 ******\n").arg(header));
}
void FormUpdater::printText(const QString &text) {
m_txtOutput->setAlignment(Qt::AlignLeft);
m_txtOutput->append(text);
}
void FormUpdater::printNewline() {
m_txtOutput->append("");
}
void FormUpdater::moveToCenterAndResize() {
resize(600, 400);
move(qApp->desktop()->screenGeometry().center() - rect().center());
}

View File

@ -1,105 +0,0 @@
// This file is part of RSS Guard.
//
// Copyright (C) 2011-2014 by Martin Rotter <rotter.martinos@gmail.com>
//
// RSS Guard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// RSS Guard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with RSS Guard. If not, see <http://www.gnu.org/licenses/>.
#ifndef FORMUPDATER_H
#define FORMUPDATER_H
#include <QMainWindow>
#include <QtGlobal>
#include <QHash>
class QTextEdit;
class QKeyEvent;
class FormUpdater : public QMainWindow {
Q_OBJECT
public:
// Describes the state of updater.
enum UpdaterState {
NoState,
ExitNormal,
ExitError
};
// Constructors and destructors.
explicit FormUpdater(QWidget *parent = 0);
virtual ~FormUpdater();
// Prints various texts.
void printText(const QString &text);
void printNewline();
void printHeading(const QString &header);
// Starts the whole update process.
void startUpgrade();
// Various parts of update process.
void saveArguments();
void printArguments();
bool printUpdateInformation();
bool doPreparationCleanup();
bool doExtractionAndCopying();
bool doFinalCleanup();
void executeMainApplication();
// Used to trigger signal informaing about new debug message.
void triggerDebugMessageConsumption(QtMsgType type, const QString &message);
// Debug handlers for messages.
#if QT_VERSION >= 0x050000
static void debugHandler(QtMsgType type,
const QMessageLogContext &placement,
const QString &message);
#else
static void debugHandler(QtMsgType type,
const char *message);
#endif
public slots:
// Should be always called on GUI thread which is enforced
// by signal/slot auto connection.
void consumeDebugMessage(QtMsgType type, const QString &message);
signals:
// Emitted if new debug messaages is produced and should be printed.
void debugMessageProduced(QtMsgType type, QString message);
protected:
// Catch the "press any key event" to exit the updater.
void keyPressEvent(QKeyEvent *event);
// Moves the window into the center of the screen and resizes it.
void moveToCenterAndResize();
// File/directory manipulators.
bool copyDirectory(QString source, QString destination);
bool removeDirectory(const QString & directory_name,
const QStringList &exception_file_list = QStringList(),
const QStringList &exception_folder_list = QStringList());
private:
UpdaterState m_state;
QTextEdit *m_txtOutput;
QHash<QString, QString> m_parsedArguments;
static FormUpdater *s_instance;
};
#endif // FORMUPDATER_H

View File

@ -1,55 +0,0 @@
// This file is part of RSS Guard.
//
// Copyright (C) 2011-2014 by Martin Rotter <rotter.martinos@gmail.com>
//
// RSS Guard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// RSS Guard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with RSS Guard. If not, see <http://www.gnu.org/licenses/>.
#include "definitions/definitions.h"
#include "qtsingleapplication/qtsingleapplication.h"
#include "updater/formupdater.h"
#include <QTranslator>
#include <QDebug>
#include <QThread>
#include <QProcess>
#include <QFileInfo>
#include <QDir>
// Main entry point to "rssguard_updater.exe".
// It expects 4 ARGUMENTS:
// 0) - the actual path of this process,
// 1) - string with current version,
// 2) - string with future version,
// 3) - path to RSS Guard ("rssguard.exe") file,
// 4) - path to update file (stored in TEMP folder).
int main(int argc, char *argv[]) {
// Instantiate base application object.
QtSingleApplication application(APP_LOW_NAME, argc, argv);
QtSingleApplication::setQuitOnLastWindowClosed(true);
FormUpdater main_form;
// Setup debug output system.
#if QT_VERSION >= 0x050000
qInstallMessageHandler(FormUpdater::debugHandler);
#else
qInstallMsgHandler(FormUpdater::debugHandler);
#endif
main_form.show();
main_form.startUpgrade();
return application.exec();
}