diff --git a/Changelog b/Changelog index de43ebec..a8235ed4 100644 --- a/Changelog +++ b/Changelog @@ -1,9 +1,22 @@ +3.1.2 +- Gain admin rights for writing MaintenanceTool config files if needed (QTIFW-1363) +- Update INSTALL file (QTIFW-1185) +- Fix initially deactivated buttons when selecting components to update (QTIFW-1320) +- Fix MaintenanceTool file write permission check on Linux and macOS (QTIFW-1324) +- Fix installer hang on Windows with empty command prompt window appearing (QTIFW-1250) +- Add IFW version information to installerbase binary on Windows (QTIFW-1397) +- Fix Mkdir undo operation fail to remove directory in Settings operation (QTIFW-1365) +- Fix IFW version information not apparent on macOS (QTIFW-1396) +- Update repository categories on server authentication request (QTIFW-1358) +- Fix recalculation of components to install in MaintenanceTool (QTIFW-694) +- Enable support for Qt 5.12. In Windows supported compiler is msvc2017 (QTIFW-1312) + 3.1.1 - Add fetch to the same pane with package categories (QTIFW-1284) - Change text in Select Components view when selection of components is not possible (QTIFW-1241) - Fix long description texts not properly shown by enabling scrolling (QTIFW-1308) - Fix install button string having a font name in French translation (QTIFW-1333) -- Fix maintenancetool size (QTIFW-1322) +- Fix maintenance tool size (QTIFW-1322) - Update Russian translation - Enable links and text selection in component description fields (QTIFW-1292) diff --git a/INSTALL b/INSTALL index e99fcf74..195f5976 100644 --- a/INSTALL +++ b/INSTALL @@ -15,32 +15,38 @@ http://code.qt.io/cgit/installer-framework/installer-framework.git/ Build a static Qt --------------------- -Building the Qt Installer Framework from sources requires Qt (version 5.5 -or newer). Supported compilers are MSVC 2013 or newer, GCC 4.7 or newer, +Building the Qt Installer Framework from sources requires Qt version 5.9.x. +Supported compilers are MSVC 2013 or newer, GCC 4.7 or newer, and Clang 3.1 or newer. If you want to ship your installer as a single file you have to build Qt and the Qt Installer Framework statically. See the Qt documentation for the prerequisites and steps to build Qt from sources. +Please read SSL Import and Export Restrictions from http://doc.qt.io/qt-5/ssl.html if +you are statically linking against OpenSSL libraries. ### Windows Recommended configuration options for Microsoft Windows: -configure -prefix %CD%\qtbase -release -static -static-runtime -target xp -accessibility -no-opengl -no-icu -no-sql-sqlite -no-qml-debug -nomake examples -nomake tests -skip qtactiveqt -skip qtenginio -skip qtlocation -skip qtmultimedia -skip qtserialport -skip qtquick1 -skip qtquickcontrols -skip qtscript -skip qtsensors -skip qtwebkit -skip qtwebsockets -skip qtxmlpatterns -skip qt3d - +configure -prefix %CD%\qtbase -release -static -static-runtime -accessibility -no-icu -no-sql-sqlite -no-qml-debug -nomake examples -nomake tests +Build Qt: +nmake (or 'mingw32-make') module-qtbase module-qtdeclarative module-qttools module-qttranslations module-qtwinextras ### Linux Recommended configuration options for Linux: -configure -prefix $PWD/qtbase -release -static -accessibility -qt-zlib -qt-libpng -qt-libjpeg -qt-xcb -qt-pcre -qt-freetype -no-glib -no-cups -no-sql-sqlite -no-qml-debug -no-opengl -no-egl -no-xinput -no-xinput2 -no-sm -no-icu -nomake examples -nomake tests -skip qtactiveqt -skip qtenginio -skip qtlocation -skip qtmultimedia -skip qtserialport -skip qtquick1 -skip qtquickcontrols -skip qtscript -skip qtsensors -skip qtwebkit -skip qtwebsockets -skip qtxmlpatterns -skip qt3d +configure -prefix $PWD/qtbase -release -static -accessibility -qt-zlib -qt-libpng -qt-libjpeg -qt-xcb -qt-pcre -no-glib -no-cups -no-sql-sqlite -no-qml-debug -no-opengl -no-egl -no-xinput2 -no-sm -no-icu -nomake examples -nomake tests -no-libudev +Build Qt: +make module-qtbase module-qtdeclarative module-qttools module-qttranslations +### macOS -### OS X +Recommended configuration options for macOS: -Recommended configuration options for OS X: - -configure -prefix $PWD/qtbase -release -static -accessibility -qt-zlib -qt-libpng -qt-libjpeg -no-cups -no-sql-sqlite -no-qml-debug -nomake examples -nomake tests -skip qtactiveqt -skip qtenginio -skip qtlocation -skip qtmultimedia -skip qtserialport -skip qtquick1 -skip qtquickcontrols -skip qtscript -skip qtsensors -skip qtwebkit -skip qtwebsockets -skip qtxmlpatterns -skip qt3d +configure -prefix $PWD/qtbase -release -static -no-securetransport -accessibility -qt-zlib -qt-libpng -qt-libjpeg -no-cups -no-sql-sqlite -no-qml-debug -nomake examples -nomake tests -no-freetype +Build Qt: +make module-qtbase module-qtdeclarative module-qttools module-qttranslations Build the Framework diff --git a/README b/README index 126d2d6d..0130bfd8 100644 --- a/README +++ b/README @@ -1,6 +1,6 @@ The Qt Installer Framework provides a set of tools and utilities to create installers for the supported desktop Qt platforms: Linux, Microsoft Windows, and -OS X. +macOS. Documentation diff --git a/dist/config/config.xml b/dist/config/config.xml index 02f979d1..1bd1bbe6 100644 --- a/dist/config/config.xml +++ b/dist/config/config.xml @@ -2,7 +2,7 @@ Qt Installer Framework Qt Installer Framework 3.2.0 - 3.2.0 + 3.2.0 Qt Project http://qt-project.org watermark.png diff --git a/dist/packages/org.qtproject.ifw.binaries/meta/package.xml b/dist/packages/org.qtproject.ifw.binaries/meta/package.xml index 36b3f63b..fd5b37e2 100644 --- a/dist/packages/org.qtproject.ifw.binaries/meta/package.xml +++ b/dist/packages/org.qtproject.ifw.binaries/meta/package.xml @@ -3,6 +3,6 @@ Qt Installer Framework Binaries Installs the binaries, examples and help files. 3.2.0 - 2019-05-27 + 2019-08-23 True diff --git a/dist/packages/org.qtproject.ifw/meta/package.xml b/dist/packages/org.qtproject.ifw/meta/package.xml index 78276cbc..f810f628 100644 --- a/dist/packages/org.qtproject.ifw/meta/package.xml +++ b/dist/packages/org.qtproject.ifw/meta/package.xml @@ -3,7 +3,7 @@ Qt Installer Framework Installs the Qt Installer Framework. 3.2.0 - 2019-05-25 + 2019-08-23 diff --git a/doc/includes/installerfw-examples-generating.qdocinc b/doc/includes/installerfw-examples-generating.qdocinc index 45ea2fc2..65ef313b 100644 --- a/doc/includes/installerfw-examples-generating.qdocinc +++ b/doc/includes/installerfw-examples-generating.qdocinc @@ -8,7 +8,7 @@ \code ..\..\bin\binarycreator.exe -c config\config.xml -p packages installer.exe \endcode - \li On Linux or OS X: + \li On Linux or macOS: \code ../../bin/binarycreator -c config/config.xml -p packages installer \endcode diff --git a/doc/installerfw-getting-started.qdoc b/doc/installerfw-getting-started.qdoc index e231e0f9..7d330013 100644 --- a/doc/installerfw-getting-started.qdoc +++ b/doc/installerfw-getting-started.qdoc @@ -65,9 +65,11 @@ If you use a statically built Qt to build the Qt Installer Framework you do not have to deliver Qt libraries, which enables you to distribute - installers as one file. + installers as one file. Please read SSL Import and Export Restrictions + from http://doc.qt.io/qt-5/ssl.html if you are statically linking against + OpenSSL libraries. - The minimum required Qt version is 5.5. + The required Qt version is 5.9.x. \section3 Configuring Qt for Windows @@ -75,24 +77,39 @@ Windows: \code - configure -prefix %CD%\qtbase -release -static -static-runtime -target xp -accessibility -no-opengl -no-icu -no-sql-sqlite -no-qml-debug -nomake examples -nomake tests -skip qtactiveqt -skip qtenginio -skip qtlocation -skip qtmultimedia -skip qtserialport -skip qtquick1 -skip qtquickcontrols -skip qtscript -skip qtsensors -skip qtwebkit -skip qtwebsockets -skip qtxmlpatterns -skip qt3d + configure -prefix %CD%\qtbase -release -static -static-runtime -accessibility -no-icu -no-sql-sqlite -no-qml-debug -nomake examples -nomake tests \endcode + Build Qt: + \code + nmake (or 'mingw32-make') module-qtbase module-qtdeclarative module-qttools module-qttranslations module-qtwinextras + \endcode + \section3 Configuring Qt for Linux We recommend that you use the following configuration options for Linux: \code - configure -prefix $PWD/qtbase -release -static -accessibility -qt-zlib -qt-libpng -qt-libjpeg -qt-xcb -qt-pcre -qt-freetype -no-glib -no-cups -no-sql-sqlite -no-qml-debug -no-opengl -no-egl -no-xinput -no-xinput2 -no-sm -no-icu -nomake examples -nomake tests -skip qtactiveqt -skip qtenginio -skip qtlocation -skip qtmultimedia -skip qtserialport -skip qtquick1 -skip qtquickcontrols -skip qtscript -skip qtsensors -skip qtwebkit -skip qtwebsockets -skip qtxmlpatterns -skip qt3d + configure -prefix $PWD/qtbase -release -static -accessibility -qt-zlib -qt-libpng -qt-libjpeg -qt-xcb -qt-pcre -no-glib -no-cups -no-sql-sqlite -no-qml-debug -no-opengl -no-egl -no-xinput2 -no-sm -no-icu -nomake examples -nomake tests -no-libudev \endcode - \section3 Configuring Qt for OS X + Build Qt: + \code + make module-qtbase module-qtdeclarative module-qttools module-qttranslations + \endcode - We recommend that you use the following configuration options for OS X: + \section3 Configuring Qt for macOS + + We recommend that you use the following configuration options for macOS: \code - configure -prefix $PWD/qtbase -release -static -accessibility -qt-zlib -qt-libpng -qt-libjpeg -no-cups -no-sql-sqlite -no-qml-debug -nomake examples -nomake tests -skip qtactiveqt -skip qtenginio -skip qtlocation -skip qtmultimedia -skip qtserialport -skip qtquick1 -skip qtquickcontrols -skip qtscript -skip qtsensors -skip qtwebkit -skip qtwebsockets -skip qtxmlpatterns -skip qt3d + configure -prefix $PWD/qtbase -release -static -no-securetransport -accessibility -qt-zlib -qt-libpng -qt-libjpeg -no-cups -no-sql-sqlite -no-qml-debug -nomake examples -nomake tests -no-freetype + \endcode + + Build Qt: + \code + make module-qtbase module-qtdeclarative module-qttools module-qttranslations \endcode \section2 Setting up Qt Installer Framework diff --git a/doc/installerfw-overview.qdoc b/doc/installerfw-overview.qdoc index ee93fcf5..9a5da194 100644 --- a/doc/installerfw-overview.qdoc +++ b/doc/installerfw-overview.qdoc @@ -37,7 +37,7 @@ create installers once, and deploy them across all the supported desktop Qt platforms without rewriting the source code. The installers will have the native look and feel on the platform where they are run: Linux, Microsoft - Windows, and OS X. + Windows, and macOS. The Qt Installer Framework tools generate installers with a set of pages that guide the users during the installation, update, or uninstallation diff --git a/doc/installerfw-using.qdoc b/doc/installerfw-using.qdoc index 178957db..30065fa5 100644 --- a/doc/installerfw-using.qdoc +++ b/doc/installerfw-using.qdoc @@ -71,7 +71,7 @@ \image ifw-user-flow-installing.png "Installation workflow" - This section uses the \e {Your Application Installer} example run on OS X + This section uses the \e {Your Application Installer} example run on macOS to illustrate the default workflow for end users. The installers have the native look and feel on each supported desktop platform, and therefore they look and feel different when run on Linux and Windows. @@ -188,7 +188,7 @@ \image ifw-user-flow-adding.png "Add components workflow" This section uses the \e {Maintenance Tool} installed by the Qt 5 installer - run on OS X as an example implementation of how end users can add components + run on macOS as an example implementation of how end users can add components after the initial installation. The Maintenance Tool contains the package manager, updater, and uninstaller. @@ -244,7 +244,7 @@ \image ifw-user-flow-removing.png "Remove components workflow" - This section uses the Qt 5 Maintenance Tool run on OS X as an example + This section uses the Qt 5 Maintenance Tool run on macOS as an example implementation of how end users can remove all or selected components. \section1 Removing All Components @@ -297,7 +297,7 @@ \image ifw-user-flow-updating.png "Updating workflow" - This section uses the Qt 5 Maintenance Tool run on OS X as an example + This section uses the Qt 5 Maintenance Tool run on macOS as an example implementation of how end users can update installed components. \section1 Starting Updater diff --git a/doc/installerfw.qdoc b/doc/installerfw.qdoc index 09c7e575..07859b0d 100644 --- a/doc/installerfw.qdoc +++ b/doc/installerfw.qdoc @@ -42,7 +42,7 @@ The Qt Installer Framework provides a set of tools and utilities to create installers for the supported desktop Qt platforms: Linux, Microsoft - Windows, and OS X. + Windows, and macOS. \note Report bugs and suggestions for the Qt Installer Framework project in the \l{https://bugreports.qt.io/browse/QTIFW}{Qt Bugtracker}. @@ -191,13 +191,13 @@ \row \li Icon \li Filename for a custom installer icon. The actual file is looked up by attaching - a '.icns' (OS X), '.ico' (Windows) or '.png' (Unix) suffix. Deprecated, + a '.icns' (macOS), '.ico' (Windows) or '.png' (Unix) suffix. Deprecated, use \c or \c instead. \row \li InstallerApplicationIcon \li Filename for a custom installer icon. The actual file is looked up by attaching - a '.icns' (OS X), '.ico' (Windows). No functionality on Unix. + a '.icns' (macOS), '.ico' (Windows). No functionality on Unix. \row \li InstallerWindowIcon \li Filename for a custom window icon in PNG format for the Installer application. @@ -430,20 +430,13 @@ component.userInterface( "MyPage" ).checkbox.checked = true; \endcode - \section2 Using Control Scripts to Add Pages - - To register a custom page, use the installer::addWizardPage() method - and the object name set in the UI file (for example, \c "MyPage"). Then - call the \c{Dynamic${ObjectName}Callback()} function (for example, - \c {DynamicMyPageCallback()}): + You can also have a callback for the page that is added. To access it, + use the object name set in the UI file (for example, \c "MyPage"). Then + create the \c{Dynamic${ObjectName}Callback} function (for example, + \c {DynamicMyPageCallback}): \code - function Controller() - { - installer.addWizardPage(component, "MyPage", QInstaller.TargetDirectory) - } - - Controller.prototype.DynamicMyPageCallback() + Component.prototype.DynamicMyPageCallback = function() { var page = gui.pageWidgetByObjectName("DynamicMyPage"); page.myButton.click, @@ -801,7 +794,7 @@ \binarycreator.exe -t \installerbase.exe -p -c \ \endcode - \li On Linux and OS X + \li On Linux and macOS \code /binarycreator -t /installerbase -p -c / @@ -819,7 +812,7 @@ \binarycreator.exe -t \installerbase.exe -p -c \ -e \endcode - \li On Linux and OS X + \li On Linux and macOS \code /binarycreator -t /installerbase -p -c / -e @@ -890,7 +883,7 @@ \row \li -s or --sign identity - \li Only available on OS X. Allows specifying a code signing identity to be + \li Only available on macOS. Allows specifying a code signing identity to be used for signing the generated app bundle. \endtable @@ -914,7 +907,7 @@ \section2 Using Icons - On OS X, if the target binary is suffixed with .app, a OS X + On macOS, if the target binary is suffixed with .app, a macOS application bundle is created. The icon that you specify in config.xml is extended with .icns and used as the icon for the created bundle. diff --git a/doc/noninteractive.qdoc b/doc/noninteractive.qdoc index 887b32ad..f532ece9 100644 --- a/doc/noninteractive.qdoc +++ b/doc/noninteractive.qdoc @@ -330,8 +330,61 @@ \row \li \c ResetComponentsButton \li Resets to already installed components. + + \row + \li \c FetchCategoryButton + \li Fetch components from a category. \endtable + \table + \header + \li Widgets + \li Brief Description + + \row + \li \c CategoryGroupBox + \li Contains checkboxes for selecting repository categories. + \endtable + + Installer Framework 3.1 introduces repository categories as a new feature. When + you use an installer that contains repository categories, you can select a category + by its display name, fetch its contents, and then select the included components for installation. + + You can fetch the components from a category as follows: + \code + Controller.prototype.ComponentSelectionPageCallback = function() + { + var page = gui.pageWidgetByObjectName("ComponentSelectionPage"); + + // if CategoryGroupBox is visible, check one of the checkboxes + // and click fetch button before selecting any components + var groupBox = gui.findChild(page, "CategoryGroupBox"); + if (groupBox) { + console.log("groupBox found"); + // findChild second argument is the display name of the checkbox + var checkBox = gui.findChild(page, "Archive"); + if (checkBox) { + console.log("checkBox found"); + console.log("checkBox name: " + checkBox.text); + if (checkBox.checked == false) { + checkBox.click(); + var fetchButton = gui.findChild(page, "FetchCategoryButton"); + if (fetchButton) { + console.log("fetchButton found"); + fetchButton.click(); + } else { + console.log("fetchButton NOT found"); + } + } + } else { + console.log("checkBox NOT found"); + } + } else { + console.log("groupBox NOT found"); + } + // you can now select components from the fetched category + } + \endcode \section2 Start Menu Directory Page @@ -430,13 +483,13 @@ Example code: \code - function Controller() + function Component() { // add page with widget \c SomePageWidget before the target directory page installer.addWizardPage(component, "SomePageWidget", QInstaller.TargetDirectory) } - Controller.prototype.DynamicSomePageWidgetCallback = function() + Component.prototype.DynamicSomePageWidgetCallback = function() { var page = gui.pageWidgetByObjectName("DynamicSomePageWidget"); page.myButton.click, //direct child of the UI file's widget diff --git a/doc/operations.qdoc b/doc/operations.qdoc index 904421be..a5346f20 100644 --- a/doc/operations.qdoc +++ b/doc/operations.qdoc @@ -130,9 +130,9 @@ \li Creates a shortcut from the file specified by \c filename to \c linkname. On Windows, this creates a .lnk file which can have - \c arguments. Furthermore, on Windows, \c filename can be + \c arguments. Furthermore, \c filename can be an HTTP or FTP URL in which case a URL shortcut is created. - On Unix, this creates a symbolic link. + The operation is currently not implemented on other platforms. \row \li CreateDesktopEntry \li "CreateDesktopEntry" \c {filename "key=value[ key2=value2[ key3=value3]]]"} @@ -243,10 +243,10 @@ \li Restarts the updater or package manager specified by \c core. \row \li Settings - \li "Settings" \c path \c method \c key \c aValue - \li Sets or removes the value \c aValue of \c key in the settings file - or registry located at \c path, depending on the value of - \c method: \c set, \c remove, \c add_array_value, and \c remove_array_value. + \li "Settings" \c path \c method \c key \c value + \li Sets or removes the \c value of \c key in the settings file located at + \c path, depending on the value of \c method: \c set, \c remove, + \c add_array_value, and \c remove_array_value. \endtable The Extract, License, and MinimumProgress operations are automatically added for matching diff --git a/doc/scripting-api/buttons.qdoc b/doc/scripting-api/buttons.qdoc index a96d6843..811bde58 100644 --- a/doc/scripting-api/buttons.qdoc +++ b/doc/scripting-api/buttons.qdoc @@ -42,13 +42,13 @@ Specifies the buttons on an installer page. \value buttons.BackButton - The \uicontrol Back button (\uicontrol {Go Back} on OS X.) + The \uicontrol Back button (\uicontrol {Go Back} on macOS.) \value buttons.NextButton - The \uicontrol Next button (\uicontrol Continue on OS X.) + The \uicontrol Next button (\uicontrol Continue on macOS.) \value buttons.CommitButton The \uicontrol Commit button. \value buttons.FinishButton - The \uicontrol Finish button (\uicontrol Done on OS X.) + The \uicontrol Finish button (\uicontrol Done on macOS.) \value buttons.CancelButton The \uicontrol Cancel button. \value buttons.HelpButton diff --git a/doc/scripting-api/qfiledialog.qdoc b/doc/scripting-api/qfiledialog.qdoc index ecce6f59..5433697c 100644 --- a/doc/scripting-api/qfiledialog.qdoc +++ b/doc/scripting-api/qfiledialog.qdoc @@ -66,6 +66,6 @@ "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)" \endcode - On Windows, and OS X, this static function will use the native file dialog + On Windows, and macOS, this static function will use the native file dialog and not a QFileDialog. */ diff --git a/doc/scripting.qdoc b/doc/scripting.qdoc index e7e398c6..68a139c4 100644 --- a/doc/scripting.qdoc +++ b/doc/scripting.qdoc @@ -265,7 +265,7 @@ \li Applications directory. For example, \c {C:\Program Files} on Windows, - \c {/opt} on Linux and \c {/Applications} on OS X. + \c {/opt} on Linux and \c {/Applications} on macOS. See also the table that lists examples of \l {Applications-directory-on-Windows} {applications directories on Windows}. diff --git a/doc/systeminfo.qdoc b/doc/systeminfo.qdoc index fde82606..5e64db48 100644 --- a/doc/systeminfo.qdoc +++ b/doc/systeminfo.qdoc @@ -58,7 +58,7 @@ kernel the installer is running on, unless the host operating system is running a form of compatibility or virtualization layer. - For Windows, Linux, and OS X this will return + For Windows, Linux, and macOS this will return \list \li "winnt" \li "linux" @@ -82,7 +82,7 @@ \endlist The release version of the operating system kernel. On Windows, it returns the version of the - NT or CE kernel. On Unix systems, including OS X, it returns the same as the \c {uname -r} + NT or CE kernel. On Unix systems, including macOS, it returns the same as the \c {uname -r} command would return. \sa QSysInfo::kernelVersion() diff --git a/doc/tutorial.qdoc b/doc/tutorial.qdoc index df53d22a..0633c94a 100644 --- a/doc/tutorial.qdoc +++ b/doc/tutorial.qdoc @@ -195,7 +195,7 @@ ..\..\bin\binarycreator.exe -c config\config.xml -p packages YourInstaller.exe \endcode - \li On Linux or OS X: + \li On Linux or macOS: \code ../../bin/binarycreator -c config/config.xml -p packages YourInstaller \endcode diff --git a/examples/doc/dynamicpage.qdoc b/examples/doc/dynamicpage.qdoc index 3dbc0d28..acbf9639 100644 --- a/examples/doc/dynamicpage.qdoc +++ b/examples/doc/dynamicpage.qdoc @@ -105,7 +105,7 @@ \code ..\..\bin\binarycreator.exe -c config\config.xml -r resources/additional.qrc -p packages installer.exe \endcode - \li On Linux or OS X: + \li On Linux or macOS: \code ../../bin/binarycreator -c config/config.xml -r resources/additional.qrc -p packages installer \endcode diff --git a/examples/doc/online.qdoc b/examples/doc/online.qdoc index b64a2d6e..90be1555 100644 --- a/examples/doc/online.qdoc +++ b/examples/doc/online.qdoc @@ -74,7 +74,7 @@ \code ..\..\bin\repogen.exe -p packages repository \endcode - \li On Linux or OS X: + \li On Linux or macOS: \code ../../bin/repogen -p packages repository \endcode @@ -114,7 +114,7 @@ \code ..\..\bin\binarycreator.exe --online-only -c config\config.xml -p packages installer.exe \endcode - \li On Linux or OS X: + \li On Linux or macOS: \code ../../bin/binarycreator --online-only -c config/config.xml -p packages installer \endcode @@ -139,7 +139,7 @@ \code ..\..\bin\repogen.exe --update-new-components -p packages_update repository \endcode - \li On Linux or OS X: + \li On Linux or macOS: \code ../../bin/repogen --update-new-components -p packages_update repository \endcode diff --git a/examples/doc/openreadme.qdoc b/examples/doc/openreadme.qdoc index 97e9a042..86a6e318 100644 --- a/examples/doc/openreadme.qdoc +++ b/examples/doc/openreadme.qdoc @@ -61,7 +61,7 @@ In installscript.qs, we use the \c Component() function to connect to the \c installationFinishedPageIsShown signal when the installation is complete and to the \c installationFinished signal when the end users click - \uicontrol Finish (\uicontrol Done on OS X): + \uicontrol Finish (\uicontrol Done on macOS): \quotefromfile openreadme/packages/or.qtproject.ifw.example.openreadme/meta/installscript.qs \skipto Component() diff --git a/examples/doc/systeminfo.qdoc b/examples/doc/systeminfo.qdoc index 027587af..11a2573c 100644 --- a/examples/doc/systeminfo.qdoc +++ b/examples/doc/systeminfo.qdoc @@ -84,9 +84,9 @@ \printto /\!validOs/ The script uses \l{systemInfo::productType}{systemInfo.productType} to differentiate - between Windows, OS X, and individual Linux distributions. + between Windows, macOS, and individual Linux distributions. - For OS X and Windows, the script checks the operating system kernel version. + For macOS and Windows, the script checks the operating system kernel version. For a mapping of kernel to operating system versions, see \l{http://en.wikipedia.org/wiki/Darwin_%28operating_system%29}{Darwin} and \l{http://en.wikipedia.org/wiki/Windows_NT}{Windows NT}. @@ -95,7 +95,7 @@ the specific distribution and version the binaries are presumably built for, the installer shows a warning in a modal dialog, but allows installation. - If the Windows or OS X version is too old, though, the script calls the \c cancelInstaller() + If the Windows or macOS version is too old, though, the script calls the \c cancelInstaller() helper function to prevent an actual installation: \printuntil /\}/ diff --git a/examples/systeminfo/packages/root/meta/installscript.qs b/examples/systeminfo/packages/root/meta/installscript.qs index 0b77b2f1..f5435b65 100644 --- a/examples/systeminfo/packages/root/meta/installscript.qs +++ b/examples/systeminfo/packages/root/meta/installscript.qs @@ -55,7 +55,7 @@ function Component() // // Check whether OS is supported. // - // For Windows and OS X we check the kernel version: + // For Windows and macOS we check the kernel version: // - Require at least Windows Vista (winnt kernel version 6.0.x) // - Require at least OS X 10.7 (Lion) (darwin kernel version 11.x) // diff --git a/examples/translations/README b/examples/translations/README index b3c20e3d..a077fe2c 100644 --- a/examples/translations/README +++ b/examples/translations/README @@ -12,4 +12,4 @@ Linux: LANGUAGE=de ./installer -On OS X and Windows you need to adapt the system settings to set German as preferred language, and then start the installer. +On macOS and Windows you need to adapt the system settings to set German as preferred language, and then start the installer. diff --git a/installerfw.pri b/installerfw.pri index b227cb70..cd1227ae 100644 --- a/installerfw.pri +++ b/installerfw.pri @@ -5,6 +5,9 @@ IFW_PRI_INCLUDED = 1 IFW_VERSION_STR = 3.2.0 IFW_VERSION = 0x030200 +IFW_VERSION_WIN32 = 3,2,0,0 + +IFW_VERSION_STR_WIN32 = $$IFW_VERSION_STR\0 IFW_REPOSITORY_FORMAT_VERSION = 1.0.0 IFW_NEWLINE = $$escape_expand(\\n\\t) @@ -123,7 +126,10 @@ isEmpty(GIT_SHA1) { DEFINES += NOMINMAX QT_NO_CAST_FROM_ASCII QT_STRICT_ITERATORS QT_USE_QSTRINGBUILDER \ "_GIT_SHA1_=$$GIT_SHA1" \ - IFW_VERSION_STR=$$IFW_VERSION_STR IFW_VERSION=$$IFW_VERSION + IFW_VERSION_STR=$$IFW_VERSION_STR \ + IFW_VERSION=$$IFW_VERSION \ + IFW_VERSION_STR_WIN32=$$IFW_VERSION_STR_WIN32 \ + IFW_VERSION_WIN32=$$IFW_VERSION_WIN32 DEFINES += IFW_REPOSITORY_FORMAT_VERSION=$$IFW_REPOSITORY_FORMAT_VERSION LIBS += -l7z diff --git a/src/libs/installer/binaryformat.cpp b/src/libs/installer/binaryformat.cpp index 9a46095c..3e7dd5a2 100644 --- a/src/libs/installer/binaryformat.cpp +++ b/src/libs/installer/binaryformat.cpp @@ -158,7 +158,7 @@ bool Resource::open() if (isOpen()) return false; - if (!m_file.open(QIODevice::ReadOnly)) { + if (!m_file.open(QIODevice::ReadOnly | QIODevice::Unbuffered)) { setErrorString(m_file.errorString()); return false; } diff --git a/src/libs/installer/componentselectionpage_p.cpp b/src/libs/installer/componentselectionpage_p.cpp index 88ea86b8..84349e4a 100644 --- a/src/libs/installer/componentselectionpage_p.cpp +++ b/src/libs/installer/componentselectionpage_p.cpp @@ -147,6 +147,10 @@ ComponentSelectionPagePrivate::ComponentSelectionPagePrivate(ComponentSelectionP m_treeViewVLayout->addWidget(m_treeView, 3); + // force a recalculation of components to install to keep the state correct + connect(q, &ComponentSelectionPage::left, + m_core, &PackageManagerCore::clearComponentsToInstallCalculated); + m_mainHLayout = new QHBoxLayout(q); m_mainHLayout->addLayout(m_treeViewVLayout, 3); m_mainHLayout->addLayout(m_descriptionVLayout, 2); diff --git a/src/libs/installer/createlocalrepositoryoperation.cpp b/src/libs/installer/createlocalrepositoryoperation.cpp index a2f7806a..0eabc8c3 100644 --- a/src/libs/installer/createlocalrepositoryoperation.cpp +++ b/src/libs/installer/createlocalrepositoryoperation.cpp @@ -38,6 +38,7 @@ #include "lib7z_facade.h" #include "packagemanagercore.h" #include "productkeycheck.h" +#include "constants.h" #include "updateoperations.h" @@ -183,6 +184,23 @@ bool CreateLocalRepositoryOperation::performOperation() } setValue(QLatin1String("createddir"), mkDirOp.value(QLatin1String("createddir"))); +#if QT_VERSION >= QT_VERSION_CHECK(5,10,0) + // Internal changes to QTemporaryFile break copying Qt resources through + // QInstaller::RemoteFileEngine. We do not register resources to be handled by + // RemoteFileEngine, instead copying using 5.9 succeeded because QFile::copy() + // creates a QTemporaryFile object internally that is handled by the remote engine. + // + // This will not work with Qt 5.10 and above as QTemporaryFile introduced a new + // rename() implementation that explicitly uses its own QTemporaryFileEngine. + // + // Fail and return early if we are working on an elevated permission directory. + if (core && !core->directoryWritable(repoPath)) { + setError(UserDefinedError); + setErrorString(tr("Creating local repository into elevated permissions " + "directory: %1 is not supported.").arg(repoPath)); + return false; + } +#endif // copy the whole meta data into local repository CopyDirectoryOperation copyDirOp(core); copyDirOp.setArguments(QStringList() << QLatin1String(":/metadata/") << repoPath); diff --git a/src/libs/installer/fileutils.cpp b/src/libs/installer/fileutils.cpp index 4347c67d..18c5f90f 100644 --- a/src/libs/installer/fileutils.cpp +++ b/src/libs/installer/fileutils.cpp @@ -286,7 +286,7 @@ void QInstaller::removeSystemGeneratedFiles(const QString &path) { if (path.isEmpty()) return; -#if defined Q_OS_OSX +#if defined Q_OS_MACOS QFile::remove(path + QLatin1String("/.DS_Store")); #elif defined Q_OS_WIN QFile::remove(path + QLatin1String("/Thumbs.db")); @@ -572,7 +572,7 @@ quint64 QInstaller::fileSize(const QFileInfo &info) bool QInstaller::isInBundle(const QString &path, QString *bundlePath) { -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS QFileInfo fi = QFileInfo(path).absoluteFilePath(); while (!fi.isRoot()) { if (fi.isBundle()) { diff --git a/src/libs/installer/messageboxhandler.cpp b/src/libs/installer/messageboxhandler.cpp index 286009e2..28e09df4 100644 --- a/src/libs/installer/messageboxhandler.cpp +++ b/src/libs/installer/messageboxhandler.cpp @@ -381,7 +381,7 @@ static QMessageBox::StandardButton showNewMessageBox(QWidget *parent, QMessageBo msgBox.setDefaultButton(button); } } -#if defined(Q_OS_OSX) +#if defined(Q_OS_MACOS) msgBox.setWindowModality(Qt::WindowModal); #endif if (msgBox.exec() == -1) diff --git a/src/libs/installer/metadatajob.cpp b/src/libs/installer/metadatajob.cpp index c69fda3d..7d7b46e7 100644 --- a/src/libs/installer/metadatajob.cpp +++ b/src/libs/installer/metadatajob.cpp @@ -326,10 +326,21 @@ void MetadataJob::xmlTaskFinished() QHash > update; update.insert(QLatin1String("replace"), qMakePair(original, replacement)); + if (s.updateRepositoryCategories(update) == Settings::UpdatesApplied) + qDebug() << "Repository categories updated."; + if (s.updateDefaultRepositories(update) == Settings::UpdatesApplied || s.updateUserRepositories(update) == Settings::UpdatesApplied) { - if (m_core->isMaintainer()) + if (m_core->isMaintainer()) { + bool gainedAdminRights = false; + if (!m_core->directoryWritable(m_core->value(scTargetDir))) { + m_core->gainAdminRights(); + gainedAdminRights = true; + } m_core->writeMaintenanceConfigFiles(); + if (gainedAdminRights) + m_core->dropAdminRights(); + } } } status = XmlDownloadRetry; @@ -716,8 +727,16 @@ MetadataJob::Status MetadataJob::parseUpdatesXml(const QList &re return XmlDownloadRetry; } } else if (s.updateDefaultRepositories(repositoryUpdates) == Settings::UpdatesApplied) { - if (m_core->isMaintainer()) + if (m_core->isMaintainer()) { + bool gainedAdminRights = false; + if (!m_core->directoryWritable(m_core->value(scTargetDir))) { + m_core->gainAdminRights(); + gainedAdminRights = true; + } m_core->writeMaintenanceConfigFiles(); + if (gainedAdminRights) + m_core->dropAdminRights(); + } m_metaFromDefaultRepositories.clear(); QFile::remove(result.target()); return XmlDownloadRetry; diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp index 4a7f4262..c154edf7 100644 --- a/src/libs/installer/packagemanagercore.cpp +++ b/src/libs/installer/packagemanagercore.cpp @@ -422,9 +422,7 @@ void PackageManagerCore::writeMaintenanceTool() d->writeMaintenanceTool(d->m_performedOperationsOld + d->m_performedOperationsCurrentSession); bool gainedAdminRights = false; - QTemporaryFile tempAdminFile(d->targetDir() - + QLatin1String("/testjsfdjlkdsjflkdsjfldsjlfds") + QString::number(qrand() % 1000)); - if (!tempAdminFile.open() || !tempAdminFile.isWritable()) { + if (!directoryWritable(d->targetDir())) { gainAdminRights(); gainedAdminRights = true; } @@ -538,6 +536,14 @@ void PackageManagerCore::componentsToInstallNeedsRecalculation() component->updateUncompressedSize(); // this is a recursive call } +/*! + \sa {installer::clearComponentsToInstallCalculated}{installer.clearComponentsToInstallCalculated} + */ +void PackageManagerCore::clearComponentsToInstallCalculated() +{ + d->m_componentsToInstallCalculated = false; +} + /*! \sa {installer::autoAcceptMessageBoxes}{installer.autoAcceptMessageBoxes} \sa autoRejectMessageBoxes(), setMessageBoxAutomaticAnswer() @@ -665,7 +671,7 @@ int PackageManagerCore::downloadNeededArchives(double partProgressSize) } /*! - Returns \c true if essential component update is found. + Returns \c true if an essential component update is found. */ bool PackageManagerCore::foundEssentialUpdate() const { @@ -673,7 +679,7 @@ bool PackageManagerCore::foundEssentialUpdate() const } /*! - Sets the value of \a foundEssentialUpdate, defaults \c true. + Sets the value of \a foundEssentialUpdate, defaults to \c true. */ void PackageManagerCore::setFoundEssentialUpdate(bool foundEssentialUpdate) { @@ -1111,8 +1117,7 @@ void PackageManagerCore::networkSettingsChanged() if (isMaintainer() ) { bool gainedAdminRights = false; - QTemporaryFile tempAdminFile(d->targetDir() + QStringLiteral("/XXXXXX")); - if (!tempAdminFile.open() || !tempAdminFile.isWritable()) { + if (!directoryWritable(d->targetDir())) { gainAdminRights(); gainedAdminRights = true; } @@ -1580,6 +1585,16 @@ Component *PackageManagerCore::componentByName(const QString &name, const QList< return nullptr; } +bool PackageManagerCore::directoryWritable(const QString &path) const +{ + return d->directoryWritable(path); +} + +bool PackageManagerCore::subdirectoriesWritable(const QString &path) const +{ + return d->subdirectoriesWritable(path); +} + /*! Returns a list of components that are marked for installation. The list can be empty. @@ -2186,7 +2201,7 @@ QString PackageManagerCore::findLibrary(const QString &name, const QStringList & #if defined(Q_OS_WIN) return findPath(QString::fromLatin1("%1.lib").arg(name), findPaths); #else -#if defined(Q_OS_OSX) +#if defined(Q_OS_MACOS) if (findPaths.isEmpty()) { findPaths.push_back(QLatin1String("/lib")); findPaths.push_back(QLatin1String("/usr/lib")); diff --git a/src/libs/installer/packagemanagercore.h b/src/libs/installer/packagemanagercore.h index 4fa2f255..f4240fde 100644 --- a/src/libs/installer/packagemanagercore.h +++ b/src/libs/installer/packagemanagercore.h @@ -121,6 +121,9 @@ public: static Component *componentByName(const QString &name, const QList &components); + bool directoryWritable(const QString &path) const; + bool subdirectoriesWritable(const QString &path) const; + bool fetchLocalPackagesTree(); LocalPackagesHash localInstalledPackages(); @@ -290,6 +293,7 @@ public Q_SLOTS: void setCompleteUninstallation(bool complete); void cancelMetaInfoJob(); void componentsToInstallNeedsRecalculation(); + void clearComponentsToInstallCalculated(); Q_SIGNALS: void aboutCalculateComponentsToInstall() const; diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp index 29c3fb03..308bfa09 100644 --- a/src/libs/installer/packagemanagercore_p.cpp +++ b/src/libs/installer/packagemanagercore_p.cpp @@ -345,6 +345,27 @@ QString PackageManagerCorePrivate::targetDir() const return m_core->value(scTargetDir); } +bool PackageManagerCorePrivate::directoryWritable(const QString &path) const +{ + QTemporaryFile tempFile(path + QStringLiteral("/tempFile") + QString::number(qrand() % 1000)); + if (!tempFile.open() || !tempFile.isWritable()) + return false; + else + return true; +} + +bool PackageManagerCorePrivate::subdirectoriesWritable(const QString &path) const +{ + // Iterate over target directory subdirectories for writing access + QDirIterator iterator(path, QDir::AllDirs | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); + while (iterator.hasNext()) { + QTemporaryFile tempFile(iterator.next() + QLatin1String("/tempFile")); + if (!tempFile.open() || !tempFile.isWritable()) + return false; + } + return true; +} + QString PackageManagerCorePrivate::configurationFileName() const { return m_core->value(scTargetConfigurationFile, QLatin1String("components.xml")); @@ -569,7 +590,7 @@ void PackageManagerCorePrivate::initialize(const QHash ¶ms #endif if (!m_core->isInstaller()) { -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS readMaintenanceConfigFiles(QCoreApplication::applicationDirPath() + QLatin1String("/../../..")); #else readMaintenanceConfigFiles(QCoreApplication::applicationDirPath()); @@ -697,7 +718,7 @@ Operation *PackageManagerCorePrivate::takeOwnedOperation(Operation *operation) QString PackageManagerCorePrivate::maintenanceToolName() const { QString filename = m_data.settings().maintenanceToolName(); -#if defined(Q_OS_OSX) +#if defined(Q_OS_MACOS) if (QInstaller::isInBundle(QCoreApplication::applicationDirPath())) filename += QLatin1String(".app/Contents/MacOS/") + filename; #elif defined(Q_OS_WIN) @@ -1013,7 +1034,7 @@ void PackageManagerCorePrivate::writeMaintenanceToolBinary(QFile *const input, q qDebug() << "Writing maintenance tool:" << maintenanceToolRenamedName; ProgressCoordinator::instance()->emitLabelAndDetailTextChanged(tr("Writing maintenance tool.")); - QTemporaryFile out; + QFile out(generateTemporaryFileName()); QInstaller::openForWrite(&out); // throws an exception in case of error if (!input->seek(0)) @@ -1023,7 +1044,7 @@ void PackageManagerCorePrivate::writeMaintenanceToolBinary(QFile *const input, q if (writeBinaryLayout) { QDir resourcePath(QFileInfo(maintenanceToolRenamedName).dir()); -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS if (!resourcePath.path().endsWith(QLatin1String("Contents/MacOS"))) throw Error(tr("Maintenance tool is not a bundle")); resourcePath.cdUp(); @@ -1031,7 +1052,7 @@ void PackageManagerCorePrivate::writeMaintenanceToolBinary(QFile *const input, q #endif // It's a bit odd to have only the magic in the data file, but this simplifies // other code a lot (since installers don't have any appended data either) - QTemporaryFile dataOut; + QFile dataOut(generateTemporaryFileName()); QInstaller::openForWrite(&dataOut); QInstaller::appendInt64(&dataOut, 0); // operations start QInstaller::appendInt64(&dataOut, 0); // operations end @@ -1049,10 +1070,9 @@ void PackageManagerCorePrivate::writeMaintenanceToolBinary(QFile *const input, q } if (!dataOut.rename(resourcePath.filePath(QLatin1String("installer.dat")))) { - throw Error(tr("Cannot write maintenance tool data to %1: %2").arg(out.fileName(), - out.errorString())); + throw Error(tr("Cannot write maintenance tool data to %1: %2").arg(dataOut.fileName(), + dataOut.errorString())); } - dataOut.setAutoRemove(false); dataOut.setPermissions(dataOut.permissions() | QFile::WriteUser | QFile::ReadGroup | QFile::ReadOther); } @@ -1077,6 +1097,11 @@ void PackageManagerCorePrivate::writeMaintenanceToolBinary(QFile *const input, q } else { qDebug() << "Failed to write permissions for maintenance tool."; } + + if (out.exists() && !out.remove()) { + qWarning() << tr("Cannot remove temporary data file \"%1\": %2") + .arg(out.fileName(), out.errorString()); + } } void PackageManagerCorePrivate::writeMaintenanceToolBinaryData(QFileDevice *output, QFile *const input, @@ -1144,16 +1169,14 @@ void PackageManagerCorePrivate::writeMaintenanceToolBinaryData(QFileDevice *outp void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOperations) { bool gainedAdminRights = false; - QTemporaryFile tempAdminFile(targetDir() + QLatin1String("/testjsfdjlkdsjflkdsjfldsjlfds") - + QString::number(qrand() % 1000)); - if (!tempAdminFile.open() || !tempAdminFile.isWritable()) { + if (!directoryWritable(targetDir())) { m_core->gainAdminRights(); gainedAdminRights = true; } const QString targetAppDirPath = QFileInfo(maintenanceToolName()).path(); if (!QDir().exists(targetAppDirPath)) { - // create the directory containing the maintenance tool (like a bundle structure on OS X...) + // create the directory containing the maintenance tool (like a bundle structure on macOS...) Operation *op = createOwnedOperation(QLatin1String("Mkdir")); op->setArguments(QStringList() << targetAppDirPath); performOperationThreaded(op, Backup); @@ -1161,7 +1184,7 @@ void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOper performedOperations.append(takeOwnedOperation(op)); } -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS // if it is a bundle, we need some stuff in it... const QString sourceAppDirPath = QCoreApplication::applicationDirPath(); if (isInstaller() && QInstaller::isInBundle(sourceAppDirPath)) { @@ -1321,7 +1344,7 @@ void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOper // On Mac data is always in a separate file so that the binary can be signed. // On other platforms data is in separate file only after install so that the // maintenancetool sign does not break. -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS QDir dataPath(QFileInfo(binaryName).dir()); dataPath.cdUp(); dataPath.cd(QLatin1String("Resources")); @@ -1336,7 +1359,7 @@ void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOper newBinaryWritten = true; QFile tmp(binaryName); QInstaller::openForRead(&tmp); -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS writeMaintenanceToolBinary(&tmp, tmp.size(), true); #else writeMaintenanceToolBinary(&tmp, layout.endOfBinaryContent - layout.binaryContentSize, true); @@ -1348,7 +1371,7 @@ void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOper m_core->setValue(QLatin1String("installedOperationAreSorted"), QLatin1String("true")); try { - QTemporaryFile file; + QFile file(generateTemporaryFileName()); QInstaller::openForWrite(&file); writeMaintenanceToolBinaryData(&file, &input, performedOperations, layout); QInstaller::appendInt64(&file, BinaryContent::MagicCookieDat); @@ -1363,7 +1386,6 @@ void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOper throw Error(tr("Cannot write maintenance tool binary data to %1: %2") .arg(file.fileName(), file.errorString())); } - file.setAutoRemove(false); file.setPermissions(file.permissions() | QFile::WriteUser | QFile::ReadGroup | QFile::ReadOther); } catch (const Error &/*error*/) { @@ -1455,8 +1477,7 @@ bool PackageManagerCorePrivate::runInstaller() } } } else if (QDir(target).exists()) { - QTemporaryFile tempAdminFile(target + QLatin1String("/adminrights")); - if (!tempAdminFile.open() || !tempAdminFile.isWritable()) + if (!directoryWritable(targetDir())) adminRightsGained = m_core->gainAdminRights(); } @@ -1536,8 +1557,8 @@ bool PackageManagerCorePrivate::runInstaller() Operation *createRepo = createOwnedOperation(QLatin1String("CreateLocalRepository")); if (createRepo) { QString binaryFile = QCoreApplication::applicationFilePath(); -#ifdef Q_OS_OSX - // The installer binary on OSX does not contain the binary content, it's put into +#ifdef Q_OS_MACOS + // The installer binary on macOS does not contain the binary content, it's put into // the resources folder as separate file. Adjust the actual binary path. No error // checking here since we will fail later while reading the binary content. QDir resourcePath(QFileInfo(binaryFile).dir()); @@ -1622,10 +1643,16 @@ bool PackageManagerCorePrivate::runPackageUpdater() //to have some progress for the cleanup/write component.xml step ProgressCoordinator::instance()->addReservePercentagePoints(1); +#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS) // check if we need admin rights and ask before the action happens - if (!QTemporaryFile(targetDir() + QStringLiteral("/XXXXXX")).open()) + // on Linux and macOS also check target directory subdirectories + if (!directoryWritable(targetDir()) || !subdirectoriesWritable(targetDir())) adminRightsGained = m_core->gainAdminRights(); - +#else + // check if we need admin rights and ask before the action happens + if (!directoryWritable(targetDir())) + adminRightsGained = m_core->gainAdminRights(); +#endif const QList componentsToInstall = m_core->orderedComponentsToInstall(); qDebug() << "Install size:" << componentsToInstall.size() << "components"; @@ -1792,8 +1819,7 @@ bool PackageManagerCorePrivate::runUninstaller() setStatus(PackageManagerCore::Running); // check if we need to run elevated and ask before the action happens - QTemporaryFile tempAdminFile(targetDir() + QLatin1String("/adminrights")); - if (!tempAdminFile.open() || !tempAdminFile.isWritable()) + if (!directoryWritable(targetDir())) adminRightsGained = m_core->gainAdminRights(); OperationList undoOperations = m_performedOperationsOld; @@ -2005,7 +2031,7 @@ void PackageManagerCorePrivate::deleteMaintenanceTool() // every other platform has no problem if we just delete ourselves now QFile maintenanceTool(QFileInfo(installerBinaryPath()).absoluteFilePath()); maintenanceTool.remove(); -# ifdef Q_OS_OSX +# ifdef Q_OS_MACOS if (QInstaller::isInBundle(installerBinaryPath())) { const QLatin1String cdUp("/../../.."); removeDirectoryThreaded(QFileInfo(installerBinaryPath() + cdUp).absoluteFilePath()); diff --git a/src/libs/installer/packagemanagercore_p.h b/src/libs/installer/packagemanagercore_p.h index e0817c57..3e8f831a 100644 --- a/src/libs/installer/packagemanagercore_p.h +++ b/src/libs/installer/packagemanagercore_p.h @@ -92,6 +92,9 @@ public: QString targetDir() const; QString registerPath(); + bool directoryWritable(const QString &path) const; + bool subdirectoriesWritable(const QString &path) const; + QString maintenanceToolName() const; QString installerBinaryPath() const; diff --git a/src/libs/installer/packagemanagercoredata.cpp b/src/libs/installer/packagemanagercoredata.cpp index 41c6f111..599352fb 100644 --- a/src/libs/installer/packagemanagercoredata.cpp +++ b/src/libs/installer/packagemanagercoredata.cpp @@ -57,7 +57,7 @@ PackageManagerCoreData::PackageManagerCoreData(const QHash &va #ifdef Q_OS_WIN m_variables.insert(QLatin1String("os"), QLatin1String("win")); -#elif defined(Q_OS_OSX) +#elif defined(Q_OS_MACOS) m_variables.insert(QLatin1String("os"), QLatin1String("mac")); #elif defined(Q_OS_LINUX) m_variables.insert(QLatin1String("os"), QLatin1String("x11")); @@ -110,10 +110,8 @@ void PackageManagerCoreData::setDynamicPredefinedVariables() TCHAR buffer[MAX_PATH + 1] = { 0 }; SHGetFolderPath(nullptr, CSIDL_PROGRAM_FILES, nullptr, 0, buffer); dir = QString::fromWCharArray(buffer); -#elif defined (Q_OS_OSX) - dir = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation).value(1); - if (dir.isEmpty()) - dir = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation).value(0); +#elif defined (Q_OS_MACOS) + dir = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation).value(0); #endif m_variables.insert(QLatin1String("ApplicationsDir"), dir); diff --git a/src/libs/installer/packagemanagergui.cpp b/src/libs/installer/packagemanagergui.cpp index db1b99d3..934570ae 100644 --- a/src/libs/installer/packagemanagergui.cpp +++ b/src/libs/installer/packagemanagergui.cpp @@ -305,7 +305,7 @@ PackageManagerGui::PackageManagerGui(PackageManagerCore *core, QWidget *parent) setWindowTitle(tr("Maintain %1").arg(m_core->value(scTitle))); setWindowFlags(windowFlags() &~ Qt::WindowContextHelpButtonHint); -#ifndef Q_OS_OSX +#ifndef Q_OS_MACOS setWindowIcon(QIcon(m_core->settings().installerWindowIcon())); #else setPixmap(QWizard::BackgroundPixmap, m_core->settings().background()); @@ -408,7 +408,7 @@ PackageManagerGui::~PackageManagerGui() \list \li \c Classic - Classic UI style for Windows 7 and earlier. \li \c Modern - Modern UI style for Windows 8. - \li \c Mac - UI style for OS X. + \li \c Mac - UI style for macOS. \li \c Aero - Aero Peek for Windows 7. \endlist */ @@ -1543,7 +1543,7 @@ void IntroductionPage::setErrorMessage(const QString &error) { QPalette palette; const PackageManagerCore::Status s = packageManagerCore()->status(); - if (s == PackageManagerCore::Failure || s == PackageManagerCore::Failure) { + if (s == PackageManagerCore::Failure) { palette.setColor(QPalette::WindowText, Qt::red); } else { palette.setColor(QPalette::WindowText, palette.color(QPalette::WindowText)); @@ -1911,6 +1911,11 @@ void ComponentSelectionPage::entering() setColoredSubTitle(tr(strings[index])); d->updateTreeView(); + + // check component model state so we can enable needed component selection buttons + if (core->isUpdater()) + d->onModelStateChanged(d->m_currentModel->checkedState()); + setModified(isComplete()); if (core->settings().repositoryCategories().count() > 0 && !core->isOfflineOnly() && !core->isUpdater()) { @@ -2173,7 +2178,7 @@ bool TargetDirectoryPage::validatePage() const QFileInfo fi(targetDir); if (fi.isDir()) { QString fileName = packageManagerCore()->settings().maintenanceToolName(); -#if defined(Q_OS_OSX) +#if defined(Q_OS_MACOS) if (QInstaller::isInBundle(QCoreApplication::applicationDirPath())) fileName += QLatin1String(".app/Contents/MacOS/") + fileName; #elif defined(Q_OS_WIN) @@ -2844,7 +2849,7 @@ void FinishedPage::entering() } if (packageManagerCore()->isMaintainer()) { -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS gui()->setOption(QWizard::NoCancelButton, false); #endif if (QAbstractButton *cancel = gui()->button(QWizard::CancelButton)) { @@ -2908,7 +2913,7 @@ void FinishedPage::entering() */ void FinishedPage::leaving() { -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS gui()->setOption(QWizard::NoCancelButton, true); #endif diff --git a/src/libs/installer/remoteclient.cpp b/src/libs/installer/remoteclient.cpp index e208620c..ad1e5ecf 100644 --- a/src/libs/installer/remoteclient.cpp +++ b/src/libs/installer/remoteclient.cpp @@ -29,6 +29,8 @@ #include "remoteclient.h" #include "remoteclient_p.h" +#include + namespace QInstaller { RemoteClient *RemoteClient::s_instance = nullptr; @@ -61,6 +63,18 @@ QString RemoteClient::authorizationKey() const return d->m_key; } +QString RemoteClient::socketPathName(const QString &socketName) const +{ + QString socketPathName; + if (socketName.startsWith(QLatin1Char('/'))) { + socketPathName = socketName; + } else { + socketPathName = QDir::tempPath(); + socketPathName += QLatin1Char('/') + socketName; + } + return socketPathName; +} + /*! Initializes the client with \a socketName, with the \a key the client sends to authenticate with the server, \a mode and \a startAs. @@ -69,7 +83,17 @@ void RemoteClient::init(const QString &socketName, const QString &key, Protocol: Protocol::StartAs startAs) { Q_D(RemoteClient); + + // Since Qt 5.12.0, we should determince the full socket path on Unix + // platforms before calling QLocalSocketPrivate::_q_connectToSocket(). + // Otherwise the new canonical implementation of QDir::tempPath() + // presents unintended usage of RemoteFileEngine. + +#if QT_VERSION >= QT_VERSION_CHECK(5,12,0) && defined(Q_OS_UNIX) + d->init(socketPathName(socketName), key, mode, startAs); +#else d->init(socketName, key, mode, startAs); +#endif } void RemoteClient::setAuthorizationFallbackDisabled(bool disabled) diff --git a/src/libs/installer/remoteclient.h b/src/libs/installer/remoteclient.h index c2090bf9..419acccf 100644 --- a/src/libs/installer/remoteclient.h +++ b/src/libs/installer/remoteclient.h @@ -54,6 +54,7 @@ public: QString socketName() const; QString authorizationKey() const; + QString socketPathName(const QString &socketName) const; bool isActive() const; void setActive(bool active); diff --git a/src/libs/installer/remotefileengine.cpp b/src/libs/installer/remotefileengine.cpp index 05f4ec21..3c54d1e2 100644 --- a/src/libs/installer/remotefileengine.cpp +++ b/src/libs/installer/remotefileengine.cpp @@ -324,9 +324,9 @@ bool RemoteFileEngine::open(QIODevice::OpenMode mode) { if (connectToServer()) { return callRemoteMethod(QString::fromLatin1(Protocol::QAbstractFileEngineOpen), - static_cast(mode)); + static_cast(mode | QIODevice::Unbuffered)); } - return m_fileEngine.open(mode); + return m_fileEngine.open(mode | QIODevice::Unbuffered); } /*! diff --git a/src/libs/installer/remoteserver.cpp b/src/libs/installer/remoteserver.cpp index 9d178ca0..66cfefeb 100644 --- a/src/libs/installer/remoteserver.cpp +++ b/src/libs/installer/remoteserver.cpp @@ -65,7 +65,7 @@ void RemoteServer::start() if (d->m_localServer) return; -#if defined(Q_OS_UNIX) && !defined(Q_OS_OSX) +#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) // avoid writing to stderr: // the parent process has redirected stderr to a pipe to work with sudo, // but is not reading anymore -> writing to stderr will block after a while. @@ -93,7 +93,17 @@ void RemoteServer::start() void RemoteServer::init(const QString &socketName, const QString &key, Protocol::Mode mode) { Q_D(RemoteServer); + + // Since Qt 5.12.0, we should determince the full socket path on Unix + // platforms before calling QLocalSocketPrivate::_q_connectToSocket(). + // Otherwise the new canonical implementation of QDir::tempPath() + // presents unintended usage of RemoteFileEngine. + +#if QT_VERSION >= QT_VERSION_CHECK(5,12,0) && defined(Q_OS_UNIX) + d->m_socketName = socketPathName(socketName); +#else d->m_socketName = socketName; +#endif d->m_key = key; d->m_mode = mode; } @@ -116,6 +126,18 @@ QString RemoteServer::authorizationKey() const return d->m_key; } +QString RemoteServer::socketPathName(const QString &socketName) const +{ + QString socketPathName; + if (socketName.startsWith(QLatin1Char('/'))) { + socketPathName = socketName; + } else { + socketPathName = QDir::tempPath(); + socketPathName += QLatin1Char('/') + socketName; + } + return socketPathName; +} + /*! Restarts the watchdog that tries to kill the server. */ diff --git a/src/libs/installer/remoteserver.h b/src/libs/installer/remoteserver.h index e32bcf14..aa69baa5 100644 --- a/src/libs/installer/remoteserver.h +++ b/src/libs/installer/remoteserver.h @@ -53,6 +53,7 @@ public: QString socketName() const; QString authorizationKey() const; + QString socketPathName(const QString &socketName) const; private slots: void restartWatchdog(); diff --git a/src/libs/installer/remoteserverconnection.cpp b/src/libs/installer/remoteserverconnection.cpp index 5a47bc47..b188e694 100644 --- a/src/libs/installer/remoteserverconnection.cpp +++ b/src/libs/installer/remoteserverconnection.cpp @@ -382,7 +382,14 @@ void RemoteServerConnection::handleQFSFileEngine(QIODevice *socket, const QStrin } else if (command == QLatin1String(Protocol::QAbstractFileEngineCopy)) { QString newName; data >>newName; +#ifdef Q_OS_LINUX + // QFileSystemEngine::copyFile() is currently unimplemented on Linux, + // copy using QFile instead of directly with QFSFileEngine. + QFile file(m_engine->fileName(QAbstractFileEngine::AbsoluteName)); + sendData(socket, file.copy(newName)); +#else sendData(socket, m_engine->copy(newName)); +#endif } else if (command == QLatin1String(Protocol::QAbstractFileEngineEntryList)) { qint32 filters; QStringList filterNames; diff --git a/src/libs/installer/repository.cpp b/src/libs/installer/repository.cpp index a165b861..e186073c 100644 --- a/src/libs/installer/repository.cpp +++ b/src/libs/installer/repository.cpp @@ -208,7 +208,7 @@ QString Repository::categoryname() const } /*! - Sets the category name to \a categoryname if the repository belongs to an category. + Sets the category name to \a categoryname if the repository belongs to a category. */ void Repository::setCategoryName(const QString &categoryname) { diff --git a/src/libs/installer/repositorycategory.cpp b/src/libs/installer/repositorycategory.cpp index 42fb41c9..ce06480c 100644 --- a/src/libs/installer/repositorycategory.cpp +++ b/src/libs/installer/repositorycategory.cpp @@ -28,6 +28,7 @@ #include "repositorycategory.h" #include "filedownloaderfactory.h" +#include "constants.h" #include #include @@ -102,16 +103,20 @@ void RepositoryCategory::setTooltip(const QString &tooltip) */ QSet RepositoryCategory::repositories() const { - return variantListToSet(m_data.values(QLatin1String("Repositories"))); + return variantListToSet(m_data.values(scRepositories)); } /*! - Inserts a set of \a repositories to the category. + Inserts a set of \a repositories to the category. Removes old \a repositories + if \a replace is set to \c true. */ -void RepositoryCategory::setRepositories(const QSet repositories) +void RepositoryCategory::setRepositories(const QSet repositories, const bool replace) { + if (replace) + m_data.remove(scRepositories); + foreach (const Repository &repository, repositories) - m_data.insertMulti(QLatin1String("Repositories"), QVariant().fromValue(repository)); + m_data.insertMulti(scRepositories, QVariant().fromValue(repository)); } /*! @@ -119,7 +124,7 @@ void RepositoryCategory::setRepositories(const QSet repositories) */ void RepositoryCategory::addRepository(const Repository repository) { - m_data.insertMulti(QLatin1String("Repositories"), QVariant().fromValue(repository)); + m_data.insertMulti(scRepositories, QVariant().fromValue(repository)); } /*! diff --git a/src/libs/installer/repositorycategory.h b/src/libs/installer/repositorycategory.h index 98d5df7b..1996103a 100644 --- a/src/libs/installer/repositorycategory.h +++ b/src/libs/installer/repositorycategory.h @@ -54,7 +54,7 @@ public: void setTooltip(const QString &tooltip); QSet repositories() const; - void setRepositories(const QSet repositories); + void setRepositories(const QSet repositories, const bool replace = false); void addRepository(const Repository repository); bool isEnabled() const; diff --git a/src/libs/installer/settings.cpp b/src/libs/installer/settings.cpp index e0c9a397..3aa0baf1 100644 --- a/src/libs/installer/settings.cpp +++ b/src/libs/installer/settings.cpp @@ -472,7 +472,7 @@ QString Settings::installerWindowIcon() const QString Settings::systemIconSuffix() const { -#if defined(Q_OS_OSX) +#if defined(Q_OS_MACOS) return QLatin1String(".icns"); #elif defined(Q_OS_WIN) return QLatin1String(".ico"); @@ -616,12 +616,46 @@ void Settings::addDefaultRepositories(const QSet &repositories) d->m_data.insertMulti(scRepositories, QVariant().fromValue(repository)); } +void Settings::setRepositoryCategories(const QSet &repositories) +{ + d->m_data.remove(scRepositoryCategories); + addRepositoryCategories(repositories); +} + void Settings::addRepositoryCategories(const QSet &repositories) { foreach (const RepositoryCategory &repository, repositories) d->m_data.insertMulti(scRepositoryCategories, QVariant().fromValue(repository)); } +Settings::Update Settings::updateRepositoryCategories(const RepoHash &updates) +{ + if (updates.isEmpty()) + return Settings::NoUpdatesApplied; + + QSet categories = repositoryCategories(); + QList categoriesList = categories.values(); + QPair updateValues = updates.value(QLatin1String("replace")); + + bool update = false; + + foreach (RepositoryCategory category, categoriesList) { + QSet repositories = category.repositories(); + if (repositories.contains(updateValues.first)) { + update = true; + repositories.remove(updateValues.first); + repositories.insert(updateValues.second); + category.setRepositories(repositories, true); + categoriesList.replace(categoriesList.indexOf(category), category); + } + } + if (update) { + categories = categoriesList.toSet(); + setRepositoryCategories(categories); + } + return update ? Settings::UpdatesApplied : Settings::NoUpdatesApplied; +} + static bool apply(const RepoHash &updates, QHash *reposToUpdate) { bool update = false; diff --git a/src/libs/installer/settings.h b/src/libs/installer/settings.h index 55b94d74..fff2324f 100644 --- a/src/libs/installer/settings.h +++ b/src/libs/installer/settings.h @@ -115,13 +115,16 @@ public: QSet repositories() const; QSet defaultRepositories() const; - QSet repositoryCategories() const; - QMap organizedRepositoryCategories() const; void setDefaultRepositories(const QSet &repositories); void addDefaultRepositories(const QSet &repositories); - void addRepositoryCategories(const QSet &repositories); Settings::Update updateDefaultRepositories(const RepoHash &updates); + QSet repositoryCategories() const; + QMap organizedRepositoryCategories() const; + void setRepositoryCategories(const QSet &repositories); + void addRepositoryCategories(const QSet &repositories); + Settings::Update updateRepositoryCategories(const RepoHash &updates); + QSet temporaryRepositories() const; void setTemporaryRepositories(const QSet &repositories, bool replace); void addTemporaryRepositories(const QSet &repositories, bool replace); diff --git a/src/libs/installer/settingsoperation.cpp b/src/libs/installer/settingsoperation.cpp index e6d88b71..ccded868 100644 --- a/src/libs/installer/settingsoperation.cpp +++ b/src/libs/installer/settingsoperation.cpp @@ -180,7 +180,7 @@ bool SettingsOperation::undoOperation() if (!settingsFile.remove()) qWarning().noquote() << settingsFile.errorString(); if (!value(QLatin1String("createddir")).toString().isEmpty()) { - KDUpdater::MkdirOperation mkDirOperation; + KDUpdater::MkdirOperation mkDirOperation(packageManager()); mkDirOperation.setArguments(QStringList() << QFileInfo(path).absolutePath()); mkDirOperation.setValue(QLatin1String("createddir"), value(QLatin1String("createddir"))); diff --git a/src/libs/installer/systeminfo.cpp b/src/libs/installer/systeminfo.cpp index eb4e9cde..6a1976c4 100644 --- a/src/libs/installer/systeminfo.cpp +++ b/src/libs/installer/systeminfo.cpp @@ -76,7 +76,7 @@ QString SystemInfo::currentCpuArchitecture() const kernel the installer is running on, unless the host operating system is running a form of compatibility or virtualization layer. - For Windows, Linux, and OS X this will return: + For Windows, Linux, and macOS this will return: \list \li "winnt" \li "linux" @@ -96,7 +96,7 @@ QString SystemInfo::kernelType() const \property SystemInfo::kernelVersion The release version of the operating system kernel. On Windows, it returns the version of the - NT or CE kernel. On Unix systems, including OS X, it returns the same as the \c {uname -r} + NT or CE kernel. On Unix systems, including macOS, it returns the same as the \c {uname -r} command would return. Example values are: diff --git a/src/libs/kdtools/updateoperation.cpp b/src/libs/kdtools/updateoperation.cpp index dc40b0e1..1dcb0014 100644 --- a/src/libs/kdtools/updateoperation.cpp +++ b/src/libs/kdtools/updateoperation.cpp @@ -455,7 +455,7 @@ QDomDocument UpdateOperation::toXml() const bool UpdateOperation::fromXml(const QDomDocument &doc) { QString target = QCoreApplication::applicationDirPath(); - // Does not change target on non OSX platforms. + // Does not change target on non macOS platforms. if (QInstaller::isInBundle(target, &target)) target = QDir::cleanPath(target + QLatin1String("/..")); diff --git a/src/sdk/commandlineparser.cpp b/src/sdk/commandlineparser.cpp index 80aa0afa..3d0d2412 100644 --- a/src/sdk/commandlineparser.cpp +++ b/src/sdk/commandlineparser.cpp @@ -51,7 +51,7 @@ CommandLineParser::CommandLineParser() QLatin1String("Verbose mode. Prints out more information."))); m_parser.addOption(QCommandLineOption(QLatin1String(CommandLineOptions::Proxy), - QLatin1String("Use system proxy on Windows and Linux. This option has no effect on OS X."))); + QLatin1String("Use system proxy on Windows and Linux. This option has no effect on macOS."))); m_parser.addOption(QCommandLineOption(QLatin1String(CommandLineOptions::NoProxy), QLatin1String("Do not use system proxy."))); diff --git a/src/sdk/installerbase.rc b/src/sdk/installerbase.rc index 6229466b..ae7c36ae 100644 --- a/src/sdk/installerbase.rc +++ b/src/sdk/installerbase.rc @@ -1,3 +1,21 @@ +#include + +/* Version info for Windows binary */ +VS_VERSION_INFO VERSIONINFO + FILEVERSION IFW_VERSION_WIN32 + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "FileVersion", IFW_VERSION_STR_WIN32 + END + END + END +/* End of version info */ + IDI_ICON1 ICON DISCARDABLE "installerbase.ico" diff --git a/src/sdk/main.cpp b/src/sdk/main.cpp index 819d512c..336ff51b 100644 --- a/src/sdk/main.cpp +++ b/src/sdk/main.cpp @@ -44,7 +44,7 @@ #include -#if defined(Q_OS_OSX) or defined(Q_OS_UNIX) +#if defined(Q_OS_MACOS) or defined(Q_OS_UNIX) # include # include #endif @@ -66,7 +66,7 @@ int main(int argc, char *argv[]) } #endif // increase maximum numbers of file descriptors -#if defined (Q_OS_OSX) +#if defined (Q_OS_MACOS) QCoreApplication::setSetuidAllowed(true); struct rlimit rl; getrlimit(RLIMIT_NOFILE, &rl); @@ -141,7 +141,7 @@ int main(int argc, char *argv[]) Qt::CaseInsensitive) == 0); if (production) { argumentsValid = (!key.isEmpty()) && (!socketName.isEmpty()); -#if defined(Q_OS_UNIX) && !defined(Q_OS_OSX) +#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) /* In production mode detach child so that sudo waiting on us will terminate. */ pid_t child = fork(); if (child <= -1) { @@ -166,7 +166,7 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } -#if defined(Q_OS_OSX) +#if defined(Q_OS_MACOS) // make sure effective == real user id. uid_t realUserId = getuid(); uid_t effectiveUserId = geteuid(); diff --git a/src/sdk/sdkapp.h b/src/sdk/sdkapp.h index 17d0ac5e..68d7a243 100644 --- a/src/sdk/sdkapp.h +++ b/src/sdk/sdkapp.h @@ -73,21 +73,21 @@ public: as the binary layout cannot be appended to the actual maintenance tool binary itself because of signing. - On OS X: This function will return always the .dat file + On macOS: This function will return always the .dat file .dat file is located inside the resource folder in the application - bundle in OS X. + bundle in macOS. */ QString binaryFile() const { QString binaryFile = QCoreApplication::applicationFilePath(); - // The installer binary on OSX and Windows does not contain the binary + // The installer binary on macOS and Windows does not contain the binary // content, it's put into the resources folder as separate file. // Adjust the actual binary path. No error checking here since we // will fail later while reading the binary content. QDir resourcePath(QFileInfo(binaryFile).dir()); -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS resourcePath.cdUp(); resourcePath.cd(QLatin1String("Resources")); #endif @@ -116,7 +116,7 @@ public: QString bundlePath; if (QInstaller::isInBundle(fi.absoluteFilePath(), &bundlePath)) fi.setFile(bundlePath); -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS return fi.absoluteDir().filePath(fi.baseName() + QLatin1String(".dat")); #else return fi.absoluteDir().filePath(qApp->applicationName() + QLatin1String(".dat")); diff --git a/src/sdk/translations/ifw_de.ts b/src/sdk/translations/ifw_de.ts index 4d684b80..95b9c829 100644 --- a/src/sdk/translations/ifw_de.ts +++ b/src/sdk/translations/ifw_de.ts @@ -1365,15 +1365,15 @@ Fehler beim Laden von %2 Willkommen zum %1-Einrichtungsassistenten. - Add or remove components + &Add or remove components Komponenten hinzufügen oder entfernen - Update components + &Update components Komponenten aktualisieren - Remove all components + &Remove all components Alle Komponenten entfernen @@ -1393,7 +1393,7 @@ Fehler beim Laden von %2 Nur lokale Paketverwaltung verfügbar. - Quit + &Quit Beenden diff --git a/src/sdk/translations/ifw_es.ts b/src/sdk/translations/ifw_es.ts index c08595b3..760adaf9 100644 --- a/src/sdk/translations/ifw_es.ts +++ b/src/sdk/translations/ifw_es.ts @@ -1327,15 +1327,15 @@ Error al descargar %2 Bienvenido al Asistente de instalación de %1. - Add or remove components + &Add or remove components Agregar o quitar componentes - Update components + &Update components Actualizar componentes - Remove all components + &Remove all components Quitar todos los componentes @@ -1355,7 +1355,7 @@ Error al descargar %2 Solo está disponible la administración de paquetes locales. - Quit + &Quit Salir diff --git a/src/sdk/translations/ifw_fr.ts b/src/sdk/translations/ifw_fr.ts index 07bde6e5..504d0f37 100644 --- a/src/sdk/translations/ifw_fr.ts +++ b/src/sdk/translations/ifw_fr.ts @@ -1327,15 +1327,15 @@ Erreur lors du chargement de %2 Bienvenue dans l’assistant d’installation de %1 - Add or remove components + &Add or remove components Ajouter ou supprimer des composants - Update components + &Update components Mettre à jour des composants - Remove all components + &Remove all components Supprimer tous les composants @@ -1355,7 +1355,7 @@ Erreur lors du chargement de %2 Seule la gestion des paquetages locaux est disponible. - Quit + &Quit Quitter diff --git a/src/sdk/translations/ifw_it.ts b/src/sdk/translations/ifw_it.ts index a35a2c7e..5be3c821 100644 --- a/src/sdk/translations/ifw_it.ts +++ b/src/sdk/translations/ifw_it.ts @@ -1327,15 +1327,15 @@ Errore durante il caricamento di %2 Installazione guidata di %1. - Add or remove components + &Add or remove components Aggiungi o rimuovi componenti - Update components + &Update components Aggiorna componenti - Remove all components + &Remove all components Rimuovi tutti i componenti @@ -1355,7 +1355,7 @@ Errore durante il caricamento di %2 Disponibile solo gestione pacchetto locale. - Quit + &Quit Esci diff --git a/src/sdk/translations/ifw_ja.ts b/src/sdk/translations/ifw_ja.ts index 146a56fe..47d86552 100644 --- a/src/sdk/translations/ifw_ja.ts +++ b/src/sdk/translations/ifw_ja.ts @@ -1327,15 +1327,15 @@ Error while loading %2 %1 設定ウィザードへようこそ。 - Add or remove components + &Add or remove components コンポーネントの追加または削除 - Update components + &Update components コンポーネントの更新 - Remove all components + &Remove all components すべてのコンポーネントを削除 @@ -1355,7 +1355,7 @@ Error while loading %2 ローカル パッケージ管理のみ利用可能です。 - Quit + &Quit 中止 diff --git a/src/sdk/translations/ifw_pl.ts b/src/sdk/translations/ifw_pl.ts index 714ebb5e..b557bfdc 100644 --- a/src/sdk/translations/ifw_pl.ts +++ b/src/sdk/translations/ifw_pl.ts @@ -1327,15 +1327,15 @@ Błąd podczas wczytywania %2 Witamy w Kreatorze konfiguracji %1. - Add or remove components + &Add or remove components Dodaj lub usuń elementy - Update components + &Update components Zaktualizuj elementy - Remove all components + &Remove all components Usuń wszystkie elementy @@ -1355,7 +1355,7 @@ Błąd podczas wczytywania %2 Dostępne jedynie lokalne zarządzanie pakietami. - Quit + &Quit Zakończ diff --git a/src/sdk/translations/ifw_zh_CN.ts b/src/sdk/translations/ifw_zh_CN.ts index bdeddf1b..363a46fd 100644 --- a/src/sdk/translations/ifw_zh_CN.ts +++ b/src/sdk/translations/ifw_zh_CN.ts @@ -1327,15 +1327,15 @@ Error while loading %2 欢迎使用 %1 安装向导。 - Add or remove components + &Add or remove components 添加或移除组件 - Update components + &Update components 更新组件 - Remove all components + &Remove all components 移除所有组件 @@ -1355,7 +1355,7 @@ Error while loading %2 仅本地软件包管理可用。 - Quit + &Quit 退出 diff --git a/tests/auto/installer/binaryformat/tst_binaryformat.cpp b/tests/auto/installer/binaryformat/tst_binaryformat.cpp index 6b40452c..c9cd2b00 100644 --- a/tests/auto/installer/binaryformat/tst_binaryformat.cpp +++ b/tests/auto/installer/binaryformat/tst_binaryformat.cpp @@ -128,7 +128,7 @@ private slots: // throws QInstaller::BinaryContent::findMagicCookie(&file, QInstaller::BinaryContent::MagicCookie); } catch (const QInstaller::Error &error) { - QCOMPARE(qPrintable(error.message()), "No marker found, stopped after 71.00 KiB."); + QCOMPARE(qPrintable(error.message()), "No marker found, stopped after 71.00 KB."); } catch (...) { QFAIL("Unexpected error."); } diff --git a/tests/auto/installer/packagemanagercore/tst_packagemanagercore.cpp b/tests/auto/installer/packagemanagercore/tst_packagemanagercore.cpp index 47fb41bf..67fa7e2c 100644 --- a/tests/auto/installer/packagemanagercore/tst_packagemanagercore.cpp +++ b/tests/auto/installer/packagemanagercore/tst_packagemanagercore.cpp @@ -34,6 +34,7 @@ #include #include +#include #include #include @@ -118,15 +119,18 @@ private slots: QVERIFY(core.calculateComponentsToInstall()); { - QTemporaryFile dummy(testDirectory + QLatin1String("/dummy")); - dummy.open(); + QFile dummy(testDirectory + QLatin1String("/dummy")); + QVERIFY(dummy.open(QIODevice::ReadWrite)); core.runInstaller(); QVERIFY(QDir(testDirectory).exists()); QVERIFY(QFileInfo(dummy.fileName()).exists()); + + dummy.close(); + QVERIFY(dummy.remove()); } - QDir().rmdir(testDirectory); + QVERIFY(QDir().rmdir(testDirectory)); ProgressCoordinator::instance()->reset(); } @@ -257,6 +261,58 @@ private slots: core.calculateComponentsToInstall(); QCOMPARE(core.requiredDiskSpace(), 250ULL); } + + void testDirectoryWritable() + { + PackageManagerCore core; + + const QString testDirectory = QInstaller::generateTemporaryFileName(); + QVERIFY(QDir().mkpath(testDirectory)); + QVERIFY(QDir(testDirectory).exists()); + + // should be writable + QVERIFY(core.directoryWritable(testDirectory)); + +#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS) + QFile dirDevice(testDirectory); + dirDevice.setPermissions(QFileDevice::ReadOwner | QFileDevice::ExeOwner); + + // should not be writable + QVERIFY(!core.directoryWritable(testDirectory)); + + dirDevice.setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner | QFileDevice::ExeOwner); +#endif + QVERIFY(QDir().rmdir(testDirectory)); + } + + void testSubdirectoriesWritable() + { + PackageManagerCore core; + + const QString testDirectory = QInstaller::generateTemporaryFileName(); + QVERIFY(QDir().mkpath(testDirectory)); + QVERIFY(QDir(testDirectory).exists()); + + const QString testSubdirectory = testDirectory + "/" + QString::number(qrand() % 1000); + + QVERIFY(QDir().mkpath(testSubdirectory)); + QVERIFY(QDir(testSubdirectory).exists()); + + // should be writable + QVERIFY(core.subdirectoriesWritable(testDirectory)); + +#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS) + QFile dirDevice(testSubdirectory); + dirDevice.setPermissions(QFileDevice::ReadOwner | QFileDevice::ExeOwner); + + // should not be writable + QVERIFY(!core.subdirectoriesWritable(testDirectory)); + + dirDevice.setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner | QFileDevice::ExeOwner); +#endif + QVERIFY(QDir().rmdir(testSubdirectory)); + QVERIFY(QDir().rmdir(testDirectory)); + } }; diff --git a/tests/auto/installer/repository/tst_repository.cpp b/tests/auto/installer/repository/tst_repository.cpp index 8d5d278a..7b8405ba 100644 --- a/tests/auto/installer/repository/tst_repository.cpp +++ b/tests/auto/installer/repository/tst_repository.cpp @@ -1,4 +1,6 @@ #include "repository.h" +#include "repositorycategory.h" +#include "settings.h" #include #include @@ -114,6 +116,51 @@ private slots: s1 >> r1; s2 >> r2; QCOMPARE(r1, r2); } + + void testUpdateRepositoryCategories() + { + Settings settings; + + RepositoryCategory category; + category.setEnabled(true); + category.setDisplayName(QLatin1String("category")); + + Repository original(QUrl("http://example.com/"), true); + original.setEnabled(true); + category.addRepository(original); + + Repository replacement = original; + replacement.setUsername(QLatin1String("user")); + replacement.setPassword(QLatin1String("pass")); + + QSet categories; + categories.insert(category); + settings.setRepositoryCategories(categories); + + QHash> update; + + // non-empty update + update.insert(QLatin1String("replace"), qMakePair(original, replacement)); + QVERIFY(settings.updateRepositoryCategories(update) == Settings::UpdatesApplied); + + // verify that the values really updated + QVERIFY(settings.repositoryCategories().values().at(0) + .repositories().values().at(0).username() == "user"); + + QVERIFY(settings.repositoryCategories().values().at(0) + .repositories().values().at(0).password() == "pass"); + + // empty update + update.clear(); + QVERIFY(settings.updateRepositoryCategories(update) == Settings::NoUpdatesApplied); + + // non-matching repository update + Repository nonMatching(QUrl("https://www.qt.io/"), true); + nonMatching.setEnabled(true); + + update.insert(QLatin1String("replace"), qMakePair(nonMatching, replacement)); + QVERIFY(settings.updateRepositoryCategories(update) == Settings::NoUpdatesApplied); + } }; QTEST_MAIN(tst_Repository) diff --git a/tests/auto/installer/scriptengine/tst_scriptengine.cpp b/tests/auto/installer/scriptengine/tst_scriptengine.cpp index 7118d067..b7c602e2 100644 --- a/tests/auto/installer/scriptengine/tst_scriptengine.cpp +++ b/tests/auto/installer/scriptengine/tst_scriptengine.cpp @@ -280,7 +280,11 @@ private slots: // ignore Output from script setExpectedScriptOutput("function receive()"); +#if QT_VERSION >= QT_VERSION_CHECK(5,12,0) + QTest::ignoreMessage(QtWarningMsg, ":38: ReferenceError: foo is not defined"); +#else QTest::ignoreMessage(QtWarningMsg, ":38: ReferenceError: foo is not defined"); +#endif emiter.produceSignal(); const QJSValue value = m_scriptEngine->evaluate(""); diff --git a/tests/auto/installer/settings/tst_settings.cpp b/tests/auto/installer/settings/tst_settings.cpp index 0edf3fd7..ab8611e1 100644 --- a/tests/auto/installer/settings/tst_settings.cpp +++ b/tests/auto/installer/settings/tst_settings.cpp @@ -49,7 +49,7 @@ void tst_Settings::loadTutorialConfig() QCOMPARE(settings.installerApplicationIcon(), QLatin1String(":/installer.ico")); QCOMPARE(settings.installerWindowIcon(), QLatin1String(":/installer.ico")); QCOMPARE(settings.systemIconSuffix(), QLatin1String(".ico")); -#elif defined(Q_OS_OSX) +#elif defined(Q_OS_MACOS) QCOMPARE(settings.installerApplicationIcon(), QLatin1String(":/installer.icns")); QCOMPARE(settings.installerWindowIcon(), QLatin1String(":/installer.icns")); QCOMPARE(settings.systemIconSuffix(), QLatin1String(".icns")); diff --git a/tools/binarycreator/binarycreator.cpp b/tools/binarycreator/binarycreator.cpp index 5de4ff74..f9a8f31d 100644 --- a/tools/binarycreator/binarycreator.cpp +++ b/tools/binarycreator/binarycreator.cpp @@ -263,7 +263,7 @@ static QVersionNumber readMachOMinimumSystemVersion(QIODevice *device) static int assemble(Input input, const QInstaller::Settings &settings, const QString &signingIdentity) { -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS if (QInstaller::isInBundle(input.installerExePath)) { const QString bundle = input.installerExePath; // if the input file was a bundle @@ -330,9 +330,12 @@ static int assemble(Input input, const QInstaller::Settings &settings, const QSt << endl; plistStream << QLatin1String("\tCFBundlePackageType") << endl; plistStream << QLatin1String("\tAPPL") << endl; - plistStream << QLatin1String("\tCFBundleGetInfoString") << endl; #define QUOTE_(x) #x #define QUOTE(x) QUOTE_(x) + plistStream << QLatin1String("\tCFBundleShortVersionString") << endl; + plistStream << QLatin1String("\t") << QLatin1String(QUOTE(IFW_VERSION_STR)) << ("") + << endl; + plistStream << QLatin1String("\tCFBundleVersion") << endl; plistStream << QLatin1String("\t") << QLatin1String(QUOTE(IFW_VERSION_STR)) << ("") << endl; #undef QUOTE @@ -391,7 +394,7 @@ static int assemble(Input input, const QInstaller::Settings &settings, const QSt // no error handling as this is not fatal setApplicationIcon(tempFile, settings.installerApplicationIcon()); } -#elif defined(Q_OS_OSX) +#elif defined(Q_OS_MACOS) if (isBundle) { // no error handling as this is not fatal const QString copyscript = QDir::temp().absoluteFilePath(QLatin1String("copylibsintobundle.sh")); @@ -408,7 +411,7 @@ static int assemble(Input input, const QInstaller::Settings &settings, const QSt QTemporaryFile out; QString targetName = input.outputPath; -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS QDir resourcePath(QFileInfo(input.outputPath).dir()); resourcePath.cdUp(); resourcePath.cd(QLatin1String("Resources")); @@ -429,7 +432,7 @@ static int assemble(Input input, const QInstaller::Settings &settings, const QSt QInstaller::openForWrite(&out); QFile exe(input.installerExePath); -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS if (!exe.copy(input.outputPath)) { throw Error(QString::fromLatin1("Cannot copy %1 to %2: %3").arg(exe.fileName(), input.outputPath, exe.errorString())); @@ -474,7 +477,7 @@ static int assemble(Input input, const QInstaller::Settings &settings, const QSt #endif QFile::remove(tempFile); -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS if (isBundle && !signingIdentity.isEmpty()) { qDebug() << "Signing .app bundle..."; @@ -657,7 +660,7 @@ static void printUsage() std::cout << " -rcc|--compile-resource Compiles the default resource and outputs the result into" << std::endl; std::cout << " 'update.rcc' in the current path." << std::endl; -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS std::cout << " -s|--sign identity Sign generated app bundle using the given code " << std::endl; std::cout << " signing identity" << std::endl; #endif @@ -715,7 +718,7 @@ void copyConfigData(const QString &configFile, const QString &targetDir) QString targetFile; QFileInfo elementFileInfo; if (tagName == QLatin1String("Icon") || tagName == QLatin1String("InstallerApplicationIcon")) { -#if defined(Q_OS_OSX) +#if defined(Q_OS_MACOS) const QString suffix = QLatin1String(".icns"); #elif defined(Q_OS_WIN) const QString suffix = QLatin1String(".ico"); @@ -882,7 +885,7 @@ int main(int argc, char **argv) continue; } else if (*it == QLatin1String("-rcc") || *it == QLatin1String("--compile-resource")) { compileResource = true; -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS } else if (*it == QLatin1String("-s") || *it == QLatin1String("--sign")) { ++it; if (it == args.end() || it->startsWith(QLatin1String("-"))) @@ -983,7 +986,7 @@ int main(int argc, char **argv) confInternal.setValue(QLatin1String("offlineOnly"), offlineOnly); } -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS // on mac, we enforce building a bundle if (!target.endsWith(QLatin1String(".app")) && !target.endsWith(QLatin1String(".dmg"))) target += QLatin1String(".app"); diff --git a/tools/binarycreator/resources/copylibsintobundle.sh b/tools/binarycreator/resources/copylibsintobundle.sh index c6765364..1ad5da4d 100644 --- a/tools/binarycreator/resources/copylibsintobundle.sh +++ b/tools/binarycreator/resources/copylibsintobundle.sh @@ -71,7 +71,7 @@ function handleFile() if [ `basename $FILE` != $NAME ]; then - # this part handles libraries which are Mac OS X frameworks + # this part handles libraries which are macOS frameworks if echo $lib | grep '\.framework' >/dev/null; then local FRAMEWORKPATH=`echo $lib | sed -ne 's,\(.*\.framework\).*,\1,p'` local FRAMEWORKNAME=`basename $FRAMEWORKPATH` diff --git a/tools/devtool/binaryreplace.cpp b/tools/devtool/binaryreplace.cpp index 7497f219..97dac37d 100644 --- a/tools/devtool/binaryreplace.cpp +++ b/tools/devtool/binaryreplace.cpp @@ -99,7 +99,7 @@ int BinaryReplace::replace(const QString &source, const QString &target) result = EXIT_FAILURE; try { QFile installerBaseNew(newInstallerBasePath); -#ifndef Q_OS_OSX +#ifndef Q_OS_MACOS QFile installerBaseOld(target); QInstaller::openForAppend(&installerBaseNew); diff --git a/tools/devtool/main.cpp b/tools/devtool/main.cpp index d75ab4e8..dbe8f2b0 100644 --- a/tools/devtool/main.cpp +++ b/tools/devtool/main.cpp @@ -168,7 +168,7 @@ int main(int argc, char *argv[]) if (QInstaller::isInBundle(path, &bundlePath)) { path = QDir(bundlePath).filePath(QLatin1String("Contents/Resources/installer.dat")); } -#ifndef Q_OS_OSX +#ifndef Q_OS_MACOS QFileInfo fi = QFileInfo(path); bundlePath = path; QString tmp = QDir(fi.path()).filePath(QLatin1String("installer.dat"));