Merge remote-tracking branch 'origin/3.1' into master

Change-Id: I8b203e12283374aed707e0e89c2f73d44ff296cb
This commit is contained in:
Katja Marttila 2019-08-23 11:05:07 +03:00
commit 516492370b
71 changed files with 603 additions and 198 deletions

View File

@ -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 3.1.1
- Add fetch to the same pane with package categories (QTIFW-1284) - 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) - 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 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 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 - Update Russian translation
- Enable links and text selection in component description fields (QTIFW-1292) - Enable links and text selection in component description fields (QTIFW-1292)

24
INSTALL
View File

@ -15,32 +15,38 @@ http://code.qt.io/cgit/installer-framework/installer-framework.git/
Build a static Qt Build a static Qt
--------------------- ---------------------
Building the Qt Installer Framework from sources requires Qt (version 5.5 Building the Qt Installer Framework from sources requires Qt version 5.9.x.
or newer). Supported compilers are MSVC 2013 or newer, GCC 4.7 or newer, Supported compilers are MSVC 2013 or newer, GCC 4.7 or newer,
and Clang 3.1 or newer. and Clang 3.1 or newer.
If you want to ship your installer as a single file you have to build If you want to ship your installer as a single file you have to build
Qt and the Qt Installer Framework statically. Qt and the Qt Installer Framework statically.
See the Qt documentation for the prerequisites and steps to build Qt from sources. 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 ### Windows
Recommended configuration options for Microsoft 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 ### Linux
Recommended configuration options for 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 -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:
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 make module-qtbase module-qtdeclarative module-qttools module-qttranslations
Build the Framework Build the Framework

2
README
View File

@ -1,6 +1,6 @@
The Qt Installer Framework provides a set of tools and utilities to create The Qt Installer Framework provides a set of tools and utilities to create
installers for the supported desktop Qt platforms: Linux, Microsoft Windows, and installers for the supported desktop Qt platforms: Linux, Microsoft Windows, and
OS X. macOS.
Documentation Documentation

View File

@ -2,7 +2,7 @@
<Installer> <Installer>
<Name>Qt Installer Framework</Name> <Name>Qt Installer Framework</Name>
<Title>Qt Installer Framework 3.2.0</Title> <Title>Qt Installer Framework 3.2.0</Title>
<Version>3.2.0 </Version> <Version>3.2.0</Version>
<Publisher>Qt Project</Publisher> <Publisher>Qt Project</Publisher>
<ProductUrl>http://qt-project.org</ProductUrl> <ProductUrl>http://qt-project.org</ProductUrl>
<Watermark>watermark.png</Watermark> <Watermark>watermark.png</Watermark>

View File

@ -3,6 +3,6 @@
<DisplayName>Qt Installer Framework Binaries</DisplayName> <DisplayName>Qt Installer Framework Binaries</DisplayName>
<Description>Installs the binaries, examples and help files.</Description> <Description>Installs the binaries, examples and help files.</Description>
<Version>3.2.0</Version> <Version>3.2.0</Version>
<ReleaseDate>2019-05-27</ReleaseDate> <ReleaseDate>2019-08-23</ReleaseDate>
<Default>True</Default> <Default>True</Default>
</Package> </Package>

View File

@ -3,7 +3,7 @@
<DisplayName>Qt Installer Framework</DisplayName> <DisplayName>Qt Installer Framework</DisplayName>
<Description>Installs the Qt Installer Framework.</Description> <Description>Installs the Qt Installer Framework.</Description>
<Version>3.2.0</Version> <Version>3.2.0</Version>
<ReleaseDate>2019-05-25</ReleaseDate> <ReleaseDate>2019-08-23</ReleaseDate>
<Licenses> <Licenses>
<License name="The Qt Company GPL Exception 1.0" file="LICENSE.GPL3-EXCEPT" /> <License name="The Qt Company GPL Exception 1.0" file="LICENSE.GPL3-EXCEPT" />
<License name="Third Party Code Licenses" file="3RDPARTY" /> <License name="Third Party Code Licenses" file="3RDPARTY" />

View File

@ -8,7 +8,7 @@
\code \code
..\..\bin\binarycreator.exe -c config\config.xml -p packages installer.exe ..\..\bin\binarycreator.exe -c config\config.xml -p packages installer.exe
\endcode \endcode
\li On Linux or OS X: \li On Linux or macOS:
\code \code
../../bin/binarycreator -c config/config.xml -p packages installer ../../bin/binarycreator -c config/config.xml -p packages installer
\endcode \endcode

View File

@ -65,9 +65,11 @@
If you use a statically built Qt to build the Qt Installer Framework 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 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 \section3 Configuring Qt for Windows
@ -75,24 +77,39 @@
Windows: Windows:
\code \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 \endcode
Build Qt:
\code
nmake (or 'mingw32-make') module-qtbase module-qtdeclarative module-qttools module-qttranslations module-qtwinextras
\endcode
\section3 Configuring Qt for Linux \section3 Configuring Qt for Linux
We recommend that you use the following configuration options for Linux: We recommend that you use the following configuration options for Linux:
\code \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 \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 \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 \endcode
\section2 Setting up Qt Installer Framework \section2 Setting up Qt Installer Framework

View File

@ -37,7 +37,7 @@
create installers once, and deploy them across all the supported desktop create installers once, and deploy them across all the supported desktop
Qt platforms without rewriting the source code. The installers will have the 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 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 The Qt Installer Framework tools generate installers with a set of pages
that guide the users during the installation, update, or uninstallation that guide the users during the installation, update, or uninstallation

View File

@ -71,7 +71,7 @@
\image ifw-user-flow-installing.png "Installation workflow" \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 to illustrate the default workflow for end users. The installers have the
native look and feel on each supported desktop platform, and therefore they native look and feel on each supported desktop platform, and therefore they
look and feel different when run on Linux and Windows. look and feel different when run on Linux and Windows.
@ -188,7 +188,7 @@
\image ifw-user-flow-adding.png "Add components workflow" \image ifw-user-flow-adding.png "Add components workflow"
This section uses the \e {Maintenance Tool} installed by the Qt 5 installer 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 after the initial installation. The Maintenance Tool contains the package
manager, updater, and uninstaller. manager, updater, and uninstaller.
@ -244,7 +244,7 @@
\image ifw-user-flow-removing.png "Remove components workflow" \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. implementation of how end users can remove all or selected components.
\section1 Removing All Components \section1 Removing All Components
@ -297,7 +297,7 @@
\image ifw-user-flow-updating.png "Updating workflow" \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. implementation of how end users can update installed components.
\section1 Starting Updater \section1 Starting Updater

View File

@ -42,7 +42,7 @@
The Qt Installer Framework provides a set of tools and utilities to The Qt Installer Framework provides a set of tools and utilities to
create installers for the supported desktop Qt platforms: Linux, Microsoft 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 \note Report bugs and suggestions for the Qt Installer Framework project
in the \l{https://bugreports.qt.io/browse/QTIFW}{Qt Bugtracker}. in the \l{https://bugreports.qt.io/browse/QTIFW}{Qt Bugtracker}.
@ -191,13 +191,13 @@
\row \row
\li Icon \li Icon
\li Filename for a custom installer icon. The actual file is looked up by attaching \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 <InstallerApplicationIcon> or \c <InstallerWindowIcon> use \c <InstallerApplicationIcon> or \c <InstallerWindowIcon>
instead. instead.
\row \row
\li InstallerApplicationIcon \li InstallerApplicationIcon
\li Filename for a custom installer icon. The actual file is looked up by attaching \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 \row
\li InstallerWindowIcon \li InstallerWindowIcon
\li Filename for a custom window icon in PNG format for the Installer application. \li Filename for a custom window icon in PNG format for the Installer application.
@ -430,20 +430,13 @@
component.userInterface( "MyPage" ).checkbox.checked = true; component.userInterface( "MyPage" ).checkbox.checked = true;
\endcode \endcode
\section2 Using Control Scripts to Add Pages 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
To register a custom page, use the installer::addWizardPage() method create the \c{Dynamic${ObjectName}Callback} function (for example,
and the object name set in the UI file (for example, \c "MyPage"). Then \c {DynamicMyPageCallback}):
call the \c{Dynamic${ObjectName}Callback()} function (for example,
\c {DynamicMyPageCallback()}):
\code \code
function Controller() Component.prototype.DynamicMyPageCallback = function()
{
installer.addWizardPage(component, "MyPage", QInstaller.TargetDirectory)
}
Controller.prototype.DynamicMyPageCallback()
{ {
var page = gui.pageWidgetByObjectName("DynamicMyPage"); var page = gui.pageWidgetByObjectName("DynamicMyPage");
page.myButton.click, page.myButton.click,
@ -801,7 +794,7 @@
<location-of-ifw>\binarycreator.exe -t <location-of-ifw>\installerbase.exe -p <package_directory> -c <config_directory>\<config_file> <installer_name> <location-of-ifw>\binarycreator.exe -t <location-of-ifw>\installerbase.exe -p <package_directory> -c <config_directory>\<config_file> <installer_name>
\endcode \endcode
\li On Linux and OS X \li On Linux and macOS
\code \code
<location-of-ifw>/binarycreator -t <location-of-ifw>/installerbase -p <package_directory> -c <config_directory>/<config_file> <installer_name> <location-of-ifw>/binarycreator -t <location-of-ifw>/installerbase -p <package_directory> -c <config_directory>/<config_file> <installer_name>
@ -819,7 +812,7 @@
<location-of-ifw>\binarycreator.exe -t <location-of-ifw>\installerbase.exe -p <package_directory> -c <config_directory>\<config_file> -e <packages> <installer_name> <location-of-ifw>\binarycreator.exe -t <location-of-ifw>\installerbase.exe -p <package_directory> -c <config_directory>\<config_file> -e <packages> <installer_name>
\endcode \endcode
\li On Linux and OS X \li On Linux and macOS
\code \code
<location-of-ifw>/binarycreator -t <location-of-ifw>/installerbase -p <package_directory> -c <config_directory>/<config_file> -e <packages> <installer_name> <location-of-ifw>/binarycreator -t <location-of-ifw>/installerbase -p <package_directory> -c <config_directory>/<config_file> -e <packages> <installer_name>
@ -890,7 +883,7 @@
\row \row
\li -s or --sign identity \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. used for signing the generated app bundle.
\endtable \endtable
@ -914,7 +907,7 @@
\section2 Using Icons \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 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. extended with .icns and used as the icon for the created bundle.

View File

@ -330,8 +330,61 @@
\row \row
\li \c ResetComponentsButton \li \c ResetComponentsButton
\li Resets to already installed components. \li Resets to already installed components.
\row
\li \c FetchCategoryButton
\li Fetch components from a category.
\endtable \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 \section2 Start Menu Directory Page
@ -430,13 +483,13 @@
Example code: Example code:
\code \code
function Controller() function Component()
{ {
// add page with widget \c SomePageWidget before the target directory page // add page with widget \c SomePageWidget before the target directory page
installer.addWizardPage(component, "SomePageWidget", QInstaller.TargetDirectory) installer.addWizardPage(component, "SomePageWidget", QInstaller.TargetDirectory)
} }
Controller.prototype.DynamicSomePageWidgetCallback = function() Component.prototype.DynamicSomePageWidgetCallback = function()
{ {
var page = gui.pageWidgetByObjectName("DynamicSomePageWidget"); var page = gui.pageWidgetByObjectName("DynamicSomePageWidget");
page.myButton.click, //direct child of the UI file's widget page.myButton.click, //direct child of the UI file's widget

View File

@ -130,9 +130,9 @@
\li Creates a shortcut from the file specified by \c filename to \li Creates a shortcut from the file specified by \c filename to
\c linkname. \c linkname.
On Windows, this creates a .lnk file which can have 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. 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 \row
\li CreateDesktopEntry \li CreateDesktopEntry
\li "CreateDesktopEntry" \c {filename "key=value[ key2=value2[ key3=value3]]]"} \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. \li Restarts the updater or package manager specified by \c core.
\row \row
\li Settings \li Settings
\li "Settings" \c path \c method \c key \c aValue \li "Settings" \c path \c method \c key \c value
\li Sets or removes the value \c aValue of \c key in the settings file \li Sets or removes the \c value of \c key in the settings file located at
or registry located at \c path, depending on the value of \c path, depending on the value of \c method: \c set, \c remove,
\c method: \c set, \c remove, \c add_array_value, and \c remove_array_value. \c add_array_value, and \c remove_array_value.
\endtable \endtable
The Extract, License, and MinimumProgress operations are automatically added for matching The Extract, License, and MinimumProgress operations are automatically added for matching

View File

@ -42,13 +42,13 @@
Specifies the buttons on an installer page. Specifies the buttons on an installer page.
\value buttons.BackButton \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 \value buttons.NextButton
The \uicontrol Next button (\uicontrol Continue on OS X.) The \uicontrol Next button (\uicontrol Continue on macOS.)
\value buttons.CommitButton \value buttons.CommitButton
The \uicontrol Commit button. The \uicontrol Commit button.
\value buttons.FinishButton \value buttons.FinishButton
The \uicontrol Finish button (\uicontrol Done on OS X.) The \uicontrol Finish button (\uicontrol Done on macOS.)
\value buttons.CancelButton \value buttons.CancelButton
The \uicontrol Cancel button. The \uicontrol Cancel button.
\value buttons.HelpButton \value buttons.HelpButton

View File

@ -66,6 +66,6 @@
"Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)" "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"
\endcode \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. and not a QFileDialog.
*/ */

View File

@ -265,7 +265,7 @@
\li Applications directory. \li Applications directory.
For example, \c {C:\Program Files} on Windows, 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} See also the table that lists examples of \l {Applications-directory-on-Windows}
{applications directories on Windows}. {applications directories on Windows}.

View File

@ -58,7 +58,7 @@
kernel the installer is running on, unless the host operating system is running a form of kernel the installer is running on, unless the host operating system is running a form of
compatibility or virtualization layer. compatibility or virtualization layer.
For Windows, Linux, and OS X this will return For Windows, Linux, and macOS this will return
\list \list
\li "winnt" \li "winnt"
\li "linux" \li "linux"
@ -82,7 +82,7 @@
\endlist \endlist
The release version of the operating system kernel. On Windows, it returns the version of the 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. command would return.
\sa QSysInfo::kernelVersion() \sa QSysInfo::kernelVersion()

View File

@ -195,7 +195,7 @@
..\..\bin\binarycreator.exe -c config\config.xml -p packages YourInstaller.exe ..\..\bin\binarycreator.exe -c config\config.xml -p packages YourInstaller.exe
\endcode \endcode
\li On Linux or OS X: \li On Linux or macOS:
\code \code
../../bin/binarycreator -c config/config.xml -p packages YourInstaller ../../bin/binarycreator -c config/config.xml -p packages YourInstaller
\endcode \endcode

View File

@ -105,7 +105,7 @@
\code \code
..\..\bin\binarycreator.exe -c config\config.xml -r resources/additional.qrc -p packages installer.exe ..\..\bin\binarycreator.exe -c config\config.xml -r resources/additional.qrc -p packages installer.exe
\endcode \endcode
\li On Linux or OS X: \li On Linux or macOS:
\code \code
../../bin/binarycreator -c config/config.xml -r resources/additional.qrc -p packages installer ../../bin/binarycreator -c config/config.xml -r resources/additional.qrc -p packages installer
\endcode \endcode

View File

@ -74,7 +74,7 @@
\code \code
..\..\bin\repogen.exe -p packages repository ..\..\bin\repogen.exe -p packages repository
\endcode \endcode
\li On Linux or OS X: \li On Linux or macOS:
\code \code
../../bin/repogen -p packages repository ../../bin/repogen -p packages repository
\endcode \endcode
@ -114,7 +114,7 @@
\code \code
..\..\bin\binarycreator.exe --online-only -c config\config.xml -p packages installer.exe ..\..\bin\binarycreator.exe --online-only -c config\config.xml -p packages installer.exe
\endcode \endcode
\li On Linux or OS X: \li On Linux or macOS:
\code \code
../../bin/binarycreator --online-only -c config/config.xml -p packages installer ../../bin/binarycreator --online-only -c config/config.xml -p packages installer
\endcode \endcode
@ -139,7 +139,7 @@
\code \code
..\..\bin\repogen.exe --update-new-components -p packages_update repository ..\..\bin\repogen.exe --update-new-components -p packages_update repository
\endcode \endcode
\li On Linux or OS X: \li On Linux or macOS:
\code \code
../../bin/repogen --update-new-components -p packages_update repository ../../bin/repogen --update-new-components -p packages_update repository
\endcode \endcode

View File

@ -61,7 +61,7 @@
In installscript.qs, we use the \c Component() function to connect to the In installscript.qs, we use the \c Component() function to connect to the
\c installationFinishedPageIsShown signal when the installation is complete \c installationFinishedPageIsShown signal when the installation is complete
and to the \c installationFinished signal when the end users click 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 \quotefromfile openreadme/packages/or.qtproject.ifw.example.openreadme/meta/installscript.qs
\skipto Component() \skipto Component()

View File

@ -84,9 +84,9 @@
\printto /\!validOs/ \printto /\!validOs/
The script uses \l{systemInfo::productType}{systemInfo.productType} to differentiate 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 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/Darwin_%28operating_system%29}{Darwin} and
\l{http://en.wikipedia.org/wiki/Windows_NT}{Windows NT}. \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 specific distribution and version the binaries are presumably built for,
the installer shows a warning in a modal dialog, but allows installation. 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: helper function to prevent an actual installation:
\printuntil /\}/ \printuntil /\}/

View File

@ -55,7 +55,7 @@ function Component()
// //
// Check whether OS is supported. // 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 Windows Vista (winnt kernel version 6.0.x)
// - Require at least OS X 10.7 (Lion) (darwin kernel version 11.x) // - Require at least OS X 10.7 (Lion) (darwin kernel version 11.x)
// //

View File

@ -12,4 +12,4 @@ Linux:
LANGUAGE=de ./installer 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.

View File

@ -5,6 +5,9 @@ IFW_PRI_INCLUDED = 1
IFW_VERSION_STR = 3.2.0 IFW_VERSION_STR = 3.2.0
IFW_VERSION = 0x030200 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_REPOSITORY_FORMAT_VERSION = 1.0.0
IFW_NEWLINE = $$escape_expand(\\n\\t) 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 \ DEFINES += NOMINMAX QT_NO_CAST_FROM_ASCII QT_STRICT_ITERATORS QT_USE_QSTRINGBUILDER \
"_GIT_SHA1_=$$GIT_SHA1" \ "_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 DEFINES += IFW_REPOSITORY_FORMAT_VERSION=$$IFW_REPOSITORY_FORMAT_VERSION
LIBS += -l7z LIBS += -l7z

View File

@ -158,7 +158,7 @@ bool Resource::open()
if (isOpen()) if (isOpen())
return false; return false;
if (!m_file.open(QIODevice::ReadOnly)) { if (!m_file.open(QIODevice::ReadOnly | QIODevice::Unbuffered)) {
setErrorString(m_file.errorString()); setErrorString(m_file.errorString());
return false; return false;
} }

View File

@ -147,6 +147,10 @@ ComponentSelectionPagePrivate::ComponentSelectionPagePrivate(ComponentSelectionP
m_treeViewVLayout->addWidget(m_treeView, 3); 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 = new QHBoxLayout(q);
m_mainHLayout->addLayout(m_treeViewVLayout, 3); m_mainHLayout->addLayout(m_treeViewVLayout, 3);
m_mainHLayout->addLayout(m_descriptionVLayout, 2); m_mainHLayout->addLayout(m_descriptionVLayout, 2);

View File

@ -38,6 +38,7 @@
#include "lib7z_facade.h" #include "lib7z_facade.h"
#include "packagemanagercore.h" #include "packagemanagercore.h"
#include "productkeycheck.h" #include "productkeycheck.h"
#include "constants.h"
#include "updateoperations.h" #include "updateoperations.h"
@ -183,6 +184,23 @@ bool CreateLocalRepositoryOperation::performOperation()
} }
setValue(QLatin1String("createddir"), mkDirOp.value(QLatin1String("createddir"))); 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 // copy the whole meta data into local repository
CopyDirectoryOperation copyDirOp(core); CopyDirectoryOperation copyDirOp(core);
copyDirOp.setArguments(QStringList() << QLatin1String(":/metadata/") << repoPath); copyDirOp.setArguments(QStringList() << QLatin1String(":/metadata/") << repoPath);

View File

@ -286,7 +286,7 @@ void QInstaller::removeSystemGeneratedFiles(const QString &path)
{ {
if (path.isEmpty()) if (path.isEmpty())
return; return;
#if defined Q_OS_OSX #if defined Q_OS_MACOS
QFile::remove(path + QLatin1String("/.DS_Store")); QFile::remove(path + QLatin1String("/.DS_Store"));
#elif defined Q_OS_WIN #elif defined Q_OS_WIN
QFile::remove(path + QLatin1String("/Thumbs.db")); QFile::remove(path + QLatin1String("/Thumbs.db"));
@ -572,7 +572,7 @@ quint64 QInstaller::fileSize(const QFileInfo &info)
bool QInstaller::isInBundle(const QString &path, QString *bundlePath) bool QInstaller::isInBundle(const QString &path, QString *bundlePath)
{ {
#ifdef Q_OS_OSX #ifdef Q_OS_MACOS
QFileInfo fi = QFileInfo(path).absoluteFilePath(); QFileInfo fi = QFileInfo(path).absoluteFilePath();
while (!fi.isRoot()) { while (!fi.isRoot()) {
if (fi.isBundle()) { if (fi.isBundle()) {

View File

@ -381,7 +381,7 @@ static QMessageBox::StandardButton showNewMessageBox(QWidget *parent, QMessageBo
msgBox.setDefaultButton(button); msgBox.setDefaultButton(button);
} }
} }
#if defined(Q_OS_OSX) #if defined(Q_OS_MACOS)
msgBox.setWindowModality(Qt::WindowModal); msgBox.setWindowModality(Qt::WindowModal);
#endif #endif
if (msgBox.exec() == -1) if (msgBox.exec() == -1)

View File

@ -326,10 +326,21 @@ void MetadataJob::xmlTaskFinished()
QHash<QString, QPair<Repository, Repository> > update; QHash<QString, QPair<Repository, Repository> > update;
update.insert(QLatin1String("replace"), qMakePair(original, replacement)); update.insert(QLatin1String("replace"), qMakePair(original, replacement));
if (s.updateRepositoryCategories(update) == Settings::UpdatesApplied)
qDebug() << "Repository categories updated.";
if (s.updateDefaultRepositories(update) == Settings::UpdatesApplied if (s.updateDefaultRepositories(update) == Settings::UpdatesApplied
|| s.updateUserRepositories(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(); m_core->writeMaintenanceConfigFiles();
if (gainedAdminRights)
m_core->dropAdminRights();
}
} }
} }
status = XmlDownloadRetry; status = XmlDownloadRetry;
@ -716,8 +727,16 @@ MetadataJob::Status MetadataJob::parseUpdatesXml(const QList<FileTaskResult> &re
return XmlDownloadRetry; return XmlDownloadRetry;
} }
} else if (s.updateDefaultRepositories(repositoryUpdates) == Settings::UpdatesApplied) { } 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(); m_core->writeMaintenanceConfigFiles();
if (gainedAdminRights)
m_core->dropAdminRights();
}
m_metaFromDefaultRepositories.clear(); m_metaFromDefaultRepositories.clear();
QFile::remove(result.target()); QFile::remove(result.target());
return XmlDownloadRetry; return XmlDownloadRetry;

View File

@ -422,9 +422,7 @@ void PackageManagerCore::writeMaintenanceTool()
d->writeMaintenanceTool(d->m_performedOperationsOld + d->m_performedOperationsCurrentSession); d->writeMaintenanceTool(d->m_performedOperationsOld + d->m_performedOperationsCurrentSession);
bool gainedAdminRights = false; bool gainedAdminRights = false;
QTemporaryFile tempAdminFile(d->targetDir() if (!directoryWritable(d->targetDir())) {
+ QLatin1String("/testjsfdjlkdsjflkdsjfldsjlfds") + QString::number(qrand() % 1000));
if (!tempAdminFile.open() || !tempAdminFile.isWritable()) {
gainAdminRights(); gainAdminRights();
gainedAdminRights = true; gainedAdminRights = true;
} }
@ -538,6 +536,14 @@ void PackageManagerCore::componentsToInstallNeedsRecalculation()
component->updateUncompressedSize(); // this is a recursive call 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 {installer::autoAcceptMessageBoxes}{installer.autoAcceptMessageBoxes}
\sa autoRejectMessageBoxes(), setMessageBoxAutomaticAnswer() \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 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) void PackageManagerCore::setFoundEssentialUpdate(bool foundEssentialUpdate)
{ {
@ -1111,8 +1117,7 @@ void PackageManagerCore::networkSettingsChanged()
if (isMaintainer() ) { if (isMaintainer() ) {
bool gainedAdminRights = false; bool gainedAdminRights = false;
QTemporaryFile tempAdminFile(d->targetDir() + QStringLiteral("/XXXXXX")); if (!directoryWritable(d->targetDir())) {
if (!tempAdminFile.open() || !tempAdminFile.isWritable()) {
gainAdminRights(); gainAdminRights();
gainedAdminRights = true; gainedAdminRights = true;
} }
@ -1580,6 +1585,16 @@ Component *PackageManagerCore::componentByName(const QString &name, const QList<
return nullptr; 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 Returns a list of components that are marked for installation. The list can
be empty. be empty.
@ -2186,7 +2201,7 @@ QString PackageManagerCore::findLibrary(const QString &name, const QStringList &
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
return findPath(QString::fromLatin1("%1.lib").arg(name), findPaths); return findPath(QString::fromLatin1("%1.lib").arg(name), findPaths);
#else #else
#if defined(Q_OS_OSX) #if defined(Q_OS_MACOS)
if (findPaths.isEmpty()) { if (findPaths.isEmpty()) {
findPaths.push_back(QLatin1String("/lib")); findPaths.push_back(QLatin1String("/lib"));
findPaths.push_back(QLatin1String("/usr/lib")); findPaths.push_back(QLatin1String("/usr/lib"));

View File

@ -121,6 +121,9 @@ public:
static Component *componentByName(const QString &name, const QList<Component *> &components); static Component *componentByName(const QString &name, const QList<Component *> &components);
bool directoryWritable(const QString &path) const;
bool subdirectoriesWritable(const QString &path) const;
bool fetchLocalPackagesTree(); bool fetchLocalPackagesTree();
LocalPackagesHash localInstalledPackages(); LocalPackagesHash localInstalledPackages();
@ -290,6 +293,7 @@ public Q_SLOTS:
void setCompleteUninstallation(bool complete); void setCompleteUninstallation(bool complete);
void cancelMetaInfoJob(); void cancelMetaInfoJob();
void componentsToInstallNeedsRecalculation(); void componentsToInstallNeedsRecalculation();
void clearComponentsToInstallCalculated();
Q_SIGNALS: Q_SIGNALS:
void aboutCalculateComponentsToInstall() const; void aboutCalculateComponentsToInstall() const;

View File

@ -345,6 +345,27 @@ QString PackageManagerCorePrivate::targetDir() const
return m_core->value(scTargetDir); 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 QString PackageManagerCorePrivate::configurationFileName() const
{ {
return m_core->value(scTargetConfigurationFile, QLatin1String("components.xml")); return m_core->value(scTargetConfigurationFile, QLatin1String("components.xml"));
@ -569,7 +590,7 @@ void PackageManagerCorePrivate::initialize(const QHash<QString, QString> &params
#endif #endif
if (!m_core->isInstaller()) { if (!m_core->isInstaller()) {
#ifdef Q_OS_OSX #ifdef Q_OS_MACOS
readMaintenanceConfigFiles(QCoreApplication::applicationDirPath() + QLatin1String("/../../..")); readMaintenanceConfigFiles(QCoreApplication::applicationDirPath() + QLatin1String("/../../.."));
#else #else
readMaintenanceConfigFiles(QCoreApplication::applicationDirPath()); readMaintenanceConfigFiles(QCoreApplication::applicationDirPath());
@ -697,7 +718,7 @@ Operation *PackageManagerCorePrivate::takeOwnedOperation(Operation *operation)
QString PackageManagerCorePrivate::maintenanceToolName() const QString PackageManagerCorePrivate::maintenanceToolName() const
{ {
QString filename = m_data.settings().maintenanceToolName(); QString filename = m_data.settings().maintenanceToolName();
#if defined(Q_OS_OSX) #if defined(Q_OS_MACOS)
if (QInstaller::isInBundle(QCoreApplication::applicationDirPath())) if (QInstaller::isInBundle(QCoreApplication::applicationDirPath()))
filename += QLatin1String(".app/Contents/MacOS/") + filename; filename += QLatin1String(".app/Contents/MacOS/") + filename;
#elif defined(Q_OS_WIN) #elif defined(Q_OS_WIN)
@ -1013,7 +1034,7 @@ void PackageManagerCorePrivate::writeMaintenanceToolBinary(QFile *const input, q
qDebug() << "Writing maintenance tool:" << maintenanceToolRenamedName; qDebug() << "Writing maintenance tool:" << maintenanceToolRenamedName;
ProgressCoordinator::instance()->emitLabelAndDetailTextChanged(tr("Writing maintenance tool.")); ProgressCoordinator::instance()->emitLabelAndDetailTextChanged(tr("Writing maintenance tool."));
QTemporaryFile out; QFile out(generateTemporaryFileName());
QInstaller::openForWrite(&out); // throws an exception in case of error QInstaller::openForWrite(&out); // throws an exception in case of error
if (!input->seek(0)) if (!input->seek(0))
@ -1023,7 +1044,7 @@ void PackageManagerCorePrivate::writeMaintenanceToolBinary(QFile *const input, q
if (writeBinaryLayout) { if (writeBinaryLayout) {
QDir resourcePath(QFileInfo(maintenanceToolRenamedName).dir()); QDir resourcePath(QFileInfo(maintenanceToolRenamedName).dir());
#ifdef Q_OS_OSX #ifdef Q_OS_MACOS
if (!resourcePath.path().endsWith(QLatin1String("Contents/MacOS"))) if (!resourcePath.path().endsWith(QLatin1String("Contents/MacOS")))
throw Error(tr("Maintenance tool is not a bundle")); throw Error(tr("Maintenance tool is not a bundle"));
resourcePath.cdUp(); resourcePath.cdUp();
@ -1031,7 +1052,7 @@ void PackageManagerCorePrivate::writeMaintenanceToolBinary(QFile *const input, q
#endif #endif
// It's a bit odd to have only the magic in the data file, but this simplifies // 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) // other code a lot (since installers don't have any appended data either)
QTemporaryFile dataOut; QFile dataOut(generateTemporaryFileName());
QInstaller::openForWrite(&dataOut); QInstaller::openForWrite(&dataOut);
QInstaller::appendInt64(&dataOut, 0); // operations start QInstaller::appendInt64(&dataOut, 0); // operations start
QInstaller::appendInt64(&dataOut, 0); // operations end 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")))) { if (!dataOut.rename(resourcePath.filePath(QLatin1String("installer.dat")))) {
throw Error(tr("Cannot write maintenance tool data to %1: %2").arg(out.fileName(), throw Error(tr("Cannot write maintenance tool data to %1: %2").arg(dataOut.fileName(),
out.errorString())); dataOut.errorString()));
} }
dataOut.setAutoRemove(false);
dataOut.setPermissions(dataOut.permissions() | QFile::WriteUser | QFile::ReadGroup dataOut.setPermissions(dataOut.permissions() | QFile::WriteUser | QFile::ReadGroup
| QFile::ReadOther); | QFile::ReadOther);
} }
@ -1077,6 +1097,11 @@ void PackageManagerCorePrivate::writeMaintenanceToolBinary(QFile *const input, q
} else { } else {
qDebug() << "Failed to write permissions for maintenance tool."; 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, void PackageManagerCorePrivate::writeMaintenanceToolBinaryData(QFileDevice *output, QFile *const input,
@ -1144,16 +1169,14 @@ void PackageManagerCorePrivate::writeMaintenanceToolBinaryData(QFileDevice *outp
void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOperations) void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOperations)
{ {
bool gainedAdminRights = false; bool gainedAdminRights = false;
QTemporaryFile tempAdminFile(targetDir() + QLatin1String("/testjsfdjlkdsjflkdsjfldsjlfds") if (!directoryWritable(targetDir())) {
+ QString::number(qrand() % 1000));
if (!tempAdminFile.open() || !tempAdminFile.isWritable()) {
m_core->gainAdminRights(); m_core->gainAdminRights();
gainedAdminRights = true; gainedAdminRights = true;
} }
const QString targetAppDirPath = QFileInfo(maintenanceToolName()).path(); const QString targetAppDirPath = QFileInfo(maintenanceToolName()).path();
if (!QDir().exists(targetAppDirPath)) { 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")); Operation *op = createOwnedOperation(QLatin1String("Mkdir"));
op->setArguments(QStringList() << targetAppDirPath); op->setArguments(QStringList() << targetAppDirPath);
performOperationThreaded(op, Backup); performOperationThreaded(op, Backup);
@ -1161,7 +1184,7 @@ void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOper
performedOperations.append(takeOwnedOperation(op)); performedOperations.append(takeOwnedOperation(op));
} }
#ifdef Q_OS_OSX #ifdef Q_OS_MACOS
// if it is a bundle, we need some stuff in it... // if it is a bundle, we need some stuff in it...
const QString sourceAppDirPath = QCoreApplication::applicationDirPath(); const QString sourceAppDirPath = QCoreApplication::applicationDirPath();
if (isInstaller() && QInstaller::isInBundle(sourceAppDirPath)) { 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 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 // On other platforms data is in separate file only after install so that the
// maintenancetool sign does not break. // maintenancetool sign does not break.
#ifdef Q_OS_OSX #ifdef Q_OS_MACOS
QDir dataPath(QFileInfo(binaryName).dir()); QDir dataPath(QFileInfo(binaryName).dir());
dataPath.cdUp(); dataPath.cdUp();
dataPath.cd(QLatin1String("Resources")); dataPath.cd(QLatin1String("Resources"));
@ -1336,7 +1359,7 @@ void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOper
newBinaryWritten = true; newBinaryWritten = true;
QFile tmp(binaryName); QFile tmp(binaryName);
QInstaller::openForRead(&tmp); QInstaller::openForRead(&tmp);
#ifdef Q_OS_OSX #ifdef Q_OS_MACOS
writeMaintenanceToolBinary(&tmp, tmp.size(), true); writeMaintenanceToolBinary(&tmp, tmp.size(), true);
#else #else
writeMaintenanceToolBinary(&tmp, layout.endOfBinaryContent - layout.binaryContentSize, true); writeMaintenanceToolBinary(&tmp, layout.endOfBinaryContent - layout.binaryContentSize, true);
@ -1348,7 +1371,7 @@ void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOper
m_core->setValue(QLatin1String("installedOperationAreSorted"), QLatin1String("true")); m_core->setValue(QLatin1String("installedOperationAreSorted"), QLatin1String("true"));
try { try {
QTemporaryFile file; QFile file(generateTemporaryFileName());
QInstaller::openForWrite(&file); QInstaller::openForWrite(&file);
writeMaintenanceToolBinaryData(&file, &input, performedOperations, layout); writeMaintenanceToolBinaryData(&file, &input, performedOperations, layout);
QInstaller::appendInt64(&file, BinaryContent::MagicCookieDat); 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") throw Error(tr("Cannot write maintenance tool binary data to %1: %2")
.arg(file.fileName(), file.errorString())); .arg(file.fileName(), file.errorString()));
} }
file.setAutoRemove(false);
file.setPermissions(file.permissions() | QFile::WriteUser | QFile::ReadGroup file.setPermissions(file.permissions() | QFile::WriteUser | QFile::ReadGroup
| QFile::ReadOther); | QFile::ReadOther);
} catch (const Error &/*error*/) { } catch (const Error &/*error*/) {
@ -1455,8 +1477,7 @@ bool PackageManagerCorePrivate::runInstaller()
} }
} }
} else if (QDir(target).exists()) { } else if (QDir(target).exists()) {
QTemporaryFile tempAdminFile(target + QLatin1String("/adminrights")); if (!directoryWritable(targetDir()))
if (!tempAdminFile.open() || !tempAdminFile.isWritable())
adminRightsGained = m_core->gainAdminRights(); adminRightsGained = m_core->gainAdminRights();
} }
@ -1536,8 +1557,8 @@ bool PackageManagerCorePrivate::runInstaller()
Operation *createRepo = createOwnedOperation(QLatin1String("CreateLocalRepository")); Operation *createRepo = createOwnedOperation(QLatin1String("CreateLocalRepository"));
if (createRepo) { if (createRepo) {
QString binaryFile = QCoreApplication::applicationFilePath(); QString binaryFile = QCoreApplication::applicationFilePath();
#ifdef Q_OS_OSX #ifdef Q_OS_MACOS
// The installer binary on OSX does not contain the binary content, it's put into // 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 // 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. // checking here since we will fail later while reading the binary content.
QDir resourcePath(QFileInfo(binaryFile).dir()); QDir resourcePath(QFileInfo(binaryFile).dir());
@ -1622,10 +1643,16 @@ bool PackageManagerCorePrivate::runPackageUpdater()
//to have some progress for the cleanup/write component.xml step //to have some progress for the cleanup/write component.xml step
ProgressCoordinator::instance()->addReservePercentagePoints(1); 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 // 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(); 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<Component *> componentsToInstall = m_core->orderedComponentsToInstall(); const QList<Component *> componentsToInstall = m_core->orderedComponentsToInstall();
qDebug() << "Install size:" << componentsToInstall.size() << "components"; qDebug() << "Install size:" << componentsToInstall.size() << "components";
@ -1792,8 +1819,7 @@ bool PackageManagerCorePrivate::runUninstaller()
setStatus(PackageManagerCore::Running); setStatus(PackageManagerCore::Running);
// check if we need to run elevated and ask before the action happens // check if we need to run elevated and ask before the action happens
QTemporaryFile tempAdminFile(targetDir() + QLatin1String("/adminrights")); if (!directoryWritable(targetDir()))
if (!tempAdminFile.open() || !tempAdminFile.isWritable())
adminRightsGained = m_core->gainAdminRights(); adminRightsGained = m_core->gainAdminRights();
OperationList undoOperations = m_performedOperationsOld; OperationList undoOperations = m_performedOperationsOld;
@ -2005,7 +2031,7 @@ void PackageManagerCorePrivate::deleteMaintenanceTool()
// every other platform has no problem if we just delete ourselves now // every other platform has no problem if we just delete ourselves now
QFile maintenanceTool(QFileInfo(installerBinaryPath()).absoluteFilePath()); QFile maintenanceTool(QFileInfo(installerBinaryPath()).absoluteFilePath());
maintenanceTool.remove(); maintenanceTool.remove();
# ifdef Q_OS_OSX # ifdef Q_OS_MACOS
if (QInstaller::isInBundle(installerBinaryPath())) { if (QInstaller::isInBundle(installerBinaryPath())) {
const QLatin1String cdUp("/../../.."); const QLatin1String cdUp("/../../..");
removeDirectoryThreaded(QFileInfo(installerBinaryPath() + cdUp).absoluteFilePath()); removeDirectoryThreaded(QFileInfo(installerBinaryPath() + cdUp).absoluteFilePath());

View File

@ -92,6 +92,9 @@ public:
QString targetDir() const; QString targetDir() const;
QString registerPath(); QString registerPath();
bool directoryWritable(const QString &path) const;
bool subdirectoriesWritable(const QString &path) const;
QString maintenanceToolName() const; QString maintenanceToolName() const;
QString installerBinaryPath() const; QString installerBinaryPath() const;

View File

@ -57,7 +57,7 @@ PackageManagerCoreData::PackageManagerCoreData(const QHash<QString, QString> &va
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
m_variables.insert(QLatin1String("os"), QLatin1String("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")); m_variables.insert(QLatin1String("os"), QLatin1String("mac"));
#elif defined(Q_OS_LINUX) #elif defined(Q_OS_LINUX)
m_variables.insert(QLatin1String("os"), QLatin1String("x11")); m_variables.insert(QLatin1String("os"), QLatin1String("x11"));
@ -110,10 +110,8 @@ void PackageManagerCoreData::setDynamicPredefinedVariables()
TCHAR buffer[MAX_PATH + 1] = { 0 }; TCHAR buffer[MAX_PATH + 1] = { 0 };
SHGetFolderPath(nullptr, CSIDL_PROGRAM_FILES, nullptr, 0, buffer); SHGetFolderPath(nullptr, CSIDL_PROGRAM_FILES, nullptr, 0, buffer);
dir = QString::fromWCharArray(buffer); dir = QString::fromWCharArray(buffer);
#elif defined (Q_OS_OSX) #elif defined (Q_OS_MACOS)
dir = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation).value(1); dir = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation).value(0);
if (dir.isEmpty())
dir = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation).value(0);
#endif #endif
m_variables.insert(QLatin1String("ApplicationsDir"), dir); m_variables.insert(QLatin1String("ApplicationsDir"), dir);

View File

@ -305,7 +305,7 @@ PackageManagerGui::PackageManagerGui(PackageManagerCore *core, QWidget *parent)
setWindowTitle(tr("Maintain %1").arg(m_core->value(scTitle))); setWindowTitle(tr("Maintain %1").arg(m_core->value(scTitle)));
setWindowFlags(windowFlags() &~ Qt::WindowContextHelpButtonHint); setWindowFlags(windowFlags() &~ Qt::WindowContextHelpButtonHint);
#ifndef Q_OS_OSX #ifndef Q_OS_MACOS
setWindowIcon(QIcon(m_core->settings().installerWindowIcon())); setWindowIcon(QIcon(m_core->settings().installerWindowIcon()));
#else #else
setPixmap(QWizard::BackgroundPixmap, m_core->settings().background()); setPixmap(QWizard::BackgroundPixmap, m_core->settings().background());
@ -408,7 +408,7 @@ PackageManagerGui::~PackageManagerGui()
\list \list
\li \c Classic - Classic UI style for Windows 7 and earlier. \li \c Classic - Classic UI style for Windows 7 and earlier.
\li \c Modern - Modern UI style for Windows 8. \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. \li \c Aero - Aero Peek for Windows 7.
\endlist \endlist
*/ */
@ -1543,7 +1543,7 @@ void IntroductionPage::setErrorMessage(const QString &error)
{ {
QPalette palette; QPalette palette;
const PackageManagerCore::Status s = packageManagerCore()->status(); const PackageManagerCore::Status s = packageManagerCore()->status();
if (s == PackageManagerCore::Failure || s == PackageManagerCore::Failure) { if (s == PackageManagerCore::Failure) {
palette.setColor(QPalette::WindowText, Qt::red); palette.setColor(QPalette::WindowText, Qt::red);
} else { } else {
palette.setColor(QPalette::WindowText, palette.color(QPalette::WindowText)); palette.setColor(QPalette::WindowText, palette.color(QPalette::WindowText));
@ -1911,6 +1911,11 @@ void ComponentSelectionPage::entering()
setColoredSubTitle(tr(strings[index])); setColoredSubTitle(tr(strings[index]));
d->updateTreeView(); 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()); setModified(isComplete());
if (core->settings().repositoryCategories().count() > 0 && !core->isOfflineOnly() if (core->settings().repositoryCategories().count() > 0 && !core->isOfflineOnly()
&& !core->isUpdater()) { && !core->isUpdater()) {
@ -2173,7 +2178,7 @@ bool TargetDirectoryPage::validatePage()
const QFileInfo fi(targetDir); const QFileInfo fi(targetDir);
if (fi.isDir()) { if (fi.isDir()) {
QString fileName = packageManagerCore()->settings().maintenanceToolName(); QString fileName = packageManagerCore()->settings().maintenanceToolName();
#if defined(Q_OS_OSX) #if defined(Q_OS_MACOS)
if (QInstaller::isInBundle(QCoreApplication::applicationDirPath())) if (QInstaller::isInBundle(QCoreApplication::applicationDirPath()))
fileName += QLatin1String(".app/Contents/MacOS/") + fileName; fileName += QLatin1String(".app/Contents/MacOS/") + fileName;
#elif defined(Q_OS_WIN) #elif defined(Q_OS_WIN)
@ -2844,7 +2849,7 @@ void FinishedPage::entering()
} }
if (packageManagerCore()->isMaintainer()) { if (packageManagerCore()->isMaintainer()) {
#ifdef Q_OS_OSX #ifdef Q_OS_MACOS
gui()->setOption(QWizard::NoCancelButton, false); gui()->setOption(QWizard::NoCancelButton, false);
#endif #endif
if (QAbstractButton *cancel = gui()->button(QWizard::CancelButton)) { if (QAbstractButton *cancel = gui()->button(QWizard::CancelButton)) {
@ -2908,7 +2913,7 @@ void FinishedPage::entering()
*/ */
void FinishedPage::leaving() void FinishedPage::leaving()
{ {
#ifdef Q_OS_OSX #ifdef Q_OS_MACOS
gui()->setOption(QWizard::NoCancelButton, true); gui()->setOption(QWizard::NoCancelButton, true);
#endif #endif

View File

@ -29,6 +29,8 @@
#include "remoteclient.h" #include "remoteclient.h"
#include "remoteclient_p.h" #include "remoteclient_p.h"
#include <QDir>
namespace QInstaller { namespace QInstaller {
RemoteClient *RemoteClient::s_instance = nullptr; RemoteClient *RemoteClient::s_instance = nullptr;
@ -61,6 +63,18 @@ QString RemoteClient::authorizationKey() const
return d->m_key; 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 Initializes the client with \a socketName, with the \a key the client
sends to authenticate with the server, \a mode and \a startAs. 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) Protocol::StartAs startAs)
{ {
Q_D(RemoteClient); 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); d->init(socketName, key, mode, startAs);
#endif
} }
void RemoteClient::setAuthorizationFallbackDisabled(bool disabled) void RemoteClient::setAuthorizationFallbackDisabled(bool disabled)

View File

@ -54,6 +54,7 @@ public:
QString socketName() const; QString socketName() const;
QString authorizationKey() const; QString authorizationKey() const;
QString socketPathName(const QString &socketName) const;
bool isActive() const; bool isActive() const;
void setActive(bool active); void setActive(bool active);

View File

@ -324,9 +324,9 @@ bool RemoteFileEngine::open(QIODevice::OpenMode mode)
{ {
if (connectToServer()) { if (connectToServer()) {
return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineOpen), return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineOpen),
static_cast<qint32>(mode)); static_cast<qint32>(mode | QIODevice::Unbuffered));
} }
return m_fileEngine.open(mode); return m_fileEngine.open(mode | QIODevice::Unbuffered);
} }
/*! /*!

View File

@ -65,7 +65,7 @@ void RemoteServer::start()
if (d->m_localServer) if (d->m_localServer)
return; return;
#if defined(Q_OS_UNIX) && !defined(Q_OS_OSX) #if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
// avoid writing to stderr: // avoid writing to stderr:
// the parent process has redirected stderr to a pipe to work with sudo, // 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. // 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) void RemoteServer::init(const QString &socketName, const QString &key, Protocol::Mode mode)
{ {
Q_D(RemoteServer); 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; d->m_socketName = socketName;
#endif
d->m_key = key; d->m_key = key;
d->m_mode = mode; d->m_mode = mode;
} }
@ -116,6 +126,18 @@ QString RemoteServer::authorizationKey() const
return d->m_key; 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. Restarts the watchdog that tries to kill the server.
*/ */

View File

@ -53,6 +53,7 @@ public:
QString socketName() const; QString socketName() const;
QString authorizationKey() const; QString authorizationKey() const;
QString socketPathName(const QString &socketName) const;
private slots: private slots:
void restartWatchdog(); void restartWatchdog();

View File

@ -382,7 +382,14 @@ void RemoteServerConnection::handleQFSFileEngine(QIODevice *socket, const QStrin
} else if (command == QLatin1String(Protocol::QAbstractFileEngineCopy)) { } else if (command == QLatin1String(Protocol::QAbstractFileEngineCopy)) {
QString newName; QString newName;
data >>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)); sendData(socket, m_engine->copy(newName));
#endif
} else if (command == QLatin1String(Protocol::QAbstractFileEngineEntryList)) { } else if (command == QLatin1String(Protocol::QAbstractFileEngineEntryList)) {
qint32 filters; qint32 filters;
QStringList filterNames; QStringList filterNames;

View File

@ -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) void Repository::setCategoryName(const QString &categoryname)
{ {

View File

@ -28,6 +28,7 @@
#include "repositorycategory.h" #include "repositorycategory.h"
#include "filedownloaderfactory.h" #include "filedownloaderfactory.h"
#include "constants.h"
#include <QDataStream> #include <QDataStream>
#include <QFileInfo> #include <QFileInfo>
@ -102,16 +103,20 @@ void RepositoryCategory::setTooltip(const QString &tooltip)
*/ */
QSet<Repository> RepositoryCategory::repositories() const QSet<Repository> RepositoryCategory::repositories() const
{ {
return variantListToSet<Repository>(m_data.values(QLatin1String("Repositories"))); return variantListToSet<Repository>(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<Repository> repositories) void RepositoryCategory::setRepositories(const QSet<Repository> repositories, const bool replace)
{ {
if (replace)
m_data.remove(scRepositories);
foreach (const Repository &repository, repositories) 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<Repository> repositories)
*/ */
void RepositoryCategory::addRepository(const Repository repository) void RepositoryCategory::addRepository(const Repository repository)
{ {
m_data.insertMulti(QLatin1String("Repositories"), QVariant().fromValue(repository)); m_data.insertMulti(scRepositories, QVariant().fromValue(repository));
} }
/*! /*!

View File

@ -54,7 +54,7 @@ public:
void setTooltip(const QString &tooltip); void setTooltip(const QString &tooltip);
QSet<Repository> repositories() const; QSet<Repository> repositories() const;
void setRepositories(const QSet<Repository> repositories); void setRepositories(const QSet<Repository> repositories, const bool replace = false);
void addRepository(const Repository repository); void addRepository(const Repository repository);
bool isEnabled() const; bool isEnabled() const;

View File

@ -472,7 +472,7 @@ QString Settings::installerWindowIcon() const
QString Settings::systemIconSuffix() const QString Settings::systemIconSuffix() const
{ {
#if defined(Q_OS_OSX) #if defined(Q_OS_MACOS)
return QLatin1String(".icns"); return QLatin1String(".icns");
#elif defined(Q_OS_WIN) #elif defined(Q_OS_WIN)
return QLatin1String(".ico"); return QLatin1String(".ico");
@ -616,12 +616,46 @@ void Settings::addDefaultRepositories(const QSet<Repository> &repositories)
d->m_data.insertMulti(scRepositories, QVariant().fromValue(repository)); d->m_data.insertMulti(scRepositories, QVariant().fromValue(repository));
} }
void Settings::setRepositoryCategories(const QSet<RepositoryCategory> &repositories)
{
d->m_data.remove(scRepositoryCategories);
addRepositoryCategories(repositories);
}
void Settings::addRepositoryCategories(const QSet<RepositoryCategory> &repositories) void Settings::addRepositoryCategories(const QSet<RepositoryCategory> &repositories)
{ {
foreach (const RepositoryCategory &repository, repositories) foreach (const RepositoryCategory &repository, repositories)
d->m_data.insertMulti(scRepositoryCategories, QVariant().fromValue(repository)); d->m_data.insertMulti(scRepositoryCategories, QVariant().fromValue(repository));
} }
Settings::Update Settings::updateRepositoryCategories(const RepoHash &updates)
{
if (updates.isEmpty())
return Settings::NoUpdatesApplied;
QSet<RepositoryCategory> categories = repositoryCategories();
QList<RepositoryCategory> categoriesList = categories.values();
QPair<Repository, Repository> updateValues = updates.value(QLatin1String("replace"));
bool update = false;
foreach (RepositoryCategory category, categoriesList) {
QSet<Repository> 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<QUrl, Repository> *reposToUpdate) static bool apply(const RepoHash &updates, QHash<QUrl, Repository> *reposToUpdate)
{ {
bool update = false; bool update = false;

View File

@ -115,13 +115,16 @@ public:
QSet<Repository> repositories() const; QSet<Repository> repositories() const;
QSet<Repository> defaultRepositories() const; QSet<Repository> defaultRepositories() const;
QSet<RepositoryCategory> repositoryCategories() const;
QMap<QString, RepositoryCategory> organizedRepositoryCategories() const;
void setDefaultRepositories(const QSet<Repository> &repositories); void setDefaultRepositories(const QSet<Repository> &repositories);
void addDefaultRepositories(const QSet<Repository> &repositories); void addDefaultRepositories(const QSet<Repository> &repositories);
void addRepositoryCategories(const QSet<RepositoryCategory> &repositories);
Settings::Update updateDefaultRepositories(const RepoHash &updates); Settings::Update updateDefaultRepositories(const RepoHash &updates);
QSet<RepositoryCategory> repositoryCategories() const;
QMap<QString, RepositoryCategory> organizedRepositoryCategories() const;
void setRepositoryCategories(const QSet<RepositoryCategory> &repositories);
void addRepositoryCategories(const QSet<RepositoryCategory> &repositories);
Settings::Update updateRepositoryCategories(const RepoHash &updates);
QSet<Repository> temporaryRepositories() const; QSet<Repository> temporaryRepositories() const;
void setTemporaryRepositories(const QSet<Repository> &repositories, bool replace); void setTemporaryRepositories(const QSet<Repository> &repositories, bool replace);
void addTemporaryRepositories(const QSet<Repository> &repositories, bool replace); void addTemporaryRepositories(const QSet<Repository> &repositories, bool replace);

View File

@ -180,7 +180,7 @@ bool SettingsOperation::undoOperation()
if (!settingsFile.remove()) if (!settingsFile.remove())
qWarning().noquote() << settingsFile.errorString(); qWarning().noquote() << settingsFile.errorString();
if (!value(QLatin1String("createddir")).toString().isEmpty()) { if (!value(QLatin1String("createddir")).toString().isEmpty()) {
KDUpdater::MkdirOperation mkDirOperation; KDUpdater::MkdirOperation mkDirOperation(packageManager());
mkDirOperation.setArguments(QStringList() << QFileInfo(path).absolutePath()); mkDirOperation.setArguments(QStringList() << QFileInfo(path).absolutePath());
mkDirOperation.setValue(QLatin1String("createddir"), value(QLatin1String("createddir"))); mkDirOperation.setValue(QLatin1String("createddir"), value(QLatin1String("createddir")));

View File

@ -76,7 +76,7 @@ QString SystemInfo::currentCpuArchitecture() const
kernel the installer is running on, unless the host operating system is running a form of kernel the installer is running on, unless the host operating system is running a form of
compatibility or virtualization layer. compatibility or virtualization layer.
For Windows, Linux, and OS X this will return: For Windows, Linux, and macOS this will return:
\list \list
\li "winnt" \li "winnt"
\li "linux" \li "linux"
@ -96,7 +96,7 @@ QString SystemInfo::kernelType() const
\property SystemInfo::kernelVersion \property SystemInfo::kernelVersion
The release version of the operating system kernel. On Windows, it returns the version of the 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. command would return.
Example values are: Example values are:

View File

@ -455,7 +455,7 @@ QDomDocument UpdateOperation::toXml() const
bool UpdateOperation::fromXml(const QDomDocument &doc) bool UpdateOperation::fromXml(const QDomDocument &doc)
{ {
QString target = QCoreApplication::applicationDirPath(); 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)) if (QInstaller::isInBundle(target, &target))
target = QDir::cleanPath(target + QLatin1String("/..")); target = QDir::cleanPath(target + QLatin1String("/.."));

View File

@ -51,7 +51,7 @@ CommandLineParser::CommandLineParser()
QLatin1String("Verbose mode. Prints out more information."))); QLatin1String("Verbose mode. Prints out more information.")));
m_parser.addOption(QCommandLineOption(QLatin1String(CommandLineOptions::Proxy), 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), m_parser.addOption(QCommandLineOption(QLatin1String(CommandLineOptions::NoProxy),
QLatin1String("Do not use system proxy."))); QLatin1String("Do not use system proxy.")));

View File

@ -1,3 +1,21 @@
#include <windows.h>
/* 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 IDI_ICON1 ICON DISCARDABLE
"installerbase.ico" "installerbase.ico"

View File

@ -44,7 +44,7 @@
#include <iostream> #include <iostream>
#if defined(Q_OS_OSX) or defined(Q_OS_UNIX) #if defined(Q_OS_MACOS) or defined(Q_OS_UNIX)
# include <unistd.h> # include <unistd.h>
# include <sys/types.h> # include <sys/types.h>
#endif #endif
@ -66,7 +66,7 @@ int main(int argc, char *argv[])
} }
#endif #endif
// increase maximum numbers of file descriptors // increase maximum numbers of file descriptors
#if defined (Q_OS_OSX) #if defined (Q_OS_MACOS)
QCoreApplication::setSetuidAllowed(true); QCoreApplication::setSetuidAllowed(true);
struct rlimit rl; struct rlimit rl;
getrlimit(RLIMIT_NOFILE, &rl); getrlimit(RLIMIT_NOFILE, &rl);
@ -141,7 +141,7 @@ int main(int argc, char *argv[])
Qt::CaseInsensitive) == 0); Qt::CaseInsensitive) == 0);
if (production) { if (production) {
argumentsValid = (!key.isEmpty()) && (!socketName.isEmpty()); 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. */ /* In production mode detach child so that sudo waiting on us will terminate. */
pid_t child = fork(); pid_t child = fork();
if (child <= -1) { if (child <= -1) {
@ -166,7 +166,7 @@ int main(int argc, char *argv[])
return EXIT_FAILURE; return EXIT_FAILURE;
} }
#if defined(Q_OS_OSX) #if defined(Q_OS_MACOS)
// make sure effective == real user id. // make sure effective == real user id.
uid_t realUserId = getuid(); uid_t realUserId = getuid();
uid_t effectiveUserId = geteuid(); uid_t effectiveUserId = geteuid();

View File

@ -73,21 +73,21 @@ public:
as the binary layout cannot be appended to the actual maintenance tool binary as the binary layout cannot be appended to the actual maintenance tool binary
itself because of signing. 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 .dat file is located inside the resource folder in the application
bundle in OS X. bundle in macOS.
*/ */
QString binaryFile() const QString binaryFile() const
{ {
QString binaryFile = QCoreApplication::applicationFilePath(); 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. // content, it's put into the resources folder as separate file.
// Adjust the actual binary path. No error checking here since we // Adjust the actual binary path. No error checking here since we
// will fail later while reading the binary content. // will fail later while reading the binary content.
QDir resourcePath(QFileInfo(binaryFile).dir()); QDir resourcePath(QFileInfo(binaryFile).dir());
#ifdef Q_OS_OSX #ifdef Q_OS_MACOS
resourcePath.cdUp(); resourcePath.cdUp();
resourcePath.cd(QLatin1String("Resources")); resourcePath.cd(QLatin1String("Resources"));
#endif #endif
@ -116,7 +116,7 @@ public:
QString bundlePath; QString bundlePath;
if (QInstaller::isInBundle(fi.absoluteFilePath(), &bundlePath)) if (QInstaller::isInBundle(fi.absoluteFilePath(), &bundlePath))
fi.setFile(bundlePath); fi.setFile(bundlePath);
#ifdef Q_OS_OSX #ifdef Q_OS_MACOS
return fi.absoluteDir().filePath(fi.baseName() + QLatin1String(".dat")); return fi.absoluteDir().filePath(fi.baseName() + QLatin1String(".dat"));
#else #else
return fi.absoluteDir().filePath(qApp->applicationName() + QLatin1String(".dat")); return fi.absoluteDir().filePath(qApp->applicationName() + QLatin1String(".dat"));

View File

@ -1365,15 +1365,15 @@ Fehler beim Laden von %2</translation>
<translation>Willkommen zum %1-Einrichtungsassistenten.</translation> <translation>Willkommen zum %1-Einrichtungsassistenten.</translation>
</message> </message>
<message> <message>
<source>Add or remove components</source> <source>&amp;Add or remove components</source>
<translation>Komponenten hinzufügen oder entfernen</translation> <translation>Komponenten hinzufügen oder entfernen</translation>
</message> </message>
<message> <message>
<source>Update components</source> <source>&amp;Update components</source>
<translation>Komponenten aktualisieren</translation> <translation>Komponenten aktualisieren</translation>
</message> </message>
<message> <message>
<source>Remove all components</source> <source>&amp;Remove all components</source>
<translation>Alle Komponenten entfernen</translation> <translation>Alle Komponenten entfernen</translation>
</message> </message>
<message> <message>
@ -1393,7 +1393,7 @@ Fehler beim Laden von %2</translation>
<translation> Nur lokale Paketverwaltung verfügbar.</translation> <translation> Nur lokale Paketverwaltung verfügbar.</translation>
</message> </message>
<message> <message>
<source>Quit</source> <source>&amp;Quit</source>
<translation>Beenden</translation> <translation>Beenden</translation>
</message> </message>
</context> </context>

View File

@ -1327,15 +1327,15 @@ Error al descargar %2</translation>
<translation>Bienvenido al Asistente de instalación de %1.</translation> <translation>Bienvenido al Asistente de instalación de %1.</translation>
</message> </message>
<message> <message>
<source>Add or remove components</source> <source>&amp;Add or remove components</source>
<translation>Agregar o quitar componentes</translation> <translation>Agregar o quitar componentes</translation>
</message> </message>
<message> <message>
<source>Update components</source> <source>&amp;Update components</source>
<translation>Actualizar componentes</translation> <translation>Actualizar componentes</translation>
</message> </message>
<message> <message>
<source>Remove all components</source> <source>&amp;Remove all components</source>
<translation>Quitar todos los componentes</translation> <translation>Quitar todos los componentes</translation>
</message> </message>
<message> <message>
@ -1355,7 +1355,7 @@ Error al descargar %2</translation>
<translation> Solo está disponible la administración de paquetes locales.</translation> <translation> Solo está disponible la administración de paquetes locales.</translation>
</message> </message>
<message> <message>
<source>Quit</source> <source>&amp;Quit</source>
<translation>Salir</translation> <translation>Salir</translation>
</message> </message>
</context> </context>

View File

@ -1327,15 +1327,15 @@ Erreur lors du chargement de %2</translation>
<translation>Bienvenue dans lassistant dinstallation de %1</translation> <translation>Bienvenue dans lassistant dinstallation de %1</translation>
</message> </message>
<message> <message>
<source>Add or remove components</source> <source>&amp;Add or remove components</source>
<translation>Ajouter ou supprimer des composants</translation> <translation>Ajouter ou supprimer des composants</translation>
</message> </message>
<message> <message>
<source>Update components</source> <source>&amp;Update components</source>
<translation>Mettre à jour des composants</translation> <translation>Mettre à jour des composants</translation>
</message> </message>
<message> <message>
<source>Remove all components</source> <source>&amp;Remove all components</source>
<translation>Supprimer tous les composants</translation> <translation>Supprimer tous les composants</translation>
</message> </message>
<message> <message>
@ -1355,7 +1355,7 @@ Erreur lors du chargement de %2</translation>
<translation> Seule la gestion des paquetages locaux est disponible.</translation> <translation> Seule la gestion des paquetages locaux est disponible.</translation>
</message> </message>
<message> <message>
<source>Quit</source> <source>&amp;Quit</source>
<translation>Quitter</translation> <translation>Quitter</translation>
</message> </message>
</context> </context>

View File

@ -1327,15 +1327,15 @@ Errore durante il caricamento di %2</translation>
<translation>Installazione guidata di %1.</translation> <translation>Installazione guidata di %1.</translation>
</message> </message>
<message> <message>
<source>Add or remove components</source> <source>&amp;Add or remove components</source>
<translation>Aggiungi o rimuovi componenti</translation> <translation>Aggiungi o rimuovi componenti</translation>
</message> </message>
<message> <message>
<source>Update components</source> <source>&amp;Update components</source>
<translation>Aggiorna componenti</translation> <translation>Aggiorna componenti</translation>
</message> </message>
<message> <message>
<source>Remove all components</source> <source>&amp;Remove all components</source>
<translation>Rimuovi tutti i componenti</translation> <translation>Rimuovi tutti i componenti</translation>
</message> </message>
<message> <message>
@ -1355,7 +1355,7 @@ Errore durante il caricamento di %2</translation>
<translation> Disponibile solo gestione pacchetto locale.</translation> <translation> Disponibile solo gestione pacchetto locale.</translation>
</message> </message>
<message> <message>
<source>Quit</source> <source>&amp;Quit</source>
<translation>Esci</translation> <translation>Esci</translation>
</message> </message>
</context> </context>

View File

@ -1327,15 +1327,15 @@ Error while loading %2</source>
<translation>%1 </translation> <translation>%1 </translation>
</message> </message>
<message> <message>
<source>Add or remove components</source> <source>&amp;Add or remove components</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<source>Update components</source> <source>&amp;Update components</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<source>Remove all components</source> <source>&amp;Remove all components</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
@ -1355,7 +1355,7 @@ Error while loading %2</source>
<translation> </translation> <translation> </translation>
</message> </message>
<message> <message>
<source>Quit</source> <source>&amp;Quit</source>
<translation></translation> <translation></translation>
</message> </message>
</context> </context>

View File

@ -1327,15 +1327,15 @@ Błąd podczas wczytywania %2</translation>
<translation>Witamy w Kreatorze konfiguracji %1.</translation> <translation>Witamy w Kreatorze konfiguracji %1.</translation>
</message> </message>
<message> <message>
<source>Add or remove components</source> <source>&amp;Add or remove components</source>
<translation>Dodaj lub usuń elementy</translation> <translation>Dodaj lub usuń elementy</translation>
</message> </message>
<message> <message>
<source>Update components</source> <source>&amp;Update components</source>
<translation>Zaktualizuj elementy</translation> <translation>Zaktualizuj elementy</translation>
</message> </message>
<message> <message>
<source>Remove all components</source> <source>&amp;Remove all components</source>
<translation>Usuń wszystkie elementy</translation> <translation>Usuń wszystkie elementy</translation>
</message> </message>
<message> <message>
@ -1355,7 +1355,7 @@ Błąd podczas wczytywania %2</translation>
<translation> Dostępne jedynie lokalne zarządzanie pakietami.</translation> <translation> Dostępne jedynie lokalne zarządzanie pakietami.</translation>
</message> </message>
<message> <message>
<source>Quit</source> <source>&amp;Quit</source>
<translation>Zakończ</translation> <translation>Zakończ</translation>
</message> </message>
</context> </context>

View File

@ -1327,15 +1327,15 @@ Error while loading %2</source>
<translation>使 %1 </translation> <translation>使 %1 </translation>
</message> </message>
<message> <message>
<source>Add or remove components</source> <source>&amp;Add or remove components</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<source>Update components</source> <source>&amp;Update components</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<source>Remove all components</source> <source>&amp;Remove all components</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
@ -1355,7 +1355,7 @@ Error while loading %2</source>
<translation> </translation> <translation> </translation>
</message> </message>
<message> <message>
<source>Quit</source> <source>&amp;Quit</source>
<translation>退</translation> <translation>退</translation>
</message> </message>
</context> </context>

View File

@ -128,7 +128,7 @@ private slots:
// throws // throws
QInstaller::BinaryContent::findMagicCookie(&file, QInstaller::BinaryContent::MagicCookie); QInstaller::BinaryContent::findMagicCookie(&file, QInstaller::BinaryContent::MagicCookie);
} catch (const QInstaller::Error &error) { } 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 (...) { } catch (...) {
QFAIL("Unexpected error."); QFAIL("Unexpected error.");
} }

View File

@ -34,6 +34,7 @@
#include <progresscoordinator.h> #include <progresscoordinator.h>
#include <QDir> #include <QDir>
#include <QFile>
#include <QTemporaryFile> #include <QTemporaryFile>
#include <QTest> #include <QTest>
@ -118,15 +119,18 @@ private slots:
QVERIFY(core.calculateComponentsToInstall()); QVERIFY(core.calculateComponentsToInstall());
{ {
QTemporaryFile dummy(testDirectory + QLatin1String("/dummy")); QFile dummy(testDirectory + QLatin1String("/dummy"));
dummy.open(); QVERIFY(dummy.open(QIODevice::ReadWrite));
core.runInstaller(); core.runInstaller();
QVERIFY(QDir(testDirectory).exists()); QVERIFY(QDir(testDirectory).exists());
QVERIFY(QFileInfo(dummy.fileName()).exists()); QVERIFY(QFileInfo(dummy.fileName()).exists());
dummy.close();
QVERIFY(dummy.remove());
} }
QDir().rmdir(testDirectory); QVERIFY(QDir().rmdir(testDirectory));
ProgressCoordinator::instance()->reset(); ProgressCoordinator::instance()->reset();
} }
@ -257,6 +261,58 @@ private slots:
core.calculateComponentsToInstall(); core.calculateComponentsToInstall();
QCOMPARE(core.requiredDiskSpace(), 250ULL); 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));
}
}; };

View File

@ -1,4 +1,6 @@
#include "repository.h" #include "repository.h"
#include "repositorycategory.h"
#include "settings.h"
#include <QDataStream> #include <QDataStream>
#include <QString> #include <QString>
@ -114,6 +116,51 @@ private slots:
s1 >> r1; s2 >> r2; s1 >> r1; s2 >> r2;
QCOMPARE(r1, 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<RepositoryCategory> categories;
categories.insert(category);
settings.setRepositoryCategories(categories);
QHash<QString, QPair<Repository, Repository>> 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) QTEST_MAIN(tst_Repository)

View File

@ -280,7 +280,11 @@ private slots:
// ignore Output from script // ignore Output from script
setExpectedScriptOutput("function receive()"); setExpectedScriptOutput("function receive()");
#if QT_VERSION >= QT_VERSION_CHECK(5,12,0)
QTest::ignoreMessage(QtWarningMsg, "<Unknown File>:38: ReferenceError: foo is not defined");
#else
QTest::ignoreMessage(QtWarningMsg, ":38: ReferenceError: foo is not defined"); QTest::ignoreMessage(QtWarningMsg, ":38: ReferenceError: foo is not defined");
#endif
emiter.produceSignal(); emiter.produceSignal();
const QJSValue value = m_scriptEngine->evaluate(""); const QJSValue value = m_scriptEngine->evaluate("");

View File

@ -49,7 +49,7 @@ void tst_Settings::loadTutorialConfig()
QCOMPARE(settings.installerApplicationIcon(), QLatin1String(":/installer.ico")); QCOMPARE(settings.installerApplicationIcon(), QLatin1String(":/installer.ico"));
QCOMPARE(settings.installerWindowIcon(), QLatin1String(":/installer.ico")); QCOMPARE(settings.installerWindowIcon(), QLatin1String(":/installer.ico"));
QCOMPARE(settings.systemIconSuffix(), QLatin1String(".ico")); QCOMPARE(settings.systemIconSuffix(), QLatin1String(".ico"));
#elif defined(Q_OS_OSX) #elif defined(Q_OS_MACOS)
QCOMPARE(settings.installerApplicationIcon(), QLatin1String(":/installer.icns")); QCOMPARE(settings.installerApplicationIcon(), QLatin1String(":/installer.icns"));
QCOMPARE(settings.installerWindowIcon(), QLatin1String(":/installer.icns")); QCOMPARE(settings.installerWindowIcon(), QLatin1String(":/installer.icns"));
QCOMPARE(settings.systemIconSuffix(), QLatin1String(".icns")); QCOMPARE(settings.systemIconSuffix(), QLatin1String(".icns"));

View File

@ -263,7 +263,7 @@ static QVersionNumber readMachOMinimumSystemVersion(QIODevice *device)
static int assemble(Input input, const QInstaller::Settings &settings, const QString &signingIdentity) 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)) { if (QInstaller::isInBundle(input.installerExePath)) {
const QString bundle = input.installerExePath; const QString bundle = input.installerExePath;
// if the input file was a bundle // if the input file was a bundle
@ -330,9 +330,12 @@ static int assemble(Input input, const QInstaller::Settings &settings, const QSt
<< endl; << endl;
plistStream << QLatin1String("\t<key>CFBundlePackageType</key>") << endl; plistStream << QLatin1String("\t<key>CFBundlePackageType</key>") << endl;
plistStream << QLatin1String("\t<string>APPL</string>") << endl; plistStream << QLatin1String("\t<string>APPL</string>") << endl;
plistStream << QLatin1String("\t<key>CFBundleGetInfoString</key>") << endl;
#define QUOTE_(x) #x #define QUOTE_(x) #x
#define QUOTE(x) QUOTE_(x) #define QUOTE(x) QUOTE_(x)
plistStream << QLatin1String("\t<key>CFBundleShortVersionString</key>") << endl;
plistStream << QLatin1String("\t<string>") << QLatin1String(QUOTE(IFW_VERSION_STR)) << ("</string>")
<< endl;
plistStream << QLatin1String("\t<key>CFBundleVersion</key>") << endl;
plistStream << QLatin1String("\t<string>") << QLatin1String(QUOTE(IFW_VERSION_STR)) << ("</string>") plistStream << QLatin1String("\t<string>") << QLatin1String(QUOTE(IFW_VERSION_STR)) << ("</string>")
<< endl; << endl;
#undef QUOTE #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 // no error handling as this is not fatal
setApplicationIcon(tempFile, settings.installerApplicationIcon()); setApplicationIcon(tempFile, settings.installerApplicationIcon());
} }
#elif defined(Q_OS_OSX) #elif defined(Q_OS_MACOS)
if (isBundle) { if (isBundle) {
// no error handling as this is not fatal // no error handling as this is not fatal
const QString copyscript = QDir::temp().absoluteFilePath(QLatin1String("copylibsintobundle.sh")); 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; QTemporaryFile out;
QString targetName = input.outputPath; QString targetName = input.outputPath;
#ifdef Q_OS_OSX #ifdef Q_OS_MACOS
QDir resourcePath(QFileInfo(input.outputPath).dir()); QDir resourcePath(QFileInfo(input.outputPath).dir());
resourcePath.cdUp(); resourcePath.cdUp();
resourcePath.cd(QLatin1String("Resources")); resourcePath.cd(QLatin1String("Resources"));
@ -429,7 +432,7 @@ static int assemble(Input input, const QInstaller::Settings &settings, const QSt
QInstaller::openForWrite(&out); QInstaller::openForWrite(&out);
QFile exe(input.installerExePath); QFile exe(input.installerExePath);
#ifdef Q_OS_OSX #ifdef Q_OS_MACOS
if (!exe.copy(input.outputPath)) { if (!exe.copy(input.outputPath)) {
throw Error(QString::fromLatin1("Cannot copy %1 to %2: %3").arg(exe.fileName(), throw Error(QString::fromLatin1("Cannot copy %1 to %2: %3").arg(exe.fileName(),
input.outputPath, exe.errorString())); input.outputPath, exe.errorString()));
@ -474,7 +477,7 @@ static int assemble(Input input, const QInstaller::Settings &settings, const QSt
#endif #endif
QFile::remove(tempFile); QFile::remove(tempFile);
#ifdef Q_OS_OSX #ifdef Q_OS_MACOS
if (isBundle && !signingIdentity.isEmpty()) { if (isBundle && !signingIdentity.isEmpty()) {
qDebug() << "Signing .app bundle..."; 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::cout << " -rcc|--compile-resource Compiles the default resource and outputs the result into"
<< std::endl; << std::endl;
std::cout << " 'update.rcc' in the current path." << 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 << " -s|--sign identity Sign generated app bundle using the given code " << std::endl;
std::cout << " signing identity" << std::endl; std::cout << " signing identity" << std::endl;
#endif #endif
@ -715,7 +718,7 @@ void copyConfigData(const QString &configFile, const QString &targetDir)
QString targetFile; QString targetFile;
QFileInfo elementFileInfo; QFileInfo elementFileInfo;
if (tagName == QLatin1String("Icon") || tagName == QLatin1String("InstallerApplicationIcon")) { if (tagName == QLatin1String("Icon") || tagName == QLatin1String("InstallerApplicationIcon")) {
#if defined(Q_OS_OSX) #if defined(Q_OS_MACOS)
const QString suffix = QLatin1String(".icns"); const QString suffix = QLatin1String(".icns");
#elif defined(Q_OS_WIN) #elif defined(Q_OS_WIN)
const QString suffix = QLatin1String(".ico"); const QString suffix = QLatin1String(".ico");
@ -882,7 +885,7 @@ int main(int argc, char **argv)
continue; continue;
} else if (*it == QLatin1String("-rcc") || *it == QLatin1String("--compile-resource")) { } else if (*it == QLatin1String("-rcc") || *it == QLatin1String("--compile-resource")) {
compileResource = true; compileResource = true;
#ifdef Q_OS_OSX #ifdef Q_OS_MACOS
} else if (*it == QLatin1String("-s") || *it == QLatin1String("--sign")) { } else if (*it == QLatin1String("-s") || *it == QLatin1String("--sign")) {
++it; ++it;
if (it == args.end() || it->startsWith(QLatin1String("-"))) if (it == args.end() || it->startsWith(QLatin1String("-")))
@ -983,7 +986,7 @@ int main(int argc, char **argv)
confInternal.setValue(QLatin1String("offlineOnly"), offlineOnly); confInternal.setValue(QLatin1String("offlineOnly"), offlineOnly);
} }
#ifdef Q_OS_OSX #ifdef Q_OS_MACOS
// on mac, we enforce building a bundle // on mac, we enforce building a bundle
if (!target.endsWith(QLatin1String(".app")) && !target.endsWith(QLatin1String(".dmg"))) if (!target.endsWith(QLatin1String(".app")) && !target.endsWith(QLatin1String(".dmg")))
target += QLatin1String(".app"); target += QLatin1String(".app");

View File

@ -71,7 +71,7 @@ function handleFile()
if [ `basename $FILE` != $NAME ]; then 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 if echo $lib | grep '\.framework' >/dev/null; then
local FRAMEWORKPATH=`echo $lib | sed -ne 's,\(.*\.framework\).*,\1,p'` local FRAMEWORKPATH=`echo $lib | sed -ne 's,\(.*\.framework\).*,\1,p'`
local FRAMEWORKNAME=`basename $FRAMEWORKPATH` local FRAMEWORKNAME=`basename $FRAMEWORKPATH`

View File

@ -99,7 +99,7 @@ int BinaryReplace::replace(const QString &source, const QString &target)
result = EXIT_FAILURE; result = EXIT_FAILURE;
try { try {
QFile installerBaseNew(newInstallerBasePath); QFile installerBaseNew(newInstallerBasePath);
#ifndef Q_OS_OSX #ifndef Q_OS_MACOS
QFile installerBaseOld(target); QFile installerBaseOld(target);
QInstaller::openForAppend(&installerBaseNew); QInstaller::openForAppend(&installerBaseNew);

View File

@ -168,7 +168,7 @@ int main(int argc, char *argv[])
if (QInstaller::isInBundle(path, &bundlePath)) { if (QInstaller::isInBundle(path, &bundlePath)) {
path = QDir(bundlePath).filePath(QLatin1String("Contents/Resources/installer.dat")); path = QDir(bundlePath).filePath(QLatin1String("Contents/Resources/installer.dat"));
} }
#ifndef Q_OS_OSX #ifndef Q_OS_MACOS
QFileInfo fi = QFileInfo(path); QFileInfo fi = QFileInfo(path);
bundlePath = path; bundlePath = path;
QString tmp = QDir(fi.path()).filePath(QLatin1String("installer.dat")); QString tmp = QDir(fi.path()).filePath(QLatin1String("installer.dat"));