summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf2
-rw-r--r--Changelog67
-rw-r--r--INSTALL25
-rw-r--r--README4
-rw-r--r--coin/dependencies.yaml32
-rw-r--r--coin/instructions/common_environment.yaml4
-rw-r--r--coin/instructions/make_instructions.yaml65
-rw-r--r--coin/instructions/make_win_docs_instructions.yaml2
-rw-r--r--coin/instructions/qmake_module_build.yaml8
-rw-r--r--coin/product_dependencies.yaml3
-rw-r--r--dist/packages/org.qtproject.ifw.binaries/meta/package.xml4
-rw-r--r--dist/packages/org.qtproject.ifw/meta/package.xml4
-rw-r--r--doc/config/ifw.qdocconf19
-rw-r--r--doc/doc.pri41
-rw-r--r--doc/doc.pro12
-rw-r--r--doc/doc_targets.pri89
-rw-r--r--doc/examples/aliases.xml30
-rw-r--r--doc/examples/config.xml1
-rw-r--r--doc/images/ifw-overview.pngbin31363 -> 27901 bytes
-rw-r--r--doc/includes/IFWDoc125
-rw-r--r--doc/installerfw-getting-started.qdoc38
-rw-r--r--doc/installerfw-overview.qdoc80
-rw-r--r--doc/installerfw-reference.qdoc1
-rw-r--r--doc/installerfw-using.qdoc68
-rw-r--r--doc/installerfw.qdoc174
-rw-r--r--doc/noninteractive.qdoc12
-rw-r--r--doc/operations.qdoc33
-rw-r--r--doc/scripting-api/console.qdoc2
-rw-r--r--doc/scripting-api/gui.qdoc24
-rw-r--r--doc/scripting-api/packagemanagercore.qdoc46
-rw-r--r--doc/scripting-api/qdesktopservices.qdoc8
-rw-r--r--doc/scripting-api/qfiledialog.qdoc9
-rw-r--r--doc/scripting.qdoc2
-rw-r--r--doc/systeminfo.qdoc23
-rw-r--r--examples/componentalias/README5
-rw-r--r--examples/componentalias/componentalias.pro13
-rw-r--r--examples/componentalias/config/aliases.xml28
-rw-r--r--examples/componentalias/config/config.xml10
-rw-r--r--examples/componentalias/packages/componentA/data/installcontentA.txt2
-rw-r--r--examples/componentalias/packages/componentA/meta/package.xml8
-rw-r--r--examples/componentalias/packages/componentB/data/installcontentB.txt2
-rw-r--r--examples/componentalias/packages/componentB/meta/package.xml8
-rw-r--r--examples/componentalias/packages/componentC/data/installcontentC.txt2
-rw-r--r--examples/componentalias/packages/componentC/meta/package.xml8
-rw-r--r--examples/componentalias/packages/componentD/data/installcontentD.txt2
-rw-r--r--examples/componentalias/packages/componentD/meta/package.xml8
-rw-r--r--examples/componentalias/packages/componentE/data/installcontentE.txt2
-rw-r--r--examples/componentalias/packages/componentE/meta/package.xml8
-rw-r--r--examples/doc/componentalias.qdoc160
-rw-r--r--examples/doc/online.qdoc2
-rw-r--r--examples/doc/treename.qdoc8
-rw-r--r--examples/examples.pro1
-rw-r--r--installerfw.pri27
-rw-r--r--installerfw.pro3
-rw-r--r--src/libs/3rdparty/libarchive/archive.h4
-rw-r--r--src/libs/3rdparty/libarchive/archive_digest.c60
-rw-r--r--src/libs/3rdparty/libarchive/archive_digest_private.h10
-rw-r--r--src/libs/3rdparty/libarchive/archive_entry.h2
-rw-r--r--src/libs/3rdparty/libarchive/archive_getdate.c119
-rw-r--r--src/libs/3rdparty/libarchive/archive_hmac.c15
-rw-r--r--src/libs/3rdparty/libarchive/archive_hmac_private.h2
-rw-r--r--src/libs/3rdparty/libarchive/archive_openssl_evp_private.h3
-rw-r--r--src/libs/3rdparty/libarchive/archive_random.c35
-rw-r--r--src/libs/3rdparty/libarchive/archive_read_data_into_fd.c7
-rw-r--r--src/libs/3rdparty/libarchive/archive_read_disk_posix.c28
-rw-r--r--src/libs/3rdparty/libarchive/archive_read_disk_windows.c72
-rw-r--r--src/libs/3rdparty/libarchive/archive_read_open_file.c4
-rw-r--r--src/libs/3rdparty/libarchive/archive_read_support_filter_bzip2.c4
-rw-r--r--src/libs/3rdparty/libarchive/archive_read_support_filter_lz4.c2
-rw-r--r--src/libs/3rdparty/libarchive/archive_read_support_filter_zstd.c14
-rw-r--r--src/libs/3rdparty/libarchive/archive_read_support_format_7zip.c200
-rw-r--r--src/libs/3rdparty/libarchive/archive_read_support_format_cab.c8
-rw-r--r--src/libs/3rdparty/libarchive/archive_read_support_format_cpio.c6
-rw-r--r--src/libs/3rdparty/libarchive/archive_read_support_format_iso9660.c12
-rw-r--r--src/libs/3rdparty/libarchive/archive_read_support_format_lha.c23
-rw-r--r--src/libs/3rdparty/libarchive/archive_read_support_format_mtree.c8
-rw-r--r--src/libs/3rdparty/libarchive/archive_read_support_format_rar.c21
-rw-r--r--src/libs/3rdparty/libarchive/archive_read_support_format_rar5.c2
-rw-r--r--src/libs/3rdparty/libarchive/archive_read_support_format_warc.c6
-rw-r--r--src/libs/3rdparty/libarchive/archive_read_support_format_xar.c8
-rw-r--r--src/libs/3rdparty/libarchive/archive_read_support_format_zip.c6
-rw-r--r--src/libs/3rdparty/libarchive/archive_string.c4
-rw-r--r--src/libs/3rdparty/libarchive/archive_util.c57
-rw-r--r--src/libs/3rdparty/libarchive/archive_windows.c35
-rw-r--r--src/libs/3rdparty/libarchive/archive_write.c31
-rw-r--r--src/libs/3rdparty/libarchive/archive_write_add_filter_bzip2.c6
-rw-r--r--src/libs/3rdparty/libarchive/archive_write_add_filter_compress.c2
-rw-r--r--src/libs/3rdparty/libarchive/archive_write_add_filter_lz4.c8
-rw-r--r--src/libs/3rdparty/libarchive/archive_write_add_filter_zstd.c237
-rw-r--r--src/libs/3rdparty/libarchive/archive_write_disk_posix.c72
-rw-r--r--src/libs/3rdparty/libarchive/archive_write_disk_windows.c79
-rw-r--r--src/libs/3rdparty/libarchive/archive_write_private.h1
-rw-r--r--src/libs/3rdparty/libarchive/archive_write_set_format_7zip.c10
-rw-r--r--src/libs/3rdparty/libarchive/archive_write_set_format_iso9660.c32
-rw-r--r--src/libs/3rdparty/libarchive/archive_write_set_format_pax.c27
-rw-r--r--src/libs/3rdparty/libarchive/archive_write_set_format_warc.c25
-rw-r--r--src/libs/3rdparty/libarchive/archive_write_set_format_xar.c14
-rw-r--r--src/libs/3rdparty/libarchive/archive_write_set_format_zip.c19
-rw-r--r--src/libs/3rdparty/libarchive/config_freebsd.h7
-rw-r--r--src/libs/3rdparty/libarchive/filter_fork_windows.c9
-rw-r--r--src/libs/3rdparty/libarchive/qt_attribution.json2
-rw-r--r--src/libs/3rdparty/libarchive/xxhash.c4
-rw-r--r--src/libs/ifwtools/binarycreator.cpp54
-rw-r--r--src/libs/ifwtools/repositorygen.cpp6
-rw-r--r--src/libs/installer/binaryformat.cpp11
-rw-r--r--src/libs/installer/binaryformat.h6
-rw-r--r--src/libs/installer/binaryformatengine.cpp9
-rw-r--r--src/libs/installer/binaryformatengine.h7
-rw-r--r--src/libs/installer/calculatorbase.h3
-rw-r--r--src/libs/installer/commandlineparser.cpp15
-rw-r--r--src/libs/installer/component.cpp42
-rw-r--r--src/libs/installer/component_p.cpp1
-rw-r--r--src/libs/installer/componentalias.cpp649
-rw-r--r--src/libs/installer/componentalias.h160
-rw-r--r--src/libs/installer/componentmodel.cpp27
-rw-r--r--src/libs/installer/componentmodel.h3
-rw-r--r--src/libs/installer/componentselectionpage_p.cpp103
-rw-r--r--src/libs/installer/componentselectionpage_p.h14
-rw-r--r--src/libs/installer/constants.h19
-rw-r--r--src/libs/installer/copydirectoryoperation.cpp2
-rw-r--r--src/libs/installer/copyfiletask.cpp4
-rw-r--r--src/libs/installer/createdesktopentryoperation.cpp12
-rw-r--r--src/libs/installer/createlocalrepositoryoperation.cpp2
-rw-r--r--src/libs/installer/createshortcutoperation.cpp4
-rw-r--r--src/libs/installer/customcombobox.cpp54
-rw-r--r--src/libs/installer/customcombobox.h48
-rw-r--r--src/libs/installer/downloadarchivesjob.cpp46
-rw-r--r--src/libs/installer/downloadarchivesjob.h4
-rw-r--r--src/libs/installer/downloadfiletask.cpp22
-rw-r--r--src/libs/installer/downloadfiletask_p.h2
-rw-r--r--src/libs/installer/environmentvariablesoperation.cpp17
-rw-r--r--src/libs/installer/extractarchiveoperation.cpp10
-rw-r--r--src/libs/installer/fakestopprocessforupdateoperation.cpp6
-rw-r--r--src/libs/installer/fileutils.cpp2
-rw-r--r--src/libs/installer/genericdatacache.cpp46
-rw-r--r--src/libs/installer/genericdatacache.h9
-rw-r--r--src/libs/installer/globals.cpp61
-rw-r--r--src/libs/installer/globals.h2
-rw-r--r--src/libs/installer/globalsettingsoperation.cpp2
-rw-r--r--src/libs/installer/installer.pro10
-rw-r--r--src/libs/installer/installer_global.h8
-rw-r--r--src/libs/installer/installercalculator.cpp97
-rw-r--r--src/libs/installer/installercalculator.h9
-rw-r--r--src/libs/installer/installiconsoperation.cpp4
-rw-r--r--src/libs/installer/libarchivewrapper_p.cpp16
-rw-r--r--src/libs/installer/licenseoperation.cpp16
-rw-r--r--src/libs/installer/loggingutils.cpp39
-rw-r--r--src/libs/installer/loggingutils.h2
-rw-r--r--src/libs/installer/messageboxhandler.cpp4
-rw-r--r--src/libs/installer/metadata.cpp139
-rw-r--r--src/libs/installer/metadata.h14
-rw-r--r--src/libs/installer/metadatacache.cpp67
-rw-r--r--src/libs/installer/metadatacache.h46
-rw-r--r--src/libs/installer/metadatajob.cpp163
-rw-r--r--src/libs/installer/metadatajob.h13
-rw-r--r--src/libs/installer/metadatajob_p.h45
-rw-r--r--src/libs/installer/observer.cpp6
-rw-r--r--src/libs/installer/observer.h2
-rw-r--r--src/libs/installer/packagemanagercore.cpp614
-rw-r--r--src/libs/installer/packagemanagercore.h59
-rw-r--r--src/libs/installer/packagemanagercore_p.cpp423
-rw-r--r--src/libs/installer/packagemanagercore_p.h37
-rw-r--r--src/libs/installer/packagemanagercoredata.cpp5
-rw-r--r--src/libs/installer/packagemanagergui.cpp174
-rw-r--r--src/libs/installer/packagemanagergui.h7
-rw-r--r--src/libs/installer/packagesource.cpp6
-rw-r--r--src/libs/installer/packagesource.h8
-rw-r--r--src/libs/installer/permissionsettings.cpp34
-rw-r--r--src/libs/installer/permissionsettings.h17
-rw-r--r--src/libs/installer/productkeycheck.cpp29
-rw-r--r--src/libs/installer/productkeycheck.h9
-rw-r--r--src/libs/installer/progresscoordinator.cpp51
-rw-r--r--src/libs/installer/progresscoordinator.h6
-rw-r--r--src/libs/installer/protocol.h4
-rw-r--r--src/libs/installer/qprocesswrapper.cpp30
-rw-r--r--src/libs/installer/qprocesswrapper.h4
-rw-r--r--src/libs/installer/qsettingswrapper.cpp92
-rw-r--r--src/libs/installer/qsettingswrapper.h30
-rw-r--r--src/libs/installer/registerfiletypeoperation.cpp2
-rw-r--r--src/libs/installer/remotefileengine.cpp30
-rw-r--r--src/libs/installer/remotefileengine.h10
-rw-r--r--src/libs/installer/remoteobject.cpp7
-rw-r--r--src/libs/installer/remoteobject.h87
-rw-r--r--src/libs/installer/remoteserverconnection.cpp14
-rw-r--r--src/libs/installer/remoteserverconnection_p.h2
-rw-r--r--src/libs/installer/repository.cpp33
-rw-r--r--src/libs/installer/repository.h10
-rw-r--r--src/libs/installer/repositorycategory.cpp8
-rw-r--r--src/libs/installer/repositorycategory.h7
-rw-r--r--src/libs/installer/resources/installer.qrc1
-rw-r--r--src/libs/installer/resources/qt/etc/qt.conf0
-rw-r--r--src/libs/installer/scriptengine.cpp62
-rw-r--r--src/libs/installer/scriptengine_p.h35
-rw-r--r--src/libs/installer/settings.cpp22
-rw-r--r--src/libs/installer/settings.h4
-rw-r--r--src/libs/installer/simplemovefileoperation.cpp2
-rw-r--r--src/libs/installer/sysinfo_win.cpp4
-rw-r--r--src/libs/installer/systeminfo.cpp30
-rw-r--r--src/libs/installer/systeminfo.h5
-rw-r--r--src/libs/installer/utils.cpp2
-rw-r--r--src/libs/kdtools/filedownloader.cpp57
-rw-r--r--src/libs/kdtools/filedownloader.h2
-rw-r--r--src/libs/kdtools/filedownloader_p.h8
-rw-r--r--src/libs/kdtools/updatefinder.cpp4
-rw-r--r--src/libs/kdtools/updateoperation.cpp62
-rw-r--r--src/libs/kdtools/updateoperation.h2
-rw-r--r--src/libs/kdtools/updateoperations.cpp65
-rw-r--r--src/libs/kdtools/updateoperations.h2
-rw-r--r--src/libs/kdtools/updatesinfo.cpp16
-rw-r--r--src/libs/kdtools/updatesinfo_p.h2
-rw-r--r--src/libs/kdtools/updatesinfodata_p.h3
-rw-r--r--src/sdk/commandlineinterface.cpp39
-rw-r--r--src/sdk/installerbase.cpp4
-rw-r--r--src/sdk/main.cpp2
-rw-r--r--src/sdk/sdk.pro4
-rw-r--r--src/sdk/sdkapp.h25
-rw-r--r--src/sdk/settingsdialog.cpp20
-rw-r--r--src/sdk/settingsdialog.ui2
-rw-r--r--src/sdk/tabcontroller.cpp6
-rw-r--r--src/sdk/translations/ifw_ar.ts231
-rw-r--r--src/sdk/translations/ifw_ca.ts212
-rw-r--r--src/sdk/translations/ifw_da.ts214
-rw-r--r--src/sdk/translations/ifw_de.ts240
-rw-r--r--src/sdk/translations/ifw_es.ts236
-rw-r--r--src/sdk/translations/ifw_fr.ts236
-rw-r--r--src/sdk/translations/ifw_hr.ts220
-rw-r--r--src/sdk/translations/ifw_hu.ts206
-rw-r--r--src/sdk/translations/ifw_it.ts220
-rw-r--r--src/sdk/translations/ifw_ja.ts238
-rw-r--r--src/sdk/translations/ifw_ko.ts230
-rw-r--r--src/sdk/translations/ifw_pl.ts222
-rw-r--r--src/sdk/translations/ifw_pt_BR.ts212
-rw-r--r--src/sdk/translations/ifw_pt_PT.ts (renamed from src/sdk/translations/ifw_pt.ts)236
-rw-r--r--src/sdk/translations/ifw_ru.ts244
-rw-r--r--src/sdk/translations/ifw_zh_CN.ts235
-rw-r--r--tests/auto/installer/appendfileoperation/tst_appendfileoperation.cpp35
-rw-r--r--tests/auto/installer/binaryformat/tst_binaryformat.cpp47
-rw-r--r--tests/auto/installer/clientserver/BLACKLIST2
-rw-r--r--tests/auto/installer/clientserver/tst_clientserver.cpp4
-rw-r--r--tests/auto/installer/commandlineinstall/tst_commandlineinstall.cpp99
-rw-r--r--tests/auto/installer/componentalias/componentalias.pro8
-rw-r--r--tests/auto/installer/componentalias/data/aliases-optional.xml36
-rw-r--r--tests/auto/installer/componentalias/data/aliases-priority.xml36
-rw-r--r--tests/auto/installer/componentalias/data/aliases-versions.xml36
-rw-r--r--tests/auto/installer/componentalias/data/aliases.json38
-rw-r--r--tests/auto/installer/componentalias/data/repository/Updates.xml43
-rw-r--r--tests/auto/installer/componentalias/metadata/installer-config/aliases.xml52
-rw-r--r--tests/auto/installer/componentalias/metadata/installer-config/config.xml6
-rw-r--r--tests/auto/installer/componentalias/settings.qrc11
-rw-r--r--tests/auto/installer/componentalias/tst_componentalias.cpp269
-rw-r--r--tests/auto/installer/componentmodel/tst_componentmodel.cpp6
-rw-r--r--tests/auto/installer/copyoperationtest/tst_copyoperationtest.cpp47
-rw-r--r--tests/auto/installer/createoffline/tst_createoffline.cpp6
-rw-r--r--tests/auto/installer/createshortcutoperation/tst_createshortcutoperation.cpp1
-rw-r--r--tests/auto/installer/deleteoperation/tst_deleteoperation.cpp49
-rw-r--r--tests/auto/installer/installer.pro5
-rw-r--r--tests/auto/installer/messageboxhandler/tst_messageboxhandler.cpp3
-rw-r--r--tests/auto/installer/metadatacache/data/existing-cache/manifest.json2
-rw-r--r--tests/auto/installer/metadatacache/tst_metadatacache.cpp38
-rw-r--r--tests/auto/installer/mkdiroperationtest/tst_mkdiroperationtest.cpp28
-rw-r--r--tests/auto/installer/moveoperation/tst_moveoperation.cpp4
-rw-r--r--tests/auto/installer/packagemanagercore/tst_packagemanagercore.cpp46
-rw-r--r--tests/auto/installer/prependfileoperation/data/repository/B/1.0.2-1content.7zbin0 -> 129 bytes
-rw-r--r--tests/auto/installer/prependfileoperation/data/repository/B/1.0.2-1meta.7zbin0 -> 910 bytes
-rw-r--r--tests/auto/installer/prependfileoperation/data/repository/Updates.xml16
-rw-r--r--tests/auto/installer/prependfileoperation/data/xmloperationrepository/C/1.0.0content.7zbin0 -> 129 bytes
-rw-r--r--tests/auto/installer/prependfileoperation/data/xmloperationrepository/Updates.xml20
-rw-r--r--tests/auto/installer/prependfileoperation/prependfileoperation.pro10
-rw-r--r--tests/auto/installer/prependfileoperation/settings.qrc9
-rw-r--r--tests/auto/installer/prependfileoperation/tst_prependfileoperation.cpp180
-rw-r--r--tests/auto/installer/repository/data/repository/A/1.0.2meta.7zbin0 -> 979 bytes
-rw-r--r--tests/auto/installer/repository/data/repository/B/1.0.0meta.7zbin0 -> 998 bytes
-rw-r--r--tests/auto/installer/repository/data/repository/C/1.0.0meta.7zbin0 -> 994 bytes
-rw-r--r--tests/auto/installer/repository/data/repository/Updates.xml21
-rw-r--r--tests/auto/installer/repository/settings.qrc3
-rw-r--r--tests/auto/installer/repository/tst_repository.cpp102
-rw-r--r--tests/auto/installer/rmdiroperationtest/rmdiroperationtest.pro6
-rw-r--r--tests/auto/installer/rmdiroperationtest/tst_rmdiroperationtest.cpp111
-rw-r--r--tests/auto/installer/scriptengine/tst_scriptengine.cpp12
-rw-r--r--tests/auto/installer/settings/data/full_config.xml1
-rw-r--r--tests/auto/installer/settings/tst_settings.cpp1
-rw-r--r--tests/auto/installer/shared/packagemanager.h1
-rw-r--r--tests/auto/installer/shared/verifyinstaller.h23
-rw-r--r--tests/auto/installer/solver/tst_solver.cpp4
-rw-r--r--tools/devtool/devtool.pro3
-rw-r--r--tools/repogen/repogen.pro3
286 files changed, 9383 insertions, 2983 deletions
diff --git a/.qmake.conf b/.qmake.conf
index 95e84750e..8b71acb75 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -1,2 +1,2 @@
-VERSION=4.6.0
+VERSION=4.8.0
CONFIG=prepare_docs qt_docs_targets $$CONFIG
diff --git a/Changelog b/Changelog
index a92fce3eb..822310af7 100644
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,70 @@
+4.8.0
+- Fix occasional crash in install phase (QTIFW-3314)
+- Allow overwriting undo in some operations (QTIFW-3333, QTIFW-393)
+- Add possibility to add extra log when meta fetch fails (QTIFW-3012)
+- Fix http authorization login (QTIFW-3301)
+- Fix QDesktopServices properties (QTIFW-3334)
+- Fix maintenance tool register path parameters
+- Fix productType function return value in macos (QTIFW-3309)
+- Speed up cache validation (QTIFW-3328)
+- Fix QFileDialog documentation (QTIFW-3320)
+- Disable 'clear cache' button until new cache settings are applied (QTIFW-3252)
+- Add detailed warning when hash verification fails
+- Add security warning possibility when using additional repositories (QTIFW-3305)
+- Add possibility to add additional license text to CLI (QTIFW-3319)
+- Include minimal qt.conf file (QTIFW-3292)
+- Add Chinese and Portuquese languages (QTIFW-3325)
+- Fix translations missing in Linux and macOS (QTIFW-3310)
+- CLI: Perform commands primarily from default repositories (QTIFW-3251)
+- Add possibility to change button text (QTIFW-711)
+
+4.7.0
+- Fix CLI fail on huge amount of Updates.xml download (QTIFW-3249)
+- Prepare for Linux on ARM support (QTIFW-3073)
+- Add support for component aliases (QTIFW-2978)
+- Enable building with Qt6.2 (QTIFW-3083)
+- Enable building with Qt6.5 (QTIFW-1829)
+- Build IFW binaries with Qt6.6
+- 3rdparty: update libarchive sources to 3.7.1 release
+- Use directory separators in path asking for process to be stopped
+- Allow generating offline installers from Gui (QTIFW-3072)
+- Show progress on Welcome screen (QTIFW-3068)
+- Fix page title text on the last page (QTIFW-3060)
+- Prevent uninstalling components when error occurs (QTIFW-3069)
+- Consider full length of 'key=value' string in user arguments
+- Fix admin rights handling during installer/updater/uninstaller runs (QTIFW-2929)
+- Fix documentation about network share (QTIFW-2933)
+
+4.6.1
+- Fix crash when filtering categories (QTIFW-3085)
+- Allow setting temporary repositories for offline-only installers (QTIFW-3078)
+- DownloadArchivesJob: allow download retries for command line runs (QTIFW-3098)
+
+4.6.0
+- Unify handling of processes to close for 'updating' components (QTIFW-2927,QTIFW-3009)
+- Fix wrong extract content (QTIFW-3010)
+- Verify meta file integrity from cache (QTIFW-3023)
+- Match title and message text on the first wizard page (SQUISH-9672)
+- Allow shortcuts for https links in Windows (QTIFW-964)
+- Metadata cache: register items by renaming instead of copying (QTIFW-2971)
+- Center PackageManagerPage title and subtitle texts (QTIFW-2995)
+- Fix showSettingsButton functionality (QTIFW-810)
+- Add more verbose when archive download fails (QTBUG-11068)
+- Fix custom error message in Execute operation (QTIFW-3007)
+- Add more detailed error messages (QTIFW-2998,QTIFW-2883)
+- Make messagebox texts selectable (QTIFW-3005)
+- Fix invalid cache state (QTIFW-2998)
+- UI update (QTIFW-2943)
+- Add support for skipping fetching already cached Updates.xml files (QTIFW-2873)
+- Performance optimizations (QTIFW-2805)
+- 3rdparty: update libarchive sources to 3.6.2 release
+- Fix building with Squish version 7.0.x (SQUISH-15697)
+- Workaround possible stalls on single core systems
+- Metadata cache: clear cache in a separate thread (QTIFW-2815)
+- Fix enabled navigation buttons while metadata fetch is still in progress (QTIFW-2849)
+- Add possibility to post load install scripts (QTIFW-2820)
+- ExtractOp: fix leftover empty directories when 'targetDir' arg is used (QTIFW-2764)
+
4.5.2
- Fix freezing UI while searching components (QTIFW-2886)
- Show check box for AutoDependOn components in updater view (QTIFW-2855)
diff --git a/INSTALL b/INSTALL
index 39d0057c2..dd7d78cd8 100644
--- a/INSTALL
+++ b/INSTALL
@@ -15,15 +15,15 @@ http://code.qt.io/cgit/installer-framework/installer-framework.git/
Build a static Qt
---------------------
-Building the Qt Installer Framework from sources requires at least Qt version 5.15.2.
-Supported compilers are MSVC 2015 or newer, GCC 5 or newer,
-and Clang 11.0.0 or newer. Currently, the tested combination for Windows is Qt 5.15.2 with MSVC 2015 (Windows 10).
+Building the Qt Installer Framework from sources requires at least Qt version 6.6.0.
+Supported compilers are MSVC 2019 or newer, GCC 9 or newer,
+and Clang 13.0.0 or newer. Currently, the tested combination for Windows is Qt 6.6.0 with MSVC 2019 (Windows 10).
If you want to ship your installer as a single file you have to build
Qt and the Qt Installer Framework statically.
See the Qt documentation for the prerequisites and steps to build Qt from sources.
-Please read SSL Import and Export Restrictions from http://doc.qt.io/qt-5/ssl.html if
+Please read SSL Import and Export Restrictions from http://doc.qt.io/qt-6/ssl.html if
you are statically linking against OpenSSL libraries.
### Windows
@@ -32,21 +32,26 @@ Recommended configuration options for Microsoft Windows:
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
+cmake --build . --parallel
+cmake --install .
### Linux
Recommended configuration options for Linux:
-configure -prefix $PWD/qtbase -release -static -accessibility -qt-zlib -qt-libpng -qt-libjpeg -qt-pcre -no-glib -no-cups -no-sql-sqlite -no-feature-gssapi -no-qml-debug -no-opengl -no-egl -no-xinput2 -no-sm -no-icu -nomake examples -nomake tests -no-libudev
+configure -prefix $PWD/qtbase -release -static -accessibility -qt-zlib -qt-libpng -qt-libjpeg -qt-pcre -no-glib -no-cups -no-sql-sqlite -no-feature-gssapi -no-qml-debug -no-opengl -no-egl -no-xinput2 -no-sm -no-icu -nomake examples -nomake tests -no-libudev -bundled-xcb-xinput -qt-harfbuzz -qt-doubleconversion
+
Build Qt:
-make module-qtbase module-qtdeclarative module-qttools module-qttranslations
+cmake --build . --parallel
+cmake --install .
### macOS
Recommended configuration options for macOS:
-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
+configure -prefix $PWD/qtbase -release -static -accessibility -qt-zlib -qt-libpng -no-cups -no-sql-sqlite -no-qml-debug -nomake examples -nomake tests -no-freetype
+
Build Qt:
-make module-qtbase module-qtdeclarative module-qttools module-qttranslations
+cmake --build . --parallel
+cmake --install .
Third party dependencies
@@ -117,5 +122,5 @@ a configuration header file respective to your platform, which can be found from
Build the Framework
---------------------
-Run 'qmake && make' (or 'mingw32-make', 'nmake' ...) to build the Qt Installer
+Run 'qmake && make' (or 'nmake' ...) to build the Qt Installer
Framework. The documentation can be generated by 'make docs'.
diff --git a/README b/README
index cd57790dd..8ba25e7bc 100644
--- a/README
+++ b/README
@@ -13,8 +13,8 @@ doc directory. The documentation is also available online at
Notes
--------------------------
-To build an installer, it is advised to use a statically linked Qt (5.15.2 or
-newer). The tested and supported Qt version is 5.15.2.
+To build an installer, it is advised to use a statically linked Qt (6.6.0 or
+newer). The tested and supported Qt version is 6.6.0
See the documentation at
https://doc.qt.io/qtinstallerframework/ifw-getting-started.html
diff --git a/coin/dependencies.yaml b/coin/dependencies.yaml
index 0df7ac2a5..4b7ff4b29 100644
--- a/coin/dependencies.yaml
+++ b/coin/dependencies.yaml
@@ -1,13 +1,19 @@
-
-product_dependency:
- ../../qt/qt5:
- ref: "ifw-5.15.2"
-dependency_source: supermodule
-dependencies: [
- "../../qt/qtbase",
- "../../qt/qtsvg",
- "../../qt/qtdeclarative",
- "../../qt/qttools",
- "../../qt/qttranslations",
- "../../qt/qtwinextras"
- ]
+dependencies:
+ ../../qt/qtbase.git:
+ ref: "33f5e985e480283bb0ca9dea5f82643e825ba87c"
+ required: true
+ ../../qt/qtsvg.git:
+ ref: "da7e04eaa56c54d5486e39d2e0bd0ddb2a62b74b"
+ required: true
+ ../../qt/qtdeclarative.git:
+ ref: "e559d5cf2b66c4a973f83f173d57676a21d287ef"
+ required: true
+ ../../qt/qttools.git:
+ ref: "d7c950e5cfcda823544d3a0092a2bf435015f94d"
+ required: true
+ ../../qt/qttranslations.git:
+ ref: "94e46555acd71eb7d14dc340b623c13876101c00"
+ required: true
+ ../../qt/qt5compat.git:
+ ref: "e1fe0c83bc547ba34142c2ab06fdfea0bced7308"
+ required: true
diff --git a/coin/instructions/common_environment.yaml b/coin/instructions/common_environment.yaml
index 108211f69..f0739ee3e 100644
--- a/coin/instructions/common_environment.yaml
+++ b/coin/instructions/common_environment.yaml
@@ -105,5 +105,5 @@ instructions:
- type: Group
instructions:
- type: EnvironmentVariable
- variableName: PACKAGING_KEYS_CONFIG_URL
- variableValue: "http://ci-files01-hki.intra.qt.io/input/semisecure/packaging/packaging_secure.ini"
+ variableName: CI
+ variableValue: "true"
diff --git a/coin/instructions/make_instructions.yaml b/coin/instructions/make_instructions.yaml
index b11d0161c..aa9216ce5 100644
--- a/coin/instructions/make_instructions.yaml
+++ b/coin/instructions/make_instructions.yaml
@@ -77,13 +77,13 @@ instructions:
- type: ChangeDirectory
directory: "{{.InstallRoot}}/{{.AgentWorkingDir}}"
- type: ExecuteCommand
- command: "python3 {{.SourceDir}}/coin/create_ifw_installer.py --src-dir {{.SourceDir}} --bld-dir {{.SourceDir}} --target-dir {{.SourceDir}}/IfwInstaller --target-name QtInstallerFramework-linux-x64-4.6.0.run"
+ command: "python3 {{.SourceDir}}/coin/create_ifw_installer.py --src-dir {{.SourceDir}} --bld-dir {{.SourceDir}} --target-dir {{.SourceDir}}/IfwInstaller --target-name QtInstallerFramework-linux-x64-4.8.0.run"
maxTimeInSeconds: 36000
maxTimeBetweenOutput: 3600
userMessageOnFailure: "Failed to create ifw installer."
- type: Rename
- sourcePath: "{{.SourceDir}}/IfwInstaller/QtInstallerFramework-linux-x64-4.6.0.run"
- targetPath: "{{.InstallRoot}}/{{.AgentWorkingDir}}/QtInstallerFramework-linux-x64-4.6.0.run"
+ sourcePath: "{{.SourceDir}}/IfwInstaller/QtInstallerFramework-linux-x64-4.8.0.run"
+ targetPath: "{{.InstallRoot}}/{{.AgentWorkingDir}}/QtInstallerFramework-linux-x64-4.8.0.run"
userMessageOnFailure: "Failed to copy installer."
enable_if:
condition: and
@@ -91,44 +91,67 @@ instructions:
- condition: property
property: host.os
equals_value: Linux
+ - condition: property
+ property: target.arch
+ equals_value: X86_64
- type: Group
instructions:
- type: ChangeDirectory
directory: "{{.InstallRoot}}/{{.AgentWorkingDir}}"
- type: ExecuteCommand
- command: "python3 {{.SourceDir}}/coin/create_ifw_installer.py --src-dir {{.SourceDir}} --bld-dir {{.SourceDir}} --target-dir {{.SourceDir}}/IfwInstaller --target-name QtInstallerFramework-macOS-x64-4.6.0.app"
+ command: "python3 {{.SourceDir}}/coin/create_ifw_installer.py --src-dir {{.SourceDir}} --bld-dir {{.SourceDir}} --target-dir {{.SourceDir}}/IfwInstaller --target-name QtInstallerFramework-linux-aarch64-4.8.0.run"
maxTimeInSeconds: 36000
maxTimeBetweenOutput: 3600
userMessageOnFailure: "Failed to create ifw installer."
- - type: EnvironmentVariable
- variableName: QT_CODESIGN_IDENTITY_KEY
- variableValue: "A5GTH44LYL"
+ - type: Rename
+ sourcePath: "{{.SourceDir}}/IfwInstaller/QtInstallerFramework-linux-aarch64-4.8.0.run"
+ targetPath: "{{.InstallRoot}}/{{.AgentWorkingDir}}/QtInstallerFramework-linux-aarch64-4.8.0.run"
+ userMessageOnFailure: "Failed to copy installer."
+ enable_if:
+ condition: and
+ conditions:
+ - condition: property
+ property: host.os
+ equals_value: Linux
+ - condition: property
+ property: target.arch
+ equals_value: AARCH64
+
+ - type: Group
+ instructions:
- type: ChangeDirectory
- directory: "{{.AgentWorkingDir}}/qtsdk/qtsdk/packaging-tools"
+ directory: "{{.InstallRoot}}/{{.AgentWorkingDir}}"
- type: ExecuteCommand
- command: "python3 -m pip install pipenv==2022.4.8 --user"
- maxTimeInSeconds: 1800
- maxTimeBetweenOutput: 600
- userMessageOnFailure: "Failed to install Pipenv"
+ command: "python3 {{.SourceDir}}/coin/create_ifw_installer.py --src-dir {{.SourceDir}} --bld-dir {{.SourceDir}} --target-dir {{.SourceDir}}/IfwInstaller --target-name QtInstallerFramework-macOS-x64-4.8.0.app"
+ maxTimeInSeconds: 36000
+ maxTimeBetweenOutput: 3600
+ userMessageOnFailure: "Failed to create ifw installer."
+ - type: ChangeDirectory
+ directory: "{{.AgentWorkingDir}}/qtsdk"
- type: ExecuteCommand
- command: "python3 -m pipenv install --skip-lock"
+ command: "python3 tqtc-qtsdk/jenkins-templates/jenkins/scripts/pkg_bootstrap.py"
maxTimeInSeconds: 1800
maxTimeBetweenOutput: 600
- userMessageOnFailure: "Failed to install Pipenv requirements"
+ userMessageOnFailure: "pkg_bootstrap.py failed"
+ - type: EnvironmentVariable
+ variableName: PKG_NODE_ROOT
+ variableValue: "{{.AgentWorkingDir}}/qtsdk"
+ - type: ChangeDirectory
+ directory: "{{.AgentWorkingDir}}/qtsdk/tqtc-qtsdk/packaging_tools"
- type: ExecuteCommand
- command: "python3 -m pipenv run python sign_installer.py mac --file={{.SourceDir}}/IfwInstaller/QtInstallerFramework-macOS-x64-4.6.0.app"
+ command: "python3 -m pipenv run python sign_installer.py mac --file={{.SourceDir}}/IfwInstaller/QtInstallerFramework-macOS-x64-4.8.0.app"
maxTimeInSeconds: 36000
maxTimeBetweenOutput: 3600
userMessageOnFailure: "Failed to sign the ifw installer"
- type: ExecuteCommand
- command: "python3 -m pipenv run python notarize.py --dmg={{.SourceDir}}/IfwInstaller/QtInstallerFramework-macOS-x64-4.6.0.dmg"
+ command: "python3 -m pipenv run python notarize.py --path={{.SourceDir}}/IfwInstaller/QtInstallerFramework-macOS-x64-4.8.0.dmg"
maxTimeInSeconds: 36000
maxTimeBetweenOutput: 3600
userMessageOnFailure: "Failed to notarize the ifw installer"
- type: Rename
- sourcePath: "{{.SourceDir}}/IfwInstaller/QtInstallerFramework-macOS-x64-4.6.0.dmg"
- targetPath: "{{.InstallRoot}}/{{.AgentWorkingDir}}/QtInstallerFramework-macOS-x64-4.6.0.dmg"
+ sourcePath: "{{.SourceDir}}/IfwInstaller/QtInstallerFramework-macOS-x64-4.8.0.dmg"
+ targetPath: "{{.InstallRoot}}/{{.AgentWorkingDir}}/QtInstallerFramework-macOS-x64-4.8.0.dmg"
userMessageOnFailure: "Failed to copy installer."
enable_if:
condition: and
@@ -142,7 +165,7 @@ instructions:
- type: ChangeDirectory
directory: "{{.SourceDir}}"
- type: ExecuteCommand
- command: "{{.Env.PYTHON3_PATH}}\\python {{.SourceDir}}\\coin\\create_ifw_installer.py --src-dir {{.SourceDir}} --bld-dir {{.SourceDir}} --target-dir C:\\{{.SourceDir}}\\IfwInstaller --target-name QtInstallerFramework-windows-x64-4.6.0"
+ command: "{{.Env.PYTHON3_PATH}}\\python {{.SourceDir}}\\coin\\create_ifw_installer.py --src-dir {{.SourceDir}} --bld-dir {{.SourceDir}} --target-dir C:\\{{.SourceDir}}\\IfwInstaller --target-name QtInstallerFramework-windows-x64-4.8.0"
maxTimeInSeconds: 1200
maxTimeBetweenOutput: 1200
userMessageOnFailure: "Failed to create ifw installer."
@@ -163,8 +186,8 @@ instructions:
equals_value: Windows
- type: Rename
- sourcePath: "{{.SourceDir}}/IfwInstaller/QtInstallerFramework-windows-x64-4.6.0.exe"
- targetPath: "{{.InstallRoot}}/{{.AgentWorkingDir}}/QtInstallerFramework-windows-x64-4.6.0.exe"
+ sourcePath: "{{.SourceDir}}/IfwInstaller/QtInstallerFramework-windows-x64-4.8.0.exe"
+ targetPath: "{{.InstallRoot}}/{{.AgentWorkingDir}}/QtInstallerFramework-windows-x64-4.8.0.exe"
userMessageOnFailure: "Failed to copy installer."
enable_if:
condition: property
diff --git a/coin/instructions/make_win_docs_instructions.yaml b/coin/instructions/make_win_docs_instructions.yaml
index 5d5f28f67..ab281501a 100644
--- a/coin/instructions/make_win_docs_instructions.yaml
+++ b/coin/instructions/make_win_docs_instructions.yaml
@@ -3,7 +3,7 @@ instructions:
- type: Group
instructions:
- type: ChangeDirectory
- directory: "{{.SourceDir}}\\doc"
+ directory: "{{.SourceDir}}"
maxTimeInSeconds: 300
maxTimeBetweenOutput: 120
userMessageOnFailure: "Failed to change dir"
diff --git a/coin/instructions/qmake_module_build.yaml b/coin/instructions/qmake_module_build.yaml
index 4a475b600..3a7801b20 100644
--- a/coin/instructions/qmake_module_build.yaml
+++ b/coin/instructions/qmake_module_build.yaml
@@ -8,10 +8,10 @@ instructions:
- type: InstallSourceArchive
maxTimeInSeconds: 600
maxTimeBetweenOutput: 600
- project: qtsdk/qtsdk
- ref: 8d9c6bb366b0f3c1e46c045a6453776ae98a8051
- directory: qtsdk/qtsdk
- userMessageOnFailure: "Could not install qtsdk/qtsdk source archive. Please investigate why."
+ project: qtsdk/tqtc-qtsdk
+ ref: production
+ directory: qtsdk/tqtc-qtsdk
+ userMessageOnFailure: "Could not install qtsdk/tqtc-qtsdk source archive. Please investigate why."
- type: SetBuildDirectory
directory: "{{.SourceDir}}"
diff --git a/coin/product_dependencies.yaml b/coin/product_dependencies.yaml
new file mode 100644
index 000000000..b9ccf5020
--- /dev/null
+++ b/coin/product_dependencies.yaml
@@ -0,0 +1,3 @@
+dependencies:
+ ../../qt/tqtc-qt5.git:
+ ref: "tqtc/6.6.0"
diff --git a/dist/packages/org.qtproject.ifw.binaries/meta/package.xml b/dist/packages/org.qtproject.ifw.binaries/meta/package.xml
index 1ccc2f96e..82eed4eb2 100644
--- a/dist/packages/org.qtproject.ifw.binaries/meta/package.xml
+++ b/dist/packages/org.qtproject.ifw.binaries/meta/package.xml
@@ -2,7 +2,7 @@
<Package>
<DisplayName>Qt Installer Framework Binaries</DisplayName>
<Description>Installs the binaries, examples and help files.</Description>
- <Version>4.6.0</Version>
- <ReleaseDate>2023-01-30</ReleaseDate>
+ <Version>4.8.0</Version>
+ <ReleaseDate>2024-02-05</ReleaseDate>
<Default>True</Default>
</Package>
diff --git a/dist/packages/org.qtproject.ifw/meta/package.xml b/dist/packages/org.qtproject.ifw/meta/package.xml
index 93f4aa7d2..a5c9a2d7a 100644
--- a/dist/packages/org.qtproject.ifw/meta/package.xml
+++ b/dist/packages/org.qtproject.ifw/meta/package.xml
@@ -2,8 +2,8 @@
<Package>
<DisplayName>Qt Installer Framework</DisplayName>
<Description>Installs the Qt Installer Framework.</Description>
- <Version>4.6.0</Version>
- <ReleaseDate>2023-01-30</ReleaseDate>
+ <Version>4.8.0</Version>
+ <ReleaseDate>2024-02-05</ReleaseDate>
<Licenses>
<License name="The Qt Company GPL Exception 1.0" file="LICENSE.GPL3-EXCEPT" />
<License name="Third Party Code Licenses" file="3RDPARTY" />
diff --git a/doc/config/ifw.qdocconf b/doc/config/ifw.qdocconf
index fe9e5a498..17440d802 100644
--- a/doc/config/ifw.qdocconf
+++ b/doc/config/ifw.qdocconf
@@ -2,23 +2,21 @@ include($QT_INSTALL_DOCS/global/qt-cpp-defines.qdocconf)
include($QT_INSTALL_DOCS/global/compat.qdocconf)
include($QT_INSTALL_DOCS/global/fileextensions.qdocconf)
-moduleheader = IFWDoc
-includepaths += -I ./includes \
- -I ../src/libs/installer \
- -I ../src/libs/kdtools \
- -I ../src/libs/3rdparty/7zip/unix/CPP \
- -I ../src/libs/3rdparty/7zip/win/CPP \
- -I ../src/libs/3rdparty/libarchive
+includepaths += \
+ ../../src/libs/installer \
+ ../../src/libs/3rdparty/7zip/unix/CPP \
+ ../../src/libs/3rdparty/7zip/win/CPP \
+ ../../src/libs/3rdparty/libarchive
language = Cpp
project = "QtInstallerFramework"
description = "Qt Installer Framework Manual"
-url = http://qt-project.org/doc/qtinstallerframework/
+url = https://doc.qt.io/qtinstallerframework/
sourcedirs += ../../src/libs/installer ../../src/libs/kdtools ../includes
headerdirs += ../../src/libs/installer ../../src/libs/kdtools
-imagedirs = ../images ../templates/images
+imagedirs = ../images
exampledirs = .. \
../../examples
@@ -50,6 +48,9 @@ qhp.InstallerFramework.subprojects.manual.title = Qt Installer Framework Manual
qhp.InstallerFramework.subprojects.manual.indexTitle = Qt Installer Framework Manual
qhp.InstallerFramework.subprojects.manual.type = manual
+macro.IFW = "Qt Installer Framework"
+macro.MT = "maintenance tool"
+
# For docs, QT_VERSION resolves to IFW version
macro.ifwversion = $QT_VERSION
diff --git a/doc/doc.pri b/doc/doc.pri
new file mode 100644
index 000000000..4f6a07d6f
--- /dev/null
+++ b/doc/doc.pri
@@ -0,0 +1,41 @@
+QT += widgets concurrent network qml xml
+
+DOC_TARGETDIR = html
+INSTALL_DOC_PATH = $$IFW_BUILD_TREE/doc/$$DOC_TARGETDIR
+
+build_online_docs: \
+ DOC_FILES = $$PWD/ifw-online.qdocconf
+else: \
+ DOC_FILES = $$PWD/ifw.qdocconf
+
+qtdocs.name = QT_INSTALL_DOCS
+qtdocs.value = $$[QT_INSTALL_DOCS/src]
+qdocindex.name = QDOC_INDEX_DIR
+qdocindex.value = $$[QT_INSTALL_DOCS]
+qtver.name = QT_VERSION
+qtver.value = $$VERSION
+qtvertag.name = QT_VERSION_TAG
+qtvertag.value = $$replace(VERSION, \.,)
+QDOC_ENV += \
+ qtdocs \
+ qdocindex \
+ qtver \
+ qtvertag
+
+DOC_HTML_INSTALLDIR = $$INSTALL_DOC_PATH
+DOC_QCH_OUTDIR = $$IFW_BUILD_TREE/doc
+DOC_QCH_INSTALLDIR = $$INSTALL_DOC_PATH
+
+for (include_path, INCLUDEPATH): \
+ DOC_INCLUDES += -I $$shell_quote($$include_path)
+for (module, QT) {
+ MOD = $$replace(module, \-,_)
+ MOD_INCLUDES = $$eval(QT.$${MOD}.includes)
+ for (include_path, MOD_INCLUDES): \
+ DOC_INCLUDES += -I $$shell_quote($$include_path)
+}
+for (include_path, QMAKE_DEFAULT_INCDIRS): \
+ DOC_INCLUDES += -I $$shell_quote($$include_path)
+macos: DOC_INCLUDES += -F $$shell_quote($$[QT_INSTALL_LIBS])
+
+include(doc_targets.pri)
diff --git a/doc/doc.pro b/doc/doc.pro
deleted file mode 100644
index b22f139f0..000000000
--- a/doc/doc.pro
+++ /dev/null
@@ -1,12 +0,0 @@
-TEMPLATE = aux
-
-CONFIG += force_qt
-QT += core-private widgets concurrent network qml xml
-
-CONFIG += force_independent
-QMAKE_DOCS_TARGETDIR = html
-
-build_online_docs: \
- QMAKE_DOCS = $$PWD/ifw-online.qdocconf
-else: \
- QMAKE_DOCS = $$PWD/ifw.qdocconf
diff --git a/doc/doc_targets.pri b/doc/doc_targets.pri
new file mode 100644
index 000000000..274cf616a
--- /dev/null
+++ b/doc/doc_targets.pri
@@ -0,0 +1,89 @@
+# Creates targets for building documentation
+# (adapted from qt_docs.prf)
+#
+# Usage: Define variables (details below) and include this pri file afterwards.
+#
+# QDOC_ENV - environment variables to set for the qdoc call (see example below)
+# DOC_INDEX_PATHS - list of paths where qdoc should search for index files of dependent
+# modules (Qt index path is included by default)
+# DOC_FILES - list of qdocconf files
+# DOC_OUTDIR_POSTFIX - html is generated in $$OUT_PWD/<qdocconf_name>$$DOC_OUTDIR_POSTFIX
+# DOC_HTML_INSTALLDIR - path to install the directory of html files
+# DOC_QCH_OUTDIR - path to generate the qch files
+# DOC_QCH_INSTALLDIR - path to install the qch files
+#
+# Example for QDOC_ENV:
+# ver.name = VERSION
+# ver.value = 1.0.2
+# foo.name = FOO
+# foo.value = foo
+# QDOC_ENV = ver foo
+
+isEmpty(DOC_FILES): error("Set DOC_FILES before including doc_targets.pri")
+isEmpty(DOC_HTML_INSTALLDIR): error("Set DOC_HTML_INSTALLDIR before including doc_targets.pri")
+isEmpty(DOC_QCH_OUTDIR): error("Set DOC_QCH_OUTDIR before including doc_targets.pri")
+isEmpty(DOC_QCH_INSTALLDIR): error("Set DOC_QCH_INSTALLDIR before including doc_targets.pri")
+
+QT_TOOL_ENV = $$QDOC_ENV
+qtPrepareTool(QDOC, qdoc)
+QT_TOOL_ENV =
+
+!build_online_docs: qtPrepareLibExecTool(QHELPGENERATOR, qhelpgenerator)
+qtPrepareLibExecTool(QTATTRIBUTIONSSCANNER, qtattributionsscanner)
+
+DOCS_BASE_OUTDIR = $$OUT_PWD/doc
+DOC_INDEXES += -indexdir $$shell_quote($$[QT_INSTALL_DOCS])
+for (index_path, DOC_INDEX_PATHS): \
+ DOC_INDEXES += -indexdir $$shell_quote($$index_path)
+
+for (doc_file, DOC_FILES) {
+ !exists($$doc_file): error("Cannot find documentation specification file $$doc_file")
+ DOC_TARGET = $$replace(doc_file, ^(.*/)?(.*)\\.qdocconf$, \\2)
+ isEmpty(DOC_TARGETDIR): DOC_TARGETDIR = $$DOC_TARGET
+ DOC_OUTPUTDIR = $${DOCS_BASE_OUTDIR}/$${DOC_TARGETDIR}$${DOC_OUTDIR_POSTFIX}
+
+ html_docs_$${DOC_TARGET}.commands = $$QDOC -outputdir $$shell_quote($$DOC_OUTPUTDIR) $$doc_file $$DOC_INDEXES $$DOC_INCLUDES
+ QMAKE_EXTRA_TARGETS += html_docs_$${DOC_TARGET}
+
+ !isEmpty(html_docs.commands): html_docs.commands += &&
+ html_docs.commands += $$eval(html_docs_$${DOC_TARGET}.commands)
+
+ inst_html_docs.files += $$DOC_OUTPUTDIR
+
+ !build_online_docs {
+ qch_docs_$${DOC_TARGET}.commands = $$QHELPGENERATOR $$shell_quote($$DOC_OUTPUTDIR/$${DOC_TARGET}.qhp) -o $$shell_quote($$DOC_QCH_OUTDIR/$${DOC_TARGET}.qch)
+ qch_docs_$${DOC_TARGET}.depends = html_docs_$${DOC_TARGET}
+ QMAKE_EXTRA_TARGETS += qch_docs_$${DOC_TARGET}
+
+ !isEmpty(qch_docs.commands): qch_docs.commands += &&
+ qch_docs.commands += $$eval(qch_docs_$${DOC_TARGET}.commands)
+
+ inst_qch_docs.files += $$DOC_QCH_OUTDIR/$${DOC_TARGET}.qch
+ }
+}
+
+qtattributionsscanner.target = qtattributionsscanner
+qtattributionsscanner.commands = $$QTATTRIBUTIONSSCANNER $$shell_quote($$IFW_SOURCE_TREE) \
+ --filter "QDocModule=ifw" -o $$shell_quote($$OUT_PWD/doc/codeattributions.qdoc)
+qtattributionsscanner.CONFIG += phony
+QMAKE_EXTRA_TARGETS += qtattributionsscanner
+html_docs.depends = qtattributionsscanner
+
+!build_online_docs {
+ qch_docs.depends = html_docs
+ inst_qch_docs.path = $$DOC_QCH_INSTALLDIR
+ inst_qch_docs.CONFIG += no_check_exist no_default_install no_build
+ install_docs.depends = install_inst_qch_docs
+ docs.depends = qch_docs
+ INSTALLS += inst_qch_docs
+ QMAKE_EXTRA_TARGETS += qch_docs install_docs
+} else {
+ docs.depends = html_docs
+}
+
+inst_html_docs.path = $$DOC_HTML_INSTALLDIR
+inst_html_docs.CONFIG += no_check_exist no_default_install directory
+INSTALLS += inst_html_docs
+install_docs.depends += install_inst_html_docs
+
+QMAKE_EXTRA_TARGETS += html_docs docs
diff --git a/doc/examples/aliases.xml b/doc/examples/aliases.xml
new file mode 100644
index 000000000..1ce962f1e
--- /dev/null
+++ b/doc/examples/aliases.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+<Aliases>
+ <Alias>
+ <Name>package-full</Name>
+ <DisplayName>Full installation package</DisplayName>
+ <Description>Complete installation of the product</Description>
+ <Version>1.0.0</Version>
+ <Virtual>false</Virtual>
+ <RequiredAliases>package-essential</RequiredAliases>
+ <RequiredComponents>com.vendor.root.extras</RequiredComponents>
+ <OptionalAliases>package-optional</OptionalAliases>
+ </Alias>
+ <Alias>
+ <Name>package-essential</Name>
+ <DisplayName>Essential components</DisplayName>
+ <Description>Essential components for the product</Description>
+ <Version>1.0.0</Version>
+ <Virtual>false</Virtual>
+ <RequiredComponents>com.vendor.root.essential</RequiredComponents>
+ </Alias>
+ <Alias>
+ <Name>package-optional</Name>
+ <DisplayName>Optional components</DisplayName>
+ <Description>Optional components for the product</Description>
+ <Version>1.0.0</Version>
+ <Virtual>false</Virtual>
+ <OptionalComponents>com.vendor.root.optional1,com.vendor.root.optional2</OptionalComponents>
+ </Alias>
+</Aliases>
+
diff --git a/doc/examples/config.xml b/doc/examples/config.xml
index ef4598425..b04a413ec 100644
--- a/doc/examples/config.xml
+++ b/doc/examples/config.xml
@@ -28,4 +28,5 @@
<Url>http://www.your-repo-location/packages/</Url>
</Repository>
</RemoteRepositories>
+ <AliasDefinitionsFile>aliases.xml</AliasDefinitionsFile>
</Installer>
diff --git a/doc/images/ifw-overview.png b/doc/images/ifw-overview.png
index 4aac3cedf..8bda13d8e 100644
--- a/doc/images/ifw-overview.png
+++ b/doc/images/ifw-overview.png
Binary files differ
diff --git a/doc/includes/IFWDoc b/doc/includes/IFWDoc
deleted file mode 100644
index 6e5b4dbd4..000000000
--- a/doc/includes/IFWDoc
+++ /dev/null
@@ -1,125 +0,0 @@
-#pragma once
-
-#ifdef Q_CLANG_QDOC
-
-// installer
-#include "abstractfiletask.h"
-#include "abstracttask.h"
-#include "adminauthorization.h"
-#include "binarycontent.h"
-#include "binaryformatengine.h"
-#include "binaryformatenginehandler.h"
-#include "binaryformat.h"
-#include "binarylayout.h"
-#include "commandlineparser.h"
-#include "componentchecker.h"
-#include "component.h"
-#include "componentmodel.h"
-#include "concurrentoperationrunner.h"
-#include "constants.h"
-#include "consumeoutputoperation.h"
-#include "copydirectoryoperation.h"
-#include "copyfiletask.h"
-#include "createdesktopentryoperation.h"
-#include "createlinkoperation.h"
-#include "createlocalrepositoryoperation.h"
-#include "createshortcutoperation.h"
-#include "downloadarchivesjob.h"
-#include "downloadfiletask.h"
-#include "elevatedexecuteoperation.h"
-#include "environmentvariablesoperation.h"
-#include "errors.h"
-#include "extractarchiveoperation.h"
-#include "fakestopprocessforupdateoperation.h"
-#include "fileguard.h"
-#include "fileio.h"
-#include "fileutils.h"
-#include "genericdatacache.h"
-#include "globalsettingsoperation.h"
-#include "globals.h"
-#include "graph.h"
-#include "init.h"
-#include "installercalculator.h"
-#include "installer_global.h"
-#include "installiconsoperation.h"
-#include "keepaliveobject.h"
-#include "licenseoperation.h"
-#include "linereplaceoperation.h"
-#include "lib7z_extract.h"
-#include "lib7z_list.h"
-#include "lib7z_facade.h"
-#include "lib7zarchive.h"
-#include "libarchivearchive.h"
-#include "libarchivewrapper.h"
-#include "libarchivewrapper_p.h"
-#include "abstractarchive.h"
-#include "archivefactory.h"
-#include "directoryguard.h"
-#include "link.h"
-#include "messageboxhandler.h"
-#include "metadata.h"
-#include "metadatajob.h"
-#include "minimumprogressoperation.h"
-#include "observer.h"
-#include "operationtracer.h"
-#include "packagemanagercoredata.h"
-#include "packagemanagercore.h"
-#include "packagemanagergui.h"
-#include "packagemanagerpagefactory.h"
-#include "packagemanagerproxyfactory.h"
-#include "packagesource.h"
-#include "performinstallationform.h"
-#include "permissionsettings.h"
-#include "productkeycheck.h"
-#include "progresscoordinator.h"
-#include "protocol.h"
-#include "proxycredentialsdialog.h"
-#include "qinstallerglobal.h"
-#include "qprocesswrapper.h"
-#include "qsettingswrapper.h"
-#include "qtpatch.h"
-#include "range.h"
-#include "registerfiletypeoperation.h"
-#include "remoteclient.h"
-#include "remotefileengine.h"
-#include "remoteobject.h"
-#include "remoteserverconnection.h"
-#include "remoteserver.h"
-#include "replaceoperation.h"
-#include "repositorycategory.h"
-#include "repository.h"
-#include "runextensions.h"
-#include "scriptengine.h"
-#include "selfrestartoperation.h"
-#include "serverauthenticationdialog.h"
-#include "settings.h"
-#include "settingsoperation.h"
-#include "simplemovefileoperation.h"
-#include "systeminfo.h"
-#include "testrepository.h"
-#include "uninstallercalculator.h"
-#include "unziptask.h"
-#include "utils.h"
-
-//kdtools
-#include "environment.h"
-#include "filedownloaderfactory.h"
-#include "filedownloader.h"
-#include "genericfactory.h"
-#include "job.h"
-#include "kdtoolsglobal.h"
-#include "localpackagehub.h"
-#include "lockfile.h"
-#include "runoncechecker.h"
-#include "selfrestarter.h"
-#include "sysinfo.h"
-#include "task.h"
-#include "updatefinder.h"
-#include "update.h"
-#include "updateoperationfactory.h"
-#include "updateoperation.h"
-#include "updateoperations.h"
-#include "updater.h"
-
-#endif // Q_CLANG_QDOC
-
diff --git a/doc/installerfw-getting-started.qdoc b/doc/installerfw-getting-started.qdoc
index 8607164a0..1a86953a7 100644
--- a/doc/installerfw-getting-started.qdoc
+++ b/doc/installerfw-getting-started.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2023 The Qt Company Ltd.
+** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -39,7 +39,10 @@
\section1 Supported Platforms
You can use the Qt Installer Framework to create installers for all
- platforms supported by \l[QtDoc]{Supported Platforms}{desktop Qt}.
+ platforms supported by \l{https://doc.qt.io/qt-6/supported-platforms.html}{desktop Qt}.
+
+ If you use Linux, install also
+ \l {https://doc.qt.io/qt-6/linux-requirements.html} {Platform Plugin dependencies}.
\section1 Building from Sources
@@ -50,18 +53,24 @@
\section2 Supported Compilers
You can compile the Qt Installer Framework with Microsoft Visual Studio
- 2015 and newer, GCC 5 and newer, and Clang 11.0.0 and newer. Currently, the
- tested combination for Windows is Qt 5.15.2 with MSVC 2015 (Windows 10).
+ 2019 and newer, GCC 9 and newer, and Clang 13.0.0 and newer. Currently, the
+ tested combination for Windows is Qt 6.6.0 with MSVC 2019 (Windows 10).
\section2 Configuring Qt
If you use a statically built Qt to build the Qt Installer Framework
you do not have to deliver Qt libraries, which enables you to distribute
installers as one file. For more information about statically linking
- against OpenSSL libraries, see \l{http://doc.qt.io/qt-5/ssl.html}{SSL
+ against OpenSSL libraries, see \l{http://doc.qt.io/qt-6/ssl.html}{SSL
Import and Export Restrictions}.
- The supported Qt version is 5.15.2.
+ The supported Qt version is 6.6.0.
+
+ Get Qt sources:
+ \code
+ \l{https://wiki.qt.io/Building_Qt_6_from_Git}{Get Qt sources from git}.
+ Call init-repository with --module-subset=qt5compat, qtbase, qtdeclarative, qttools, qttranslations
+ \endcode
\section3 Configuring Qt for Windows
@@ -72,22 +81,12 @@
\endcode
- Build Qt:
- \code
- nmake (or 'mingw32-make') module-qtbase module-qtdeclarative module-qttools module-qttranslations module-qtwinextras
- \endcode
-
\section3 Configuring Qt for Linux
Use the following configuration options for Linux:
\code
- configure -prefix $PWD/qtbase -release -static -accessibility -qt-zlib -qt-libpng -qt-libjpeg -qt-pcre -no-glib -no-cups -no-sql-sqlite -no-feature-gssapi -no-qml-debug -no-opengl -no-egl -no-xinput2 -no-sm -no-icu -nomake examples -nomake tests -no-libudev
- \endcode
-
- Build Qt:
- \code
- make module-qtbase module-qtdeclarative module-qttools module-qttranslations
+ configure -prefix $PWD/qtbase -release -static -accessibility -qt-zlib -qt-libpng -qt-libjpeg -qt-pcre -no-glib -no-cups -no-sql-sqlite -no-feature-gssapi -no-qml-debug -no-opengl -no-egl -no-xinput2 -no-sm -no-icu -nomake examples -nomake tests -no-libudev -bundled-xcb-xinput -qt-harfbuzz -qt-doubleconversion
\endcode
\section3 Configuring Qt for macOS
@@ -95,12 +94,13 @@
Use the following configuration options for macOS:
\code
- 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
+ configure -prefix $PWD/qtbase -release -static -accessibility -qt-zlib -qt-libpng -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
+ cmake --build . --parallel
+ cmake --install .
\endcode
\section2 Third Party Dependencies
diff --git a/doc/installerfw-overview.qdoc b/doc/installerfw-overview.qdoc
index 7589aa915..b1ad69dc5 100644
--- a/doc/installerfw-overview.qdoc
+++ b/doc/installerfw-overview.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2023 The Qt Company Ltd.
+** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -32,21 +32,30 @@
\title Overview of Qt Installer Framework
- The Qt Installer Framework provides a set of tools and utilities to
- create installers once, and deploy them across all the supported desktop
- Qt platforms without rewriting the source code. The installers will have
- the native look and feel of the platform on which they run: Linux,
+ With Qt Installer Framework you can create both simple and complex installers
+ with thousands of components and deploy your installers across all the supported
+ desktop Qt platforms without rewriting the source code. Your final installers
+ have the native look and feel of the platform on which they run: Linux,
Microsoft Windows, and macOS.
- The Qt Installer Framework tools generate installers with a set of pages
- that guide the users during the installation, update, or uninstall
+ For example Qt installers are made with the Qt Installer Framework.
+
+ Both open-source and commercial users can download Qt Installer Framework from their
+ Qt Account.
+
+ Qt Installer Framework tools generate installers with a set of pages
+ that guide the users during the installation, update, or uninstallation
process. You supply the installable content and specify information about
it, such as the name of the product and the installer and the text for the
license agreement.
You can customize the installers by adding widgets to the predefined pages
- or by adding whole pages to offer users more options. You can
- create scripts to add operations to the installer.
+ or by adding whole pages to offer users more options.
+
+ Each installable package in the installer can contain one component script that
+ gives a comprehensive API to fine-tune how the package should be installed
+ on the system. You can, for example, add shortcuts to the desktop or register
+ file extensions for your tool.
\section1 Choosing Installer Type
@@ -55,33 +64,56 @@
\image ifw-overview.png
- Both installers install a \e {maintenance tool}, which allows you to later
- add, update, and remove components. Offline installers contain all the
- installable components and do not require network connections during the
- installation. Online installers only install the maintenance tool that then
- downloads and installs components from an online repository on a web server.
- Therefore, the size of an online installer binary is smaller and its
- download time is shorter than that of an offline installer binary. The total
- time spent downloading and running an online installer might also be shorter
- than downloading and running an offline installer if the end users do not
- install all the available components.
-
- End users can use the maintenance tool to install more components from
+ Both installers install a \e {\MT}, which allows your end users to later
+ add, update, and remove components.
+ End users can use the \MT to install more components from
the server after the initial installation, as well as to receive automatic
updates to content as soon as the updates are available on the server.
However, this works for an offline installation only if you specify a
repository address in the offline installer configuration or if end users
- specify the repository address themselves in the maintenance tool settings.
+ specify the repository address themselves in the \MT settings.
+
+ \section2 Offline Installers
+
+ Offline installers contain all the installable components and do not require
+ network connections during the installation.
Create an offline installer to enable users to directly download the
installation package on a media for installation on a computer later. You
can also distribute the installation package on a CD-ROM or USB stick, for
example.
+ \section2 Online installers
+
+ Online installers install the \MT and components from an online
+ repository on a web server. After installation, the \MT can be used to
+ modify the installation from an online repository.
+
+ The size of an online installer binary is smaller and its
+ download time is shorter than that of an offline installer binary. The total
+ time spent downloading and running an online installer might also be shorter
+ than downloading and running an offline installer if the end users do not
+ install all the available components.
+
Create an online installer to enable users to always install the latest
- versions of the content binaries.
+ versions of the content packages.
+ \list
+ \li Online repositories
+ \li Online installer
+ \endlist
+
+ \section2 Signing installers
+
+ Signing your installer is an integral step in finalizing your product. Signing
+ shows that your code is safe and secure.
+
+ Find more information on signing your installer on Windows platform
+ on \l{https://learn.microsoft.com/en-us/windows/win32/seccrypto/signtool} {Microsoft website}.
+ For more information on signing your installer in macOS, see Apple website for
+ \l{https://developer.apple.com/documentation/security/code_signing_services} {code signing}
+ and \{https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution} {notarizing}.
- \section1 Promoting Updates
+ \section1 Promoting Updates for Online Installers
Make online repositories available to promote updates to end users who
install your product. The easiest way to offer an update is to recreate
diff --git a/doc/installerfw-reference.qdoc b/doc/installerfw-reference.qdoc
index 9a57d905e..f129f1218 100644
--- a/doc/installerfw-reference.qdoc
+++ b/doc/installerfw-reference.qdoc
@@ -39,6 +39,7 @@
\li \l{Command Line Interface}
\li \l{Configuration File}
\li \l{Package Directory}
+ \li \l{Alias Definition File}
\li \l{Controller Scripting}
\li \l{Component Scripting}
\li \l{Operations}
diff --git a/doc/installerfw-using.qdoc b/doc/installerfw-using.qdoc
index 5f4674449..3cc52fb1a 100644
--- a/doc/installerfw-using.qdoc
+++ b/doc/installerfw-using.qdoc
@@ -33,12 +33,12 @@
\title End User Workflows
The end user experience is similar for offline and online installers.
- Along with your application, the installers install a maintenance tool that
+ Along with your application, the installers install a \MT that
consists of a package manager, an updater, and an uninstaller. End users can
- use the maintenance tool to add, update, and remove components. The
- maintenance tool connects to an external repository to fetch the components
+ use the \MT to add, update, and remove components. The
+ \MT connects to an external repository to fetch the components
to add or update. You can specify the repository in the configuration file
- or end users can specify it in the maintenance tool settings.
+ or end users can specify it in the \MT settings.
You can support the following end user workflows:
@@ -177,7 +177,7 @@
If end users did not select all the components available for installation
during the initial installation, they can use the package manager to install
the remaining components from a repository later. The package manager is
- part of a maintenance tool that is installed together with the application
+ part of a \MT that is installed together with the application
during the initial installation. This only works if a repository that
contains the components is available either locally or externally.
@@ -186,14 +186,14 @@
\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 {\MT} installed by the Qt 5 installer
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 \MT contains the package
manager, updater, and uninstaller.
\section1 Starting Package Manager
- When end users start the Maintenance Tool, the introduction page opens:
+ When end users start the \MT, the introduction page opens:
\image ifw-add-components-introduction.png "Introduction page"
@@ -242,12 +242,12 @@
\image ifw-user-flow-removing.png "Remove components workflow"
- This section uses the Qt 5 Maintenance Tool run on macOS as an example
+ This section uses the Qt 5 \MT run on macOS as an example
implementation of how end users can remove all or selected components.
\section1 Removing All Components
- When end users start the Maintenance Tool, the introduction page opens:
+ When end users start the \MT, the introduction page opens:
\image ifw-add-components-introduction.png "Introduction page"
@@ -294,12 +294,12 @@
\image ifw-user-flow-updating.png "Updating workflow"
- This section uses the Qt 5 Maintenance Tool run on macOS as an example
+ This section uses the Qt 5 \MT run on macOS as an example
implementation of how end users can update installed components.
\section1 Starting Updater
- When end users start the Maintenance Tool, the introduction page opens:
+ When end users start the \MT, the introduction page opens:
\image ifw-updating-introduction.png "Introduction page"
@@ -391,7 +391,7 @@
\section1 Installing Components
- Both the installer and the maintenance tool support installation of new components from
+ Both the installer and the \MT support installation of new components from
command line. The following will install the components given as an argument and
their respective dependencies:
@@ -408,10 +408,17 @@
installer.exe --root "C:\Users\MyUser\MyInstallation" install
\endcode
+ The install command can be also used for installing component aliases. If component
+ aliases are specified, the aliased components are selected for installation:
+
+ \code
+ maintenancetool.exe install alias1 alias2
+ \endcode
+
\section1 Checking for Available Updates
To print information about available component updates, run the \c check-updates
- command with the maintenance tool:
+ command with the \MT:
\code
maintenancetool.exe check-updates
@@ -444,7 +451,7 @@
\section1 Listing Installed Components
To get a list and print additional information about currently installed components, run the
- \c list command with the maintenance tool. The command also accepts an optional regular
+ \c list command with the \MT. The command also accepts an optional regular
expression argument to filter the shown component list.
\code
@@ -456,17 +463,36 @@
The \c search command can be used to search components from available repositories, or
from integrated binary content in case of an offline installer. It can be used with
no arguments to list all available components or with a regular expression to get a list
- of only components matching the pattern. The \c --filter-packages option can be
- used to specify additional filters for the search operation. For a list of usable
- information elements with the option, refer to \l{Summary of Package Information File Elements}.
+ of only components matching the pattern.
+
+ The \c --filter-packages option can be used to specify additional filters for the search
+ operation. For a list of usable information elements with the option, refer to
+ \l{Summary of Package Information File Elements}.
+
+ When the value of the \c{--type} option is set to \c package, the search command will
+ search for available components only:
+
+ \code
+ installer.exe --type package --filter-packages "DisplayName=MyComponent, Version=1.0" search "expression"
+ \endcode
+
+ When the \c{--type} option is omitted, the search command will first search for matching
+ component aliases, and if none are found, component names:
+
+ \code
+ installer.exe search "expression"
+ \endcode
+
+ When the value of the \c{--type} option is set to \c alias, the search command will
+ search for available component aliases only:
\code
- installer.exe --filter-packages "DisplayName=MyComponent, Version=1.0" search "expression"
+ installer.exe --type alias search "expression"
\endcode
\section1 Performing Full Uninstallation
- To uninstall all components and remove the program directory, including maintenance tool,
+ To uninstall all components and remove the program directory, including \MT,
run \c purge command:
\code
@@ -518,7 +544,7 @@
\c {--auto-answer OverwriteTargetDirectory=Yes}. Automatic answers are shown on the
console output and installation log.
- By default, the installer and maintenance tool will print a summary of components to be
+ By default, the installer and \MT will print a summary of components to be
affected by the command and then ask for permission to continue performing the action,
to prevent accidental changes. For unattended usage, this can be skipped by using the
\c --confirm-command option.
diff --git a/doc/installerfw.qdoc b/doc/installerfw.qdoc
index 3387987a7..4c55c6d43 100644
--- a/doc/installerfw.qdoc
+++ b/doc/installerfw.qdoc
@@ -39,9 +39,14 @@
\section1 Version \ifwversion
- The Qt Installer Framework provides a set of tools and utilities to
- create installers for the supported desktop Qt platforms: Linux, Microsoft
- Windows, and macOS.
+ Qt Installer Framework is a robust toolset for creating custom online
+ and offline installers. It’s highly configurable and customizable and works for all
+ supported Qt platforms: Linux, Microsoft Windows, and macOS.
+
+ Here are some examples to illustrate the versatility
+ of Qt Installer Framework.
+
+
\note Report bugs and suggestions for the Qt Installer Framework project
in the \l{https://bugreports.qt.io/browse/QTIFW}{Qt Bugtracker}.
@@ -72,6 +77,7 @@
\li \l{Command Line Interface}
\li \l{Configuration File}
\li \l{Package Directory}
+ \li \l{Alias Definition File}
\li \l{Controller Scripting}
\li \l{Component Scripting}
\li \l{Operations}
@@ -239,7 +245,7 @@
\li --sv, --show-virtual-components
\li Show virtual components in the installer and the package manager.
\row
- \li -i, --install-compressed-repository <URI,...>
+ \li -i, --install-compressed-repository <file,...>
\li Installs a QBSP or a 7z file. The QBSP (Board Support Package) file must be a .7z file
which contains a valid repository.
\row
@@ -255,6 +261,10 @@
\li --cp, --cache-path <path>
\li Sets the path used for local metadata cache. The path must be writable by the current user.
\row
+ \li --type package|alias
+ \li [CLI] Sets the type of the given arguments for commands supporting multiple argument types,
+ like search. Defaults to alias.
+ \row
\li --am, --accept-messages
\li [CLI] Accepts all message queries without user input.
\row
@@ -313,11 +323,11 @@
\li Command
\li Usage
\row
- \li in, install <pkg ...>
- \li Install packages given as an argument. If no packages are given, install the default package set.
+ \li in, install <pkg|alias ...>
+ \li Install packages and aliases given as an argument. If no arguments are given, install the default package set.
\row
\li ch, check-updates
- \li Show information about available updates on the maintenance tool.
+ \li Show information about available updates on the \MT.
\row
\li up, update <pkg ...>
\li Update packages given as an argument. If no packages are given, install all available updates.
@@ -325,14 +335,17 @@
\li rm, remove <pkg ...>
\li Uninstall selected packages and their child components.
\row
- \li li, list <regexp>
+ \li li, list <regexp for pkg>
\li List information about currently installed packages.
\row
- \li se, search <regexp>
- \li Search available packages. If no search pattern is given, show all available packages.
+ \li se, search <regexp for pkg|alias>
+ \li Search available aliases or packages. If no search pattern is given, show all available packages.
\note The \c --filter-packages option can be used to specify additional filters for
the search operation. See \l{Summary of Options}.
+
+ \note The \c --type option can be used to specify the content type to search.
+ See \l{Summary of Options}.
\row
\li co, create-offline <pkg ...>
\li Create offline installer from selected packages.
@@ -522,16 +535,16 @@
For more information, see \l{Configuring Repository Categories}.
\row
\li MaintenanceToolName
- \li Filename of the generated maintenance tool. Defaults to
+ \li Filename of the generated \MT. Defaults to
\e maintenancetool. The platform-specific executable file extension is
appended.
\row
\li MaintenanceToolIniFile
- \li Filename for the configuration of the generated maintenance tool. Defaults to
+ \li Filename for the configuration of the generated \MT. Defaults to
\e {MaintenanceToolName}.ini.
\row
\li MaintenanceToolAlias
- \li Filename for an alias of the maintenance tool that will be created to the
+ \li Filename for an alias of the \MT that will be created to the
Applications directory. Optional. Only used on macOS.
\row
\li RemoveTargetDir
@@ -553,6 +566,11 @@
\li RepositorySettingsPageVisible
\li Set to \c false to hide the repository settings page inside the settings dialog.
\row
+ \li AllowRepositoriesForOfflineInstaller
+ \li Set to \c false to disable usage of any temporary or user configured repositories
+ set for offline installers. The maintenance tool written by an offline installer
+ can still access the repositories. Defaults to \c true.
+ \row
\li AllowSpaceInPath
\li Set to \c false if the installation path cannot contain space characters.
\row
@@ -564,6 +582,11 @@
\li TargetConfigurationFile
\li Filename for the configuration file on the target. Default is components.xml.
\row
+ \li AliasDefinitionsFile
+ \li Filename for a XML document containing the definitions for component aliases.
+ For more information about how to declare component aliases in the file,
+ see \l{Alias Definition File}.
+ \row
\li Translations
\li List of translation files to be used for translating the user interface. To add
several translation files, specify several \c <Translation> child elements that
@@ -608,6 +631,83 @@
*/
/*!
+ \previouspage ifw-globalconfig.html
+ \page ifw-aliasconfig.html
+ \nextpage noninteractive.html
+
+ \title Alias Definition File
+
+ The alias definition file defines the available component aliases and their
+ properties. The file is typically called \c aliases.xml and located in the
+ \c config directory.
+
+ The component names of the Qt Installer Framework follow a domain-like
+ identifier syntax, for example \c com.vendor.root, \c com.vendor.root.subcomponent,
+ and so on. While this allows an easy way to construct a tree from the components when
+ running the installer in graphical mode, the names can be unintuitive for command line usage,
+ where the components are not displayed in a tree view.
+
+ Instead of relying on the domain-like names for CLI usage, the packager can also define component
+ aliases for existing components. An alias is another name for a single component or a collection
+ of components. It can be used to declare alternative names for existing components that are
+ easier to type and combine multiple components under the same alias name, for easier selection.
+
+ The following example shows a possible alias definition file:
+
+ \quotefile examples/aliases.xml
+
+ \section1 Summary of Alias Definition File Elements
+
+ The following table summarizes the elements in the alias definition file.
+
+ \table
+ \header
+ \li Element
+ \li Description
+ \row
+ \li Name
+ \li Name of component alias.
+ \row
+ \li DisplayName
+ \li Human-readable name of the component alias.
+ \row
+ \li Description
+ \li Human-readable description of the component alias.
+ \row
+ \li Version
+ \li Version number of the component alias.
+ \row
+ \li Virtual
+ \li Set to \c true to hide the component alias from the installer. This also
+ makes the alias unselectable by the user.
+ \row
+ \li RequiredComponents
+ \li Comma-separated list of identifiers of components that this
+ component alias requires. The components are selected for installation
+ when the component alias is selected. Note that the components must be
+ selectable by the user, so virtual or otherwise unselectable components
+ cannot be listed as a requirement.
+ \row
+ \li RequiredAliases
+ \li Comma-separated list of aliases that this component alias requires. The
+ required aliases are selected for installation when this component alias
+ is selected.
+ \row
+ \li OptionalComponents
+ \li Comma-separated list of identifiers of components that this component alias
+ optionally depends on. The components are selected for installation when the
+ component alias is selected, if the components exists and are user selectable.
+ Even if the components cannot be found in the installer, this alias is not marked unstable.
+ \row
+ \li OptionalAliases
+ \li Comma-separated list of aliases that this component alias optionally depends on. The
+ listed aliases are selected for installation when this component alias is selected,
+ if the aliases exist. Even if the aliases don't exists in the installer,
+ this alias is not marked unstable.
+ \endtable
+*/
+
+/*!
\previouspage ifw-updates.html
\page ifw-customizing-installers.html
\nextpage Qt Installer Framework Examples
@@ -806,7 +906,7 @@
/*!
\previouspage ifw-globalconfig.html
\page ifw-component-description.html
- \nextpage noninteractive.html
+ \nextpage ifw-aliasconfig.html
\title Package Directory
@@ -911,7 +1011,7 @@
but this does not change the visibility of the check box in the updater view
where the end user may still manually select the component for update.
- When running an installer or a maintenance tool in package manager
+ When running an installer or a \MT in package manager
mode, the selection will be performed automatically.
If the component was not installed before, it will
be selected for installation only when all components
@@ -1449,9 +1549,9 @@
\section1 devtool
- You can use \c devtool to update an existing installer or maintenance tool
+ You can use \c devtool to update an existing installer or \MT
with a new installer base, to dump binary content from an installer or
- maintenance tool to a target, and to execute operations. For a summary of
+ \MT to a target, and to execute operations. For a summary of
available operations, see \l {Operations}.
\c devtool expects the following parameters in the following order:
@@ -1480,12 +1580,12 @@
\li Display additional information.
\row
\li update <binary> <installerbase>
- \li Update an existing installer or maintenance tool with a new
+ \li Update an existing installer or \MT with a new
installer base.
\row
\li dump <binary> <folder>
\li Dump the binary content that belongs to an installer or
- maintenance tool into the target.
+ \MT into the target.
\row
\li operation <mode,name,args,...>
\li Execute an operation with a list of arguments.
@@ -1558,7 +1658,7 @@
\endcode
The installer works only if it can access the repository. If the repository is
- accessed after the installation, the maintenance tool rejects installation.
+ accessed after the installation, the \MT rejects installation.
However, uninstallation is still possible.
A repository can be enabled or disabled by default.
For repositories requiring authentication, the details can also be set here,
@@ -1780,7 +1880,7 @@
If \c{url} is itself relative, it will be resolved against the base URL of the current document.
\c{displayname} specifies how the repository should be named in the \gui Settings page
- of the Maintenance Tool.
+ of the \MT.
\c{name} and \c{password} optionally specify credentials for a protected repository.
@@ -1836,22 +1936,22 @@
\section1 Promoting Updates for the Maintenance Tool
Without additional configuration, both online and offline installers install the
- \e {maintenance tool}, that can be later used to add, update, and remove components.
- Online installers also have an option to install the maintenance tool from an online repository.
- This makes it possible to promote updates for the maintenance tool to take the advantage of latest
+ \e {\MT}, that can be later used to add, update, and remove components.
+ Online installers also have an option to install the \MT from an online repository.
+ This makes it possible to promote updates for the \MT to take the advantage of latest
new features and fixes to the Qt Installer Framework.
You should download the latest release of the Installer Framework distribution that
includes new versions of \l{binarycreator} and \l{installerbase} tools. However, to only
update vendor specific configuration like \c <Name>, \c <Title>, and \c <Publisher> to the new
- maintenance tool, you can use the tools that were used to create the original installer.
+ \MT, you can use the tools that were used to create the original installer.
\section2 Creating the Component Directory Structure for Maintenance Tool
- To make the maintenance tool update installable for end users, you need to prepare an installer
- component for the maintenance tool and create a repository for that component.
+ To make the \MT update installable for end users, you need to prepare an installer
+ component for the \MT and create a repository for that component.
- \note If you already have a component for the maintenance tool available in a repository, you
+ \note If you already have a component for the \MT available in a repository, you
can skip the instructions in this section.
A common convention is to create a \c packages directory containing the metadata and data for
@@ -1862,10 +1962,10 @@
\section2 Compiling the Update Resource
If you want to apply configuration changes, like updating the title, publisher, or product URL
- when the end user updates the maintenance tool, you need to create an update resource file.
+ when the end user updates the \MT, you need to create an update resource file.
Otherwise this step is optional.
- First, you need to compile the resource file that will contain the new maintenance tool
+ First, you need to compile the resource file that will contain the new \MT
configuration and related files:
\code
@@ -1875,8 +1975,8 @@
The command outputs the result into \c update.rcc in the current path.
The \c packages directory argument refers to the previously created directory for the maintenance
- tool component. \c config.xml contains the maintenance tool configuration. This can be the same
- file that was used for creating the online installer that is going to consume the maintenance tool
+ tool component. \c config.xml contains the \MT configuration. This can be the same
+ file that was used for creating the online installer that is going to consume the \MT
repository, or you could make modifications to change some configuration elements like the window
title and product version.
@@ -1884,9 +1984,9 @@
\section2 Getting the Maintenance Tool
- The maintenance tool for Linux and Windows is the same as the \c installerbase
+ The \MT for Linux and Windows is the same as the \c installerbase
executable located in your Qt Installer Framework's installation \c bin folder.
- For macOS the maintenance tool app bundle can be created using the \c binarycreator
+ For macOS the \MT app bundle can be created using the \c binarycreator
tool with the command line switch \c --mt or \c --create-maintenancetool. The
name of the macOS app bundle can be configured in config.xml using
the \c <MaintenanceToolName> element. The app bundle can be later signed and
@@ -1899,7 +1999,7 @@
\section2 Populating the Maintenance Tool Component
In Linux and in Windows the \c installerbase executable from Qt Installer
- Framework's installation folder, or in macOS the maintenance tool app bundle,
+ Framework's installation folder, or in macOS the \MT app bundle,
should be copied to the component's data directory. If you generated the
\c update.rcc in the \l{Compiling the Update Resource} step, copy that to
the data directory as well. The meta directory should contain a \c package.xml
@@ -1911,7 +2011,7 @@
For further information about the \c package.xml file, see
\l{Summary of Package Information File Elements}.
- \note If you are providing an update for an existing maintenance tool component, copy and overwrite the
+ \note If you are providing an update for an existing \MT component, copy and overwrite the
existing files with the updated content to the package directory and increase the value of the
\c <Version> element in the \c package.xml file.
@@ -1959,7 +2059,7 @@
After preparation the component should be uploaded to an existing or a new online repository
to make it available for end users. The instructions on how to create repositories on
this page and \l{Creating Repositories} apply also for the component containing the
- maintenance tool update.
+ \MT update.
*/
/*!
diff --git a/doc/noninteractive.qdoc b/doc/noninteractive.qdoc
index 15c85d28a..d22a17800 100644
--- a/doc/noninteractive.qdoc
+++ b/doc/noninteractive.qdoc
@@ -155,15 +155,15 @@
\row
\li \c PackageManagerRadioButton
- \li The package manager radio button shown on the page while running as maintenance tool.
+ \li The package manager radio button shown on the page while running as \MT.
\row
\li \c UpdaterRadioButton
- \li The updater radio button shown on the page while running as maintenance tool.
+ \li The updater radio button shown on the page while running as \MT.
\row
\li \c UninstallerRadioButton
- \li The uninstaller radio button shown on the page while running as maintenance tool.
+ \li The uninstaller radio button shown on the page while running as \MT.
Selected by default.
\endtable
@@ -184,10 +184,10 @@
\row
\li \c packageManagerCoreTypeChanged()
- \li Connect to this signal if you want to be notified when the type of maintenance tool
+ \li Connect to this signal if you want to be notified when the type of \MT
changes.
\note The signal is only emitted when the user has started the binary as so called
- maintenance tool (after the installation) and switches between the radio buttons.
+ \MT (after the installation) and switches between the radio buttons.
\endtable
Example code:
@@ -567,7 +567,7 @@
\row
\li \c WriteError
\li OK
- \li An error occurred while writing the maintenance tool.
+ \li An error occurred while writing the \MT.
\row
\li \c ElevationError
diff --git a/doc/operations.qdoc b/doc/operations.qdoc
index c61e2af0c..e148d6fc1 100644
--- a/doc/operations.qdoc
+++ b/doc/operations.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -40,6 +40,10 @@
the installer and an \e UNDO step that contains instructions for the
uninstaller.
+ Some operations especially in Windows might need native separators. Use
+ \c installer.toNativeSeparators() to convert separators to ones that are
+ appropriate for the underlying operating system.
+
\section1 Summary of Operations
The following table summarizes the available operations and their syntax in component
@@ -65,10 +69,16 @@
\li Copy
\li "Copy" \c source \c target
\li Copies a file from \c source to \c target.
+ \note The file will be restored during unistallation. If you want
+ to skip the copying, you can overwrite the \e UNDO by passing
+ \e UNDOOPERATION and \e "", to the end of the argument list.
\row
\li Move
\li "Move" \c source \c target
\li Moves a file from \c source to \c target.
+ \note Files restored during uninstallation. If you want to move the
+ files persistently, you can overwrite the \e UNDO by passing \e
+ UNDOOPERATION and \e "", to the end of the argument list.
\row
\li SimpleMoveFile
\li "SimpleMoveFile" \c source \c target
@@ -81,14 +91,25 @@
\li Delete
\li "Delete" \c filename
\li Deletes the file specified by \c filename.
+ \note File will be restored during uninstallation. If you want to
+ delete the files persistently, you can overwrite the \e UNDO by
+ passing \e UNDOOPERATION and \e "", to the end of the argument list.
\row
\li Mkdir
\li "Mkdir" \c path
\li Creates the directory path \c path.
+ \note Directory will be deleted during uninstallation.
+ If you want to create the directory persistently, you can overwrite the \e UNDO
+ by passing \e UNDOOPERATION and \e "", to the end of the argument list. Note that
+ during full uninstall, directory will be deleted if it was created to target directory
+ and \c RemoveTargetDir is false.
\row
\li Rmdir
\li "Rmdir" \c path
\li Removes the directory path \c path.
+ \note Directory will be recreated during uninstallation.
+ If you want to remove the directory persistently, you can overwrite the \e UNDO
+ by passing \e UNDOOPERATION and \e "", to the end of the argument list.
\row
\li CopyDirectory
\li "CopyDirectory" \c sourcePath \c targetPath
@@ -101,11 +122,17 @@
\li "AppendFile" \c filename \c text
\li Appends \c text to the file specified by \c filename. \c text is
treated as ASCII text.
+ \note Text will be removed from file during unistallation. If you want to append the
+ text persistently, you can overwrite the \e UNDO by passing \e UNDOOPERATION
+ and \e "", to the end of the argument list.
\row
\li PrependFile
\li "PrependFile" \c filename \c text
\li Prepends \c text to the file specified by \c filename. \c text
is treated as ASCII text.
+ \note Text will be removed from file during unistallation. If you want to append the
+ text persistently, you can overwrite the \e UNDO by passing \e UNDOOPERATION
+ and \e "", to the end of the argument list.
\row
\li Replace
\li "Replace" \c file \c search \c replace \c mode
@@ -149,12 +176,13 @@
\c linkname.
On Windows, this creates a .lnk file which can have
\c arguments. Furthermore, \c filename can be
- an HTTP or FTP URL in which case a URL shortcut is created.
+ an HTTP, HTTPS or FTP URL in which case a URL shortcut is created.
\note If the \c @AllUsersStartMenuProgramsPath@ is used for
placing the shortcut, then due to a problem on Windows, it will
drop any arguments to the target and any description set. In
this case, you should place the shortcut elsewhere and copy it
to the location desired.
+ \note Creating a shortcut to a network share is not supported.
The operation is currently not implemented on other platforms.
\row
\li CreateDesktopEntry
@@ -286,6 +314,7 @@
\li Sets or removes the \c value of \c key in the settings file located at
\c path, depending on the value of \c method: \c set, \c remove,
\c add_array_value, and \c remove_array_value.
+ Example: \c{component.addOperation("Settings", "path=settings.ini", "method=add", "key=myKey", "value=myValue")}
\endtable
The Extract, License, and MinimumProgress operations are automatically added for matching
diff --git a/doc/scripting-api/console.qdoc b/doc/scripting-api/console.qdoc
index 51825de9e..7785d9223 100644
--- a/doc/scripting-api/console.qdoc
+++ b/doc/scripting-api/console.qdoc
@@ -37,7 +37,7 @@
\l{console::log()}{log} method and \l installer object
\l{installer::isUpdater()}, \l{installer::isUninstaller()}, and
\l{installer::isPackageManager()} methods to display a message that
- indicates whether the maintenance tool is currently being used to update,
+ indicates whether the \MT is currently being used to update,
remove, or add components.
\code
diff --git a/doc/scripting-api/gui.qdoc b/doc/scripting-api/gui.qdoc
index 149e1bc84..b9e6c1b5f 100644
--- a/doc/scripting-api/gui.qdoc
+++ b/doc/scripting-api/gui.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -126,6 +126,28 @@
*/
/*!
+ \qmlmethod void gui::setWizardPageButtonText(int pageId, int buttonId, string buttonText)
+
+ Sets \a buttonText for button specified by \a buttonId to a installer page \a pageId.
+
+ \note In some pages, installer will change the button text when entering
+ the page. In that case, you need to connect to \c entered() -signal of the
+ page to change the \a buttonText.
+
+ \code
+ function Component()
+ {
+ var page = gui.pageByObjectName("FinishedPage");
+ page.entered.connect(Component.prototype.finishPageEntered);
+ }
+ Component.prototype.finishPageEntered = function()
+ {
+ gui.setWizardPageButtonText(QInstaller.InstallationFinished, buttons.CommitButton, "Commit");
+ }
+ \endcode
+*/
+
+/*!
\qmlmethod void gui::showSettingsButton(boolean show)
Shows the \uicontrol Settings button if \a show is \c true. This function
diff --git a/doc/scripting-api/packagemanagercore.qdoc b/doc/scripting-api/packagemanagercore.qdoc
index ac6830d33..ecf4b1eaa 100644
--- a/doc/scripting-api/packagemanagercore.qdoc
+++ b/doc/scripting-api/packagemanagercore.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -71,24 +71,6 @@
\qmlsignal installer::componentAdded(Component component)
Emitted when a new root \a component is added.
-
- \sa rootComponentsAdded(), updaterComponentsAdded()
-*/
-
-/*!
- \qmlsignal installer::rootComponentsAdded(list<Component> components)
-
- Emitted when a new list of root \a components is added.
-
- \sa componentAdded(), updaterComponentsAdded()
-*/
-
-/*!
- \qmlsignal installer::updaterComponentsAdded(list<Component> components)
-
- Emitted when a new list of updater \a components is added.
-
- \sa componentAdded(), rootComponentsAdded()
*/
/*!
@@ -615,6 +597,18 @@
*/
/*!
+ \qmlmethod bool installer::hasAdminRights()
+
+ Returns \c true if the installer has admin rights. For example, if the installer
+ was started with a root account, or the internal admin rights elevation is active.
+
+ Returns \c false otherwise.
+
+ \sa gainAdminRights()
+ \sa dropAdminRights()
+*/
+
+/*!
\qmlmethod boolean installer::isProcessRunning(string name)
Returns \c true if a process with \a name is running. On Windows, the comparison
@@ -633,15 +627,23 @@
/*!
\qmlmethod void installer::setAllowedRunningProcesses(stringlist processes)
+ \deprecated [4.6] The \MT no longer automatically checks for all running processes
+ in the installation directory for CLI runs. To check for a process to stop, use
+ \l {component::addStopProcessForUpdateRequest}{component.addStopProcessForUpdateRequest} instead.
+
Sets additional \a processes that can run when
- updating with the maintenance tool.
+ updating with the \MT.
*/
/*!
\qmlmethod stringlist installer::allowedRunningProcesses()
+ \deprecated [4.6] The \MT no longer automatically checks for all running processes
+ in the installation directory for CLI runs. To check for a process to stop, use
+ \l {component::addStopProcessForUpdateRequest}{component.addStopProcessForUpdateRequest} instead.
+
Returns processes that are allowed to run when updating with
- the maintenance tool.
+ the \MT.
*/
/*!
@@ -756,7 +758,7 @@
/*!
\qmlmethod void installer::setInstallerBaseBinary(string path)
- Sets the \c installerbase binary to use when writing the maintenance tool.
+ Sets the \c installerbase binary to use when writing the \MT.
Set the \a path if an update to the binary is available.
If not set, the executable segment of the running installer or uninstaller
diff --git a/doc/scripting-api/qdesktopservices.qdoc b/doc/scripting-api/qdesktopservices.qdoc
index 0fc6cf898..a9c8a149f 100644
--- a/doc/scripting-api/qdesktopservices.qdoc
+++ b/doc/scripting-api/qdesktopservices.qdoc
@@ -56,14 +56,18 @@
\li DesktopServices.PicturesLocation
\li DesktopServices.TempLocation
\li DesktopServices.HomeLocation
- \li DesktopServices.DataLocation
+ \li DesktopServices.AppLocalDataLocation
\li DesktopServices.CacheLocation
+ \li DesktopServices.GenericCacheLocation
\li DesktopServices.GenericDataLocation
\li DesktopServices.RuntimeLocation
\li DesktopServices.ConfigLocation
\li DesktopServices.DownloadLocation
- \li DesktopServices.GenericCacheLocation
\li DesktopServices.GenericConfigLocation
+ \li DesktopServices.AppDataLocation
+ \li DesktopServices.AppConfigLocation
+ \li DesktopServices.PublicShareLocation
+ \li DesktopServices.TemplatesLocation
\endlist
The enum values correspond to the values of the
diff --git a/doc/scripting-api/qfiledialog.qdoc b/doc/scripting-api/qfiledialog.qdoc
index 3f281f44f..6fd01de3d 100644
--- a/doc/scripting-api/qfiledialog.qdoc
+++ b/doc/scripting-api/qfiledialog.qdoc
@@ -42,17 +42,19 @@
*/
/*!
- \qmlmethod string QFileDialog::getExistingDirectory(string caption, string dir)
+ \qmlmethod string QFileDialog::getExistingDirectory(string caption, string dir, string identifier)
Returns an existing directory selected by the user.
The dialog's working directory is set to \a dir, and the caption is set to
\a caption. Either of these may be an empty string, in which case the
current directory and a default caption will be used, respectively.
+ The \a identifier is used in command line interface to allow to identify
+ specific file dialogs for automatic answer.
*/
/*!
- \qmlmethod string QFileDialog::getOpenFileName(string caption, string dir, string filter)
+ \qmlmethod string QFileDialog::getOpenFileName(string caption, string dir, string filter, string identifier)
Returns an existing file selected by the user. If the user selects
\uicontrol Cancel, returns a null string.
@@ -64,6 +66,9 @@
file name, the file will be selected. Only files that match the specified
\a filter are shown. Either of these may be an empty string.
+ The \a identifier is used in command line interface to allow to identify
+ specific file dialogs for automatic answer.
+
To specify multiple filters, separate them with two semicolons (;;). For
example:
diff --git a/doc/scripting.qdoc b/doc/scripting.qdoc
index 8854442fa..1dde6576a 100644
--- a/doc/scripting.qdoc
+++ b/doc/scripting.qdoc
@@ -94,7 +94,7 @@
\li Reference to the \l QInstaller of the component
\row
\li component
- \li Reference to the \l Component of the component
+ \li Reference to the \l{https://doc.qt.io/qtinstallerframework/qinstaller-component.html}{Component}. of the component
\endtable
\section1 Message Boxes
diff --git a/doc/systeminfo.qdoc b/doc/systeminfo.qdoc
index 1f260abdb..3695dbc07 100644
--- a/doc/systeminfo.qdoc
+++ b/doc/systeminfo.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -52,6 +52,25 @@
*/
/*!
+ \qmlproperty string systemInfo::buildCpuArchitecture
+
+ The architecture of the CPU that the application was compiled for, in text format.
+
+ Possible values include:
+ \list
+ \li "i386"
+ \li "x86_64"
+ \li "arm64"
+ \endlist
+
+ Note that this may not match the actual CPU that the application is running on if
+ there's an emulation layer or if the CPU supports multiple architectures (like x86-64
+ processors supporting i386 applications). To detect that, use \c installer.currentCpuArchitecture()
+
+ \sa QSysInfo::buildCpuArchitecture() currentCpuArchitecture
+*/
+
+/*!
\qmlproperty string systemInfo::kernelType
The type of the operating system kernel the installer was compiled for. It is also the
@@ -98,7 +117,7 @@
\list
\li "windows"
\li "opensuse" (for the Linux openSUSE distribution)
- \li "osx"
+ \li "macos"
\endlist
\sa QSysInfo::productType()
diff --git a/examples/componentalias/README b/examples/componentalias/README
new file mode 100644
index 000000000..8253c6701
--- /dev/null
+++ b/examples/componentalias/README
@@ -0,0 +1,5 @@
+Create an installer that shows how component aliases work
+
+Generate installer with:
+
+binarycreator -c config/config.xml -p packages installer
diff --git a/examples/componentalias/componentalias.pro b/examples/componentalias/componentalias.pro
new file mode 100644
index 000000000..415df49d5
--- /dev/null
+++ b/examples/componentalias/componentalias.pro
@@ -0,0 +1,13 @@
+TEMPLATE = aux
+
+INSTALLER = installer
+
+INPUT = $$PWD/config/config.xml $$PWD/packages
+example.input = INPUT
+example.output = $$INSTALLER
+example.commands = ../../bin/binarycreator -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT}
+example.CONFIG += target_predeps no_link combine
+
+QMAKE_EXTRA_COMPILERS += example
+
+OTHER_FILES = README
diff --git a/examples/componentalias/config/aliases.xml b/examples/componentalias/config/aliases.xml
new file mode 100644
index 000000000..baf89f9b1
--- /dev/null
+++ b/examples/componentalias/config/aliases.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<Aliases>
+ <Alias>
+ <Name>set1</Name>
+ <DisplayName>Component Set 1</DisplayName>
+ <Description>Alias for components A, B, and C</Description>
+ <Version>1.0.0</Version>
+ <Virtual>false</Virtual>
+ <RequiredComponents>componentA,componentB,componentC</RequiredComponents>
+ </Alias>
+ <Alias>
+ <Name>set2</Name>
+ <DisplayName>Component Set 2</DisplayName>
+ <Description>Alias for components D, and E</Description>
+ <Version>1.0.0</Version>
+ <Virtual>false</Virtual>
+ <RequiredComponents>componentD,componentE</RequiredComponents>
+ </Alias>
+ <Alias>
+ <Name>set-full</Name>
+ <DisplayName>Full Component Set</DisplayName>
+ <Description>Alias for full installation</Description>
+ <Version>1.0.0</Version>
+ <Virtual>false</Virtual>
+ <RequiredAliases>set1,set2</RequiredAliases>
+ </Alias>
+</Aliases>
+
diff --git a/examples/componentalias/config/config.xml b/examples/componentalias/config/config.xml
new file mode 100644
index 000000000..440930355
--- /dev/null
+++ b/examples/componentalias/config/config.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Installer>
+ <Name>Component Alias Example</Name>
+ <Version>1.0.0</Version>
+ <Title>Component Alias Example</Title>
+ <Publisher>Qt-Project</Publisher>
+ <StartMenuDir>Qt IFW Examples</StartMenuDir>
+ <TargetDir>@HomeDir@/IfwExamples/componentalias</TargetDir>
+ <AliasDefinitionsFile>aliases.xml</AliasDefinitionsFile>
+</Installer>
diff --git a/examples/componentalias/packages/componentA/data/installcontentA.txt b/examples/componentalias/packages/componentA/data/installcontentA.txt
new file mode 100644
index 000000000..f40001983
--- /dev/null
+++ b/examples/componentalias/packages/componentA/data/installcontentA.txt
@@ -0,0 +1,2 @@
+This file will be installed into the target directory....
+
diff --git a/examples/componentalias/packages/componentA/meta/package.xml b/examples/componentalias/packages/componentA/meta/package.xml
new file mode 100644
index 000000000..729989fd9
--- /dev/null
+++ b/examples/componentalias/packages/componentA/meta/package.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<Package>
+ <DisplayName>Component A</DisplayName>
+ <Description>This component is a part of a component alias.</Description>
+ <Version>1.0.0</Version>
+ <ReleaseDate>2014-08-25</ReleaseDate>
+ <SortingPriority>100</SortingPriority>
+</Package>
diff --git a/examples/componentalias/packages/componentB/data/installcontentB.txt b/examples/componentalias/packages/componentB/data/installcontentB.txt
new file mode 100644
index 000000000..f40001983
--- /dev/null
+++ b/examples/componentalias/packages/componentB/data/installcontentB.txt
@@ -0,0 +1,2 @@
+This file will be installed into the target directory....
+
diff --git a/examples/componentalias/packages/componentB/meta/package.xml b/examples/componentalias/packages/componentB/meta/package.xml
new file mode 100644
index 000000000..c6eba4223
--- /dev/null
+++ b/examples/componentalias/packages/componentB/meta/package.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<Package>
+ <DisplayName>Component B</DisplayName>
+ <Description>This component is a part of a component alias.</Description>
+ <Version>1.0.0</Version>
+ <ReleaseDate>2014-08-25</ReleaseDate>
+ <SortingPriority>90</SortingPriority>
+</Package>
diff --git a/examples/componentalias/packages/componentC/data/installcontentC.txt b/examples/componentalias/packages/componentC/data/installcontentC.txt
new file mode 100644
index 000000000..f40001983
--- /dev/null
+++ b/examples/componentalias/packages/componentC/data/installcontentC.txt
@@ -0,0 +1,2 @@
+This file will be installed into the target directory....
+
diff --git a/examples/componentalias/packages/componentC/meta/package.xml b/examples/componentalias/packages/componentC/meta/package.xml
new file mode 100644
index 000000000..59af43132
--- /dev/null
+++ b/examples/componentalias/packages/componentC/meta/package.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<Package>
+ <DisplayName>Component C</DisplayName>
+ <Description>This component is a part of a component alias.</Description>
+ <Version>1.0.0</Version>
+ <ReleaseDate>2014-08-25</ReleaseDate>
+ <SortingPriority>80</SortingPriority>
+</Package>
diff --git a/examples/componentalias/packages/componentD/data/installcontentD.txt b/examples/componentalias/packages/componentD/data/installcontentD.txt
new file mode 100644
index 000000000..f40001983
--- /dev/null
+++ b/examples/componentalias/packages/componentD/data/installcontentD.txt
@@ -0,0 +1,2 @@
+This file will be installed into the target directory....
+
diff --git a/examples/componentalias/packages/componentD/meta/package.xml b/examples/componentalias/packages/componentD/meta/package.xml
new file mode 100644
index 000000000..eccbd8d4a
--- /dev/null
+++ b/examples/componentalias/packages/componentD/meta/package.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<Package>
+ <DisplayName>Component D</DisplayName>
+ <Description>This component is a part of a component alias.</Description>
+ <Version>1.0.0</Version>
+ <ReleaseDate>2014-08-25</ReleaseDate>
+ <SortingPriority>70</SortingPriority>
+</Package>
diff --git a/examples/componentalias/packages/componentE/data/installcontentE.txt b/examples/componentalias/packages/componentE/data/installcontentE.txt
new file mode 100644
index 000000000..f40001983
--- /dev/null
+++ b/examples/componentalias/packages/componentE/data/installcontentE.txt
@@ -0,0 +1,2 @@
+This file will be installed into the target directory....
+
diff --git a/examples/componentalias/packages/componentE/meta/package.xml b/examples/componentalias/packages/componentE/meta/package.xml
new file mode 100644
index 000000000..95b4ebd72
--- /dev/null
+++ b/examples/componentalias/packages/componentE/meta/package.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<Package>
+ <DisplayName>Component E</DisplayName>
+ <Description>This component is a part of a component alias.</Description>
+ <Version>1.0.0</Version>
+ <ReleaseDate>2014-08-25</ReleaseDate>
+ <SortingPriority>60</SortingPriority>
+</Package>
diff --git a/examples/doc/componentalias.qdoc b/examples/doc/componentalias.qdoc
new file mode 100644
index 000000000..c4e7c8e99
--- /dev/null
+++ b/examples/doc/componentalias.qdoc
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example componentalias
+ \ingroup qtifwexamples
+ \title Component Alias Example
+
+ \brief Using installer's aliases.xml file to define component aliases and their
+ relations to other aliases and components.
+
+ \e{Component Alias} illustrates how to specify component aliases and how they influence
+ the installation and maintenance processes for command line usage.
+
+ \include installerfw-examples-configuring.qdocinc
+
+ \list
+ \li The \c <AliasDefinitionsFile> element is set to \c aliases.xml to
+ tell the installer the source for the alias definitions.
+ \endlist
+
+ \quotefile componentalias/config/config.xml
+
+ In this example, the aliases.xml file declares three component aliases. Two aliases,
+ \c set1 and \c set2 require a subset of available components, while \c set-full
+ requires the former two aliases, thus all available components.
+
+ \quotefile componentalias/config/aliases.xml
+
+ For full reference of the alias definitions file syntax, see \l{Alias Definition File}.
+
+ \include installerfw-examples-packaging.qdocinc
+
+ \section1 Referring to Component Aliases from Command Line
+
+ The declared component aliases can be used from the installer's command line interface
+ with the \c search and \c install commands.
+
+ \section2 Searching Available Component Aliases
+
+ The \c search command will by default search available aliases first, and then normal
+ components:
+
+ \code
+ $ installer search
+ \endcode
+
+ The command will print a table of aliases that were declared in the alias definition file:
+
+ \code
+ Name: set-full
+ Display name: Full Component Set
+ Description: Alias for full installation
+ Version: 1.0.0
+ Components:
+ Required aliases: set1,set2
+ ========================================
+ Name: set1
+ Display name: Component Set 1
+ Description: Alias for components A, B, and C
+ Version: 1.0.0
+ Components: componentA,componentB,componentC
+ Required aliases:
+ ========================================
+ Name: set2
+ Display name: Component Set 2
+ Description: Alias for components D, and E
+ Version: 1.0.0
+ Components: componentD,componentE
+ Required aliases:
+ \endcode
+
+ \section2 Installing Available Component Aliases
+
+ The \c install command can be used to install the components referred by a component alias:
+
+ \code
+ $ installer install set1
+ \endcode
+
+ This command is practically equivalent to selecting the components explicitly by their names:
+
+ \code
+ $ installer install componentA componentB componentC
+ \endcode
+
+ When selecting aliases for installation, the component changes summary will show
+ separate sections for components selected by a aliases, to differentiate from manual
+ selection:
+
+ \code
+ $ installer install set1 componentD
+ \endcode
+
+ This will output the following component changes summary:
+
+ \code
+ Components selected by alias "set1":
+ componentA
+ componentB
+ componentC
+ Selected components without dependencies:
+ componentD
+ \endcode
+
+ The \c <RequiredComponents> property does not declare a hard dependency for components,
+ and those can be later on updated or uninstalled individually from the alias:
+
+ \code
+ $ maintenancetool remove componentA
+ \endcode
+
+ After this, selecting the \c set1 alias for installation again would also select
+ \c componentA for reinstallation.
+
+ \section1 Virtual Component Aliases
+
+ Component aliases may be declared \c <Virtual>. This works similarly with virtual components,
+ so that they cannot be manually selected by the user and do not show in component search results.
+ Such aliases must be included by other aliases with the \c <RequiredAliases> property.
+
+ \section1 Optional Dependencies for Component Aliases
+
+ In addition to dependencies declared with \c <RequiredComponents> and \c <RequiredAliases> as
+ shown in this example, aliases may have optional dependencies declared with \c <OptionalComponents>
+ and \c <OptionalAliases> properties. The latter properties differ from the requirements in that
+ they do not cause the alias declaring the requirement to become unselectable, in case the referenced
+ components or aliases are not known to the installer.
+
+ This provides the packager some flexibility for declaring the dependencies. For example, an
+ installer may be expected to use an optional repository, which contains components that a
+ component alias optionally depends on, but the alias should be also available for installation
+ when the repository is disabled.
+
+ \include installerfw-examples-generating.qdocinc
+*/
diff --git a/examples/doc/online.qdoc b/examples/doc/online.qdoc
index f901c3445..0c14a8c26 100644
--- a/examples/doc/online.qdoc
+++ b/examples/doc/online.qdoc
@@ -150,7 +150,7 @@
only updates packages that are new, or have a higher version number.
See also the \l{Summary of repogen Parameters}.
- If you then run the maintenance tool from the previous installation and
+ If you then run the \MT from the previous installation and
select \gui {Update Components}, you should see that an update of package
\c A is available.
diff --git a/examples/doc/treename.qdoc b/examples/doc/treename.qdoc
index 22acb8e08..774b6e1fa 100644
--- a/examples/doc/treename.qdoc
+++ b/examples/doc/treename.qdoc
@@ -106,7 +106,7 @@
\section2 Multiple Tree Names in One Component Branch
Components in a single branch (\e A, \e{A.sub1}, \e{A.sub1.sub1}, \e{A.sub1.sub1.sub2} and so
- on) may each declare a separate tree name. The installer or maintenance tool calculates the
+ on) may each declare a separate tree name. The installer or \MT calculates the
new locations for components in an ascending order from leaf components to root components, so that
\e{A.sub1.sub1.sub2} is moved first and \e A last.
@@ -120,18 +120,18 @@
of the installer has installed component \e A with tree name \e ANewName1, and the
repository is updated with a new version of component \e A that declares tree name
\e ANewName2, the new location is only applied when the user updates the component
- locally with the maintenance tool.
+ locally with the \MT.
\li The automatic tree names of children of components with tree name and \c moveChildren
set to \c true are moved with the parent regardless if installed or not. Therefore, if
the user has installed component \e{A.sub1} but not component \e A, and \e A is updated
in the repository with a new tree name, the \e{A.sub1} uses also the new tree name in
- maintenance tool's component tree.
+ \MT's component tree.
\endlist
\section2 Tree Name and Name Conflicts
The tree names may conflict with existing component names or other tree names. Depending on whether
- the installer or maintenance tool is configured to allow unstable components with
+ the installer or \MT is configured to allow unstable components with
\c <AllowUnstableComponents> configuration file element, the offending components are either
registered as unstable components with their original name or not registered at all.
diff --git a/examples/examples.pro b/examples/examples.pro
index 283f81abe..eca806812 100644
--- a/examples/examples.pro
+++ b/examples/examples.pro
@@ -2,6 +2,7 @@ TEMPLATE = subdirs
SUBDIRS += \
changeuserinterface \
+ componentalias \
componenterror \
dependencies \
dynamicpage \
diff --git a/installerfw.pri b/installerfw.pri
index 5bba5cd9e..9b969e4ee 100644
--- a/installerfw.pri
+++ b/installerfw.pri
@@ -3,13 +3,14 @@
}
IFW_PRI_INCLUDED = 1
-IFW_VERSION_STR = 4.6.0
-IFW_VERSION = 0x040600
-IFW_VERSION_WIN32 = 4,6,0,0
+IFW_VERSION_STR = 4.8.0
+IFW_VERSION = 0x040800
+IFW_VERSION_WIN32 = 4,8,0,0
IFW_VERSION_STR_WIN32 = $$IFW_VERSION_STR\0
IFW_REPOSITORY_FORMAT_VERSION = 1.0.0
+IFW_CACHE_FORMAT_VERSION = 1.2.0
IFW_NEWLINE = $$escape_expand(\\n\\t)
isEmpty(IFW_DISABLE_TRANSLATIONS): IFW_DISABLE_TRANSLATIONS = $$(IFW_DISABLE_TRANSLATIONS)
@@ -97,6 +98,15 @@ win32 {
LCONVERT = $${LCONVERT}.exe
QMAKE_BINARY = $${QMAKE_BINARY}.exe
}
+
+#6.6.0 rcc has been moved to libexec in linux/mac and the RCC variable no longer
+#points to correct location
+!exists($$RCC) {
+ RCC = $$toNativeSeparators($$cleanPath($$[QT_INSTALL_LIBEXECS]/rcc))
+}
+!exists($$RCC) {
+ warning("Resource compiler '$$RCC' not found.")
+}
win32-g++*:QMAKE_CXXFLAGS += -Wno-attributes
macx:QMAKE_CXXFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden
@@ -140,7 +150,13 @@ CONFIG(static, static|shared) {
QT += concurrent network qml xml
greaterThan(QT_MAJOR_VERSION, 5):QT += core5compat
}
-CONFIG += depend_includepath no_private_qt_headers_warning c++11
+CONFIG += depend_includepath no_private_qt_headers_warning
+versionAtLeast(QT_MAJOR_VERSION, 6) {
+ CONFIG+=c++17
+} else {
+ CONFIG+=c++11
+}
+
win32:CONFIG += console
exists(".git") {
@@ -158,7 +174,8 @@ DEFINES += NOMINMAX QT_NO_CAST_FROM_ASCII QT_STRICT_ITERATORS QT_USE_QSTRINGBUIL
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 \
+ IFW_CACHE_FORMAT_VERSION=$$IFW_CACHE_FORMAT_VERSION
win32-g++*: LIBS += -lmpr -luuid
diff --git a/installerfw.pro b/installerfw.pro
index ee9e5b1cc..f8f2b5469 100644
--- a/installerfw.pro
+++ b/installerfw.pro
@@ -1,10 +1,11 @@
TEMPLATE = subdirs
-SUBDIRS += src tools doc
+SUBDIRS += src tools
tools.depends = src
requires(!cross_compile)
include (installerfw.pri)
+include (doc/doc.pri)
BUILD_TESTS = $$(BUILDTESTS)
isEmpty(BUILD_TESTS):BUILD_TESTS=$${BUILDTESTS}
diff --git a/src/libs/3rdparty/libarchive/archive.h b/src/libs/3rdparty/libarchive/archive.h
index 217ac1989..618b1a176 100644
--- a/src/libs/3rdparty/libarchive/archive.h
+++ b/src/libs/3rdparty/libarchive/archive.h
@@ -36,7 +36,7 @@
* assert that ARCHIVE_VERSION_NUMBER >= 2012108.
*/
/* Note: Compiler will complain if this does not match archive_entry.h! */
-#define ARCHIVE_VERSION_NUMBER 3006002
+#define ARCHIVE_VERSION_NUMBER 3007001
#include <sys/stat.h>
#include <stddef.h> /* for wchar_t */
@@ -157,7 +157,7 @@ __LA_DECL int archive_version_number(void);
/*
* Textual name/version of the library, useful for version displays.
*/
-#define ARCHIVE_VERSION_ONLY_STRING "3.6.2"
+#define ARCHIVE_VERSION_ONLY_STRING "3.7.1"
#define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
__LA_DECL const char * archive_version_string(void);
diff --git a/src/libs/3rdparty/libarchive/archive_digest.c b/src/libs/3rdparty/libarchive/archive_digest.c
index 3361b19ad..08a9aeb02 100644
--- a/src/libs/3rdparty/libarchive/archive_digest.c
+++ b/src/libs/3rdparty/libarchive/archive_digest.c
@@ -36,6 +36,11 @@
#error Cannot use both OpenSSL and libmd.
#endif
+/* Common in other bcrypt implementations, but missing from VS2008. */
+#ifndef BCRYPT_SUCCESS
+#define BCRYPT_SUCCESS(r) ((NTSTATUS)(r) == STATUS_SUCCESS)
+#endif
+
/*
* Message digest functions for Windows platform.
*/
@@ -48,6 +53,26 @@
/*
* Initialize a Message digest.
*/
+#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
+static int
+win_crypto_init(Digest_CTX *ctx, const WCHAR *algo)
+{
+ NTSTATUS status;
+ ctx->valid = 0;
+
+ status = BCryptOpenAlgorithmProvider(&ctx->hAlg, algo, NULL, 0);
+ if (!BCRYPT_SUCCESS(status))
+ return (ARCHIVE_FAILED);
+ status = BCryptCreateHash(ctx->hAlg, &ctx->hHash, NULL, 0, NULL, 0, 0);
+ if (!BCRYPT_SUCCESS(status)) {
+ BCryptCloseAlgorithmProvider(ctx->hAlg, 0);
+ return (ARCHIVE_FAILED);
+ }
+
+ ctx->valid = 1;
+ return (ARCHIVE_OK);
+}
+#else
static int
win_crypto_init(Digest_CTX *ctx, DWORD prov, ALG_ID algId)
{
@@ -70,6 +95,7 @@ win_crypto_init(Digest_CTX *ctx, DWORD prov, ALG_ID algId)
ctx->valid = 1;
return (ARCHIVE_OK);
}
+#endif
/*
* Update a Message digest.
@@ -81,23 +107,37 @@ win_crypto_Update(Digest_CTX *ctx, const unsigned char *buf, size_t len)
if (!ctx->valid)
return (ARCHIVE_FAILED);
+#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
+ BCryptHashData(ctx->hHash,
+ (PUCHAR)(uintptr_t)buf,
+ len, 0);
+#else
CryptHashData(ctx->hash,
(unsigned char *)(uintptr_t)buf,
(DWORD)len, 0);
+#endif
return (ARCHIVE_OK);
}
static int
win_crypto_Final(unsigned char *buf, size_t bufsize, Digest_CTX *ctx)
{
+#if !(defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA)
DWORD siglen = (DWORD)bufsize;
+#endif
if (!ctx->valid)
return (ARCHIVE_FAILED);
+#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
+ BCryptFinishHash(ctx->hHash, buf, (ULONG)bufsize, 0);
+ BCryptDestroyHash(ctx->hHash);
+ BCryptCloseAlgorithmProvider(ctx->hAlg, 0);
+#else
CryptGetHashParam(ctx->hash, HP_HASHVAL, buf, &siglen, 0);
CryptDestroyHash(ctx->hash);
CryptReleaseContext(ctx->cryptProv, 0);
+#endif
ctx->valid = 0;
return (ARCHIVE_OK);
}
@@ -276,7 +316,11 @@ __archive_md5final(archive_md5_ctx *ctx, void *md)
static int
__archive_md5init(archive_md5_ctx *ctx)
{
+#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
+ return (win_crypto_init(ctx, BCRYPT_MD5_ALGORITHM));
+#else
return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_MD5));
+#endif
}
static int
@@ -659,7 +703,11 @@ __archive_sha1final(archive_sha1_ctx *ctx, void *md)
static int
__archive_sha1init(archive_sha1_ctx *ctx)
{
+#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
+ return (win_crypto_init(ctx, BCRYPT_SHA1_ALGORITHM));
+#else
return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_SHA1));
+#endif
}
static int
@@ -919,7 +967,11 @@ __archive_sha256final(archive_sha256_ctx *ctx, void *md)
static int
__archive_sha256init(archive_sha256_ctx *ctx)
{
+#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
+ return (win_crypto_init(ctx, BCRYPT_SHA256_ALGORITHM));
+#else
return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_256));
+#endif
}
static int
@@ -1155,7 +1207,11 @@ __archive_sha384final(archive_sha384_ctx *ctx, void *md)
static int
__archive_sha384init(archive_sha384_ctx *ctx)
{
+#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
+ return (win_crypto_init(ctx, BCRYPT_SHA384_ALGORITHM));
+#else
return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_384));
+#endif
}
static int
@@ -1415,7 +1471,11 @@ __archive_sha512final(archive_sha512_ctx *ctx, void *md)
static int
__archive_sha512init(archive_sha512_ctx *ctx)
{
+#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
+ return (win_crypto_init(ctx, BCRYPT_SHA512_ALGORITHM));
+#else
return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_512));
+#endif
}
static int
diff --git a/src/libs/3rdparty/libarchive/archive_digest_private.h b/src/libs/3rdparty/libarchive/archive_digest_private.h
index 9b3bd6621..339b4edca 100644
--- a/src/libs/3rdparty/libarchive/archive_digest_private.h
+++ b/src/libs/3rdparty/libarchive/archive_digest_private.h
@@ -164,6 +164,15 @@
defined(ARCHIVE_CRYPTO_SHA256_WIN) ||\
defined(ARCHIVE_CRYPTO_SHA384_WIN) ||\
defined(ARCHIVE_CRYPTO_SHA512_WIN)
+#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
+/* don't use bcrypt when XP needs to be supported */
+#include <bcrypt.h>
+typedef struct {
+ int valid;
+ BCRYPT_ALG_HANDLE hAlg;
+ BCRYPT_HASH_HANDLE hHash;
+} Digest_CTX;
+#else
#include <windows.h>
#include <wincrypt.h>
typedef struct {
@@ -172,6 +181,7 @@ typedef struct {
HCRYPTHASH hash;
} Digest_CTX;
#endif
+#endif
/* typedefs */
#if defined(ARCHIVE_CRYPTO_MD5_LIBC)
diff --git a/src/libs/3rdparty/libarchive/archive_entry.h b/src/libs/3rdparty/libarchive/archive_entry.h
index e579e9f33..c15460b96 100644
--- a/src/libs/3rdparty/libarchive/archive_entry.h
+++ b/src/libs/3rdparty/libarchive/archive_entry.h
@@ -30,7 +30,7 @@
#define ARCHIVE_ENTRY_H_INCLUDED
/* Note: Compiler will complain if this does not match archive.h! */
-#define ARCHIVE_VERSION_NUMBER 3006002
+#define ARCHIVE_VERSION_NUMBER 3007001
/*
* Note: archive_entry.h is for use outside of libarchive; the
diff --git a/src/libs/3rdparty/libarchive/archive_getdate.c b/src/libs/3rdparty/libarchive/archive_getdate.c
index 39e224cb9..20ab1b158 100644
--- a/src/libs/3rdparty/libarchive/archive_getdate.c
+++ b/src/libs/3rdparty/libarchive/archive_getdate.c
@@ -698,13 +698,9 @@ Convert(time_t Month, time_t Day, time_t Year,
time_t Julian;
int i;
struct tm *ltime;
-#if defined(HAVE_LOCALTIME_R) || defined(HAVE__LOCALTIME64_S)
+#if defined(HAVE_LOCALTIME_R) || defined(HAVE_LOCALTIME_S)
struct tm tmbuf;
#endif
-#if defined(HAVE__LOCALTIME64_S)
- errno_t terr;
- __time64_t tmptime;
-#endif
if (Year < 69)
Year += 2000;
@@ -731,15 +727,10 @@ Convert(time_t Month, time_t Day, time_t Year,
Julian *= DAY;
Julian += Timezone;
Julian += Hours * HOUR + Minutes * MINUTE + Seconds;
-#if defined(HAVE_LOCALTIME_R)
+#if defined(HAVE_LOCALTIME_S)
+ ltime = localtime_s(&tmbuf, &Julian) ? NULL : &tmbuf;
+#elif defined(HAVE_LOCALTIME_R)
ltime = localtime_r(&Julian, &tmbuf);
-#elif defined(HAVE__LOCALTIME64_S)
- tmptime = Julian;
- terr = _localtime64_s(&tmbuf, &tmptime);
- if (terr)
- ltime = NULL;
- else
- ltime = &tmbuf;
#else
ltime = localtime(&Julian);
#endif
@@ -755,36 +746,21 @@ DSTcorrect(time_t Start, time_t Future)
time_t StartDay;
time_t FutureDay;
struct tm *ltime;
-#if defined(HAVE_LOCALTIME_R) || defined(HAVE__LOCALTIME64_S)
+#if defined(HAVE_LOCALTIME_R) || defined(HAVE_LOCALTIME_S)
struct tm tmbuf;
#endif
-#if defined(HAVE__LOCALTIME64_S)
- errno_t terr;
- __time64_t tmptime;
-#endif
-
-#if defined(HAVE_LOCALTIME_R)
+#if defined(HAVE_LOCALTIME_S)
+ ltime = localtime_s(&tmbuf, &Start) ? NULL : &tmbuf;
+#elif defined(HAVE_LOCALTIME_R)
ltime = localtime_r(&Start, &tmbuf);
-#elif defined(HAVE__LOCALTIME64_S)
- tmptime = Start;
- terr = _localtime64_s(&tmbuf, &tmptime);
- if (terr)
- ltime = NULL;
- else
- ltime = &tmbuf;
#else
ltime = localtime(&Start);
#endif
StartDay = (ltime->tm_hour + 1) % 24;
-#if defined(HAVE_LOCALTIME_R)
+#if defined(HAVE_LOCALTIME_S)
+ ltime = localtime_s(&tmbuf, &Future) ? NULL : &tmbuf;
+#elif defined(HAVE_LOCALTIME_R)
ltime = localtime_r(&Future, &tmbuf);
-#elif defined(HAVE__LOCALTIME64_S)
- tmptime = Future;
- terr = _localtime64_s(&tmbuf, &tmptime);
- if (terr)
- ltime = NULL;
- else
- ltime = &tmbuf;
#else
ltime = localtime(&Future);
#endif
@@ -799,24 +775,15 @@ RelativeDate(time_t Start, time_t zone, int dstmode,
{
struct tm *tm;
time_t t, now;
-#if defined(HAVE_GMTIME_R) || defined(HAVE__GMTIME64_S)
+#if defined(HAVE_GMTIME_R) || defined(HAVE_GMTIME_S)
struct tm tmbuf;
#endif
-#if defined(HAVE__GMTIME64_S)
- errno_t terr;
- __time64_t tmptime;
-#endif
t = Start - zone;
-#if defined(HAVE_GMTIME_R)
+#if defined(HAVE_GMTIME_S)
+ tm = gmtime_s(&tmbuf, &t) ? NULL : &tmbuf;
+#elif defined(HAVE_GMTIME_R)
tm = gmtime_r(&t, &tmbuf);
-#elif defined(HAVE__GMTIME64_S)
- tmptime = t;
- terr = _gmtime64_s(&tmbuf, &tmptime);
- if (terr)
- tm = NULL;
- else
- tm = &tmbuf;
#else
tm = gmtime(&t);
#endif
@@ -835,25 +802,16 @@ RelativeMonth(time_t Start, time_t Timezone, time_t RelMonth)
struct tm *tm;
time_t Month;
time_t Year;
-#if defined(HAVE_LOCALTIME_R) || defined(HAVE__LOCALTIME64_S)
+#if defined(HAVE_LOCALTIME_R) || defined(HAVE_LOCALTIME_S)
struct tm tmbuf;
#endif
-#if defined(HAVE__LOCALTIME64_S)
- errno_t terr;
- __time64_t tmptime;
-#endif
if (RelMonth == 0)
return 0;
-#if defined(HAVE_LOCALTIME_R)
+#if defined(HAVE_LOCALTIME_S)
+ tm = localtime_s(&tmbuf, &Start) ? NULL : &tmbuf;
+#elif defined(HAVE_LOCALTIME_R)
tm = localtime_r(&Start, &tmbuf);
-#elif defined(HAVE__LOCALTIME64_S)
- tmptime = Start;
- terr = _localtime64_s(&tmbuf, &tmptime);
- if (terr)
- tm = NULL;
- else
- tm = &tmbuf;
#else
tm = localtime(&Start);
#endif
@@ -993,10 +951,6 @@ __archive_get_date(time_t now, const char *p)
time_t Start;
time_t tod;
long tzone;
-#if defined(HAVE__LOCALTIME64_S) || defined(HAVE__GMTIME64_S)
- errno_t terr;
- __time64_t tmptime;
-#endif
/* Clear out the parsed token array. */
memset(tokens, 0, sizeof(tokens));
@@ -1005,36 +959,26 @@ __archive_get_date(time_t now, const char *p)
gds = &_gds;
/* Look up the current time. */
-#if defined(HAVE_LOCALTIME_R)
+#if defined(HAVE_LOCALTIME_S)
+ tm = localtime_s(&local, &now) ? NULL : &local;
+#elif defined(HAVE_LOCALTIME_R)
tm = localtime_r(&now, &local);
-#elif defined(HAVE__LOCALTIME64_S)
- tmptime = now;
- terr = _localtime64_s(&local, &tmptime);
- if (terr)
- tm = NULL;
- else
- tm = &local;
#else
memset(&local, 0, sizeof(local));
tm = localtime(&now);
#endif
if (tm == NULL)
return -1;
-#if !defined(HAVE_LOCALTIME_R) && !defined(HAVE__LOCALTIME64_S)
+#if !defined(HAVE_LOCALTIME_R) && !defined(HAVE_LOCALTIME_S)
local = *tm;
#endif
/* Look up UTC if we can and use that to determine the current
* timezone offset. */
-#if defined(HAVE_GMTIME_R)
+#if defined(HAVE_GMTIME_S)
+ gmt_ptr = gmtime_s(&gmt, &now) ? NULL : &gmt;
+#elif defined(HAVE_GMTIME_R)
gmt_ptr = gmtime_r(&now, &gmt);
-#elif defined(HAVE__GMTIME64_S)
- tmptime = now;
- terr = _gmtime64_s(&gmt, &tmptime);
- if (terr)
- gmt_ptr = NULL;
- else
- gmt_ptr = &gmt;
#else
memset(&gmt, 0, sizeof(gmt));
gmt_ptr = gmtime(&now);
@@ -1076,15 +1020,10 @@ __archive_get_date(time_t now, const char *p)
* time components instead of the local timezone. */
if (gds->HaveZone && gmt_ptr != NULL) {
now -= gds->Timezone;
-#if defined(HAVE_GMTIME_R)
+#if defined(HAVE_GMTIME_S)
+ gmt_ptr = gmtime_s(&gmt, &now) ? NULL : &gmt;
+#elif defined(HAVE_GMTIME_R)
gmt_ptr = gmtime_r(&now, &gmt);
-#elif defined(HAVE__GMTIME64_S)
- tmptime = now;
- terr = _gmtime64_s(&gmt, &tmptime);
- if (terr)
- gmt_ptr = NULL;
- else
- gmt_ptr = &gmt;
#else
gmt_ptr = gmtime(&now);
#endif
diff --git a/src/libs/3rdparty/libarchive/archive_hmac.c b/src/libs/3rdparty/libarchive/archive_hmac.c
index 012fe1596..edb3bf5ab 100644
--- a/src/libs/3rdparty/libarchive/archive_hmac.c
+++ b/src/libs/3rdparty/libarchive/archive_hmac.c
@@ -231,15 +231,20 @@ static int
__hmac_sha1_init(archive_hmac_sha1_ctx *ctx, const uint8_t *key, size_t key_len)
{
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
- OSSL_PARAM params[2];
+ EVP_MAC *mac;
- EVP_MAC *mac = EVP_MAC_fetch(NULL, "HMAC", NULL);
+ char sha1[] = "SHA1";
+ OSSL_PARAM params[] = {
+ OSSL_PARAM_utf8_string("digest", sha1, sizeof(sha1) - 1),
+ OSSL_PARAM_END
+ };
+
+ mac = EVP_MAC_fetch(NULL, "HMAC", NULL);
*ctx = EVP_MAC_CTX_new(mac);
+ EVP_MAC_free(mac);
if (*ctx == NULL)
return -1;
- EVP_MAC_free(mac);
- params[0] = OSSL_PARAM_construct_utf8_string("digest", "SHA1", 0);
- params[1] = OSSL_PARAM_construct_end();
+
EVP_MAC_init(*ctx, key, key_len, params);
#else
*ctx = HMAC_CTX_new();
diff --git a/src/libs/3rdparty/libarchive/archive_hmac_private.h b/src/libs/3rdparty/libarchive/archive_hmac_private.h
index 50044a045..d0fda7f96 100644
--- a/src/libs/3rdparty/libarchive/archive_hmac_private.h
+++ b/src/libs/3rdparty/libarchive/archive_hmac_private.h
@@ -77,6 +77,8 @@ typedef struct hmac_sha1_ctx archive_hmac_sha1_ctx;
#include <openssl/opensslv.h>
#include <openssl/hmac.h>
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/params.h>
+
typedef EVP_MAC_CTX *archive_hmac_sha1_ctx;
#else
diff --git a/src/libs/3rdparty/libarchive/archive_openssl_evp_private.h b/src/libs/3rdparty/libarchive/archive_openssl_evp_private.h
index ebb06702d..8ac477280 100644
--- a/src/libs/3rdparty/libarchive/archive_openssl_evp_private.h
+++ b/src/libs/3rdparty/libarchive/archive_openssl_evp_private.h
@@ -33,7 +33,8 @@
#include <openssl/evp.h>
#include <openssl/opensslv.h>
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
#include <stdlib.h> /* malloc, free */
#include <string.h> /* memset */
static inline EVP_MD_CTX *EVP_MD_CTX_new(void)
diff --git a/src/libs/3rdparty/libarchive/archive_random.c b/src/libs/3rdparty/libarchive/archive_random.c
index 9d1aa493f..301765acd 100644
--- a/src/libs/3rdparty/libarchive/archive_random.c
+++ b/src/libs/3rdparty/libarchive/archive_random.c
@@ -51,16 +51,27 @@ __FBSDID("$FreeBSD$");
#include <pthread.h>
#endif
-static void arc4random_buf(void *, size_t);
+static void la_arc4random_buf(void *, size_t);
#endif /* HAVE_ARC4RANDOM_BUF */
#include "archive.h"
#include "archive_random_private.h"
-#if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__)
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
+/* don't use bcrypt when XP needs to be supported */
+#include <bcrypt.h>
+
+/* Common in other bcrypt implementations, but missing from VS2008. */
+#ifndef BCRYPT_SUCCESS
+#define BCRYPT_SUCCESS(r) ((NTSTATUS)(r) == STATUS_SUCCESS)
+#endif
+
+#elif defined(HAVE_WINCRYPT_H)
#include <wincrypt.h>
#endif
+#endif
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
@@ -75,6 +86,20 @@ int
archive_random(void *buf, size_t nbytes)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
+# if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
+ NTSTATUS status;
+ BCRYPT_ALG_HANDLE hAlg;
+
+ status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM, NULL, 0);
+ if (!BCRYPT_SUCCESS(status))
+ return ARCHIVE_FAILED;
+ status = BCryptGenRandom(hAlg, buf, nbytes, 0);
+ BCryptCloseAlgorithmProvider(hAlg, 0);
+ if (!BCRYPT_SUCCESS(status))
+ return ARCHIVE_FAILED;
+
+ return ARCHIVE_OK;
+# else
HCRYPTPROV hProv;
BOOL success;
@@ -92,6 +117,10 @@ archive_random(void *buf, size_t nbytes)
}
/* TODO: Does this case really happen? */
return ARCHIVE_FAILED;
+# endif
+#elif !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__))
+ la_arc4random_buf(buf, nbytes);
+ return ARCHIVE_OK;
#else
arc4random_buf(buf, nbytes);
return ARCHIVE_OK;
@@ -256,7 +285,7 @@ arc4_getbyte(void)
}
static void
-arc4random_buf(void *_buf, size_t n)
+la_arc4random_buf(void *_buf, size_t n)
{
uint8_t *buf = (uint8_t *)_buf;
_ARC4_LOCK();
diff --git a/src/libs/3rdparty/libarchive/archive_read_data_into_fd.c b/src/libs/3rdparty/libarchive/archive_read_data_into_fd.c
index b4398f1ec..f16ca5c82 100644
--- a/src/libs/3rdparty/libarchive/archive_read_data_into_fd.c
+++ b/src/libs/3rdparty/libarchive/archive_read_data_into_fd.c
@@ -95,8 +95,13 @@ archive_read_data_into_fd(struct archive *a, int fd)
"archive_read_data_into_fd");
can_lseek = (fstat(fd, &st) == 0) && S_ISREG(st.st_mode);
- if (!can_lseek)
+ if (!can_lseek) {
nulls = calloc(1, nulls_size);
+ if (!nulls) {
+ r = ARCHIVE_FATAL;
+ goto cleanup;
+ }
+ }
while ((r = archive_read_data_block(a, &buff, &size, &target_offset)) ==
ARCHIVE_OK) {
diff --git a/src/libs/3rdparty/libarchive/archive_read_disk_posix.c b/src/libs/3rdparty/libarchive/archive_read_disk_posix.c
index 5a94ec5d4..8d5c32f03 100644
--- a/src/libs/3rdparty/libarchive/archive_read_disk_posix.c
+++ b/src/libs/3rdparty/libarchive/archive_read_disk_posix.c
@@ -1670,6 +1670,11 @@ setup_current_filesystem(struct archive_read_disk *a)
else
t->current_filesystem->name_max = nm;
#endif
+ if (t->current_filesystem->name_max == 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Cannot determine name_max");
+ return (ARCHIVE_FAILED);
+ }
#endif /* USE_READDIR_R */
return (ARCHIVE_OK);
}
@@ -1860,8 +1865,17 @@ setup_current_filesystem(struct archive_read_disk *a)
#if defined(USE_READDIR_R)
/* Set maximum filename length. */
+#if defined(HAVE_STATVFS)
+ t->current_filesystem->name_max = svfs.f_namemax;
+#else
t->current_filesystem->name_max = sfs.f_namelen;
#endif
+ if (t->current_filesystem->name_max == 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Cannot determine name_max");
+ return (ARCHIVE_FAILED);
+ }
+#endif
return (ARCHIVE_OK);
}
@@ -1942,6 +1956,11 @@ setup_current_filesystem(struct archive_read_disk *a)
#if defined(USE_READDIR_R)
/* Set maximum filename length. */
t->current_filesystem->name_max = svfs.f_namemax;
+ if (t->current_filesystem->name_max == 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Cannot determine name_max");
+ return (ARCHIVE_FAILED);
+ }
#endif
return (ARCHIVE_OK);
}
@@ -1996,6 +2015,11 @@ setup_current_filesystem(struct archive_read_disk *a)
else
t->current_filesystem->name_max = nm;
# endif /* _PC_NAME_MAX */
+ if (t->current_filesystem->name_max == 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Cannot determine name_max");
+ return (ARCHIVE_FAILED);
+ }
#endif /* USE_READDIR_R */
return (ARCHIVE_OK);
}
@@ -2543,7 +2567,11 @@ tree_current_lstat(struct tree *t)
#else
if (tree_enter_working_dir(t) != 0)
return NULL;
+#ifdef HAVE_LSTAT
if (lstat(tree_current_access_path(t), &t->lst) != 0)
+#else
+ if (la_stat(tree_current_access_path(t), &t->lst) != 0)
+#endif
#endif
return NULL;
t->flags |= hasLstat;
diff --git a/src/libs/3rdparty/libarchive/archive_read_disk_windows.c b/src/libs/3rdparty/libarchive/archive_read_disk_windows.c
index f9d139557..f92a78a21 100644
--- a/src/libs/3rdparty/libarchive/archive_read_disk_windows.c
+++ b/src/libs/3rdparty/libarchive/archive_read_disk_windows.c
@@ -418,9 +418,19 @@ la_linkname_from_pathw(const wchar_t *path, wchar_t **outbuf, int *linktype)
FILE_FLAG_OPEN_REPARSE_POINT;
int ret;
+# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
+ CREATEFILE2_EXTENDED_PARAMETERS createExParams;
+ ZeroMemory(&createExParams, sizeof(createExParams));
+ createExParams.dwSize = sizeof(createExParams);
+ createExParams.dwFileFlags = flag;
+ h = CreateFile2(path, 0,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ OPEN_EXISTING, &createExParams);
+#else
h = CreateFileW(path, 0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
OPEN_EXISTING, flag, NULL);
+#endif
if (h == INVALID_HANDLE_VALUE) {
la_dosmaperr(GetLastError());
return (-1);
@@ -1067,16 +1077,29 @@ next_entry(struct archive_read_disk *a, struct tree *t,
if (archive_entry_filetype(entry) == AE_IFREG &&
archive_entry_size(entry) > 0) {
DWORD flags = FILE_FLAG_BACKUP_SEMANTICS;
+#if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
+ CREATEFILE2_EXTENDED_PARAMETERS createExParams;
+#endif
if (t->async_io)
flags |= FILE_FLAG_OVERLAPPED;
if (t->direct_io)
flags |= FILE_FLAG_NO_BUFFERING;
else
flags |= FILE_FLAG_SEQUENTIAL_SCAN;
+#if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
+ ZeroMemory(&createExParams, sizeof(createExParams));
+ createExParams.dwSize = sizeof(createExParams);
+ createExParams.dwFileFlags = flags;
+ t->entry_fh = CreateFile2(tree_current_access_path(t),
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ OPEN_EXISTING, &createExParams);
+#else
t->entry_fh = CreateFileW(tree_current_access_path(t),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, OPEN_EXISTING, flags, NULL);
+#endif
if (t->entry_fh == INVALID_HANDLE_VALUE) {
la_dosmaperr(GetLastError());
archive_set_error(&a->archive, errno,
@@ -1547,6 +1570,9 @@ close_and_restore_time(HANDLE h, struct tree *t, struct restore_time *rt)
{
HANDLE handle;
int r = 0;
+#if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
+ CREATEFILE2_EXTENDED_PARAMETERS createExParams;
+#endif
if (h == INVALID_HANDLE_VALUE && AE_IFLNK == rt->filetype)
return (0);
@@ -1560,8 +1586,16 @@ close_and_restore_time(HANDLE h, struct tree *t, struct restore_time *rt)
if ((t->flags & needsRestoreTimes) == 0)
return (r);
+#if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
+ ZeroMemory(&createExParams, sizeof(createExParams));
+ createExParams.dwSize = sizeof(createExParams);
+ createExParams.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS;
+ handle = CreateFile2(rt->full_path, FILE_WRITE_ATTRIBUTES,
+ 0, OPEN_EXISTING, &createExParams);
+#else
handle = CreateFileW(rt->full_path, FILE_WRITE_ATTRIBUTES,
0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+#endif
if (handle == INVALID_HANDLE_VALUE) {
errno = EINVAL;
return (-1);
@@ -2046,12 +2080,24 @@ tree_current_file_information(struct tree *t, BY_HANDLE_FILE_INFORMATION *st,
HANDLE h;
int r;
DWORD flag = FILE_FLAG_BACKUP_SEMANTICS;
-
+# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
+ CREATEFILE2_EXTENDED_PARAMETERS createExParams;
+#endif
+
if (sim_lstat && tree_current_is_physical_link(t))
flag |= FILE_FLAG_OPEN_REPARSE_POINT;
+# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
+ ZeroMemory(&createExParams, sizeof(createExParams));
+ createExParams.dwSize = sizeof(createExParams);
+ createExParams.dwFileFlags = flag;
+ h = CreateFile2(tree_current_access_path(t), 0,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ OPEN_EXISTING, &createExParams);
+#else
h = CreateFileW(tree_current_access_path(t), 0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
OPEN_EXISTING, flag, NULL);
+#endif
if (h == INVALID_HANDLE_VALUE) {
la_dosmaperr(GetLastError());
t->tree_errno = errno;
@@ -2257,7 +2303,10 @@ archive_read_disk_entry_from_file(struct archive *_a,
} else {
WIN32_FIND_DATAW findData;
DWORD flag, desiredAccess;
-
+# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
+ CREATEFILE2_EXTENDED_PARAMETERS createExParams;
+#endif
+
h = FindFirstFileW(path, &findData);
if (h == INVALID_HANDLE_VALUE) {
la_dosmaperr(GetLastError());
@@ -2279,9 +2328,18 @@ archive_read_disk_entry_from_file(struct archive *_a,
} else
desiredAccess = GENERIC_READ;
+# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
+ ZeroMemory(&createExParams, sizeof(createExParams));
+ createExParams.dwSize = sizeof(createExParams);
+ createExParams.dwFileFlags = flag;
+ h = CreateFile2(path, desiredAccess,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ OPEN_EXISTING, &createExParams);
+#else
h = CreateFileW(path, desiredAccess,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
OPEN_EXISTING, flag, NULL);
+#endif
if (h == INVALID_HANDLE_VALUE) {
la_dosmaperr(GetLastError());
archive_set_error(&a->archive, errno,
@@ -2342,9 +2400,19 @@ archive_read_disk_entry_from_file(struct archive *_a,
if (fd >= 0) {
h = (HANDLE)_get_osfhandle(fd);
} else {
+# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
+ CREATEFILE2_EXTENDED_PARAMETERS createExParams;
+ ZeroMemory(&createExParams, sizeof(createExParams));
+ createExParams.dwSize = sizeof(createExParams);
+ createExParams.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS;
+ h = CreateFile2(path, GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ OPEN_EXISTING, &createExParams);
+#else
h = CreateFileW(path, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+#endif
if (h == INVALID_HANDLE_VALUE) {
la_dosmaperr(GetLastError());
archive_set_error(&a->archive, errno,
diff --git a/src/libs/3rdparty/libarchive/archive_read_open_file.c b/src/libs/3rdparty/libarchive/archive_read_open_file.c
index 101dae6cd..03719e8bf 100644
--- a/src/libs/3rdparty/libarchive/archive_read_open_file.c
+++ b/src/libs/3rdparty/libarchive/archive_read_open_file.c
@@ -154,10 +154,10 @@ file_skip(struct archive *a, void *client_data, int64_t request)
#ifdef __ANDROID__
/* fileno() isn't safe on all platforms ... see above. */
if (lseek(fileno(mine->f), skip, SEEK_CUR) < 0)
-#elif HAVE_FSEEKO
- if (fseeko(mine->f, skip, SEEK_CUR) != 0)
#elif HAVE__FSEEKI64
if (_fseeki64(mine->f, skip, SEEK_CUR) != 0)
+#elif HAVE_FSEEKO
+ if (fseeko(mine->f, skip, SEEK_CUR) != 0)
#else
if (fseek(mine->f, skip, SEEK_CUR) != 0)
#endif
diff --git a/src/libs/3rdparty/libarchive/archive_read_support_filter_bzip2.c b/src/libs/3rdparty/libarchive/archive_read_support_filter_bzip2.c
index 793d605c8..9158e668e 100644
--- a/src/libs/3rdparty/libarchive/archive_read_support_filter_bzip2.c
+++ b/src/libs/3rdparty/libarchive/archive_read_support_filter_bzip2.c
@@ -230,7 +230,7 @@ bzip2_filter_read(struct archive_read_filter *self, const void **p)
/* Empty our output buffer. */
state->stream.next_out = state->out_block;
- state->stream.avail_out = state->out_block_size;
+ state->stream.avail_out = (uint32_t)state->out_block_size;
/* Try to fill the output buffer. */
for (;;) {
@@ -288,7 +288,7 @@ bzip2_filter_read(struct archive_read_filter *self, const void **p)
return (ARCHIVE_FATAL);
}
state->stream.next_in = (char *)(uintptr_t)read_buf;
- state->stream.avail_in = ret;
+ state->stream.avail_in = (uint32_t)ret;
/* There is no more data, return whatever we have. */
if (ret == 0) {
state->eof = 1;
diff --git a/src/libs/3rdparty/libarchive/archive_read_support_filter_lz4.c b/src/libs/3rdparty/libarchive/archive_read_support_filter_lz4.c
index 1e99542d7..d0fc1a83e 100644
--- a/src/libs/3rdparty/libarchive/archive_read_support_filter_lz4.c
+++ b/src/libs/3rdparty/libarchive/archive_read_support_filter_lz4.c
@@ -584,7 +584,7 @@ lz4_filter_read_data_block(struct archive_read_filter *self, const void **p)
state->out_block + prefix64k, (int)compressed_size,
state->flags.block_maximum_size,
state->out_block,
- prefix64k);
+ (int)prefix64k);
#else
uncompressed_size = LZ4_decompress_safe_withPrefix64k(
read_buf + 4,
diff --git a/src/libs/3rdparty/libarchive/archive_read_support_filter_zstd.c b/src/libs/3rdparty/libarchive/archive_read_support_filter_zstd.c
index 39f25f1bf..1959b5ac3 100644
--- a/src/libs/3rdparty/libarchive/archive_read_support_filter_zstd.c
+++ b/src/libs/3rdparty/libarchive/archive_read_support_filter_zstd.c
@@ -115,9 +115,9 @@ zstd_bidder_bid(struct archive_read_filter_bidder *self,
unsigned prefix;
/* Zstd frame magic values */
- const unsigned zstd_magic = 0xFD2FB528U;
- const unsigned zstd_magic_skippable_start = 0x184D2A50U;
- const unsigned zstd_magic_skippable_mask = 0xFFFFFFF0;
+ unsigned zstd_magic = 0xFD2FB528U;
+ unsigned zstd_magic_skippable_start = 0x184D2A50U;
+ unsigned zstd_magic_skippable_mask = 0xFFFFFFF0;
(void) self; /* UNUSED */
@@ -170,7 +170,7 @@ static int
zstd_bidder_init(struct archive_read_filter *self)
{
struct private_data *state;
- const size_t out_block_size = ZSTD_DStreamOutSize();
+ size_t out_block_size = ZSTD_DStreamOutSize();
void *out_block;
ZSTD_DStream *dstream;
@@ -211,6 +211,7 @@ zstd_filter_read(struct archive_read_filter *self, const void **p)
ssize_t avail_in;
ZSTD_outBuffer out;
ZSTD_inBuffer in;
+ size_t ret;
state = (struct private_data *)self->data;
@@ -219,7 +220,7 @@ zstd_filter_read(struct archive_read_filter *self, const void **p)
/* Try to fill the output buffer. */
while (out.pos < out.size && !state->eof) {
if (!state->in_frame) {
- const size_t ret = ZSTD_initDStream(state->dstream);
+ ret = ZSTD_initDStream(state->dstream);
if (ZSTD_isError(ret)) {
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
@@ -249,8 +250,7 @@ zstd_filter_read(struct archive_read_filter *self, const void **p)
in.pos = 0;
{
- const size_t ret =
- ZSTD_decompressStream(state->dstream, &out, &in);
+ ret = ZSTD_decompressStream(state->dstream, &out, &in);
if (ZSTD_isError(ret)) {
archive_set_error(&self->archive->archive,
diff --git a/src/libs/3rdparty/libarchive/archive_read_support_format_7zip.c b/src/libs/3rdparty/libarchive/archive_read_support_format_7zip.c
index 0ba4bee35..b171bea01 100644
--- a/src/libs/3rdparty/libarchive/archive_read_support_format_7zip.c
+++ b/src/libs/3rdparty/libarchive/archive_read_support_format_7zip.c
@@ -41,6 +41,9 @@ __FBSDID("$FreeBSD$");
#ifdef HAVE_ZLIB_H
#include <zlib.h>
#endif
+#ifdef HAVE_ZSTD_H
+#include <zstd.h>
+#endif
#include "archive.h"
#include "archive_entry.h"
@@ -80,8 +83,11 @@ __FBSDID("$FreeBSD$");
#define _7Z_IA64 0x03030401
#define _7Z_ARM 0x03030501
#define _7Z_ARMTHUMB 0x03030701
+#define _7Z_ARM64 0xa
#define _7Z_SPARC 0x03030805
+#define _7Z_ZSTD 0x4F71101 /* Copied from https://github.com/mcmilk/7-Zip-zstd.git */
+
/*
* 7-Zip header property IDs.
*/
@@ -278,6 +284,11 @@ struct _7zip {
z_stream stream;
int stream_valid;
#endif
+ /* Decoding Zstandard data. */
+#if HAVE_ZSTD_H
+ ZSTD_DStream *zstd_dstream;
+ int zstdstream_valid;
+#endif
/* Decoding PPMd data. */
int ppmd7_stat;
CPpmd7 ppmd7_context;
@@ -397,6 +408,9 @@ static int setup_decode_folder(struct archive_read *, struct _7z_folder *,
int);
static void x86_Init(struct _7zip *);
static size_t x86_Convert(struct _7zip *, uint8_t *, size_t);
+static void arm_Init(struct _7zip *);
+static size_t arm_Convert(struct _7zip *, uint8_t *, size_t);
+static size_t arm64_Convert(struct _7zip *, uint8_t *, size_t);
static ssize_t Bcj2_Decode(struct _7zip *, uint8_t *, size_t);
@@ -1027,10 +1041,13 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
case _7Z_COPY:
case _7Z_BZ2:
case _7Z_DEFLATE:
+ case _7Z_ZSTD:
case _7Z_PPMD:
if (coder2 != NULL) {
if (coder2->codec != _7Z_X86 &&
- coder2->codec != _7Z_X86_BCJ2) {
+ coder2->codec != _7Z_X86_BCJ2 &&
+ coder2->codec != _7Z_ARM &&
+ coder2->codec != _7Z_ARM64) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
"Unsupported filter %lx for %lx",
@@ -1041,6 +1058,8 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
zip->bcj_state = 0;
if (coder2->codec == _7Z_X86)
x86_Init(zip);
+ else if (coder2->codec == _7Z_ARM)
+ arm_Init(zip);
}
break;
default:
@@ -1137,6 +1156,12 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
filters[fi].id = LZMA_FILTER_ARMTHUMB;
fi++;
break;
+#ifdef LZMA_FILTER_ARM64
+ case _7Z_ARM64:
+ filters[fi].id = LZMA_FILTER_ARM64;
+ fi++;
+ break;
+#endif
case _7Z_SPARC:
filters[fi].id = LZMA_FILTER_SPARC;
fi++;
@@ -1222,6 +1247,22 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
"BZ2 codec is unsupported");
return (ARCHIVE_FAILED);
#endif
+ case _7Z_ZSTD:
+ {
+#if defined(HAVE_ZSTD_H)
+ if (zip->zstdstream_valid) {
+ ZSTD_freeDStream(zip->zstd_dstream);
+ zip->zstdstream_valid = 0;
+ }
+ zip->zstd_dstream = ZSTD_createDStream();
+ zip->zstdstream_valid = 1;
+ break;
+#else
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "ZSTD codec is unsupported");
+ return (ARCHIVE_FAILED);
+#endif
+ }
case _7Z_DEFLATE:
#ifdef HAVE_ZLIB_H
if (zip->stream_valid)
@@ -1436,9 +1477,9 @@ decompress(struct archive_read *a, struct _7zip *zip,
#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
case _7Z_BZ2:
zip->bzstream.next_in = (char *)(uintptr_t)t_next_in;
- zip->bzstream.avail_in = t_avail_in;
+ zip->bzstream.avail_in = (uint32_t)t_avail_in;
zip->bzstream.next_out = (char *)(uintptr_t)t_next_out;
- zip->bzstream.avail_out = t_avail_out;
+ zip->bzstream.avail_out = (uint32_t)t_avail_out;
r = BZ2_bzDecompress(&(zip->bzstream));
switch (r) {
case BZ_STREAM_END: /* Found end of stream. */
@@ -1488,6 +1529,22 @@ decompress(struct archive_read *a, struct _7zip *zip,
t_avail_out = zip->stream.avail_out;
break;
#endif
+#ifdef HAVE_ZSTD_H
+ case _7Z_ZSTD:
+ {
+ ZSTD_inBuffer input = { t_next_in, t_avail_in, 0 }; // src, size, pos
+ ZSTD_outBuffer output = { t_next_out, t_avail_out, 0 }; // dst, size, pos
+
+ size_t const zret = ZSTD_decompressStream(zip->zstd_dstream, &output, &input);
+ if (ZSTD_isError(zret)) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Zstd decompression failed: %s", ZSTD_getErrorName(zret));
+ return ARCHIVE_FAILED;
+ }
+ t_avail_in -= input.pos;
+ t_avail_out -= output.pos;
+ break;
+ }
+#endif
case _7Z_PPMD:
{
uint64_t flush_bytes;
@@ -1572,16 +1629,23 @@ decompress(struct archive_read *a, struct _7zip *zip,
/*
* Decord BCJ.
*/
- if (zip->codec != _7Z_LZMA2 && zip->codec2 == _7Z_X86) {
- size_t l = x86_Convert(zip, buff, *outbytes);
- zip->odd_bcj_size = *outbytes - l;
- if (zip->odd_bcj_size > 0 && zip->odd_bcj_size <= 4 &&
- o_avail_in && ret != ARCHIVE_EOF) {
- memcpy(zip->odd_bcj, ((unsigned char *)buff) + l,
- zip->odd_bcj_size);
- *outbytes = l;
- } else
- zip->odd_bcj_size = 0;
+ if (zip->codec != _7Z_LZMA2) {
+ if (zip->codec2 == _7Z_X86) {
+ size_t l = x86_Convert(zip, buff, *outbytes);
+
+ zip->odd_bcj_size = *outbytes - l;
+ if (zip->odd_bcj_size > 0 && zip->odd_bcj_size <= 4 &&
+ o_avail_in && ret != ARCHIVE_EOF) {
+ memcpy(zip->odd_bcj, ((unsigned char *)buff) + l,
+ zip->odd_bcj_size);
+ *outbytes = l;
+ } else
+ zip->odd_bcj_size = 0;
+ } else if (zip->codec2 == _7Z_ARM) {
+ *outbytes = arm_Convert(zip, buff, *outbytes);
+ } else if (zip->codec2 == _7Z_ARM64) {
+ *outbytes = arm64_Convert(zip, buff, *outbytes);
+ }
}
/*
@@ -3727,6 +3791,116 @@ x86_Convert(struct _7zip *zip, uint8_t *data, size_t size)
return (bufferPos);
}
+static void
+arm_Init(struct _7zip *zip)
+{
+ zip->bcj_ip = 8;
+}
+
+static size_t
+arm_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
+{
+ // This function was adapted from
+ // static size_t bcj_arm(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+ // in https://git.tukaani.org/xz-embedded.git
+
+ /*
+ * Branch/Call/Jump (BCJ) filter decoders
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <https://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+ size_t i;
+ uint32_t addr;
+
+ for (i = 0; i + 4 <= size; i += 4) {
+ if (buf[i + 3] == 0xEB) {
+ // Calculate the transformed addr.
+ addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8)
+ | ((uint32_t)buf[i + 2] << 16);
+ addr <<= 2;
+ addr -= zip->bcj_ip + (uint32_t)i;
+ addr >>= 2;
+
+ // Store the transformed addr in buf.
+ buf[i] = (uint8_t)addr;
+ buf[i + 1] = (uint8_t)(addr >> 8);
+ buf[i + 2] = (uint8_t)(addr >> 16);
+ }
+ }
+
+ zip->bcj_ip += (uint32_t)i;
+
+ return i;
+}
+
+static size_t
+arm64_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
+{
+ // This function was adapted from
+ // static size_t bcj_arm64(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+ // in https://git.tukaani.org/xz-embedded.git
+
+ /*
+ * Branch/Call/Jump (BCJ) filter decoders
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <https://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+ size_t i;
+ uint32_t instr;
+ uint32_t addr;
+
+ for (i = 0; i + 4 <= size; i += 4) {
+ instr = (uint32_t)buf[i]
+ | ((uint32_t)buf[i+1] << 8)
+ | ((uint32_t)buf[i+2] << 16)
+ | ((uint32_t)buf[i+3] << 24);
+
+ if ((instr >> 26) == 0x25) {
+ /* BL instruction */
+ addr = instr - ((zip->bcj_ip + (uint32_t)i) >> 2);
+ instr = 0x94000000 | (addr & 0x03FFFFFF);
+
+ buf[i] = (uint8_t)instr;
+ buf[i+1] = (uint8_t)(instr >> 8);
+ buf[i+2] = (uint8_t)(instr >> 16);
+ buf[i+3] = (uint8_t)(instr >> 24);
+ } else if ((instr & 0x9F000000) == 0x90000000) {
+ /* ADRP instruction */
+ addr = ((instr >> 29) & 3) | ((instr >> 3) & 0x1FFFFC);
+
+ /* Only convert values in the range +/-512 MiB. */
+ if ((addr + 0x020000) & 0x1C0000)
+ continue;
+
+ addr -= (zip->bcj_ip + (uint32_t)i) >> 12;
+
+ instr &= 0x9000001F;
+ instr |= (addr & 3) << 29;
+ instr |= (addr & 0x03FFFC) << 3;
+ instr |= (0U - (addr & 0x020000)) & 0xE00000;
+
+ buf[i] = (uint8_t)instr;
+ buf[i+1] = (uint8_t)(instr >> 8);
+ buf[i+2] = (uint8_t)(instr >> 16);
+ buf[i+3] = (uint8_t)(instr >> 24);
+ }
+ }
+
+ zip->bcj_ip += (uint32_t)i;
+
+ return i;
+}
+
/*
* Brought from LZMA SDK.
*
diff --git a/src/libs/3rdparty/libarchive/archive_read_support_format_cab.c b/src/libs/3rdparty/libarchive/archive_read_support_format_cab.c
index 4d5029b1b..3b552a84d 100644
--- a/src/libs/3rdparty/libarchive/archive_read_support_format_cab.c
+++ b/src/libs/3rdparty/libarchive/archive_read_support_format_cab.c
@@ -2294,10 +2294,10 @@ lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
(br->cache_buffer << 48) |
((uint64_t)strm->next_in[1]) << 40 |
((uint64_t)strm->next_in[0]) << 32 |
- ((uint32_t)strm->next_in[3]) << 24 |
- ((uint32_t)strm->next_in[2]) << 16 |
- ((uint32_t)strm->next_in[5]) << 8 |
- (uint32_t)strm->next_in[4];
+ ((uint64_t)strm->next_in[3]) << 24 |
+ ((uint64_t)strm->next_in[2]) << 16 |
+ ((uint64_t)strm->next_in[5]) << 8 |
+ (uint64_t)strm->next_in[4];
strm->next_in += 6;
strm->avail_in -= 6;
br->cache_avail += 6 * 8;
diff --git a/src/libs/3rdparty/libarchive/archive_read_support_format_cpio.c b/src/libs/3rdparty/libarchive/archive_read_support_format_cpio.c
index 6b8ae33a4..9adcfd335 100644
--- a/src/libs/3rdparty/libarchive/archive_read_support_format_cpio.c
+++ b/src/libs/3rdparty/libarchive/archive_read_support_format_cpio.c
@@ -441,7 +441,7 @@ archive_read_format_cpio_read_header(struct archive_read *a,
/* Compare name to "TRAILER!!!" to test for end-of-archive. */
if (namelength == 11 && strncmp((const char *)h, "TRAILER!!!",
- 11) == 0) {
+ 10) == 0) {
/* TODO: Store file location of start of block. */
archive_clear_error(&a->archive);
return (ARCHIVE_EOF);
@@ -985,14 +985,14 @@ archive_read_format_cpio_cleanup(struct archive_read *a)
static int64_t
le4(const unsigned char *p)
{
- return ((p[0] << 16) + (((int64_t)p[1]) << 24) + (p[2] << 0) + (p[3] << 8));
+ return ((p[0] << 16) | (((int64_t)p[1]) << 24) | (p[2] << 0) | (p[3] << 8));
}
static int64_t
be4(const unsigned char *p)
{
- return ((((int64_t)p[0]) << 24) + (p[1] << 16) + (p[2] << 8) + (p[3]));
+ return ((((int64_t)p[0]) << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]));
}
/*
diff --git a/src/libs/3rdparty/libarchive/archive_read_support_format_iso9660.c b/src/libs/3rdparty/libarchive/archive_read_support_format_iso9660.c
index 33bf330cb..f5414be2a 100644
--- a/src/libs/3rdparty/libarchive/archive_read_support_format_iso9660.c
+++ b/src/libs/3rdparty/libarchive/archive_read_support_format_iso9660.c
@@ -1901,7 +1901,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
* NUMBER of RRIP "PX" extension.
* Note: Old mkisofs did not record that FILE SERIAL NUMBER
* in ISO images.
- * Note2: xorriso set 0 to the location of a symlink file.
+ * Note2: xorriso set 0 to the location of a symlink file.
*/
if (file->size == 0 && location >= 0) {
/* If file->size is zero, its location points wrong place,
@@ -1955,7 +1955,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
* made by makefs is not zero and its location is
* the same as those of next regular file. That is
* the same as hard like file and it causes unexpected
- * error.
+ * error.
*/
if (file->size > 0 &&
(file->mode & AE_IFMT) == AE_IFLNK) {
@@ -2747,7 +2747,7 @@ next_cache_entry(struct archive_read *a, struct iso9660 *iso9660,
* If directory entries all which are descendant of
* rr_moved are still remaining, expose their.
*/
- if (iso9660->re_files.first != NULL &&
+ if (iso9660->re_files.first != NULL &&
iso9660->rr_moved != NULL &&
iso9660->rr_moved->rr_moved_has_re_only)
/* Expose "rr_moved" entry. */
@@ -3180,11 +3180,11 @@ isodate17(const unsigned char *v)
static time_t
time_from_tm(struct tm *t)
{
-#if HAVE_TIMEGM
+#if HAVE__MKGMTIME
+ return _mkgmtime(t);
+#elif HAVE_TIMEGM
/* Use platform timegm() if available. */
return (timegm(t));
-#elif HAVE__MKGMTIME64
- return (_mkgmtime64(t));
#else
/* Else use direct calculation using POSIX assumptions. */
/* First, fix up tm_yday based on the year/month/day. */
diff --git a/src/libs/3rdparty/libarchive/archive_read_support_format_lha.c b/src/libs/3rdparty/libarchive/archive_read_support_format_lha.c
index bcfd42e1d..1c64b2900 100644
--- a/src/libs/3rdparty/libarchive/archive_read_support_format_lha.c
+++ b/src/libs/3rdparty/libarchive/archive_read_support_format_lha.c
@@ -1818,13 +1818,16 @@ lha_crc16(uint16_t crc, const void *pp, size_t len)
/* This if statement expects compiler optimization will
* remove the statement which will not be executed. */
#undef bswap16
+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#endif
#if defined(_MSC_VER) && _MSC_VER >= 1400 /* Visual Studio */
# define bswap16(x) _byteswap_ushort(x)
#elif defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || __GNUC__ > 4)
/* GCC 4.8 and later has __builtin_bswap16() */
# define bswap16(x) __builtin_bswap16(x)
-#elif defined(__clang__)
-/* All clang versions have __builtin_bswap16() */
+#elif defined(__clang__) && __has_builtin(__builtin_bswap16)
+/* Newer clang versions have __builtin_bswap16() */
# define bswap16(x) __builtin_bswap16(x)
#else
# define bswap16(x) ((((x) >> 8) & 0xff) | ((x) << 8))
@@ -2009,10 +2012,10 @@ lzh_br_fillup(struct lzh_stream *strm, struct lzh_br *br)
((uint64_t)strm->next_in[0]) << 48 |
((uint64_t)strm->next_in[1]) << 40 |
((uint64_t)strm->next_in[2]) << 32 |
- ((uint32_t)strm->next_in[3]) << 24 |
- ((uint32_t)strm->next_in[4]) << 16 |
- ((uint32_t)strm->next_in[5]) << 8 |
- (uint32_t)strm->next_in[6];
+ ((uint64_t)strm->next_in[3]) << 24 |
+ ((uint64_t)strm->next_in[4]) << 16 |
+ ((uint64_t)strm->next_in[5]) << 8 |
+ (uint64_t)strm->next_in[6];
strm->next_in += 7;
strm->avail_in -= 7;
br->cache_avail += 7 * 8;
@@ -2022,10 +2025,10 @@ lzh_br_fillup(struct lzh_stream *strm, struct lzh_br *br)
(br->cache_buffer << 48) |
((uint64_t)strm->next_in[0]) << 40 |
((uint64_t)strm->next_in[1]) << 32 |
- ((uint32_t)strm->next_in[2]) << 24 |
- ((uint32_t)strm->next_in[3]) << 16 |
- ((uint32_t)strm->next_in[4]) << 8 |
- (uint32_t)strm->next_in[5];
+ ((uint64_t)strm->next_in[2]) << 24 |
+ ((uint64_t)strm->next_in[3]) << 16 |
+ ((uint64_t)strm->next_in[4]) << 8 |
+ (uint64_t)strm->next_in[5];
strm->next_in += 6;
strm->avail_in -= 6;
br->cache_avail += 6 * 8;
diff --git a/src/libs/3rdparty/libarchive/archive_read_support_format_mtree.c b/src/libs/3rdparty/libarchive/archive_read_support_format_mtree.c
index 2bc3ba066..a5fa30e3c 100644
--- a/src/libs/3rdparty/libarchive/archive_read_support_format_mtree.c
+++ b/src/libs/3rdparty/libarchive/archive_read_support_format_mtree.c
@@ -1280,7 +1280,13 @@ parse_file(struct archive_read *a, struct archive_entry *entry,
mtree->fd = -1;
st = NULL;
}
- } else if (lstat(path, st) == -1) {
+ }
+#ifdef HAVE_LSTAT
+ else if (lstat(path, st) == -1)
+#else
+ else if (la_stat(path, st) == -1)
+#endif
+ {
st = NULL;
}
diff --git a/src/libs/3rdparty/libarchive/archive_read_support_format_rar.c b/src/libs/3rdparty/libarchive/archive_read_support_format_rar.c
index 793e8e985..16b6e6eed 100644
--- a/src/libs/3rdparty/libarchive/archive_read_support_format_rar.c
+++ b/src/libs/3rdparty/libarchive/archive_read_support_format_rar.c
@@ -1062,7 +1062,7 @@ archive_read_format_rar_read_header(struct archive_read *a,
return (ARCHIVE_FATAL);
}
p = h;
- crc32_val = crc32(crc32_val, (const unsigned char *)p, to_read);
+ crc32_val = crc32(crc32_val, (const unsigned char *)p, (unsigned int)to_read);
__archive_read_consume(a, to_read);
skip -= to_read;
}
@@ -1830,13 +1830,9 @@ read_exttime(const char *p, struct rar *rar, const char *endp)
struct tm *tm;
time_t t;
long nsec;
-#if defined(HAVE_LOCALTIME_R) || defined(HAVE__LOCALTIME64_S)
+#if defined(HAVE_LOCALTIME_R) || defined(HAVE_LOCALTIME_S)
struct tm tmbuf;
#endif
-#if defined(HAVE__LOCALTIME64_S)
- errno_t terr;
- __time64_t tmptime;
-#endif
if (p + 2 > endp)
return (-1);
@@ -1868,15 +1864,10 @@ read_exttime(const char *p, struct rar *rar, const char *endp)
rem = (((unsigned)(unsigned char)*p) << 16) | (rem >> 8);
p++;
}
-#if defined(HAVE_LOCALTIME_R)
+#if defined(HAVE_LOCALTIME_S)
+ tm = localtime_s(&tmbuf, &t) ? NULL : &tmbuf;
+#elif defined(HAVE_LOCALTIME_R)
tm = localtime_r(&t, &tmbuf);
-#elif defined(HAVE__LOCALTIME64_S)
- tmptime = t;
- terr = _localtime64_s(&tmbuf, &tmptime);
- if (terr)
- tm = NULL;
- else
- tm = &tmbuf;
#else
tm = localtime(&t);
#endif
@@ -3446,7 +3437,7 @@ compile_program(const uint8_t *bytes, size_t length)
prog = calloc(1, sizeof(*prog));
if (!prog)
return NULL;
- prog->fingerprint = crc32(0, bytes, length) | ((uint64_t)length << 32);
+ prog->fingerprint = crc32(0, bytes, (unsigned int)length) | ((uint64_t)length << 32);
if (membr_bits(&br, 1))
{
diff --git a/src/libs/3rdparty/libarchive/archive_read_support_format_rar5.c b/src/libs/3rdparty/libarchive/archive_read_support_format_rar5.c
index 38979cbe9..1f9099439 100644
--- a/src/libs/3rdparty/libarchive/archive_read_support_format_rar5.c
+++ b/src/libs/3rdparty/libarchive/archive_read_support_format_rar5.c
@@ -2475,7 +2475,7 @@ static void update_crc(struct rar5* rar, const uint8_t* p, size_t to_read) {
* `stored_crc32` info filled in. */
if(rar->file.stored_crc32 > 0) {
rar->file.calculated_crc32 =
- crc32(rar->file.calculated_crc32, p, to_read);
+ crc32(rar->file.calculated_crc32, p, (unsigned int)to_read);
}
/* Check if the file uses an optional BLAKE2sp checksum
diff --git a/src/libs/3rdparty/libarchive/archive_read_support_format_warc.c b/src/libs/3rdparty/libarchive/archive_read_support_format_warc.c
index 27329962d..61ab29ea1 100644
--- a/src/libs/3rdparty/libarchive/archive_read_support_format_warc.c
+++ b/src/libs/3rdparty/libarchive/archive_read_support_format_warc.c
@@ -530,11 +530,11 @@ strtoi_lim(const char *str, const char **ep, int llim, int ulim)
static time_t
time_from_tm(struct tm *t)
{
-#if HAVE_TIMEGM
+#if HAVE__MKGMTIME
+ return _mkgmtime(t);
+#elif HAVE_TIMEGM
/* Use platform timegm() if available. */
return (timegm(t));
-#elif HAVE__MKGMTIME64
- return (_mkgmtime64(t));
#else
/* Else use direct calculation using POSIX assumptions. */
/* First, fix up tm_yday based on the year/month/day. */
diff --git a/src/libs/3rdparty/libarchive/archive_read_support_format_xar.c b/src/libs/3rdparty/libarchive/archive_read_support_format_xar.c
index ec5b06eda..ec9cb1981 100644
--- a/src/libs/3rdparty/libarchive/archive_read_support_format_xar.c
+++ b/src/libs/3rdparty/libarchive/archive_read_support_format_xar.c
@@ -1127,7 +1127,7 @@ atohex(unsigned char *b, size_t bsize, const char *p, size_t psize)
x |= p[1] - '0';
else
return (-1);
-
+
*b++ = x;
bsize--;
p += 2;
@@ -1139,11 +1139,11 @@ atohex(unsigned char *b, size_t bsize, const char *p, size_t psize)
static time_t
time_from_tm(struct tm *t)
{
-#if HAVE_TIMEGM
+#if HAVE__MKGMTIME
+ return _mkgmtime(t);
+#elif HAVE_TIMEGM
/* Use platform timegm() if available. */
return (timegm(t));
-#elif HAVE__MKGMTIME64
- return (_mkgmtime64(t));
#else
/* Else use direct calculation using POSIX assumptions. */
/* First, fix up tm_yday based on the year/month/day. */
diff --git a/src/libs/3rdparty/libarchive/archive_read_support_format_zip.c b/src/libs/3rdparty/libarchive/archive_read_support_format_zip.c
index 9d6c900b2..c3b9b5755 100644
--- a/src/libs/3rdparty/libarchive/archive_read_support_format_zip.c
+++ b/src/libs/3rdparty/libarchive/archive_read_support_format_zip.c
@@ -2186,11 +2186,11 @@ zip_read_data_zipx_bzip2(struct archive_read *a, const void **buff,
/* Setup buffer boundaries. */
zip->bzstream.next_in = (char*)(uintptr_t) compressed_buff;
- zip->bzstream.avail_in = in_bytes;
+ zip->bzstream.avail_in = (uint32_t)in_bytes;
zip->bzstream.total_in_hi32 = 0;
zip->bzstream.total_in_lo32 = 0;
zip->bzstream.next_out = (char*) zip->uncompressed_buffer;
- zip->bzstream.avail_out = zip->uncompressed_buffer_size;
+ zip->bzstream.avail_out = (uint32_t)zip->uncompressed_buffer_size;
zip->bzstream.total_out_hi32 = 0;
zip->bzstream.total_out_lo32 = 0;
@@ -2227,7 +2227,7 @@ zip_read_data_zipx_bzip2(struct archive_read *a, const void **buff,
to_consume = zip->bzstream.total_in_lo32;
__archive_read_consume(a, to_consume);
- total_out = ((uint64_t) zip->bzstream.total_out_hi32 << 32) +
+ total_out = ((uint64_t) zip->bzstream.total_out_hi32 << 32) |
zip->bzstream.total_out_lo32;
zip->entry_bytes_remaining -= to_consume;
diff --git a/src/libs/3rdparty/libarchive/archive_string.c b/src/libs/3rdparty/libarchive/archive_string.c
index 69458e1a1..accf52631 100644
--- a/src/libs/3rdparty/libarchive/archive_string.c
+++ b/src/libs/3rdparty/libarchive/archive_string.c
@@ -1324,6 +1324,10 @@ free_sconv_object(struct archive_string_conv *sc)
}
#if defined(_WIN32) && !defined(__CYGWIN__)
+# if defined(WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+# define GetOEMCP() CP_OEMCP
+# endif
+
static unsigned
my_atoi(const char *p)
{
diff --git a/src/libs/3rdparty/libarchive/archive_util.c b/src/libs/3rdparty/libarchive/archive_util.c
index b1582edbe..40603c483 100644
--- a/src/libs/3rdparty/libarchive/archive_util.c
+++ b/src/libs/3rdparty/libarchive/archive_util.c
@@ -42,9 +42,20 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:1
#ifdef HAVE_STRING_H
#include <string.h>
#endif
-#if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__)
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
+/* don't use bcrypt when XP needs to be supported */
+#include <bcrypt.h>
+
+/* Common in other bcrypt implementations, but missing from VS2008. */
+#ifndef BCRYPT_SUCCESS
+#define BCRYPT_SUCCESS(r) ((NTSTATUS)(r) == STATUS_SUCCESS)
+#endif
+
+#elif defined(HAVE_WINCRYPT_H)
#include <wincrypt.h>
#endif
+#endif
#ifdef HAVE_ZLIB_H
#include <zlib.h>
#endif
@@ -233,14 +244,16 @@ __archive_mktempx(const char *tmpdir, wchar_t *template)
L'm', L'n', L'o', L'p', L'q', L'r', L's', L't',
L'u', L'v', L'w', L'x', L'y', L'z'
};
- HCRYPTPROV hProv;
struct archive_wstring temp_name;
wchar_t *ws;
DWORD attr;
wchar_t *xp, *ep;
int fd;
-
- hProv = (HCRYPTPROV)NULL;
+#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
+ BCRYPT_ALG_HANDLE hAlg = NULL;
+#else
+ HCRYPTPROV hProv = (HCRYPTPROV)NULL;
+#endif
fd = -1;
ws = NULL;
@@ -314,23 +327,42 @@ __archive_mktempx(const char *tmpdir, wchar_t *template)
abort();
}
+#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
+ if (!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM,
+ NULL, 0))) {
+ la_dosmaperr(GetLastError());
+ goto exit_tmpfile;
+ }
+#else
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT)) {
la_dosmaperr(GetLastError());
goto exit_tmpfile;
}
+#endif
for (;;) {
wchar_t *p;
HANDLE h;
+# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
+ CREATEFILE2_EXTENDED_PARAMETERS createExParams;
+#endif
/* Generate a random file name through CryptGenRandom(). */
p = xp;
+#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
+ if (!BCRYPT_SUCCESS(BCryptGenRandom(hAlg, (PUCHAR)p,
+ (DWORD)(ep - p)*sizeof(wchar_t), 0))) {
+ la_dosmaperr(GetLastError());
+ goto exit_tmpfile;
+ }
+#else
if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t),
(BYTE*)p)) {
la_dosmaperr(GetLastError());
goto exit_tmpfile;
}
+#endif
for (; p < ep; p++)
*p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];
@@ -347,6 +379,17 @@ __archive_mktempx(const char *tmpdir, wchar_t *template)
/* mkstemp */
attr = FILE_ATTRIBUTE_NORMAL;
}
+# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
+ ZeroMemory(&createExParams, sizeof(createExParams));
+ createExParams.dwSize = sizeof(createExParams);
+ createExParams.dwFileAttributes = attr & 0xFFFF;
+ createExParams.dwFileFlags = attr & 0xFFF00000;
+ h = CreateFile2(ws,
+ GENERIC_READ | GENERIC_WRITE | DELETE,
+ 0,/* Not share */
+ CREATE_NEW,
+ &createExParams);
+#else
h = CreateFileW(ws,
GENERIC_READ | GENERIC_WRITE | DELETE,
0,/* Not share */
@@ -354,6 +397,7 @@ __archive_mktempx(const char *tmpdir, wchar_t *template)
CREATE_NEW,/* Create a new file only */
attr,
NULL);
+#endif
if (h == INVALID_HANDLE_VALUE) {
/* The same file already exists. retry with
* a new filename. */
@@ -372,8 +416,13 @@ __archive_mktempx(const char *tmpdir, wchar_t *template)
break;/* success! */
}
exit_tmpfile:
+#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
+ if (hAlg != NULL)
+ BCryptCloseAlgorithmProvider(hAlg, 0);
+#else
if (hProv != (HCRYPTPROV)NULL)
CryptReleaseContext(hProv, 0);
+#endif
free(ws);
if (template == temp_name.s)
archive_wstring_free(&temp_name);
diff --git a/src/libs/3rdparty/libarchive/archive_windows.c b/src/libs/3rdparty/libarchive/archive_windows.c
index 624e27009..ebc5eefb8 100644
--- a/src/libs/3rdparty/libarchive/archive_windows.c
+++ b/src/libs/3rdparty/libarchive/archive_windows.c
@@ -234,7 +234,11 @@ la_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode,
{
wchar_t *wpath;
HANDLE handle;
+# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
+ CREATEFILE2_EXTENDED_PARAMETERS createExParams;
+#endif
+#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)
handle = CreateFileA(path, dwDesiredAccess, dwShareMode,
lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
hTemplateFile);
@@ -242,12 +246,25 @@ la_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode,
return (handle);
if (GetLastError() != ERROR_PATH_NOT_FOUND)
return (handle);
+#endif
wpath = __la_win_permissive_name(path);
if (wpath == NULL)
- return (handle);
+ return INVALID_HANDLE_VALUE;
+# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
+ ZeroMemory(&createExParams, sizeof(createExParams));
+ createExParams.dwSize = sizeof(createExParams);
+ createExParams.dwFileAttributes = dwFlagsAndAttributes & 0xFFFF;
+ createExParams.dwFileFlags = dwFlagsAndAttributes & 0xFFF00000;
+ createExParams.dwSecurityQosFlags = dwFlagsAndAttributes & 0x000F00000;
+ createExParams.lpSecurityAttributes = lpSecurityAttributes;
+ createExParams.hTemplateFile = hTemplateFile;
+ handle = CreateFile2(wpath, dwDesiredAccess, dwShareMode,
+ dwCreationDisposition, &createExParams);
+#else /* !WINAPI_PARTITION_DESKTOP */
handle = CreateFileW(wpath, dwDesiredAccess, dwShareMode,
lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
hTemplateFile);
+#endif /* !WINAPI_PARTITION_DESKTOP */
free(wpath);
return (handle);
}
@@ -305,7 +322,10 @@ __la_open(const char *path, int flags, ...)
* "Permission denied" error.
*/
attr = GetFileAttributesA(path);
- if (attr == (DWORD)-1 && GetLastError() == ERROR_PATH_NOT_FOUND) {
+#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)
+ if (attr == (DWORD)-1 && GetLastError() == ERROR_PATH_NOT_FOUND)
+#endif
+ {
ws = __la_win_permissive_name(path);
if (ws == NULL) {
errno = EINVAL;
@@ -320,7 +340,7 @@ __la_open(const char *path, int flags, ...)
}
if (attr & FILE_ATTRIBUTE_DIRECTORY) {
HANDLE handle;
-
+#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)
if (ws != NULL)
handle = CreateFileW(ws, 0, 0, NULL,
OPEN_EXISTING,
@@ -333,6 +353,15 @@ __la_open(const char *path, int flags, ...)
FILE_FLAG_BACKUP_SEMANTICS |
FILE_ATTRIBUTE_READONLY,
NULL);
+#else /* !WINAPI_PARTITION_DESKTOP */
+ CREATEFILE2_EXTENDED_PARAMETERS createExParams;
+ ZeroMemory(&createExParams, sizeof(createExParams));
+ createExParams.dwSize = sizeof(createExParams);
+ createExParams.dwFileAttributes = FILE_ATTRIBUTE_READONLY;
+ createExParams.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS;
+ handle = CreateFile2(ws, 0, 0,
+ OPEN_EXISTING, &createExParams);
+#endif /* !WINAPI_PARTITION_DESKTOP */
free(ws);
if (handle == INVALID_HANDLE_VALUE) {
la_dosmaperr(GetLastError());
diff --git a/src/libs/3rdparty/libarchive/archive_write.c b/src/libs/3rdparty/libarchive/archive_write.c
index 27626b541..ec3c95c56 100644
--- a/src/libs/3rdparty/libarchive/archive_write.c
+++ b/src/libs/3rdparty/libarchive/archive_write.c
@@ -310,6 +310,25 @@ __archive_write_output(struct archive_write *a, const void *buff, size_t length)
return (__archive_write_filter(a->filter_first, buff, length));
}
+static int
+__archive_write_filters_flush(struct archive_write *a)
+{
+ struct archive_write_filter *f;
+ int ret, ret1;
+
+ ret = ARCHIVE_OK;
+ for (f = a->filter_first; f != NULL; f = f->next_filter) {
+ if (f->flush != NULL && f->bytes_written > 0) {
+ ret1 = (f->flush)(f);
+ if (ret1 < ret)
+ ret = ret1;
+ if (ret1 < ARCHIVE_WARN)
+ f->state = ARCHIVE_WRITE_FILTER_STATE_FATAL;
+ }
+ }
+ return (ret);
+}
+
int
__archive_write_nulls(struct archive_write *a, size_t length)
{
@@ -740,6 +759,18 @@ _archive_write_header(struct archive *_a, struct archive_entry *entry)
return (ARCHIVE_FAILED);
}
+ /* Flush filters at boundary. */
+ r2 = __archive_write_filters_flush(a);
+ if (r2 == ARCHIVE_FAILED) {
+ return (ARCHIVE_FAILED);
+ }
+ if (r2 == ARCHIVE_FATAL) {
+ a->archive.state = ARCHIVE_STATE_FATAL;
+ return (ARCHIVE_FATAL);
+ }
+ if (r2 < ret)
+ ret = r2;
+
/* Format and write header. */
r2 = ((a->format_write_header)(a, entry));
if (r2 == ARCHIVE_FAILED) {
diff --git a/src/libs/3rdparty/libarchive/archive_write_add_filter_bzip2.c b/src/libs/3rdparty/libarchive/archive_write_add_filter_bzip2.c
index 7001e9c6b..3e5c0891a 100644
--- a/src/libs/3rdparty/libarchive/archive_write_add_filter_bzip2.c
+++ b/src/libs/3rdparty/libarchive/archive_write_add_filter_bzip2.c
@@ -190,7 +190,7 @@ archive_compressor_bzip2_open(struct archive_write_filter *f)
memset(&data->stream, 0, sizeof(data->stream));
data->stream.next_out = data->compressed;
- data->stream.avail_out = data->compressed_buffer_size;
+ data->stream.avail_out = (uint32_t)data->compressed_buffer_size;
f->write = archive_compressor_bzip2_write;
/* Initialize compression library */
@@ -244,7 +244,7 @@ archive_compressor_bzip2_write(struct archive_write_filter *f,
/* Compress input data to output buffer */
SET_NEXT_IN(data, buff);
- data->stream.avail_in = length;
+ data->stream.avail_in = (uint32_t)length;
if (drive_compressor(f, data, 0))
return (ARCHIVE_FATAL);
return (ARCHIVE_OK);
@@ -313,7 +313,7 @@ drive_compressor(struct archive_write_filter *f,
return (ARCHIVE_FATAL);
}
data->stream.next_out = data->compressed;
- data->stream.avail_out = data->compressed_buffer_size;
+ data->stream.avail_out = (uint32_t)data->compressed_buffer_size;
}
/* If there's nothing to do, we're done. */
diff --git a/src/libs/3rdparty/libarchive/archive_write_add_filter_compress.c b/src/libs/3rdparty/libarchive/archive_write_add_filter_compress.c
index d404fae7d..3ed269fce 100644
--- a/src/libs/3rdparty/libarchive/archive_write_add_filter_compress.c
+++ b/src/libs/3rdparty/libarchive/archive_write_add_filter_compress.c
@@ -352,7 +352,7 @@ archive_compressor_compress_write(struct archive_write_filter *f,
while (length--) {
c = *bp++;
state->in_count++;
- state->cur_fcode = (c << 16) + state->cur_code;
+ state->cur_fcode = (c << 16) | state->cur_code;
i = ((c << HSHIFT) ^ state->cur_code); /* Xor hashing. */
if (state->hashtab[i] == state->cur_fcode) {
diff --git a/src/libs/3rdparty/libarchive/archive_write_add_filter_lz4.c b/src/libs/3rdparty/libarchive/archive_write_add_filter_lz4.c
index cf19fadd5..6ac450357 100644
--- a/src/libs/3rdparty/libarchive/archive_write_add_filter_lz4.c
+++ b/src/libs/3rdparty/libarchive/archive_write_add_filter_lz4.c
@@ -518,10 +518,10 @@ drive_compressor_independence(struct archive_write_filter *f, const char *p,
} else {
/* The buffer is not compressed. The compressed size was
* bigger than its uncompressed size. */
- archive_le32enc(data->out, length | 0x80000000);
+ archive_le32enc(data->out, (uint32_t)(length | 0x80000000));
data->out += 4;
memcpy(data->out, p, length);
- outsize = length;
+ outsize = (uint32_t)length;
}
data->out += outsize;
if (data->block_checksum) {
@@ -603,10 +603,10 @@ drive_compressor_dependence(struct archive_write_filter *f, const char *p,
} else {
/* The buffer is not compressed. The compressed size was
* bigger than its uncompressed size. */
- archive_le32enc(data->out, length | 0x80000000);
+ archive_le32enc(data->out, (uint32_t)(length | 0x80000000));
data->out += 4;
memcpy(data->out, p, length);
- outsize = length;
+ outsize = (uint32_t)length;
}
data->out += outsize;
if (data->block_checksum) {
diff --git a/src/libs/3rdparty/libarchive/archive_write_add_filter_zstd.c b/src/libs/3rdparty/libarchive/archive_write_add_filter_zstd.c
index e85b7669c..584cfb668 100644
--- a/src/libs/3rdparty/libarchive/archive_write_add_filter_zstd.c
+++ b/src/libs/3rdparty/libarchive/archive_write_add_filter_zstd.c
@@ -31,6 +31,9 @@ __FBSDID("$FreeBSD$");
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
@@ -50,10 +53,21 @@ __FBSDID("$FreeBSD$");
struct private_data {
int compression_level;
- int threads;
+ int threads;
#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR
+ enum {
+ running,
+ finishing,
+ resetting,
+ } state;
+ int frame_per_file;
+ size_t min_frame_size;
+ size_t max_frame_size;
+ size_t cur_frame;
+ size_t cur_frame_in;
+ size_t cur_frame_out;
+ size_t total_in;
ZSTD_CStream *cstream;
- int64_t total_in;
ZSTD_outBuffer out;
#else
struct archive_write_program_data *pdata;
@@ -75,6 +89,7 @@ static int archive_compressor_zstd_options(struct archive_write_filter *,
static int archive_compressor_zstd_open(struct archive_write_filter *);
static int archive_compressor_zstd_write(struct archive_write_filter *,
const void *, size_t);
+static int archive_compressor_zstd_flush(struct archive_write_filter *);
static int archive_compressor_zstd_close(struct archive_write_filter *);
static int archive_compressor_zstd_free(struct archive_write_filter *);
#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR
@@ -103,6 +118,7 @@ archive_write_add_filter_zstd(struct archive *_a)
f->data = data;
f->open = &archive_compressor_zstd_open;
f->options = &archive_compressor_zstd_options;
+ f->flush = &archive_compressor_zstd_flush;
f->close = &archive_compressor_zstd_close;
f->free = &archive_compressor_zstd_free;
f->code = ARCHIVE_FILTER_ZSTD;
@@ -110,6 +126,11 @@ archive_write_add_filter_zstd(struct archive *_a)
data->compression_level = CLEVEL_DEFAULT;
data->threads = 0;
#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR
+ data->frame_per_file = 0;
+ data->min_frame_size = 0;
+ data->max_frame_size = SIZE_MAX;
+ data->cur_frame_in = 0;
+ data->cur_frame_out = 0;
data->cstream = ZSTD_createCStream();
if (data->cstream == NULL) {
free(data);
@@ -147,29 +168,18 @@ archive_compressor_zstd_free(struct archive_write_filter *f)
return (ARCHIVE_OK);
}
-static int string_is_numeric (const char* value)
+static int string_to_number(const char *string, intmax_t *numberp)
{
- size_t len = strlen(value);
- size_t i;
-
- if (len == 0) {
- return (ARCHIVE_WARN);
- }
- else if (len == 1 && !(value[0] >= '0' && value[0] <= '9')) {
- return (ARCHIVE_WARN);
- }
- else if (!(value[0] >= '0' && value[0] <= '9') &&
- value[0] != '-' && value[0] != '+') {
- return (ARCHIVE_WARN);
- }
-
- for (i = 1; i < len; i++) {
- if (!(value[i] >= '0' && value[i] <= '9')) {
- return (ARCHIVE_WARN);
- }
- }
-
- return (ARCHIVE_OK);
+ char *end;
+
+ if (string == NULL || *string == '\0')
+ return (ARCHIVE_WARN);
+ *numberp = strtoimax(string, &end, 10);
+ if (end == string || *end != '\0' || errno == EOVERFLOW) {
+ *numberp = 0;
+ return (ARCHIVE_WARN);
+ }
+ return (ARCHIVE_OK);
}
/*
@@ -182,13 +192,13 @@ archive_compressor_zstd_options(struct archive_write_filter *f, const char *key,
struct private_data *data = (struct private_data *)f->data;
if (strcmp(key, "compression-level") == 0) {
- int level = atoi(value);
+ intmax_t level;
+ if (string_to_number(value, &level) != ARCHIVE_OK) {
+ return (ARCHIVE_WARN);
+ }
/* If we don't have the library, hard-code the max level */
int minimum = CLEVEL_MIN;
int maximum = CLEVEL_MAX;
- if (string_is_numeric(value) != ARCHIVE_OK) {
- return (ARCHIVE_WARN);
- }
#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR
maximum = ZSTD_maxCLevel();
#if ZSTD_VERSION_NUMBER >= MINVER_MINCLEVEL
@@ -204,22 +214,43 @@ archive_compressor_zstd_options(struct archive_write_filter *f, const char *key,
if (level < minimum || level > maximum) {
return (ARCHIVE_WARN);
}
- data->compression_level = level;
+ data->compression_level = (int)level;
return (ARCHIVE_OK);
} else if (strcmp(key, "threads") == 0) {
- int threads = atoi(value);
- if (string_is_numeric(value) != ARCHIVE_OK) {
+ intmax_t threads;
+ if (string_to_number(value, &threads) != ARCHIVE_OK) {
return (ARCHIVE_WARN);
}
-
- int minimum = 0;
-
- if (threads < minimum) {
+ if (threads < 0) {
return (ARCHIVE_WARN);
}
-
- data->threads = threads;
+ data->threads = (int)threads;
+ return (ARCHIVE_OK);
+#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR
+ } else if (strcmp(key, "frame-per-file") == 0) {
+ data->frame_per_file = 1;
+ return (ARCHIVE_OK);
+ } else if (strcmp(key, "min-frame-size") == 0) {
+ intmax_t min_frame_size;
+ if (string_to_number(value, &min_frame_size) != ARCHIVE_OK) {
+ return (ARCHIVE_WARN);
+ }
+ if (min_frame_size < 0) {
+ return (ARCHIVE_WARN);
+ }
+ data->min_frame_size = min_frame_size;
+ return (ARCHIVE_OK);
+ } else if (strcmp(key, "max-frame-size") == 0) {
+ intmax_t max_frame_size;
+ if (string_to_number(value, &max_frame_size) != ARCHIVE_OK) {
+ return (ARCHIVE_WARN);
+ }
+ if (max_frame_size < 1024) {
+ return (ARCHIVE_WARN);
+ }
+ data->max_frame_size = max_frame_size;
return (ARCHIVE_OK);
+#endif
}
/* Note: The "warn" return is just to inform the options
@@ -281,15 +312,22 @@ archive_compressor_zstd_write(struct archive_write_filter *f, const void *buff,
size_t length)
{
struct private_data *data = (struct private_data *)f->data;
- int ret;
- /* Update statistics */
- data->total_in += length;
+ return (drive_compressor(f, data, 0, buff, length));
+}
- if ((ret = drive_compressor(f, data, 0, buff, length)) != ARCHIVE_OK)
- return (ret);
+/*
+ * Flush the compressed stream.
+ */
+static int
+archive_compressor_zstd_flush(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
- return (ARCHIVE_OK);
+ if (data->frame_per_file && data->state == running &&
+ data->cur_frame_out > data->min_frame_size)
+ data->state = finishing;
+ return (drive_compressor(f, data, 1, NULL, 0));
}
/*
@@ -300,57 +338,72 @@ archive_compressor_zstd_close(struct archive_write_filter *f)
{
struct private_data *data = (struct private_data *)f->data;
- /* Finish zstd frame */
- return drive_compressor(f, data, 1, NULL, 0);
+ if (data->state == running)
+ data->state = finishing;
+ return (drive_compressor(f, data, 1, NULL, 0));
}
/*
* Utility function to push input data through compressor,
* writing full output blocks as necessary.
- *
- * Note that this handles both the regular write case (finishing ==
- * false) and the end-of-archive case (finishing == true).
*/
static int
drive_compressor(struct archive_write_filter *f,
- struct private_data *data, int finishing, const void *src, size_t length)
+ struct private_data *data, int flush, const void *src, size_t length)
{
- ZSTD_inBuffer in = (ZSTD_inBuffer) { src, length, 0 };
+ ZSTD_inBuffer in = { .src = src, .size = length, .pos = 0 };
+ size_t ipos, opos, zstdret = 0;
+ int ret;
for (;;) {
- if (data->out.pos == data->out.size) {
- const int ret = __archive_write_filter(f->next_filter,
- data->out.dst, data->out.size);
+ ipos = in.pos;
+ opos = data->out.pos;
+ switch (data->state) {
+ case running:
+ if (in.pos == in.size)
+ return (ARCHIVE_OK);
+ zstdret = ZSTD_compressStream(data->cstream,
+ &data->out, &in);
+ if (ZSTD_isError(zstdret))
+ goto zstd_fatal;
+ break;
+ case finishing:
+ zstdret = ZSTD_endStream(data->cstream, &data->out);
+ if (ZSTD_isError(zstdret))
+ goto zstd_fatal;
+ if (zstdret == 0)
+ data->state = resetting;
+ break;
+ case resetting:
+ ZSTD_CCtx_reset(data->cstream, ZSTD_reset_session_only);
+ data->cur_frame++;
+ data->cur_frame_in = 0;
+ data->cur_frame_out = 0;
+ data->state = running;
+ break;
+ }
+ data->total_in += in.pos - ipos;
+ data->cur_frame_in += in.pos - ipos;
+ data->cur_frame_out += data->out.pos - opos;
+ if (data->state == running &&
+ data->cur_frame_in >= data->max_frame_size) {
+ data->state = finishing;
+ }
+ if (data->out.pos == data->out.size ||
+ (flush && data->out.pos > 0)) {
+ ret = __archive_write_filter(f->next_filter,
+ data->out.dst, data->out.pos);
if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
+ goto fatal;
data->out.pos = 0;
}
-
- /* If there's nothing to do, we're done. */
- if (!finishing && in.pos == in.size)
- return (ARCHIVE_OK);
-
- {
- const size_t zstdret = !finishing ?
- ZSTD_compressStream(data->cstream, &data->out, &in)
- : ZSTD_endStream(data->cstream, &data->out);
-
- if (ZSTD_isError(zstdret)) {
- archive_set_error(f->archive,
- ARCHIVE_ERRNO_MISC,
- "Zstd compression failed: %s",
- ZSTD_getErrorName(zstdret));
- return (ARCHIVE_FATAL);
- }
-
- /* If we're finishing, 0 means nothing left to flush */
- if (finishing && zstdret == 0) {
- const int ret = __archive_write_filter(f->next_filter,
- data->out.dst, data->out.pos);
- return (ret);
- }
- }
}
+zstd_fatal:
+ archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+ "Zstd compression failed: %s",
+ ZSTD_getErrorName(zstdret));
+fatal:
+ return (ARCHIVE_FATAL);
}
#else /* HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR */
@@ -367,17 +420,9 @@ archive_compressor_zstd_open(struct archive_write_filter *f)
archive_strcpy(&as, "zstd --no-check");
if (data->compression_level < CLEVEL_STD_MIN) {
- struct archive_string as2;
- archive_string_init(&as2);
- archive_string_sprintf(&as2, " --fast=%d", -data->compression_level);
- archive_string_concat(&as, &as2);
- archive_string_free(&as2);
+ archive_string_sprintf(&as, " --fast=%d", -data->compression_level);
} else {
- struct archive_string as2;
- archive_string_init(&as2);
- archive_string_sprintf(&as2, " -%d", data->compression_level);
- archive_string_concat(&as, &as2);
- archive_string_free(&as2);
+ archive_string_sprintf(&as, " -%d", data->compression_level);
}
if (data->compression_level > CLEVEL_STD_MAX) {
@@ -385,11 +430,7 @@ archive_compressor_zstd_open(struct archive_write_filter *f)
}
if (data->threads != 0) {
- struct archive_string as2;
- archive_string_init(&as2);
- archive_string_sprintf(&as2, " --threads=%d", data->threads);
- archive_string_concat(&as, &as2);
- archive_string_free(&as2);
+ archive_string_sprintf(&as, " --threads=%d", data->threads);
}
f->write = archive_compressor_zstd_write;
@@ -408,6 +449,14 @@ archive_compressor_zstd_write(struct archive_write_filter *f, const void *buff,
}
static int
+archive_compressor_zstd_flush(struct archive_write_filter *f)
+{
+ (void)f; /* UNUSED */
+
+ return (ARCHIVE_OK);
+}
+
+static int
archive_compressor_zstd_close(struct archive_write_filter *f)
{
struct private_data *data = (struct private_data *)f->data;
diff --git a/src/libs/3rdparty/libarchive/archive_write_disk_posix.c b/src/libs/3rdparty/libarchive/archive_write_disk_posix.c
index 09a5eef03..c8c2e1058 100644
--- a/src/libs/3rdparty/libarchive/archive_write_disk_posix.c
+++ b/src/libs/3rdparty/libarchive/archive_write_disk_posix.c
@@ -397,6 +397,7 @@ static int set_times_from_entry(struct archive_write_disk *);
static struct fixup_entry *sort_dir_list(struct fixup_entry *p);
static ssize_t write_data_block(struct archive_write_disk *,
const char *, size_t);
+static void close_file_descriptor(struct archive_write_disk *);
static int _archive_write_disk_close(struct archive *);
static int _archive_write_disk_free(struct archive *);
@@ -514,7 +515,12 @@ lazy_stat(struct archive_write_disk *a)
* XXX At this point, symlinks should not be hit, otherwise
* XXX a race occurred. Do we want to check explicitly for that?
*/
- if (lstat(a->name, &a->st) == 0) {
+#ifdef HAVE_LSTAT
+ if (lstat(a->name, &a->st) == 0)
+#else
+ if (la_stat(a->name, &a->st) == 0)
+#endif
+ {
a->pst = &a->st;
return (ARCHIVE_OK);
}
@@ -1605,12 +1611,12 @@ hfs_write_data_block(struct archive_write_disk *a, const char *buff,
"Seek failed");
return (ARCHIVE_FATAL);
} else if (a->offset > a->fd_offset) {
- int64_t skip = a->offset - a->fd_offset;
+ uint64_t skip = a->offset - a->fd_offset;
char nullblock[1024];
memset(nullblock, 0, sizeof(nullblock));
while (skip > 0) {
- if (skip > (int64_t)sizeof(nullblock))
+ if (skip > sizeof(nullblock))
bytes_written = hfs_write_decmpfs_block(
a, nullblock, sizeof(nullblock));
else
@@ -1725,8 +1731,10 @@ _archive_write_disk_finish_entry(struct archive *_a)
else
r = hfs_write_data_block(
a, null_d, a->file_remaining_bytes);
- if (r < 0)
+ if (r < 0) {
+ close_file_descriptor(a);
return ((int)r);
+ }
}
#endif
} else {
@@ -1735,6 +1743,7 @@ _archive_write_disk_finish_entry(struct archive *_a)
a->filesize == 0) {
archive_set_error(&a->archive, errno,
"File size could not be restored");
+ close_file_descriptor(a);
return (ARCHIVE_FAILED);
}
#endif
@@ -1744,8 +1753,10 @@ _archive_write_disk_finish_entry(struct archive *_a)
* to see what happened.
*/
a->pst = NULL;
- if ((ret = lazy_stat(a)) != ARCHIVE_OK)
- return (ret);
+ if ((ret = lazy_stat(a)) != ARCHIVE_OK) {
+ close_file_descriptor(a);
+ return (ret);
+ }
/* We can use lseek()/write() to extend the file if
* ftruncate didn't work or isn't available. */
if (a->st.st_size < a->filesize) {
@@ -1753,11 +1764,13 @@ _archive_write_disk_finish_entry(struct archive *_a)
if (lseek(a->fd, a->filesize - 1, SEEK_SET) < 0) {
archive_set_error(&a->archive, errno,
"Seek failed");
+ close_file_descriptor(a);
return (ARCHIVE_FATAL);
}
if (write(a->fd, &nul, 1) < 0) {
archive_set_error(&a->archive, errno,
"Write to restore size failed");
+ close_file_descriptor(a);
return (ARCHIVE_FATAL);
}
a->pst = NULL;
@@ -2154,7 +2167,11 @@ restore_entry(struct archive_write_disk *a)
* then don't follow it.
*/
if (r != 0 || !S_ISDIR(a->mode))
+#ifdef HAVE_LSTAT
r = lstat(a->name, &a->st);
+#else
+ r = la_stat(a->name, &a->st);
+#endif
if (r != 0) {
archive_set_error(&a->archive, errno,
"Can't stat existing object");
@@ -2550,7 +2567,12 @@ _archive_write_disk_close(struct archive *_a)
goto skip_fixup_entry;
} else
#endif
- if (lstat(p->name, &st) != 0 ||
+ if (
+#ifdef HAVE_LSTAT
+ lstat(p->name, &st) != 0 ||
+#else
+ la_stat(p->name, &st) != 0 ||
+#endif
la_verify_filetype(st.st_mode,
p->filetype) == 0) {
goto skip_fixup_entry;
@@ -2565,7 +2587,12 @@ _archive_write_disk_close(struct archive *_a)
goto skip_fixup_entry;
} else
#endif
- if (lstat(p->name, &st) != 0 ||
+ if (
+#ifdef HAVE_LSTAT
+ lstat(p->name, &st) != 0 ||
+#else
+ la_stat(p->name, &st) != 0 ||
+#endif
la_verify_filetype(st.st_mode,
p->filetype) == 0) {
goto skip_fixup_entry;
@@ -2785,8 +2812,8 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
!(defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT))
/* Platform doesn't have lstat, so we can't look for symlinks. */
(void)path; /* UNUSED */
- (void)error_number; /* UNUSED */
- (void)error_string; /* UNUSED */
+ (void)a_eno; /* UNUSED */
+ (void)a_estr; /* UNUSED */
(void)flags; /* UNUSED */
(void)checking_linkname; /* UNUSED */
return (ARCHIVE_OK);
@@ -2859,8 +2886,10 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
/* Check that we haven't hit a symlink. */
#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)
r = fstatat(chdir_fd, head, &st, AT_SYMLINK_NOFOLLOW);
-#else
+#elif defined(HAVE_LSTAT)
r = lstat(head, &st);
+#else
+ r = la_stat(head, &st);
#endif
if (r != 0) {
tail[0] = c;
@@ -3558,7 +3587,9 @@ set_time(int fd, int mode, const char *name,
(void)fd; /* UNUSED */
(void)mode; /* UNUSED */
(void)name; /* UNUSED */
+ (void)atime; /* UNUSED */
(void)atime_nsec; /* UNUSED */
+ (void)mtime; /* UNUSED */
(void)mtime_nsec; /* UNUSED */
return (ARCHIVE_WARN);
#endif
@@ -4391,7 +4422,12 @@ fixup_appledouble(struct archive_write_disk *a, const char *pathname)
*/
archive_strncpy(&datafork, pathname, p - pathname);
archive_strcat(&datafork, p + 2);
- if (lstat(datafork.s, &st) == -1 ||
+ if (
+#ifdef HAVE_LSTAT
+ lstat(datafork.s, &st) == -1 ||
+#else
+ la_stat(datafork.s, &st) == -1 ||
+#endif
(st.st_mode & AE_IFMT) != AE_IFREG)
goto skip_appledouble;
@@ -4707,5 +4743,17 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
}
#endif
+/*
+ * Close the file descriptor if one is open.
+ */
+static void close_file_descriptor(struct archive_write_disk* a)
+{
+ if (a->fd >= 0) {
+ close(a->fd);
+ a->fd = -1;
+ }
+}
+
+
#endif /* !_WIN32 || __CYGWIN__ */
diff --git a/src/libs/3rdparty/libarchive/archive_write_disk_windows.c b/src/libs/3rdparty/libarchive/archive_write_disk_windows.c
index 88df3ce02..7b9ea7493 100644
--- a/src/libs/3rdparty/libarchive/archive_write_disk_windows.c
+++ b/src/libs/3rdparty/libarchive/archive_write_disk_windows.c
@@ -254,9 +254,9 @@ static ssize_t _archive_write_disk_data_block(struct archive *, const void *,
* which is high-16-bits of nFileIndexHigh. */
#define bhfi_ino(bhfi) \
((((int64_t)((bhfi)->nFileIndexHigh & 0x0000FFFFUL)) << 32) \
- + (bhfi)->nFileIndexLow)
+ | (bhfi)->nFileIndexLow)
#define bhfi_size(bhfi) \
- ((((int64_t)(bhfi)->nFileSizeHigh) << 32) + (bhfi)->nFileSizeLow)
+ ((((int64_t)(bhfi)->nFileSizeHigh) << 32) | (bhfi)->nFileSizeLow)
static int
file_information(struct archive_write_disk *a, wchar_t *path,
@@ -266,6 +266,9 @@ file_information(struct archive_write_disk *a, wchar_t *path,
int r;
DWORD flag = FILE_FLAG_BACKUP_SEMANTICS;
WIN32_FIND_DATAW findData;
+# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
+ CREATEFILE2_EXTENDED_PARAMETERS createExParams;
+#endif
if (sim_lstat || mode != NULL) {
h = FindFirstFileW(path, &findData);
@@ -290,14 +293,27 @@ file_information(struct archive_write_disk *a, wchar_t *path,
(findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK)))
flag |= FILE_FLAG_OPEN_REPARSE_POINT;
+# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
+ ZeroMemory(&createExParams, sizeof(createExParams));
+ createExParams.dwSize = sizeof(createExParams);
+ createExParams.dwFileFlags = flag;
+ h = CreateFile2(a->name, 0, 0,
+ OPEN_EXISTING, &createExParams);
+#else
h = CreateFileW(a->name, 0, 0, NULL,
OPEN_EXISTING, flag, NULL);
+#endif
if (h == INVALID_HANDLE_VALUE &&
GetLastError() == ERROR_INVALID_NAME) {
wchar_t *full;
full = __la_win_permissive_name_w(path);
+# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
+ h = CreateFile2(full, 0, 0,
+ OPEN_EXISTING, &createExParams);
+#else
h = CreateFileW(full, 0, 0, NULL,
OPEN_EXISTING, flag, NULL);
+#endif
free(full);
}
if (h == INVALID_HANDLE_VALUE) {
@@ -559,6 +575,7 @@ la_mktemp(struct archive_write_disk *a)
return (fd);
}
+#if _WIN32_WINNT < _WIN32_WINNT_VISTA
static void *
la_GetFunctionKernel32(const char *name)
{
@@ -574,18 +591,24 @@ la_GetFunctionKernel32(const char *name)
}
return (void *)GetProcAddress(lib, name);
}
+#endif
static int
la_CreateHardLinkW(wchar_t *linkname, wchar_t *target)
{
- static BOOLEAN (WINAPI *f)(LPWSTR, LPWSTR, LPSECURITY_ATTRIBUTES);
- static int set;
+ static BOOL (WINAPI *f)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);
BOOL ret;
+#if _WIN32_WINNT < _WIN32_WINNT_XP
+ static int set;
+/* CreateHardLinkW is available since XP and always loaded */
if (!set) {
set = 1;
f = la_GetFunctionKernel32("CreateHardLinkW");
}
+#else
+ f = CreateHardLinkW;
+#endif
if (!f) {
errno = ENOTSUP;
return (0);
@@ -624,7 +647,6 @@ static int
la_CreateSymbolicLinkW(const wchar_t *linkname, const wchar_t *target,
int linktype) {
static BOOLEAN (WINAPI *f)(LPCWSTR, LPCWSTR, DWORD);
- static int set;
wchar_t *ttarget, *p;
size_t len;
DWORD attrs = 0;
@@ -632,10 +654,20 @@ la_CreateSymbolicLinkW(const wchar_t *linkname, const wchar_t *target,
DWORD newflags = 0;
BOOL ret = 0;
+#if _WIN32_WINNT < _WIN32_WINNT_VISTA
+/* CreateSymbolicLinkW is available since Vista and always loaded */
+ static int set;
if (!set) {
set = 1;
f = la_GetFunctionKernel32("CreateSymbolicLinkW");
}
+#else
+# if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+ f = CreateSymbolicLinkW;
+# else
+ f = NULL;
+# endif
+#endif
if (!f)
return (0);
@@ -1185,6 +1217,8 @@ _archive_write_disk_finish_entry(struct archive *_a)
if (la_ftruncate(a->fh, a->filesize) == -1) {
archive_set_error(&a->archive, errno,
"File size could not be restored");
+ CloseHandle(a->fh);
+ a->fh = INVALID_HANDLE_VALUE;
return (ARCHIVE_FAILED);
}
}
@@ -1656,6 +1690,9 @@ create_filesystem_object(struct archive_write_disk *a)
mode_t final_mode, mode;
int r;
DWORD attrs = 0;
+# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
+ CREATEFILE2_EXTENDED_PARAMETERS createExParams;
+#endif
/* We identify hard/symlinks according to the link names. */
/* Since link(2) and symlink(2) don't handle modes, we're done here. */
@@ -1719,8 +1756,16 @@ create_filesystem_object(struct archive_write_disk *a)
a->todo = 0;
a->deferred = 0;
} else if (r == 0 && a->filesize > 0) {
+# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
+ ZeroMemory(&createExParams, sizeof(createExParams));
+ createExParams.dwSize = sizeof(createExParams);
+ createExParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
+ a->fh = CreateFile2(namefull, GENERIC_WRITE, 0,
+ TRUNCATE_EXISTING, &createExParams);
+#else
a->fh = CreateFileW(namefull, GENERIC_WRITE, 0, NULL,
TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+#endif
if (a->fh == INVALID_HANDLE_VALUE) {
la_dosmaperr(GetLastError());
r = errno;
@@ -1783,14 +1828,27 @@ create_filesystem_object(struct archive_write_disk *a)
a->tmpname = NULL;
fullname = a->name;
/* O_WRONLY | O_CREAT | O_EXCL */
+# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
+ ZeroMemory(&createExParams, sizeof(createExParams));
+ createExParams.dwSize = sizeof(createExParams);
+ createExParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
+ a->fh = CreateFile2(fullname, GENERIC_WRITE, 0,
+ CREATE_NEW, &createExParams);
+#else
a->fh = CreateFileW(fullname, GENERIC_WRITE, 0, NULL,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
+#endif
if (a->fh == INVALID_HANDLE_VALUE &&
GetLastError() == ERROR_INVALID_NAME &&
fullname == a->name) {
fullname = __la_win_permissive_name_w(a->name);
+# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
+ a->fh = CreateFile2(fullname, GENERIC_WRITE, 0,
+ CREATE_NEW, &createExParams);
+#else
a->fh = CreateFileW(fullname, GENERIC_WRITE, 0, NULL,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
+#endif
}
if (a->fh == INVALID_HANDLE_VALUE) {
if (GetLastError() == ERROR_ACCESS_DENIED) {
@@ -2551,14 +2609,25 @@ set_times(struct archive_write_disk *a,
hw = NULL;
} else {
wchar_t *ws;
+# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
+ CREATEFILE2_EXTENDED_PARAMETERS createExParams;
+#endif
if (S_ISLNK(mode))
return (ARCHIVE_OK);
ws = __la_win_permissive_name_w(name);
if (ws == NULL)
goto settimes_failed;
+# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
+ ZeroMemory(&createExParams, sizeof(createExParams));
+ createExParams.dwSize = sizeof(createExParams);
+ createExParams.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS;
+ hw = CreateFile2(ws, FILE_WRITE_ATTRIBUTES, 0,
+ OPEN_EXISTING, &createExParams);
+#else
hw = CreateFileW(ws, FILE_WRITE_ATTRIBUTES,
0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+#endif
free(ws);
if (hw == INVALID_HANDLE_VALUE)
goto settimes_failed;
diff --git a/src/libs/3rdparty/libarchive/archive_write_private.h b/src/libs/3rdparty/libarchive/archive_write_private.h
index 155fdd734..6522e6521 100644
--- a/src/libs/3rdparty/libarchive/archive_write_private.h
+++ b/src/libs/3rdparty/libarchive/archive_write_private.h
@@ -53,6 +53,7 @@ struct archive_write_filter {
const char *key, const char *value);
int (*open)(struct archive_write_filter *);
int (*write)(struct archive_write_filter *, const void *, size_t);
+ int (*flush)(struct archive_write_filter *);
int (*close)(struct archive_write_filter *);
int (*free)(struct archive_write_filter *);
void *data;
diff --git a/src/libs/3rdparty/libarchive/archive_write_set_format_7zip.c b/src/libs/3rdparty/libarchive/archive_write_set_format_7zip.c
index d5ca9a665..1e40601c4 100644
--- a/src/libs/3rdparty/libarchive/archive_write_set_format_7zip.c
+++ b/src/libs/3rdparty/libarchive/archive_write_set_format_7zip.c
@@ -165,7 +165,7 @@ struct file {
mode_t mode;
uint32_t crc32;
- signed int dir:1;
+ unsigned dir:1;
};
struct _7zip {
@@ -1809,11 +1809,11 @@ compression_init_encoder_bzip2(struct archive *a,
* of ugly hackery to convert a const * pointer to
* a non-const pointer. */
strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
- strm->avail_in = lastrm->avail_in;
+ strm->avail_in = (uint32_t)lastrm->avail_in;
strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
strm->next_out = (char *)lastrm->next_out;
- strm->avail_out = lastrm->avail_out;
+ strm->avail_out = (uint32_t)lastrm->avail_out;
strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
if (BZ2_bzCompressInit(strm, level, 0, 30) != BZ_OK) {
@@ -1842,11 +1842,11 @@ compression_code_bzip2(struct archive *a,
* of ugly hackery to convert a const * pointer to
* a non-const pointer. */
strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
- strm->avail_in = lastrm->avail_in;
+ strm->avail_in = (uint32_t)lastrm->avail_in;
strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
strm->next_out = (char *)lastrm->next_out;
- strm->avail_out = lastrm->avail_out;
+ strm->avail_out = (uint32_t)lastrm->avail_out;
strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
r = BZ2_bzCompress(strm,
diff --git a/src/libs/3rdparty/libarchive/archive_write_set_format_iso9660.c b/src/libs/3rdparty/libarchive/archive_write_set_format_iso9660.c
index 58b7216a8..2a3ae07fa 100644
--- a/src/libs/3rdparty/libarchive/archive_write_set_format_iso9660.c
+++ b/src/libs/3rdparty/libarchive/archive_write_set_format_iso9660.c
@@ -289,12 +289,12 @@ struct isoent {
struct extr_rec *current;
} extr_rec_list;
- signed int virtual:1;
+ unsigned int virtual:1;
/* If set to one, this file type is a directory.
* A convenience flag to be used as
* "archive_entry_filetype(isoent->file->entry) == AE_IFDIR".
*/
- signed int dir:1;
+ unsigned int dir:1;
};
struct hardlink {
@@ -652,7 +652,7 @@ struct iso_option {
#define VOLUME_IDENTIFIER_SIZE 32
/*
- * Usage : !zisofs [DEFAULT]
+ * Usage : !zisofs [DEFAULT]
* : Disable to generate RRIP 'ZF' extension.
* : zisofs
* : Make files zisofs file and generate RRIP 'ZF'
@@ -689,7 +689,7 @@ struct iso9660 {
uint64_t bytes_remaining;
int need_multi_extent;
- /* Temporary string buffer for Joliet extension. */
+ /* Temporary string buffer for Joliet extension. */
struct archive_string utf16be;
struct archive_string mbs;
@@ -755,9 +755,9 @@ struct iso9660 {
/* Used for making zisofs. */
struct {
- signed int detect_magic:1;
- signed int making:1;
- signed int allzero:1;
+ unsigned int detect_magic:1;
+ unsigned int making:1;
+ unsigned int allzero:1;
unsigned char magic_buffer[64];
int magic_cnt;
@@ -2521,12 +2521,11 @@ get_gmoffset(struct tm *tm)
static void
get_tmfromtime(struct tm *tm, time_t *t)
{
-#if HAVE_LOCALTIME_R
+#if HAVE_LOCALTIME_S
+ localtime_s(tm, t);
+#elif HAVE_LOCALTIME_R
tzset();
localtime_r(t, tm);
-#elif HAVE__LOCALTIME64_S
- __time64_t tmp_t = (__time64_t) *t; //time_t may be shorter than 64 bits
- _localtime64_s(tm, &tmp_t);
#else
memcpy(tm, localtime(t), sizeof(*tm));
#endif
@@ -4074,11 +4073,8 @@ write_information_block(struct archive_write *a)
}
memset(info.s, 0, info_size);
opt = 0;
-#if defined(HAVE__CTIME64_S)
- {
- __time64_t iso9660_birth_time_tmp = (__time64_t) iso9660->birth_time; //time_t may be shorter than 64 bits
- _ctime64_s(buf, sizeof(buf), &(iso9660_birth_time_tmp));
- }
+#if defined(HAVE_CTIME_S)
+ ctime_s(buf, sizeof(buf), &(iso9660->birth_time));
#elif defined(HAVE_CTIME_R)
ctime_r(&(iso9660->birth_time), buf);
#else
@@ -7802,8 +7798,8 @@ struct zisofs_extract {
uint64_t pz_uncompressed_size;
size_t uncompressed_buffer_size;
- signed int initialized:1;
- signed int header_passed:1;
+ unsigned int initialized:1;
+ unsigned int header_passed:1;
uint32_t pz_offset;
unsigned char *block_pointers;
diff --git a/src/libs/3rdparty/libarchive/archive_write_set_format_pax.c b/src/libs/3rdparty/libarchive/archive_write_set_format_pax.c
index cf1f4770e..c9c159164 100644
--- a/src/libs/3rdparty/libarchive/archive_write_set_format_pax.c
+++ b/src/libs/3rdparty/libarchive/archive_write_set_format_pax.c
@@ -100,6 +100,7 @@ static int has_non_ASCII(const char *);
static void sparse_list_clear(struct pax *);
static int sparse_list_add(struct pax *, int64_t, int64_t);
static char *url_encode(const char *in);
+static time_t get_ustar_max_mtime(void);
/*
* Set output format to 'restricted pax' format.
@@ -595,6 +596,8 @@ archive_write_pax_header(struct archive_write *a,
need_extension = 0;
pax = (struct pax *)a->format_data;
+ const time_t ustar_max_mtime = get_ustar_max_mtime();
+
/* Sanity check. */
if (archive_entry_pathname(entry_original) == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
@@ -1116,16 +1119,13 @@ archive_write_pax_header(struct archive_write *a,
}
/*
- * Technically, the mtime field in the ustar header can
- * support 33 bits, but many platforms use signed 32-bit time
- * values. The cutoff of 0x7fffffff here is a compromise.
* Yes, this check is duplicated just below; this helps to
* avoid writing an mtime attribute just to handle a
* high-resolution timestamp in "restricted pax" mode.
*/
if (!need_extension &&
((archive_entry_mtime(entry_main) < 0)
- || (archive_entry_mtime(entry_main) >= 0x7fffffff)))
+ || (archive_entry_mtime(entry_main) >= ustar_max_mtime)))
need_extension = 1;
/* I use a star-compatible file flag attribute. */
@@ -1190,7 +1190,7 @@ archive_write_pax_header(struct archive_write *a,
if (a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_RESTRICTED ||
need_extension) {
if (archive_entry_mtime(entry_main) < 0 ||
- archive_entry_mtime(entry_main) >= 0x7fffffff ||
+ archive_entry_mtime(entry_main) >= ustar_max_mtime ||
archive_entry_mtime_nsec(entry_main) != 0)
add_pax_attr_time(&(pax->pax_header), "mtime",
archive_entry_mtime(entry_main),
@@ -1428,7 +1428,7 @@ archive_write_pax_header(struct archive_write *a,
/* Copy mtime, but clip to ustar limits. */
s = archive_entry_mtime(entry_main);
if (s < 0) { s = 0; }
- if (s >= 0x7fffffff) { s = 0x7fffffff; }
+ if (s > ustar_max_mtime) { s = ustar_max_mtime; }
archive_entry_set_mtime(pax_attr_entry, s, 0);
/* Standard ustar doesn't support atime. */
@@ -2046,3 +2046,18 @@ sparse_list_add(struct pax *pax, int64_t offset, int64_t length)
return (_sparse_list_add_block(pax, offset, length, 0));
}
+static time_t
+get_ustar_max_mtime(void)
+{
+ /*
+ * Technically, the mtime field in the ustar header can
+ * support 33 bits. We are using all of them to keep
+ * tar/test/test_option_C_mtree.c simple and passing after 2038.
+ * For platforms that use signed 32-bit time values we
+ * use the 32-bit maximum.
+ */
+ if (sizeof(time_t) > sizeof(int32_t))
+ return (time_t)0x1ffffffff;
+ else
+ return (time_t)0x7fffffff;
+}
diff --git a/src/libs/3rdparty/libarchive/archive_write_set_format_warc.c b/src/libs/3rdparty/libarchive/archive_write_set_format_warc.c
index 46b057341..0ef003e2f 100644
--- a/src/libs/3rdparty/libarchive/archive_write_set_format_warc.c
+++ b/src/libs/3rdparty/libarchive/archive_write_set_format_warc.c
@@ -329,30 +329,21 @@ xstrftime(struct archive_string *as, const char *fmt, time_t t)
{
/** like strftime(3) but for time_t objects */
struct tm *rt;
-#if defined(HAVE_GMTIME_R) || defined(HAVE__GMTIME64_S)
+#if defined(HAVE_GMTIME_R) || defined(HAVE_GMTIME_S)
struct tm timeHere;
#endif
-#if defined(HAVE__GMTIME64_S)
- errno_t terr;
- __time64_t tmptime;
-#endif
char strtime[100];
size_t len;
-#ifdef HAVE_GMTIME_R
- if ((rt = gmtime_r(&t, &timeHere)) == NULL)
- return;
-#elif defined(HAVE__GMTIME64_S)
- tmptime = t;
- terr = _gmtime64_s(&timeHere, &tmptime);
- if (terr)
- rt = NULL;
- else
- rt = &timeHere;
+#if defined(HAVE_GMTIME_S)
+ rt = gmtime_s(&timeHere, &t) ? NULL : &timeHere;
+#elif defined(HAVE_GMTIME_R)
+ rt = gmtime_r(&t, &timeHere);
#else
- if ((rt = gmtime(&t)) == NULL)
- return;
+ rt = gmtime(&t);
#endif
+ if (!rt)
+ return;
/* leave the hard yacker to our role model strftime() */
len = strftime(strtime, sizeof(strtime)-1, fmt, rt);
archive_strncat(as, strtime, len);
diff --git a/src/libs/3rdparty/libarchive/archive_write_set_format_xar.c b/src/libs/3rdparty/libarchive/archive_write_set_format_xar.c
index d885f5c25..7307757d3 100644
--- a/src/libs/3rdparty/libarchive/archive_write_set_format_xar.c
+++ b/src/libs/3rdparty/libarchive/archive_write_set_format_xar.c
@@ -212,8 +212,8 @@ struct file {
struct heap_data data;
struct archive_string script;
- signed int virtual:1;
- signed int dir:1;
+ unsigned int virtual:1;
+ unsigned int dir:1;
};
struct hardlink {
@@ -906,15 +906,11 @@ xmlwrite_time(struct archive_write *a, xmlTextWriterPtr writer,
{
char timestr[100];
struct tm tm;
-#if defined(HAVE__GMTIME64_S)
- __time64_t tmptime;
-#endif
-#if defined(HAVE_GMTIME_R)
+#if defined(HAVE_GMTIME_S)
+ gmtime_s(&tm, &t);
+#elif defined(HAVE_GMTIME_R)
gmtime_r(&t, &tm);
-#elif defined(HAVE__GMTIME64_S)
- tmptime = t;
- _gmtime64_s(&tm, &tmptime);
#else
memcpy(&tm, gmtime(&t), sizeof(tm));
#endif
diff --git a/src/libs/3rdparty/libarchive/archive_write_set_format_zip.c b/src/libs/3rdparty/libarchive/archive_write_set_format_zip.c
index 8c14a7027..6821049c9 100644
--- a/src/libs/3rdparty/libarchive/archive_write_set_format_zip.c
+++ b/src/libs/3rdparty/libarchive/archive_write_set_format_zip.c
@@ -1382,25 +1382,14 @@ dos_time(const time_t unix_time)
{
struct tm *t;
unsigned int dt;
-#if defined(HAVE_LOCALTIME_R) || defined(HAVE__LOCALTIME64_S)
+#if defined(HAVE_LOCALTIME_R) || defined(HAVE_LOCALTIME_S)
struct tm tmbuf;
#endif
-#if defined(HAVE__LOCALTIME64_S)
- errno_t terr;
- __time64_t tmptime;
-#endif
- /* This will not preserve time when creating/extracting the archive
- * on two systems with different time zones. */
-#if defined(HAVE_LOCALTIME_R)
+#if defined(HAVE_LOCALTIME_S)
+ t = localtime_s(&tmbuf, &unix_time) ? NULL : &tmbuf;
+#elif defined(HAVE_LOCALTIME_R)
t = localtime_r(&unix_time, &tmbuf);
-#elif defined(HAVE__LOCALTIME64_S)
- tmptime = unix_time;
- terr = _localtime64_s(&tmbuf, &tmptime);
- if (terr)
- t = NULL;
- else
- t = &tmbuf;
#else
t = localtime(&unix_time);
#endif
diff --git a/src/libs/3rdparty/libarchive/config_freebsd.h b/src/libs/3rdparty/libarchive/config_freebsd.h
index 758621c4b..669f27246 100644
--- a/src/libs/3rdparty/libarchive/config_freebsd.h
+++ b/src/libs/3rdparty/libarchive/config_freebsd.h
@@ -111,6 +111,8 @@
#define HAVE_FCNTL 1
#define HAVE_FCNTL_H 1
#define HAVE_FDOPENDIR 1
+#define HAVE_FNMATCH 1
+#define HAVE_FNMATCH_H 1
#define HAVE_FORK 1
#define HAVE_FSEEKO 1
#define HAVE_FSTAT 1
@@ -123,6 +125,8 @@
#define HAVE_GETEUID 1
#define HAVE_GETGRGID_R 1
#define HAVE_GETGRNAM_R 1
+#define HAVE_GETLINE 1
+#define HAVE_GETOPT_OPTRESET 1
#define HAVE_GETPID 1
#define HAVE_GETPWNAM_R 1
#define HAVE_GETPWUID_R 1
@@ -201,6 +205,7 @@
#define HAVE_SYS_MOUNT_H 1
#define HAVE_SYS_PARAM_H 1
#define HAVE_SYS_POLL_H 1
+#define HAVE_SYS_QUEUE_H 1
#define HAVE_SYS_SELECT_H 1
#define HAVE_SYS_STATVFS_H 1
#define HAVE_SYS_STAT_H 1
@@ -234,7 +239,7 @@
#define HAVE_WMEMCPY 1
#define HAVE_WMEMMOVE 1
#define HAVE_ZLIB_H 1
-#define TIME_WITH_SYS_TIME 1
+#define HAVE_SYS_TIME_H 1
#if __FreeBSD_version >= 800505
#define HAVE_LIBLZMA 1
diff --git a/src/libs/3rdparty/libarchive/filter_fork_windows.c b/src/libs/3rdparty/libarchive/filter_fork_windows.c
index 0b963975b..9e49c5655 100644
--- a/src/libs/3rdparty/libarchive/filter_fork_windows.c
+++ b/src/libs/3rdparty/libarchive/filter_fork_windows.c
@@ -31,6 +31,7 @@
#include "filter_fork.h"
+#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
/* There are some editions of Windows ("nano server," for example) that
* do not host user32.dll. If we want to keep running on those editions,
* we need to delay-load WaitForInputIdle. */
@@ -224,6 +225,14 @@ fail:
__archive_cmdline_free(acmd);
return ARCHIVE_FAILED;
}
+#else /* !WINAPI_PARTITION_DESKTOP */
+int
+__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout, HANDLE *out_child)
+{
+ (void)cmd; (void)child_stdin; (void) child_stdout; (void) out_child;
+ return ARCHIVE_FAILED;
+}
+#endif /* !WINAPI_PARTITION_DESKTOP */
void
__archive_check_child(int in, int out)
diff --git a/src/libs/3rdparty/libarchive/qt_attribution.json b/src/libs/3rdparty/libarchive/qt_attribution.json
index df03d1702..76db5e26a 100644
--- a/src/libs/3rdparty/libarchive/qt_attribution.json
+++ b/src/libs/3rdparty/libarchive/qt_attribution.json
@@ -5,7 +5,7 @@
"Description": "Multi-format archive and compression library.",
"QtUsage": "Used for reading and writing archive files in Qt Installer Framework",
"Homepage": "https://www.libarchive.org",
- "Version": "3.6.2",
+ "Version": "3.7.1",
"License": "BSD 2-clause \"Simplified\" License",
"LicenseId": "BSD-2-Clause",
"LicenseFile": "COPYING",
diff --git a/src/libs/3rdparty/libarchive/xxhash.c b/src/libs/3rdparty/libarchive/xxhash.c
index f96e9d934..beacd2391 100644
--- a/src/libs/3rdparty/libarchive/xxhash.c
+++ b/src/libs/3rdparty/libarchive/xxhash.c
@@ -149,6 +149,10 @@ typedef struct _U32_S { U32 v; } _PACKED U32_S;
#if GCC_VERSION >= 409
__attribute__((__no_sanitize_undefined__))
+#else
+# if defined(__clang__)
+__attribute__((no_sanitize("undefined")))
+# endif
#endif
#if defined(_MSC_VER)
static __inline U32 A32(const void * x)
diff --git a/src/libs/ifwtools/binarycreator.cpp b/src/libs/ifwtools/binarycreator.cpp
index 52603cad5..341052650 100644
--- a/src/libs/ifwtools/binarycreator.cpp
+++ b/src/libs/ifwtools/binarycreator.cpp
@@ -262,7 +262,7 @@ static int assemble(Input input, const QInstaller::Settings &settings, const Bin
QFile pkgInfo(fi.filePath() + QLatin1String("/Contents/PkgInfo"));
pkgInfo.open(QIODevice::WriteOnly);
QTextStream pkgInfoStream(&pkgInfo);
- pkgInfoStream << QLatin1String("APPL????") << endl;
+ pkgInfoStream << QLatin1String("APPL????") << Qt::endl;
}
QString iconFile;
@@ -282,44 +282,44 @@ static int assemble(Input input, const QInstaller::Settings &settings, const Bin
QFile infoPList(fi.filePath() + QLatin1String("/Contents/Info.plist"));
infoPList.open(QIODevice::WriteOnly);
QTextStream plistStream(&infoPList);
- plistStream << QLatin1String("<?xml version=\"1.0\" encoding=\"UTF-8\"?>") << endl;
+ plistStream << QLatin1String("<?xml version=\"1.0\" encoding=\"UTF-8\"?>") << Qt::endl;
plistStream << QLatin1String("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" "
- "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">") << endl;
- plistStream << QLatin1String("<plist version=\"1.0\">") << endl;
- plistStream << QLatin1String("<dict>") << endl;
- plistStream << QLatin1String("\t<key>CFBundleIconFile</key>") << endl;
+ "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">") << Qt::endl;
+ plistStream << QLatin1String("<plist version=\"1.0\">") << Qt::endl;
+ plistStream << QLatin1String("<dict>") << Qt::endl;
+ plistStream << QLatin1String("\t<key>CFBundleIconFile</key>") << Qt::endl;
plistStream << QLatin1String("\t<string>") << iconTargetFile << QLatin1String("</string>")
- << endl;
- plistStream << QLatin1String("\t<key>CFBundlePackageType</key>") << endl;
- plistStream << QLatin1String("\t<string>APPL</string>") << endl;
+ << Qt::endl;
+ plistStream << QLatin1String("\t<key>CFBundlePackageType</key>") << Qt::endl;
+ plistStream << QLatin1String("\t<string>APPL</string>") << Qt::endl;
#define QUOTE_(x) #x
#define QUOTE(x) QUOTE_(x)
- plistStream << QLatin1String("\t<key>CFBundleShortVersionString</key>") << endl;
+ plistStream << QLatin1String("\t<key>CFBundleShortVersionString</key>") << Qt::endl;
plistStream << QLatin1String("\t<string>") << QLatin1String(QUOTE(IFW_VERSION_STR)) << ("</string>")
- << endl;
- plistStream << QLatin1String("\t<key>CFBundleVersion</key>") << endl;
+ << Qt::endl;
+ plistStream << QLatin1String("\t<key>CFBundleVersion</key>") << Qt::endl;
plistStream << QLatin1String("\t<string>") << QLatin1String(QUOTE(IFW_VERSION_STR)) << ("</string>")
- << endl;
+ << Qt::endl;
#undef QUOTE
#undef QUOTE_
- plistStream << QLatin1String("\t<key>CFBundleSignature</key>") << endl;
- plistStream << QLatin1String("\t<string>\?\?\?\?</string>") << endl;
- plistStream << QLatin1String("\t<key>CFBundleExecutable</key>") << endl;
+ plistStream << QLatin1String("\t<key>CFBundleSignature</key>") << Qt::endl;
+ plistStream << QLatin1String("\t<string>\?\?\?\?</string>") << Qt::endl;
+ plistStream << QLatin1String("\t<key>CFBundleExecutable</key>") << Qt::endl;
plistStream << QLatin1String("\t<string>") << fi.completeBaseName() << QLatin1String("</string>")
- << endl;
- plistStream << QLatin1String("\t<key>CFBundleIdentifier</key>") << endl;
- plistStream << QLatin1String("\t<string>com.yourcompany.installerbase</string>") << endl;
- plistStream << QLatin1String("\t<key>NOTE</key>") << endl;
+ << Qt::endl;
+ plistStream << QLatin1String("\t<key>CFBundleIdentifier</key>") << Qt::endl;
+ plistStream << QLatin1String("\t<string>com.yourcompany.installerbase</string>") << Qt::endl;
+ plistStream << QLatin1String("\t<key>NOTE</key>") << Qt::endl;
plistStream << QLatin1String("\t<string>This file was generated by Qt Installer Framework.</string>")
- << endl;
- plistStream << QLatin1String("\t<key>NSPrincipalClass</key>") << endl;
- plistStream << QLatin1String("\t<string>NSApplication</string>") << endl;
+ << Qt::endl;
+ plistStream << QLatin1String("\t<key>NSPrincipalClass</key>") << Qt::endl;
+ plistStream << QLatin1String("\t<string>NSApplication</string>") << Qt::endl;
if (!minimumSystemVersion.isEmpty()) {
- plistStream << QLatin1String("\t<key>LSMinimumSystemVersion</key>") << endl;
- plistStream << QLatin1String("\t<string>") << minimumSystemVersion << QLatin1String("</string>") << endl;
+ plistStream << QLatin1String("\t<key>LSMinimumSystemVersion</key>") << Qt::endl;
+ plistStream << QLatin1String("\t<string>") << minimumSystemVersion << QLatin1String("</string>") << Qt::endl;
}
- plistStream << QLatin1String("</dict>") << endl;
- plistStream << QLatin1String("</plist>") << endl;
+ plistStream << QLatin1String("</dict>") << Qt::endl;
+ plistStream << QLatin1String("</plist>") << Qt::endl;
input.outputPath = QString::fromLatin1("%1/Contents/MacOS/%2").arg(input.outputPath)
.arg(fi.completeBaseName());
diff --git a/src/libs/ifwtools/repositorygen.cpp b/src/libs/ifwtools/repositorygen.cpp
index c54fb846b..9232a02d4 100644
--- a/src/libs/ifwtools/repositorygen.cpp
+++ b/src/libs/ifwtools/repositorygen.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -188,7 +188,7 @@ static bool findMetaFile(const QString &repositoryDir, const QDomElement &packag
const QDomNodeList c1 = packageUpdate.childNodes();
for (int i = 0; i < c1.count(); ++i) {
const QDomElement e1 = c1.at(i).toElement();
- for (const QString &meta : qAsConst(*scMetaElements)) {
+ for (const QString &meta : scMetaElements) {
if (e1.tagName() == meta) {
metaElementFound = true;
break;
@@ -377,7 +377,7 @@ void QInstallerTools::copyMetaData(const QString &_targetDir, const QString &met
if (!filePath.endsWith(QLatin1String(".sha1"), Qt::CaseInsensitive)) {
const QString fileName = QFileInfo(filePath).fileName();
// remove unnecessary version string from filename and add it to the list
- realContentFiles.append(fileName.mid(info.version.count()));
+ realContentFiles.append(fileName.mid(info.version.size()));
}
}
diff --git a/src/libs/installer/binaryformat.cpp b/src/libs/installer/binaryformat.cpp
index 9ed7742db..ad80ba7bb 100644
--- a/src/libs/installer/binaryformat.cpp
+++ b/src/libs/installer/binaryformat.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -153,12 +153,19 @@ void Resource::setName(const QByteArray &name)
Opens a resource in QIODevice::ReadOnly mode. The function returns \c true
if successful.
*/
+#if QT_VERSION < QT_VERSION_CHECK(6, 3, 0)
bool Resource::open()
+#else
+bool Resource::open(std::optional<QFile::Permissions> permissions)
+#endif
{
if (isOpen())
return false;
-
+#if QT_VERSION < QT_VERSION_CHECK(6, 3, 0)
if (!m_file.open(QIODevice::ReadOnly | QIODevice::Unbuffered)) {
+#else
+ if (!m_file.open(QIODevice::ReadOnly | QIODevice::Unbuffered, permissions)) {
+#endif
setErrorString(m_file.errorString());
return false;
}
diff --git a/src/libs/installer/binaryformat.h b/src/libs/installer/binaryformat.h
index 26d510530..e7505a341 100644
--- a/src/libs/installer/binaryformat.h
+++ b/src/libs/installer/binaryformat.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -58,7 +58,11 @@ public:
Resource(const QString &path, const Range<qint64> &segment);
~Resource();
+#if QT_VERSION < QT_VERSION_CHECK(6, 3, 0)
bool open();
+#else
+ bool open(std::optional<QFile::Permissions> permissions = std::nullopt);
+#endif
void close() override;
bool seek(qint64 pos) override;
diff --git a/src/libs/installer/binaryformatengine.cpp b/src/libs/installer/binaryformatengine.cpp
index 681e6db79..7f00c8d47 100644
--- a/src/libs/installer/binaryformatengine.cpp
+++ b/src/libs/installer/binaryformatengine.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -127,9 +127,16 @@ bool BinaryFormatEngine::close()
/*!
\internal
*/
+#if QT_VERSION < QT_VERSION_CHECK(6, 3, 0)
bool BinaryFormatEngine::open(QIODevice::OpenMode mode)
+#else
+bool BinaryFormatEngine::open(QIODevice::OpenMode mode, std::optional<QFile::Permissions> permissions)
+#endif
{
Q_UNUSED(mode)
+#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)
+ Q_UNUSED(permissions)
+#endif
return m_resource.isNull() ? false : m_resource->open();
}
diff --git a/src/libs/installer/binaryformatengine.h b/src/libs/installer/binaryformatengine.h
index bf72e5f1f..9321e9d9c 100644
--- a/src/libs/installer/binaryformatengine.h
+++ b/src/libs/installer/binaryformatengine.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -47,7 +47,12 @@ public:
bool copy(const QString &newName) override;
bool close() override;
+#if QT_VERSION < QT_VERSION_CHECK(6, 3, 0)
bool open(QIODevice::OpenMode mode) override;
+#else
+ bool open(QIODevice::OpenMode mode,
+ std::optional<QFile::Permissions> permissions = std::nullopt) override;
+#endif
qint64 pos() const override;
qint64 read(char *data, qint64 maxlen) override;
bool seek(qint64 offset) override;
diff --git a/src/libs/installer/calculatorbase.h b/src/libs/installer/calculatorbase.h
index baf51c5b4..351658f99 100644
--- a/src/libs/installer/calculatorbase.h
+++ b/src/libs/installer/calculatorbase.h
@@ -49,7 +49,8 @@ public:
VirtualDependent, // "No dependencies to virtual component"
Dependent, // "Added as dependency for %1." / "Removed as dependency component is removed"
Automatic, // "Component(s) added as automatic dependencies" / "Removed as autodependency component is removed"
- Resolved // "Component(s) that have resolved Dependencies"
+ Resolved, // "Component(s) that have resolved Dependencies"
+ Alias // "Components added from selected alias"
};
CalculatorBase(PackageManagerCore *core);
diff --git a/src/libs/installer/commandlineparser.cpp b/src/libs/installer/commandlineparser.cpp
index a91ab0128..f9e1f663e 100644
--- a/src/libs/installer/commandlineparser.cpp
+++ b/src/libs/installer/commandlineparser.cpp
@@ -48,7 +48,7 @@ CommandLineParser::CommandLineParser()
"headless mode. The installation operations can be invoked with the following commands and "
"options. Note that the options marked with \"CLI\" are available in the headless mode only.\n")
+ QLatin1String("\nCommands:\n")
- + indent + QString::fromLatin1("%1, %2 - install default or selected packages - <pkg ...>\n")
+ + indent + QString::fromLatin1("%1, %2 - install default or selected packages and aliases - <pkg|alias ...>\n")
.arg(CommandLineOptions::scInstallShort, CommandLineOptions::scInstallLong)
+ indent + QString::fromLatin1("%1, %2 - show available updates information on maintenance tool\n")
.arg(CommandLineOptions::scCheckUpdatesShort, CommandLineOptions::scCheckUpdatesLong)
@@ -56,13 +56,16 @@ CommandLineParser::CommandLineParser()
.arg(CommandLineOptions::scUpdateShort, CommandLineOptions::scUpdateLong)
+ indent + QString::fromLatin1("%1, %2 - uninstall packages and their child components - <pkg ...>\n")
.arg(CommandLineOptions::scRemoveShort, CommandLineOptions::scRemoveLong)
- + indent + QString::fromLatin1("%1, %2 - list currently installed packages - <regexp>\n")
+ + indent + QString::fromLatin1("%1, %2 - list currently installed packages - <regexp for pkg>\n")
.arg(CommandLineOptions::scListShort, CommandLineOptions::scListLong)
- + indent + QString::fromLatin1("%1, %2 - search available packages - <regexp>\n")
+ + indent + QString::fromLatin1("%1, %2 - search available aliases or packages - <regexp for pkg|alias>\n")
.arg(CommandLineOptions::scSearchShort, CommandLineOptions::scSearchLong)
+ indent + indent + QString::fromLatin1("Note: The --%1 option can be used to specify\n")
.arg(CommandLineOptions::scFilterPackagesLong)
+ indent + indent + QLatin1String("additional filters for the search operation\n")
+ + indent + indent + QString::fromLatin1("Note: The --%1 option can be used to specify\n")
+ .arg(CommandLineOptions::scTypeLong)
+ + indent + indent + QLatin1String("the content type to search\n")
+ indent + QString::fromLatin1("%1, %2 - create offline installer from selected packages - <pkg ...>\n")
.arg(CommandLineOptions::scCreateOfflineShort, CommandLineOptions::scCreateOfflineLong)
+ indent + QString::fromLatin1("%1, %2 - clear contents of the local metadata cache\n")
@@ -177,6 +180,12 @@ CommandLineParser::CommandLineParser()
<< CommandLineOptions::scLocalCachePathShort << CommandLineOptions::scLocalCachePathLong,
QLatin1String("Sets the path used for local metadata cache. The path must be writable by the current user."),
QLatin1String("path")));
+ addOption(QCommandLineOption(QStringList()
+ << CommandLineOptions::scTypeLong,
+ QLatin1String("[CLI] Sets the type of the given arguments for commands supporting multiple argument types, "
+ "like \"search\". By default aliases are searched first, and if no matching aliases are found, "
+ "then packages are searched with the same search pattern."),
+ QLatin1String("package|alias")));
// Message query options
addOptionWithContext(QCommandLineOption(QStringList() << CommandLineOptions::scAcceptMessageQueryShort
diff --git a/src/libs/installer/component.cpp b/src/libs/installer/component.cpp
index edd03a191..ce76a2927 100644
--- a/src/libs/installer/component.cpp
+++ b/src/libs/installer/component.cpp
@@ -46,6 +46,9 @@
#include <QtCore/QDirIterator>
#include <QtCore/QTranslator>
#include <QtCore/QRegularExpression>
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+#include <QtCore/QTextCodec>
+#endif
#include <QApplication>
#include <QtConcurrentFilter>
@@ -61,6 +64,11 @@
#include <private/qv4object_p.h>
#include <algorithm>
+#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
+#include <QJSEngine>
+#else
+#include <QQmlEngine>
+#endif
using namespace QInstaller;
@@ -244,6 +252,11 @@ Component::Component(PackageManagerCore *core)
: d(new ComponentPrivate(core, this))
, m_defaultArchivePath(scTargetDirPlaceholder)
{
+#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
+ QJSEngine::setObjectOwnership(this, QJSEngine::CppOwnership);
+#else
+ QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
+#endif
setPrivate(d);
connect(this, &Component::valueChanged, this, &Component::updateModelData);
@@ -667,11 +680,11 @@ void Component::loadTranslations(const QDir &directory, const QStringList &qms)
continue; // do not load the file if it does not match the UI language
}
- QScopedPointer<QTranslator> translator(new QTranslator(this));
+ std::unique_ptr<QTranslator> translator(new QTranslator(this));
if (translator->load(filename)) {
// Do not throw if translator returns false as it may just be an intentionally
// empty file. See also QTBUG-31031
- qApp->installTranslator(translator.take());
+ qApp->installTranslator(translator.release());
}
}
}
@@ -693,13 +706,13 @@ void Component::loadUserInterfaces(const QDir &directory, const QStringList &uis
it.fileName(), file.errorString(), tr(scClearCacheHint), packageManagerCore()->settings().localCachePath()));
}
- static QUiLoader loader;
- loader.setTranslationEnabled(true);
- loader.setLanguageChangeEnabled(true);
- QWidget *const widget = loader.load(&file, 0);
+ QUiLoader *const loader = ProductKeyCheck::instance()->uiLoader();
+ loader->setTranslationEnabled(true);
+ loader->setLanguageChangeEnabled(true);
+ QWidget *const widget = loader->load(&file, 0);
if (!widget) {
throw Error(tr("Cannot load the requested UI file \"%1\": %2.\n\n%3 \"%4\"").arg(
- it.fileName(), loader.errorString(), tr(scClearCacheHint), packageManagerCore()->settings().localCachePath()));
+ it.fileName(), loader->errorString(), tr(scClearCacheHint), packageManagerCore()->settings().localCachePath()));
}
d->scriptEngine()->newQObject(widget);
d->m_userInterfaces.insert(widget->objectName(), widget);
@@ -748,7 +761,9 @@ void Component::loadLicenses(const QString &directory, const QHash<QString, QVar
file.fileName(), file.errorString(), tr(scClearCacheHint), packageManagerCore()->settings().localCachePath()));
}
QTextStream stream(&file);
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
stream.setCodec("UTF-8");
+#endif
license.insert(scContent, stream.readAll());
d->m_licenses.insert(it.key(), license);
}
@@ -960,6 +975,12 @@ QStringList Component::archives() const
static const QRegularExpression regExp(scCaretSymbol);
QString pathString = scInstallerPrefixWithOneArgs.arg(name());
QStringList archivesNameList = QDir(pathString).entryList();
+
+ // In resources we may have older version of archives, this can happen
+ // when there is offline installer with same component with lower version
+ // number and newer version is available online
+ archivesNameList = archivesNameList.filter(value(scVersion));
+
//RegExp "^" means line beginning
archivesNameList.replaceInStrings(regExp, pathString);
return archivesNameList;
@@ -1089,7 +1110,7 @@ OperationList Component::operations(const Operation::OperationGroups &mask) cons
licenses.insert(values.at(i).value(scFile).toString(),
values.at(i).value(scContent));
}
- d->m_licenseOperation->setValue(scLicenses, licenses);
+ d->m_licenseOperation->setValue(scLicensesValue, licenses);
d->m_operations.append(d->m_licenseOperation);
}
}
@@ -1174,9 +1195,6 @@ Operation *Component::createOperation(const QString &operationName, const QStrin
return operation;
}
- if (operation->name() == scDelete)
- operation->setValue(scPerformUndo, false);
-
// Operation can contain variables which are resolved when performing the operation
if (operation->requiresUnreplacedVariables())
operation->setArguments(parameters);
@@ -1239,7 +1257,7 @@ inline bool convert(QQmlV4Function *func, QStringList *toArgs)
QV4::Object *array = val->as<QV4::Object>();
uint length = array->getLength();
for (uint ii = 0; ii < length; ++ii) {
- valtmp = array->getIndexed(ii);
+ valtmp = array->get(ii);
*toArgs << valtmp->toQStringNoThrow();
}
} else {
diff --git a/src/libs/installer/component_p.cpp b/src/libs/installer/component_p.cpp
index 7cf47c925..bf3941274 100644
--- a/src/libs/installer/component_p.cpp
+++ b/src/libs/installer/component_p.cpp
@@ -188,6 +188,7 @@ void ComponentModelHelper::setCheckable(bool checkable)
setData(Qt::Unchecked, Qt::CheckStateRole);
}
changeFlags(checkable, Qt::ItemIsUserCheckable);
+ m_componentPrivate->m_vars[scCheckable] = checkable ? scTrue : scFalse;
}
/*!
diff --git a/src/libs/installer/componentalias.cpp b/src/libs/installer/componentalias.cpp
new file mode 100644
index 000000000..955d715fd
--- /dev/null
+++ b/src/libs/installer/componentalias.cpp
@@ -0,0 +1,649 @@
+/**************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#include "componentalias.h"
+
+#include "constants.h"
+#include "globals.h"
+#include "packagemanagercore.h"
+#include "updater.h"
+
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QJsonArray>
+
+namespace QInstaller {
+
+static const QStringList scPossibleElements {
+ scName,
+ scDisplayName,
+ scDescription,
+ scVersion,
+ scVirtual,
+ scRequiredComponents,
+ scRequiredAliases,
+ scOptionalComponents,
+ scOptionalAliases,
+ scReleaseDate
+};
+
+/*!
+ \inmodule QtInstallerFramework
+ \class QInstaller::AliasSource
+ \brief Describes a source for alias declarations.
+*/
+
+/*!
+ \enum QInstaller::AliasSource::SourceFileFormat
+
+ This enum type holds the possible file formats for alias source:
+
+ \value Unknown
+ Invalid or unknown file format.
+ \value Xml
+ XML file format.
+ \value Json
+ JSON file format.
+*/
+
+/*!
+ Constructs an alias source with empty information.
+*/
+AliasSource::AliasSource()
+ : priority(-1)
+{}
+
+/*!
+ Constructs an alias source with source file format \a aFormat, filename \a aFilename, and priority \a aPriority.
+*/
+AliasSource::AliasSource(SourceFileFormat aFormat, const QString &aFilename, int aPriority)
+ : format(aFormat)
+ , filename(aFilename)
+ , priority(aPriority)
+{}
+
+/*!
+ Copy-constructs an alias source from \a other.
+*/
+AliasSource::AliasSource(const AliasSource &other)
+{
+ format = other.format;
+ filename = other.filename;
+ priority = other.priority;
+}
+
+/*!
+ Returns the hash value for the \a key, using \a seed to seed the calculation.
+*/
+hashValue qHash(const AliasSource &key, hashValue seed)
+{
+ return qHash(key.filename, seed) ^ key.priority;
+}
+
+/*!
+ Returns \c true if \a lhs and \a rhs are equal; otherwise returns \c false.
+*/
+bool operator==(const AliasSource &lhs, const AliasSource &rhs)
+{
+ return lhs.filename == rhs.filename && lhs.priority == rhs.priority && lhs.format == rhs.format;
+}
+
+/*!
+ \inmodule QtInstallerFramework
+ \class QInstaller::AliasFinder
+ \brief Creates component alias objects from parsed alias source files, based
+ on version and source priorities.
+*/
+
+/*!
+ Constructs a new alias finder with \a core as the package manager instance.
+*/
+AliasFinder::AliasFinder(PackageManagerCore *core)
+ : m_core(core)
+{
+}
+
+/*!
+ Destroys the finder and cleans unreleased results.
+*/
+AliasFinder::~AliasFinder()
+{
+ clear();
+}
+
+/*!
+ Runs the finder. Parses the alias source files and creates component alias
+ objects based on the parsed data. Same alias may be declared in multiple source
+ files, thus source priority and version information is used to decide which
+ source is used for creating the alias object.
+
+ Any previous results are cleared when calling this.
+
+ Returns \c true if at least one alias was found, \c false otherwise.
+*/
+bool AliasFinder::run()
+{
+ clear();
+
+ if (m_sources.isEmpty())
+ return false;
+
+ // 1. Parse source files
+ for (auto &source : qAsConst(m_sources)) {
+ if (source.format == AliasSource::SourceFileFormat::Unknown) {
+ qCWarning(QInstaller::lcInstallerInstallLog)
+ << "Unknown alias source format for file:" << source.filename;
+ continue;
+ }
+ if (source.format == AliasSource::SourceFileFormat::Xml)
+ parseXml(source);
+ else if (source.format == AliasSource::SourceFileFormat::Json)
+ parseJson(source);
+ }
+
+ // 2. Create aliases based on priority & version
+ for (auto &data : qAsConst(m_aliasData)) {
+ const QString name = data.value(scName).toString();
+ const Resolution resolution = checkPriorityAndVersion(data);
+ if (resolution == Resolution::KeepExisting)
+ continue;
+
+ if (resolution == Resolution::RemoveExisting)
+ delete m_aliases.take(name);
+
+ ComponentAlias *alias = new ComponentAlias(m_core);
+ AliasData::const_iterator it;
+ for (it = data.cbegin(); it != data.cend(); ++it) {
+ if (it.value().canConvert<QString>())
+ alias->setValue(it.key(), it.value().toString());
+ }
+ m_aliases.insert(name, alias);
+ }
+
+ return !m_aliases.isEmpty();
+}
+
+/*!
+ Returns a list of the found aliases.
+*/
+QList<ComponentAlias *> AliasFinder::aliases() const
+{
+ return m_aliases.values();
+}
+
+/*!
+ Sets the alias sources to look alias information from to \a sources.
+*/
+void AliasFinder::setAliasSources(const QSet<AliasSource> &sources)
+{
+ clear();
+ m_sources = sources;
+}
+
+/*!
+ Clears the results of the finder.
+*/
+void AliasFinder::clear()
+{
+ qDeleteAll(m_aliases);
+
+ m_aliases.clear();
+ m_aliasData.clear();
+}
+
+/*!
+ Reads an XML file specified by \a filename, and constructs a variant map of
+ the data for each alias.
+
+ Returns \c true on success, \c false otherwise.
+*/
+bool AliasFinder::parseXml(AliasSource source)
+{
+ QFile file(source.filename);
+ if (!file.open(QIODevice::ReadOnly)) {
+ qCWarning(QInstaller::lcInstallerInstallLog)
+ << "Cannot open alias definition for reading:" << file.errorString();
+ return false;
+ }
+
+ QString error;
+ int errorLine;
+ int errorColumn;
+
+ QDomDocument doc;
+ if (!doc.setContent(&file, &error, &errorLine, &errorColumn)) {
+ qCWarning(QInstaller::lcInstallerInstallLog)
+ << "Cannot read alias definition document:" << error
+ << "line:" << errorLine << "column:" << errorColumn;
+ return false;
+ }
+ file.close();
+
+ const QDomElement root = doc.documentElement();
+ const QDomNodeList children = root.childNodes();
+
+ for (int i = 0; i < children.count(); ++i) {
+ const QDomElement el = children.at(i).toElement();
+ const QString tag = el.tagName();
+ if (el.isNull() || tag != scAlias) {
+ qCWarning(lcInstallerInstallLog) << "Unexpected element name:" << tag;
+ continue;
+ }
+
+ AliasData data;
+ data.insert(QLatin1String("source"), QVariant::fromValue(source));
+
+ const QDomNodeList c2 = el.childNodes();
+ for (int j = 0; j < c2.count(); ++j) {
+ const QDomElement el2 = c2.at(j).toElement();
+ const QString tag2 = el2.tagName();
+ if (!scPossibleElements.contains(tag2)) {
+ qCWarning(lcInstallerInstallLog) << "Unexpected element name:" << tag2;
+ continue;
+ }
+ data.insert(tag2, el2.text());
+ }
+
+ m_aliasData.insert(data.value(scName).toString(), data);
+ }
+
+ return true;
+}
+
+/*!
+ Reads a JSON file specified by \a source, and constructs a variant map of
+ the data for each alias.
+
+ Returns \c true on success, \c false otherwise.
+*/
+bool AliasFinder::parseJson(AliasSource source)
+{
+ QFile file(source.filename);
+ if (!file.open(QIODevice::ReadOnly)) {
+ qCWarning(QInstaller::lcInstallerInstallLog)
+ << "Cannot open alias definition for reading:" << file.errorString();
+ return false;
+ }
+
+ const QByteArray jsonData = file.readAll();
+ const QJsonDocument doc(QJsonDocument::fromJson(jsonData));
+ const QJsonObject docJsonObject = doc.object();
+
+ const QJsonArray aliases = docJsonObject.value(QLatin1String("alias-packages")).toArray();
+ for (auto &it : aliases) {
+ AliasData data;
+ data.insert(QLatin1String("source"), QVariant::fromValue(source));
+
+ QJsonObject aliasObj = it.toObject();
+ for (const auto &key : aliasObj.keys()) {
+ if (!scPossibleElements.contains(key)) {
+ qCWarning(lcInstallerInstallLog) << "Unexpected element name:" << key;
+ continue;
+ }
+
+ const QJsonValue jsonValue = aliasObj.value(key);
+ if (key == scRequiredComponents || key == scRequiredAliases
+ || key == scOptionalComponents || key == scOptionalAliases) {
+ const QJsonArray requirements = jsonValue.toArray();
+ QString requiresString;
+
+ for (const auto &it2 : requirements) {
+ requiresString.append(it2.toString());
+ if (it2 != requirements.last())
+ requiresString.append(QLatin1Char(','));
+ }
+
+ data.insert(key, requiresString);
+ } else if (key == scVirtual) {
+ data.insert(key, QVariant(jsonValue.toBool()))->toString();
+ } else {
+ data.insert(key, jsonValue.toString());
+ }
+ }
+
+ m_aliasData.insert(data.value(scName).toString(), data);
+ }
+
+ return true;
+}
+
+/*!
+ Checks whether \a data should be used for creating a new alias object,
+ based on version and source priority.
+
+ If an alias of the same name exists, always use the one with the higher
+ version. If the new alias has the same version but a higher
+ priority, use the new new alias. Otherwise keep the already existing alias.
+
+ Returns the resolution of the check.
+*/
+AliasFinder::Resolution AliasFinder::checkPriorityAndVersion(const AliasData &data) const
+{
+ for (const auto &existingData : m_aliasData.values(data.value(scName).toString())) {
+ if (existingData == data)
+ continue;
+
+ const int versionMatch = KDUpdater::compareVersion(data.value(scVersion).toString(),
+ existingData.value(scVersion).toString());
+
+ const AliasSource newSource = data.value(QLatin1String("source")).value<AliasSource>();
+ const AliasSource oldSource = existingData.value(QLatin1String("source")).value<AliasSource>();
+
+ if (versionMatch > 0) {
+ // new alias has higher version, use
+ qCDebug(QInstaller::lcDeveloperBuild).nospace() << "Remove Alias 'Name: "
+ << data.value(scName).toString() << ", Version: " << existingData.value(scVersion).toString()
+ << ", Source: " << oldSource.filename
+ << "' found an alias with higher version 'Name: "
+ << data.value(scName).toString() << ", Version: " << data.value(scVersion).toString()
+ << ", Source: " << newSource.filename << "'";
+
+ return Resolution::RemoveExisting;
+ }
+
+ if ((versionMatch == 0) && (newSource.priority > oldSource.priority)) {
+ // new alias version equals but priority is higher, use
+ qCDebug(QInstaller::lcDeveloperBuild).nospace() << "Remove Alias 'Name: "
+ << data.value(scName).toString() << ", Priority: " << oldSource.priority
+ << ", Source: " << oldSource.filename
+ << "' found an alias with higher priority 'Name: "
+ << data.value(scName).toString() << ", Priority: " << newSource.priority
+ << ", Source: " << newSource.filename << "'";
+
+ return Resolution::RemoveExisting;
+ }
+
+ return Resolution::KeepExisting; // otherwise keep existing
+ }
+
+ return Resolution::AddNew;
+}
+
+/*!
+ \inmodule QtInstallerFramework
+ \class QInstaller::ComponentAlias
+ \brief The ComponentAlias class represents an alias for single or multiple components.
+*/
+
+/*!
+ \enum QInstaller::ComponentAlias::UnstableError
+
+ This enum type holds the possible reasons for marking an alias unstable:
+
+ \value ReferenceToUnstable
+ Alias requires another alias that is marked unstable.
+ \value MissingComponent
+ Alias requires a component that is missing.
+ \value UnselectableComponent
+ Alias requires a component that cannot be selected.
+ \value MissingAlias
+ Alias requires another alias that is missing.
+ \value ComponentNameConfict
+ Alias has a name that conflicts with a name of a component
+*/
+
+/*!
+ Constructs a new component alias with \a core as the package manager instance.
+*/
+ComponentAlias::ComponentAlias(PackageManagerCore *core)
+ : m_core(core)
+ , m_selected(false)
+ , m_unstable(false)
+{
+}
+
+/*!
+ Destructs the alias.
+*/
+ComponentAlias::~ComponentAlias()
+{
+}
+
+/*!
+ Returns the name of the alias.
+*/
+QString ComponentAlias::name() const
+{
+ return m_variables.value(scName);
+}
+
+/*!
+ Returns the display name of the alias.
+*/
+QString ComponentAlias::displayName() const
+{
+ return m_variables.value(scDisplayName);
+}
+
+/*!
+ Returns the description text of the alias.
+*/
+QString ComponentAlias::description() const
+{
+ return m_variables.value(scDescription);
+}
+
+/*!
+ Returns the version of the alias.
+*/
+QString ComponentAlias::version() const
+{
+ return m_variables.value(scVersion);
+}
+
+/*!
+ Returns \c true if the alias is virtual, \c false otherwise.
+
+ Virtual aliases are aliases that cannot be selected by the
+ user, and are invisible. They can be required by other aliases however.
+*/
+bool ComponentAlias::isVirtual() const
+{
+ return m_variables.value(scVirtual, scFalse).toLower() == scTrue;
+}
+
+/*!
+ Returns \c true if the alias is selected for installation, \c false otherwise.
+*/
+bool ComponentAlias::isSelected() const
+{
+ return m_selected;
+}
+
+/*!
+ Sets the selection state of the alias to \a selected. The selection
+ does not have an effect if the alias is unselectable.
+*/
+void ComponentAlias::setSelected(bool selected)
+{
+ if (selected && (isUnstable() || isVirtual()))
+ return;
+
+ m_selected = selected;
+}
+
+/*!
+ Returns the list of components required by this alias, or an
+ empty list if this alias does not require any components.
+*/
+QList<Component *> ComponentAlias::components()
+{
+ if (m_components.isEmpty()) {
+ const QStringList componentList = QInstaller::splitStringWithComma(
+ m_variables.value(scRequiredComponents));
+
+ const QStringList optionalComponentList = QInstaller::splitStringWithComma(
+ m_variables.value(scOptionalComponents));
+
+ addRequiredComponents(componentList, false);
+ addRequiredComponents(optionalComponentList, true);
+ }
+
+ return m_components;
+}
+
+/*!
+ Returns the list of other aliases required by this alias, or an
+ empty list if this alias does not require any other aliases.
+*/
+QList<ComponentAlias *> ComponentAlias::aliases()
+{
+ if (m_aliases.isEmpty()) {
+ const QStringList aliasList = QInstaller::splitStringWithComma(
+ m_variables.value(scRequiredAliases));
+
+ const QStringList optionalAliasList = QInstaller::splitStringWithComma(
+ m_variables.value(scOptionalAliases));
+
+ addRequiredAliases(aliasList, false);
+ addRequiredAliases(optionalAliasList, true);
+ }
+
+ return m_aliases;
+}
+
+/*!
+ Returns the value specified by \a key, with an optional default value \a defaultValue.
+*/
+QString ComponentAlias::value(const QString &key, const QString &defaultValue) const
+{
+ return m_variables.value(key, defaultValue);
+}
+
+/*!
+ Sets the value specified by \a key to \a value. If the value exists already,
+ it is replaced with the new value.
+*/
+void ComponentAlias::setValue(const QString &key, const QString &value)
+{
+ const QString normalizedValue = m_core->replaceVariables(value);
+ if (m_variables.value(key) == normalizedValue)
+ return;
+
+ m_variables[key] = normalizedValue;
+}
+
+/*!
+ Returns all keys for the component alias values.
+*/
+QStringList ComponentAlias::keys() const
+{
+ return m_variables.keys();
+}
+
+/*!
+ Returns \c true if the alias is marked unstable, \c false otherwise.
+*/
+bool ComponentAlias::isUnstable() const
+{
+ return m_unstable;
+}
+
+/*!
+ Sets the alias unstable with \a error, and a \a message describing the error.
+*/
+void ComponentAlias::setUnstable(UnstableError error, const QString &message)
+{
+ setSelected(false);
+ m_unstable = true;
+
+ const QMetaEnum metaEnum = QMetaEnum::fromType<ComponentAlias::UnstableError>();
+ emit m_core->unstableComponentFound(
+ QLatin1String(metaEnum.valueToKey(error)), message, name());
+}
+
+/*!
+ \internal
+
+ Adds the \a aliases to the list of required aliases by this alias. If \a optional
+ is \c true, missing alias references are ignored.
+*/
+void ComponentAlias::addRequiredAliases(const QStringList &aliases, const bool optional)
+{
+ for (const auto &aliasName : aliases) {
+ ComponentAlias *alias = m_core->aliasByName(aliasName);
+ if (!alias) {
+ if (optional)
+ continue;
+
+ const QString error = QLatin1String("No required alias found by name: ") + aliasName;
+ qCWarning(lcInstallerInstallLog) << error;
+
+ setUnstable(UnstableError::MissingAlias, error);
+ continue;
+ }
+
+ if (alias->isUnstable()) {
+ const QString error = QLatin1String("Alias requires another alias "
+ "that is marked unstable: ") + aliasName;
+ qCWarning(lcInstallerInstallLog) << error;
+
+ setUnstable(UnstableError::ReferenceToUnstable, error);
+ continue;
+ }
+
+ m_aliases.append(alias);
+ }
+}
+
+/*!
+ \internal
+
+ Adds the \a components to the list of required components by this alias. If \a optional
+ is \c true, missing component references are ignored.
+*/
+void ComponentAlias::addRequiredComponents(const QStringList &components, const bool optional)
+{
+ for (const auto &componentName : components) {
+ Component *component = m_core->componentByName(componentName);
+ if (!component) {
+ if (optional)
+ continue;
+
+ const QString error = QLatin1String("No required component found by name: ")
+ + componentName;
+ qCWarning(lcInstallerInstallLog) << error;
+
+ setUnstable(UnstableError::MissingComponent, error);
+ continue;
+ }
+
+ if (component->isUnstable() || !component->isCheckable()) {
+ const QString error = QLatin1String("Alias requires component that is uncheckable or unstable: ")
+ + componentName;
+ qCWarning(lcInstallerInstallLog) << error;
+
+ setUnstable(UnstableError::UnselectableComponent, error);
+ continue;
+ }
+
+ m_components.append(component);
+ }
+}
+
+} // namespace QInstaller
diff --git a/src/libs/installer/componentalias.h b/src/libs/installer/componentalias.h
new file mode 100644
index 000000000..e99c343d9
--- /dev/null
+++ b/src/libs/installer/componentalias.h
@@ -0,0 +1,160 @@
+/**************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#ifndef COMPONENTALIAS_H
+#define COMPONENTALIAS_H
+
+#include "installer_global.h"
+
+#include <QHash>
+#include <QMetaEnum>
+#include <QString>
+#include <QSet>
+
+namespace QInstaller {
+
+class Component;
+class ComponentAlias;
+class PackageManagerCore;
+
+struct INSTALLER_EXPORT AliasSource
+{
+ enum class SourceFileFormat {
+ Unknown = -1,
+ Xml = 0,
+ Json
+ };
+
+ AliasSource();
+ AliasSource(SourceFileFormat aFormat, const QString &aFilename, int aPriority);
+ AliasSource(const AliasSource &other);
+
+ SourceFileFormat format;
+ QString filename;
+ int priority;
+};
+
+INSTALLER_EXPORT hashValue qHash(const AliasSource &key, hashValue seed);
+INSTALLER_EXPORT bool operator==(const AliasSource &lhs, const AliasSource &rhs);
+
+class INSTALLER_EXPORT AliasFinder
+{
+public:
+ using AliasData = QVariantMap;
+ using AliasDataHash = QMultiHash<QString, AliasData>;
+
+ enum struct Resolution {
+ AddNew,
+ KeepExisting,
+ RemoveExisting
+ };
+
+ explicit AliasFinder(PackageManagerCore *core);
+ ~AliasFinder();
+
+ bool run();
+ QList<ComponentAlias *> aliases() const;
+
+ void setAliasSources(const QSet<AliasSource> &sources);
+
+private:
+ void clear();
+ Resolution checkPriorityAndVersion(const AliasData &data) const;
+
+ bool parseXml(AliasSource source);
+ bool parseJson(AliasSource source);
+
+private:
+ PackageManagerCore *const m_core;
+
+ QSet<AliasSource> m_sources;
+ AliasDataHash m_aliasData;
+ QHash<QString, ComponentAlias *> m_aliases;
+};
+
+class INSTALLER_EXPORT ComponentAlias : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY_MOVE(ComponentAlias)
+
+public:
+ enum UnstableError {
+ ReferenceToUnstable = 0,
+ MissingComponent,
+ UnselectableComponent,
+ MissingAlias,
+ ComponentNameConfict
+ };
+ Q_ENUM(UnstableError)
+
+ ComponentAlias(PackageManagerCore *core);
+ ~ComponentAlias();
+
+ QString name() const;
+ QString displayName() const;
+ QString description() const;
+
+ QString version() const;
+
+ bool isVirtual() const;
+
+ bool isSelected() const;
+ void setSelected(bool selected);
+
+ QList<Component *> components();
+ QList<ComponentAlias *> aliases();
+
+ QString value(const QString &key, const QString &defaultValue = QString()) const;
+ void setValue(const QString &key, const QString &value);
+ QStringList keys() const;
+
+ bool isUnstable() const;
+ void setUnstable(UnstableError error, const QString &message = QString());
+
+private:
+ void addRequiredAliases(const QStringList &aliases, const bool optional);
+ void addRequiredComponents(const QStringList &components, const bool optional);
+
+private:
+ PackageManagerCore *const m_core;
+
+ QHash<QString, QString> m_variables;
+
+ bool m_selected;
+ bool m_unstable;
+
+ QList<Component *> m_components;
+ QList<ComponentAlias *> m_aliases;
+};
+
+} // namespace QInstaller
+
+Q_DECLARE_METATYPE(QInstaller::ComponentAlias *)
+Q_DECLARE_METATYPE(QInstaller::AliasSource);
+
+#endif // COMPONENTALIAS_H
diff --git a/src/libs/installer/componentmodel.cpp b/src/libs/installer/componentmodel.cpp
index dbb80f2f6..1e8dd1ff7 100644
--- a/src/libs/installer/componentmodel.cpp
+++ b/src/libs/installer/componentmodel.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -335,6 +335,22 @@ QSet<Component *> ComponentModel::uncheckable() const
return m_uncheckable;
}
+bool ComponentModel::componentsSelected() const
+{
+ if (m_core->isInstaller() || m_core->isUpdater())
+ return checked().count();
+
+ if (checkedState().testFlag(ComponentModel::DefaultChecked) == false)
+ return true;
+
+ const QSet<Component *> uncheckables = uncheckable();
+ for (auto &component : uncheckables) {
+ if (component->forcedInstallation() && !component->isInstalled())
+ return true; // allow installation for new forced components
+ }
+ return false;
+}
+
/*!
Returns a pointer to the PackageManagerCore this model belongs to.
*/
@@ -562,12 +578,11 @@ QSet<QModelIndex> ComponentModel::updateCheckedState(const ComponentSet &compone
for (int i = sortedNodes.count(); i > 0; i--) {
Component * const node = sortedNodes.at(i - 1);
- bool checkable = true;
- if (node->value(scCheckable, scTrue).toLower() == scFalse) {
- checkable = false;
- }
+ if (!node->isEnabled() || node->isUnstable())
+ continue;
- if ((!node->isCheckable() && checkable) || !node->isEnabled() || node->isUnstable())
+ //Do not let forced installations to be uninstalled
+ if (!m_core->isUpdater() && node->forcedInstallation() && (node->checkState() != Qt::Unchecked))
continue;
if (!m_core->isUpdater() && !node->autoDependencies().isEmpty())
diff --git a/src/libs/installer/componentmodel.h b/src/libs/installer/componentmodel.h
index 1e8a2d297..c93dd60ae 100644
--- a/src/libs/installer/componentmodel.h
+++ b/src/libs/installer/componentmodel.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -80,6 +80,7 @@ public:
QSet<Component *> partially() const;
QSet<Component *> unchecked() const;
QSet<Component *> uncheckable() const;
+ bool componentsSelected() const;
PackageManagerCore *core() const;
ComponentModel::ModelState checkedState() const;
diff --git a/src/libs/installer/componentselectionpage_p.cpp b/src/libs/installer/componentselectionpage_p.cpp
index 7f82ef47d..b68eebf06 100644
--- a/src/libs/installer/componentselectionpage_p.cpp
+++ b/src/libs/installer/componentselectionpage_p.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2023 The Qt Company Ltd.
+** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -35,6 +35,7 @@
#include "component.h"
#include "fileutils.h"
#include "messageboxhandler.h"
+#include "customcombobox.h"
#include <QTreeView>
#include <QLabel>
@@ -50,7 +51,6 @@
#include <QStackedLayout>
#include <QStackedWidget>
#include <QLineEdit>
-#include <QComboBox>
#include <QStandardItemModel>
#include <QStyledItemDelegate>
@@ -71,22 +71,20 @@ ComponentSelectionPagePrivate::ComponentSelectionPagePrivate(ComponentSelectionP
: q(qq)
, m_core(core)
, m_treeView(new QTreeView(q))
- , m_allModel(m_core->defaultComponentModel())
- , m_updaterModel(m_core->updaterComponentModel())
- , m_currentModel(m_allModel)
- , m_allowCompressedRepositoryInstall(false)
, m_tabWidget(nullptr)
, m_descriptionBaseWidget(nullptr)
, m_categoryWidget(Q_NULLPTR)
+ , m_allowCreateOfflineInstaller(false)
, m_categoryLayoutVisible(false)
- , m_proxyModel(new ComponentSortFilterProxyModel(q))
+ , m_allModel(m_core->defaultComponentModel())
+ , m_updaterModel(m_core->updaterComponentModel())
+ , m_currentModel(m_allModel)
+ , m_proxyModel(m_core->componentSortFilterProxyModel())
, m_componentsResolved(false)
, m_headerStretchLastSection(false)
{
m_treeView->setObjectName(QLatin1String("ComponentsTreeView"));
m_treeView->setUniformRowHeights(true);
- m_proxyModel->setRecursiveFilteringEnabled(true);
- m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
m_descriptionBaseWidget = new QWidget(q);
m_descriptionBaseWidget->setObjectName(QLatin1String("DescriptionBaseWidget"));
@@ -121,10 +119,21 @@ ComponentSelectionPagePrivate::ComponentSelectionPagePrivate(ComponentSelectionP
m_sizeLabel->setObjectName(QLatin1String("ComponentSizeLabel"));
descriptionVLayout->addWidget(m_sizeLabel);
+ m_createOfflinePushButton = new QPushButton(q);
+ m_createOfflinePushButton->setVisible(false);
+ m_createOfflinePushButton->setText(ComponentSelectionPage::tr("Create Offline Installer"));
+ m_createOfflinePushButton->setToolTip(
+ ComponentSelectionPage::tr("Create offline installer from selected components, instead "
+ "of installing now."));
+
+ connect(m_createOfflinePushButton, &QPushButton::clicked,
+ this, &ComponentSelectionPagePrivate::createOfflineButtonClicked);
+ connect(q, &ComponentSelectionPage::completeChanged,
+ this, [&]() { m_createOfflinePushButton->setEnabled(q->isComplete()); });
+
m_qbspPushButton = new QPushButton(q);
m_qbspPushButton->setVisible(false);
m_qbspPushButton->setText(ComponentSelectionPage::tr("Browse &QBSP files"));
- m_qbspPushButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
m_qbspPushButton->setToolTip(
ComponentSelectionPage::tr("Select a Qt Board Support Package file to install "
"additional content that is not directly available from the online repositories."));
@@ -133,18 +142,28 @@ ComponentSelectionPagePrivate::ComponentSelectionPagePrivate(ComponentSelectionP
this, &ComponentSelectionPagePrivate::qbspButtonClicked);
m_rightSideVLayout->addWidget(m_descriptionBaseWidget);
- m_rightSideVLayout->addWidget(m_qbspPushButton, 0, Qt::AlignRight | Qt::AlignBottom);
+ m_rightSideVLayout->addWidget(m_createOfflinePushButton);
+ m_rightSideVLayout->addWidget(m_qbspPushButton);
QHBoxLayout *topHLayout = new QHBoxLayout;
- m_checkStateComboBox = new QComboBox(q);
+
+ // Using custom combobox to workaround QTBUG-90595
+ m_checkStateComboBox = new CustomComboBox(q);
+#ifdef Q_OS_MACOS
QStyledItemDelegate *delegate = new QStyledItemDelegate(this);
m_checkStateComboBox->setItemDelegate(delegate);
+#endif
m_checkStateComboBox->setObjectName(QLatin1String("CheckStateComboBox"));
topHLayout->addWidget(m_checkStateComboBox);
connect(m_checkStateComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &ComponentSelectionPagePrivate::updateAllCheckStates);
+ // Workaround invisible placeholder text
+ QPalette palette = m_checkStateComboBox->palette();
+ palette.setColor(QPalette::PlaceholderText, palette.color(QPalette::Text));
+ m_checkStateComboBox->setPalette(palette);
+
m_checkStateComboBox->setPlaceholderText(ComponentSelectionPage::tr("Select"));
if (m_core->isInstaller()) {
m_checkStateComboBox->insertItem(scCheckDefaultIndex, ComponentSelectionPage::tr("Default"));
@@ -215,10 +234,6 @@ ComponentSelectionPagePrivate::ComponentSelectionPagePrivate(ComponentSelectionP
connect(m_core, SIGNAL(metaJobInfoMessage(QString)), this, SLOT(setMessage(QString)));
connect(m_core, &PackageManagerCore::metaJobTotalProgress, this,
&ComponentSelectionPagePrivate::setTotalProgress);
-
-#ifdef INSTALLCOMPRESSED
- allowCompressedRepositoryInstall();
-#endif
}
ComponentSelectionPagePrivate::~ComponentSelectionPagePrivate()
@@ -226,14 +241,14 @@ ComponentSelectionPagePrivate::~ComponentSelectionPagePrivate()
}
-void ComponentSelectionPagePrivate::allowCompressedRepositoryInstall()
+void ComponentSelectionPagePrivate::setAllowCreateOfflineInstaller(bool allow)
{
- m_allowCompressedRepositoryInstall = true;
+ m_allowCreateOfflineInstaller = allow;
}
void ComponentSelectionPagePrivate::showCompressedRepositoryButton()
{
- if (m_allowCompressedRepositoryInstall)
+ if (m_core->allowCompressedRepositoryInstall())
m_qbspPushButton->setVisible(true);
}
@@ -242,6 +257,14 @@ void ComponentSelectionPagePrivate::hideCompressedRepositoryButton()
m_qbspPushButton->setVisible(false);
}
+void ComponentSelectionPagePrivate::showCreateOfflineInstallerButton(bool show)
+{
+ if (show && m_allowCreateOfflineInstaller)
+ m_createOfflinePushButton->setVisible(m_core->isInstaller() && !m_core->isOfflineOnly());
+ else
+ m_createOfflinePushButton->setVisible(false);
+}
+
void ComponentSelectionPagePrivate::setupCategoryLayout()
{
if (m_categoryWidget)
@@ -288,11 +311,11 @@ void ComponentSelectionPagePrivate::showCategoryLayout(bool show)
if (show) {
m_rightSideVLayout->removeWidget(m_descriptionBaseWidget);
m_tabWidget->insertTab(0, m_descriptionBaseWidget, tr("Information"));
- m_rightSideVLayout->insertWidget(m_rightSideVLayout->count() - 1, m_tabWidget);
+ m_rightSideVLayout->insertWidget(0, m_tabWidget);
} else {
m_tabWidget->removeTab(0);
m_rightSideVLayout->removeWidget(m_tabWidget);
- m_rightSideVLayout->insertWidget(m_rightSideVLayout->count() - 1, m_descriptionBaseWidget);
+ m_rightSideVLayout->insertWidget(0, m_descriptionBaseWidget);
m_descriptionBaseWidget->setVisible(true);
}
m_tabWidget->setVisible(show);
@@ -463,27 +486,6 @@ void ComponentSelectionPagePrivate::deselectAll()
m_currentModel->setCheckedState(ComponentModel::AllUnchecked);
}
-void ComponentSelectionPagePrivate::enableRepositoryCategory(const QString &repositoryName, bool enable)
-{
- QMap<QString, RepositoryCategory> organizedRepositoryCategories = m_core->settings().organizedRepositoryCategories();
-
- QMap<QString, RepositoryCategory>::iterator i = organizedRepositoryCategories.find(repositoryName);
- RepositoryCategory repoCategory;
- while (i != organizedRepositoryCategories.end() && i.key() == repositoryName) {
- repoCategory = i.value();
- i++;
- }
-
- RepositoryCategory replacement = repoCategory;
- replacement.setEnabled(enable);
- QSet<RepositoryCategory> tmpRepoCategories = m_core->settings().repositoryCategories();
- if (tmpRepoCategories.contains(repoCategory)) {
- tmpRepoCategories.remove(repoCategory);
- tmpRepoCategories.insert(replacement);
- m_core->settings().addRepositoryCategories(tmpRepoCategories);
- }
-}
-
void ComponentSelectionPagePrivate::updateWidgetVisibility(bool show)
{
if (show)
@@ -511,7 +513,7 @@ void ComponentSelectionPagePrivate::fetchRepositoryCategories()
QList<QCheckBox*> checkboxes = m_categoryGroupBox->findChildren<QCheckBox *>();
for (int i = 0; i < checkboxes.count(); i++) {
QCheckBox *checkbox = checkboxes.at(i);
- enableRepositoryCategory(checkbox->objectName(), checkbox->isChecked());
+ m_core->enableRepositoryCategory(checkbox->objectName(), checkbox->isChecked());
}
if (!m_core->fetchRemotePackagesTree()) {
@@ -522,6 +524,12 @@ void ComponentSelectionPagePrivate::fetchRepositoryCategories()
m_searchLineEdit->text().isEmpty() ? expandDefault() : expandSearchResults();
}
+void ComponentSelectionPagePrivate::createOfflineButtonClicked()
+{
+ m_core->setOfflineGenerator();
+ q->gui()->button(QWizard::NextButton)->click();
+}
+
void ComponentSelectionPagePrivate::qbspButtonClicked()
{
QString defaultDownloadDirectory =
@@ -530,15 +538,8 @@ void ComponentSelectionPagePrivate::qbspButtonClicked()
ComponentSelectionPage::tr("Open File"),defaultDownloadDirectory,
QLatin1String("QBSP or 7z Files (*.qbsp *.7z)"));
- QSet<Repository> set;
- foreach (QString fileName, fileNames) {
- Repository repository = Repository::fromUserInput(fileName, true);
- repository.setEnabled(true);
- set.insert(repository);
- }
- if (set.count() > 0) {
+ if (m_core->addQBspRepositories(fileNames)) {
updateWidgetVisibility(true);
- m_core->settings().addTemporaryRepositories(set, false);
if (!m_core->fetchCompressedPackagesTree()) {
MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(),
QLatin1String("FailToFetchPackages"), tr("Error"), m_core->error());
diff --git a/src/libs/installer/componentselectionpage_p.h b/src/libs/installer/componentselectionpage_p.h
index ed68fafa4..187fce61d 100644
--- a/src/libs/installer/componentselectionpage_p.h
+++ b/src/libs/installer/componentselectionpage_p.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2023 The Qt Company Ltd.
+** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -48,13 +48,13 @@ class QVBoxLayout;
class QHBoxLayout;
class QGridLayout;
class QStackedLayout;
-class QComboBox;
namespace QInstaller {
class PackageManagerCore;
class ComponentModel;
class ComponentSelectionPage;
+class CustomComboBox;
class ComponentSelectionPagePrivate : public QObject
{
@@ -66,9 +66,10 @@ public:
explicit ComponentSelectionPagePrivate(ComponentSelectionPage *qq, PackageManagerCore *core);
~ComponentSelectionPagePrivate();
- void allowCompressedRepositoryInstall();
+ void setAllowCreateOfflineInstaller(bool allow);
void showCompressedRepositoryButton();
void hideCompressedRepositoryButton();
+ void showCreateOfflineInstallerButton(bool show);
void setupCategoryLayout();
void showCategoryLayout(bool show);
void updateTreeView();
@@ -81,9 +82,9 @@ public slots:
void updateAllCheckStates(int which);
void selectAll();
void deselectAll();
- void enableRepositoryCategory(const QString &repositoryName, bool enable);
void updateWidgetVisibility(bool show);
void fetchRepositoryCategories();
+ void createOfflineButtonClicked();
void qbspButtonClicked();
void onProgressChanged(int progress);
void setMessage(const QString &msg);
@@ -105,15 +106,16 @@ private:
QWidget *m_descriptionBaseWidget;
QLabel *m_sizeLabel;
QLabel *m_descriptionLabel;
+ QPushButton *m_createOfflinePushButton;
QPushButton *m_qbspPushButton;
- QComboBox *m_checkStateComboBox;
+ CustomComboBox *m_checkStateComboBox;
QWidget *m_categoryWidget;
QGroupBox *m_categoryGroupBox;
QLabel *m_metadataProgressLabel;
QProgressBar *m_progressBar;
QGridLayout *m_mainGLayout;
QVBoxLayout *m_rightSideVLayout;
- bool m_allowCompressedRepositoryInstall;
+ bool m_allowCreateOfflineInstaller;
bool m_categoryLayoutVisible;
ComponentModel *m_allModel;
ComponentModel *m_updaterModel;
diff --git a/src/libs/installer/constants.h b/src/libs/installer/constants.h
index ecd85fe11..7bf816b5f 100644
--- a/src/libs/installer/constants.h
+++ b/src/libs/installer/constants.h
@@ -60,6 +60,11 @@ static const QLatin1String scDisplayName("DisplayName");
static const QLatin1String scTreeName("TreeName");
static const QLatin1String scAutoTreeName("AutoTreeName");
static const QLatin1String scDependencies("Dependencies");
+static const QLatin1String scAlias("Alias");
+static const QLatin1String scRequiredAliases("RequiredAliases");
+static const QLatin1String scRequiredComponents("RequiredComponents");
+static const QLatin1String scOptionalAliases("OptionalAliases");
+static const QLatin1String scOptionalComponents("OptionalComponents");
static const QLatin1String scLocalDependencies("LocalDependencies");
static const QLatin1String scAutoDependOn("AutoDependOn");
static const QLatin1String scNewComponent("NewComponent");
@@ -75,7 +80,7 @@ static const QLatin1String scMetadataName("MetadataName");
static const QLatin1String scContentSha1("ContentSha1");
static const QLatin1String scCheckSha1CheckSum("CheckSha1CheckSum");
-static const char *scClearCacheHint = QT_TR_NOOP(
+static const char * const scClearCacheHint = QT_TR_NOOP(
"This may be solved by restarting the application after clearing the cache from:");
// symbols
@@ -102,6 +107,7 @@ static const QLatin1String scInstallDate("InstallDate");
static const QLatin1String scUserInterfaces("UserInterfaces");
static const QLatin1String scTranslations("Translations");
static const QLatin1String scLicenses("Licenses");
+static const QLatin1String scLicensesValue("licenses");
static const QLatin1String scLicense("License");
static const QLatin1String scOperations("Operations");
static const QLatin1String scInstallScript("installScript");
@@ -123,7 +129,6 @@ static const QLatin1String scMinimumProgress("MinimumProgress");
static const QLatin1String scDelete("Delete");
static const QLatin1String scCopy("Copy");
static const QLatin1String scMkdir("Mkdir");
-static const QLatin1String scPerformUndo("performUndo");
static const QLatin1String scIsDefault("isDefault");
static const QLatin1String scAdmin("admin");
static const QLatin1String scTwoArgs("%1/%2/");
@@ -152,6 +157,7 @@ static const QLatin1String scRemoteRepositories("RemoteRepositories");
static const QLatin1String scRepositoryCategories("RepositoryCategories");
static const QLatin1String scRepositorySettingsPageVisible("RepositorySettingsPageVisible");
static const QLatin1String scAllowSpaceInPath("AllowSpaceInPath");
+static const QLatin1String scAllowRepositoriesForOfflineInstaller("AllowRepositoriesForOfflineInstaller");
static const QLatin1String scWizardStyle("WizardStyle");
static const QLatin1String scStyleSheet("StyleSheet");
static const QLatin1String scTitleColor("TitleColor");
@@ -174,7 +180,15 @@ static const QLatin1String scBanner("Banner");
static const QLatin1String scLogo("Logo");
static const QLatin1String scBackground("Background");
static const QLatin1String scPageListPixmap("PageListPixmap");
+static const QLatin1String scAliasDefinitionsFile("AliasDefinitionsFile");
const char scRelocatable[] = "@RELOCATABLE_PATH@";
+
+static const QStringList scMetaElements = {
+ QLatin1String("Script"),
+ QLatin1String("Licenses"),
+ QLatin1String("UserInterfaces"),
+ QLatin1String("Translations")
+};
}
namespace CommandLineOptions {
@@ -271,6 +285,7 @@ static const QLatin1String scFilterPackagesShort("fp");
static const QLatin1String scFilterPackagesLong("filter-packages");
static const QLatin1String scLocalCachePathShort("cp");
static const QLatin1String scLocalCachePathLong("cache-path");
+static const QLatin1String scTypeLong("type");
// Developer options
static const QLatin1String scScriptShort("s");
diff --git a/src/libs/installer/copydirectoryoperation.cpp b/src/libs/installer/copydirectoryoperation.cpp
index a2ef2cf5a..c0fec0649 100644
--- a/src/libs/installer/copydirectoryoperation.cpp
+++ b/src/libs/installer/copydirectoryoperation.cpp
@@ -153,7 +153,7 @@ bool CopyDirectoryOperation::performOperation()
bool CopyDirectoryOperation::undoOperation()
{
- if (parseUndoOperationArguments().count() > 0)
+ if (skipUndoOperation())
return true;
if (!checkArgumentCount(2))
diff --git a/src/libs/installer/copyfiletask.cpp b/src/libs/installer/copyfiletask.cpp
index 72b28d896..856feda01 100644
--- a/src/libs/installer/copyfiletask.cpp
+++ b/src/libs/installer/copyfiletask.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -112,7 +112,7 @@ void CopyFileTask::doTask(QFutureInterface<FileTaskResult> &fi)
observer.addSample(read);
observer.timerEvent(nullptr);
observer.addBytesTransfered(read);
- observer.addCheckSumData(buffer.data(), read);
+ observer.addCheckSumData(buffer.left(read));
fi.setProgressValueAndText(observer.progressValue(), observer.progressText());
}
diff --git a/src/libs/installer/createdesktopentryoperation.cpp b/src/libs/installer/createdesktopentryoperation.cpp
index c3988a8ec..a19fd773a 100644
--- a/src/libs/installer/createdesktopentryoperation.cpp
+++ b/src/libs/installer/createdesktopentryoperation.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -32,6 +32,7 @@
#include "globals.h"
#include "adminauthorization.h"
#include "remoteclient.h"
+#include "packagemanagercore.h"
#include <QDir>
#include <QFile>
@@ -64,7 +65,7 @@ QString CreateDesktopEntryOperation::absoluteFileName()
XDG_DATA_HOME.push_back(QDir::home().absoluteFilePath(QLatin1String(".local/share"))); // default user-specific path
- if (AdminAuthorization::hasAdminRights() || RemoteClient::instance().isActive())
+ if (packageManager() && packageManager()->hasAdminRights())
XDG_DATA_HOME.push_front(QLatin1String("/usr/local/share")); // default system-wide path
const QStringList directories = XDG_DATA_HOME;
@@ -151,15 +152,16 @@ bool CreateDesktopEntryOperation::performOperation()
setDefaultFilePermissions(filename, DefaultFilePermissions::Executable);
- QTextStream stream(&file);
- stream.setCodec("UTF-8");
- stream << QLatin1String("[Desktop Entry]") << endl;
+ QString outString;
+ QTextStream stream(&outString);
+ stream << QLatin1String("[Desktop Entry]") << Qt::endl;
// Type=Application\nExec=qtcreator\nPath=...
const QStringList pairs = values.split(QLatin1Char('\n'));
for (QStringList::const_iterator it = pairs.begin(); it != pairs.end(); ++it)
stream << *it << Qt::endl;
+ file.write(outString.toUtf8());
return true;
}
diff --git a/src/libs/installer/createlocalrepositoryoperation.cpp b/src/libs/installer/createlocalrepositoryoperation.cpp
index 7090f9a8b..286cc9b5b 100644
--- a/src/libs/installer/createlocalrepositoryoperation.cpp
+++ b/src/libs/installer/createlocalrepositoryoperation.cpp
@@ -378,7 +378,7 @@ bool CreateLocalRepositoryOperation::performOperation()
bool CreateLocalRepositoryOperation::undoOperation()
{
- if (parseUndoOperationArguments().count() > 0)
+ if (skipUndoOperation())
return true;
if (!checkArgumentCount(2))
diff --git a/src/libs/installer/createshortcutoperation.cpp b/src/libs/installer/createshortcutoperation.cpp
index 57f901c2f..894b5843b 100644
--- a/src/libs/installer/createshortcutoperation.cpp
+++ b/src/libs/installer/createshortcutoperation.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -110,6 +110,7 @@ static bool createLink(const QString &fileName, const QString &linkName, QString
IUnknown *iunkn = nullptr;
if (fileName.toLower().startsWith(QLatin1String("http:"))
+ || fileName.toLower().startsWith(QLatin1String("https:"))
|| fileName.toLower().startsWith(QLatin1String("ftp:"))) {
IUniformResourceLocator *iurl = nullptr;
if (FAILED(CoCreateInstance(CLSID_InternetShortcut, nullptr, CLSCTX_INPROC_SERVER,
@@ -176,6 +177,7 @@ static bool createLink(const QString &fileName, const QString &linkName, QString
Q_UNUSED(linkName)
Q_UNUSED(iconPath)
Q_UNUSED(iconId)
+ Q_UNUSED(description)
return true;
#endif
}
diff --git a/src/libs/installer/customcombobox.cpp b/src/libs/installer/customcombobox.cpp
new file mode 100644
index 000000000..998364fe4
--- /dev/null
+++ b/src/libs/installer/customcombobox.cpp
@@ -0,0 +1,54 @@
+/**************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#include "customcombobox.h"
+
+#include <QStylePainter>
+
+using namespace QInstaller;
+
+CustomComboBox::CustomComboBox(QWidget *parent)
+ : QComboBox(parent)
+{
+}
+
+void CustomComboBox::paintEvent(QPaintEvent *e)
+{
+ if (currentIndex() < 0 && !placeholderText().isEmpty()) {
+ QStylePainter painter(this);
+ painter.setPen(palette().color(QPalette::Text));
+ QStyleOptionComboBox opt;
+ initStyleOption(&opt);
+ painter.drawComplexControl(QStyle::CC_ComboBox, opt);
+ opt.palette.setBrush(QPalette::ButtonText, opt.palette.placeholderText());
+ opt.currentText = placeholderText();
+ painter.drawControl(QStyle::CE_ComboBoxLabel, opt);
+ } else {
+ QComboBox::paintEvent(e);
+ }
+}
diff --git a/src/libs/installer/customcombobox.h b/src/libs/installer/customcombobox.h
new file mode 100644
index 000000000..e022da5a8
--- /dev/null
+++ b/src/libs/installer/customcombobox.h
@@ -0,0 +1,48 @@
+/**************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#ifndef CUSTOMCOMBOBOX_H
+#define CUSTOMCOMBOBOX_H
+
+#include <QComboBox>
+
+namespace QInstaller {
+
+class CustomComboBox : public QComboBox
+{
+ Q_OBJECT
+public:
+ CustomComboBox(QWidget *parent = nullptr);
+
+protected:
+ void paintEvent(QPaintEvent *e) override;
+};
+
+} // namespace QInstaller
+
+#endif // CUSTOMCOMBOBOX_H
diff --git a/src/libs/installer/downloadarchivesjob.cpp b/src/libs/installer/downloadarchivesjob.cpp
index 48700bd12..65eead1f9 100644
--- a/src/libs/installer/downloadarchivesjob.cpp
+++ b/src/libs/installer/downloadarchivesjob.cpp
@@ -44,10 +44,12 @@ using namespace QInstaller;
using namespace KDUpdater;
+static constexpr uint scMaxRetries = 5;
+
/*!
Creates a new DownloadArchivesJob with parent \a core.
*/
-DownloadArchivesJob::DownloadArchivesJob(PackageManagerCore *core)
+DownloadArchivesJob::DownloadArchivesJob(PackageManagerCore *core, const QString &objectName)
: Job(core)
, m_core(core)
, m_downloader(nullptr)
@@ -58,8 +60,10 @@ DownloadArchivesJob::DownloadArchivesJob(PackageManagerCore *core)
, m_progressChangedTimerId(0)
, m_totalSizeToDownload(0)
, m_totalSizeDownloaded(0)
+ , m_retryCount(scMaxRetries)
{
setCapabilities(Cancelable);
+ setObjectName(objectName);
}
/*!
@@ -289,17 +293,24 @@ void DownloadArchivesJob::registerFile()
const QMessageBox::Button res =
MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(),
QLatin1String("DownloadError"), tr("Download Error"), tr("Hash verification while "
- "downloading failed. This is a temporary error, please retry."),
- QMessageBox::Retry | QMessageBox::Cancel, QMessageBox::Cancel);
-
- // If run from command line instance, do not continue if hash verification failed.
- // Same download is tried again and again causing infinite loop if hash not
- // fixed to repositories.
- if (res == QMessageBox::Cancel || m_core->isCommandLineInstance()) {
- finishWithError(tr("Cannot verify Hash"));
+ "downloading failed. This is a temporary error, please retry.\n\n"
+ "Expected: %1 \nDownloaded: %2").arg(QString::fromLatin1(m_currentHash), QString::fromLatin1(m_downloader->sha1Sum().toHex())),
+ QMessageBox::Retry | QMessageBox::Cancel, QMessageBox::Retry);
+
+ if (res == QMessageBox::Cancel) {
+ finishWithError(tr("Cannot verify Hash\nExpected: %1 \nDownloaded: %2")
+ .arg(QString::fromLatin1(m_currentHash), QString::fromLatin1(m_downloader->sha1Sum().toHex())));
return;
}
+ // When using command line instance, only retry a number of times to avoid
+ // infinite loop in case the automatic answer for the messagebox is "Retry"
+ if (m_core->isCommandLineInstance() && (--m_retryCount == 0)) {
+ finishWithError(tr("Retry count (%1) exceeded").arg(scMaxRetries));
+ return;
+ }
} else {
+ m_retryCount = scMaxRetries;
+
++m_archivesDownloaded;
m_totalSizeDownloaded += QFile(m_downloader->downloadedFileName()).size();
if (m_progressChangedTimerId) {
@@ -330,14 +341,21 @@ void DownloadArchivesJob::downloadFailed(const QString &error)
const QMessageBox::StandardButton b =
MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(),
QLatin1String("archiveDownloadError"), tr("Download Error"), tr("Cannot download archive %1: %2")
- .arg(m_archivesToDownload.first().sourceUrl, error), QMessageBox::Retry | QMessageBox::Cancel);
+ .arg(m_archivesToDownload.first().sourceUrl, error), QMessageBox::Retry | QMessageBox::Cancel,
+ QMessageBox::Retry);
+
+ if (b == QMessageBox::Retry) {
+ // When using command line instance, only retry a number of times to avoid
+ // infinite loop in case the automatic answer for the messagebox is "Retry"
+ if (m_core->isCommandLineInstance() && (--m_retryCount == 0)) {
+ finishWithError(tr("Retry count (%1) exceeded").arg(scMaxRetries));
+ return;
+ }
- // Do not call fetchNextArchiveHash when using command line instance,
- // installer tries to download the same archive causing infinite loop
- if (b == QMessageBox::Retry && !m_core->isCommandLineInstance())
QMetaObject::invokeMethod(this, "fetchNextArchiveHash", Qt::QueuedConnection);
- else
+ } else {
downloadCanceled();
+ }
}
void DownloadArchivesJob::finishWithError(const QString &error)
diff --git a/src/libs/installer/downloadarchivesjob.h b/src/libs/installer/downloadarchivesjob.h
index c156d0244..5155c881a 100644
--- a/src/libs/installer/downloadarchivesjob.h
+++ b/src/libs/installer/downloadarchivesjob.h
@@ -51,7 +51,7 @@ class DownloadArchivesJob : public Job
Q_OBJECT
public:
- explicit DownloadArchivesJob(PackageManagerCore *core);
+ explicit DownloadArchivesJob(PackageManagerCore *core, const QString &objectName);
~DownloadArchivesJob();
int numberOfDownloads() const { return m_archivesDownloaded; }
@@ -103,6 +103,8 @@ private:
quint64 m_totalSizeToDownload;
quint64 m_totalSizeDownloaded;
QElapsedTimer m_totalDownloadSpeedTimer;
+
+ uint m_retryCount;
};
} // namespace QInstaller
diff --git a/src/libs/installer/downloadfiletask.cpp b/src/libs/installer/downloadfiletask.cpp
index 1b9f81ecc..a959677a9 100644
--- a/src/libs/installer/downloadfiletask.cpp
+++ b/src/libs/installer/downloadfiletask.cpp
@@ -1,7 +1,7 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -30,6 +30,7 @@
#include "downloadfiletask_p.h"
#include "globals.h"
+#include "productkeycheck.h"
#include <QCoreApplication>
#include <QDir>
@@ -197,7 +198,7 @@ void Downloader::onReadyRead()
data.observer->addSample(read);
data.observer->addBytesTransfered(read);
- data.observer->addCheckSumData(buffer.data(), read);
+ data.observer->addCheckSumData(buffer.left(read));
int progress = m_finished * 100;
for (const auto &pair : m_downloads)
@@ -246,7 +247,7 @@ void Downloader::onFinished(QNetworkReply *reply)
if (!ba.isEmpty()) {
data.observer->addSample(ba.size());
data.observer->addBytesTransfered(ba.size());
- data.observer->addCheckSumData(ba.data(), ba.size());
+ data.observer->addCheckSumData(ba);
}
const QByteArray expectedCheckSum = data.taskItem.value(TaskRole::Checksum).toByteArray();
@@ -269,7 +270,7 @@ void Downloader::onFinished(QNetworkReply *reply)
}
}
-void Downloader::onError(QNetworkReply::NetworkError error)
+void Downloader::errorOccurred(QNetworkReply::NetworkError error)
{
QNetworkReply *const reply = qobject_cast<QNetworkReply *>(sender());
@@ -286,6 +287,10 @@ void Downloader::onError(QNetworkReply::NetworkError error)
if (data.taskItem.source().contains(QLatin1String("Updates.xml"), Qt::CaseInsensitive)) {
qCWarning(QInstaller::lcServer) << QString::fromLatin1("Network error while downloading '%1': %2.").arg(
data.taskItem.source(), reply->errorString());
+ } else if (data.taskItem.source().contains(QLatin1String("_meta"), Qt::CaseInsensitive)) {
+ QString errorString = tr("Network error while downloading '%1': %2.").arg(data.taskItem.source(), reply->errorString());
+ errorString.append(ProductKeyCheck::instance()->additionalMetaDownloadWarning());
+ m_futureInterface->reportException(TaskException(errorString));
} else {
m_futureInterface->reportException(
TaskException(tr("Network error while downloading '%1': %2.").arg(
@@ -395,14 +400,17 @@ QNetworkReply *Downloader::startDownload(const FileTaskItem &item)
.arg(source.toString(), source.errorString())));
return 0;
}
+ QNetworkRequest request(source);
+ request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::ManualRedirectPolicy);
+ request.setAttribute(QNetworkRequest::Http2AllowedAttribute, false);
- QNetworkReply *reply = m_nam.get(QNetworkRequest(source));
+ QNetworkReply *reply = m_nam.get(request);
std::unique_ptr<Data> data(new Data(item));
m_downloads[reply] = std::move(data);
connect(reply, &QIODevice::readyRead, this, &Downloader::onReadyRead);
- connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this,
- SLOT(onError(QNetworkReply::NetworkError)));
+ connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this,
+ SLOT(errorOccurred(QNetworkReply::NetworkError)));
#ifndef QT_NO_SSL
connect(reply, &QNetworkReply::sslErrors, this, &Downloader::onSslErrors);
#endif
diff --git a/src/libs/installer/downloadfiletask_p.h b/src/libs/installer/downloadfiletask_p.h
index 3dfce27b4..4750d5134 100644
--- a/src/libs/installer/downloadfiletask_p.h
+++ b/src/libs/installer/downloadfiletask_p.h
@@ -86,7 +86,7 @@ private slots:
void doDownload();
void onReadyRead();
void onFinished(QNetworkReply *reply);
- void onError(QNetworkReply::NetworkError error);
+ void errorOccurred(QNetworkReply::NetworkError error);
void onSslErrors(const QList<QSslError> &sslErrors);
void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
void onAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator);
diff --git a/src/libs/installer/environmentvariablesoperation.cpp b/src/libs/installer/environmentvariablesoperation.cpp
index 902687164..94cd1e36f 100644
--- a/src/libs/installer/environmentvariablesoperation.cpp
+++ b/src/libs/installer/environmentvariablesoperation.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -30,6 +30,7 @@
#include "qsettingswrapper.h"
#include <stdlib.h>
+#include <QDir>
#include "environment.h"
#include "globals.h"
@@ -110,6 +111,12 @@ bool handleRegExpandSz(const QString &regPath, const QString &name,
}
}
}
+#else
+ Q_UNUSED(regPath)
+ Q_UNUSED(name)
+ Q_UNUSED(value)
+ Q_UNUSED(errorString)
+ Q_UNUSED(error)
#endif
return setAsExpandSZ;
}
@@ -162,11 +169,11 @@ UpdateOperation::Error undoSetting(const QString &regPath,
if (actual != value)
{
- //For unknown reason paths with @TargetDir@ variable get modified
- //so that Windows file separators get replaced with unix style separators,
- //fix separators before matching to actual value in register
+ //Ignore the separators
+ static const QRegularExpression regex(QLatin1String("(\\\\|/)"));
QString tempValue = value;
- QString fixedValue = tempValue.replace(QLatin1Char('/'), QLatin1Char('\\'));
+ QString fixedValue = tempValue.replace(regex, QDir::separator());
+ actual = actual.replace(regex, QDir::separator());
if (actual != fixedValue) //key changed, don't undo
return UpdateOperation::UserDefinedError;
diff --git a/src/libs/installer/extractarchiveoperation.cpp b/src/libs/installer/extractarchiveoperation.cpp
index 162bd1609..b00a67190 100644
--- a/src/libs/installer/extractarchiveoperation.cpp
+++ b/src/libs/installer/extractarchiveoperation.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -103,7 +103,7 @@ void ExtractArchiveOperation::backup()
return;
}
- const bool hasAdminRights = (AdminAuthorization::hasAdminRights() || RemoteClient::instance().isActive());
+ const bool hasAdminRights = (packageManager() && packageManager()->hasAdminRights());
const bool canCreateSymLinks = QInstaller::canCreateSymbolicLinks();
bool needsAdminRights = false;
@@ -215,7 +215,8 @@ bool ExtractArchiveOperation::performOperation()
}
files[i] = replacePath(files.at(i), installDir, QLatin1String(scRelocatable));
}
- out << files;
+ if (!files.isEmpty())
+ out << files;
setValue(QLatin1String("files"), file.fileName());
file.close();
} else {
@@ -253,7 +254,8 @@ bool ExtractArchiveOperation::undoOperation()
if (!readDataFileContents(targetDir, &files))
return false;
}
- startUndoProcess(files);
+ if (!files.isEmpty())
+ startUndoProcess(files);
if (!useStringListType)
deleteDataFile(m_relocatedDataFileName);
diff --git a/src/libs/installer/fakestopprocessforupdateoperation.cpp b/src/libs/installer/fakestopprocessforupdateoperation.cpp
index 67d60a92f..bdd8625eb 100644
--- a/src/libs/installer/fakestopprocessforupdateoperation.cpp
+++ b/src/libs/installer/fakestopprocessforupdateoperation.cpp
@@ -31,6 +31,8 @@
#include "messageboxhandler.h"
#include "packagemanagercore.h"
+#include <QDir>
+
using namespace KDUpdater;
using namespace QInstaller;
@@ -79,11 +81,11 @@ bool FakeStopProcessForUpdateOperation::undoOperation()
if (processes.count() == 1) {
setError(UpdateOperation::UserDefinedError, tr("This process should be stopped before "
- "continuing: %1").arg(processes.first()));
+ "continuing: %1").arg(QDir::toNativeSeparators(processes.first())));
} else {
const QString sep = QString::fromWCharArray(L"\n \u2022 "); // Unicode bullet
setError(UpdateOperation::UserDefinedError, tr("These processes should be stopped before "
- "continuing: %1").arg(sep + processes.join(sep)));
+ "continuing: %1").arg(sep + QDir::toNativeSeparators(processes.join(sep))));
}
return false;
}
diff --git a/src/libs/installer/fileutils.cpp b/src/libs/installer/fileutils.cpp
index 2147a8978..044eeb34f 100644
--- a/src/libs/installer/fileutils.cpp
+++ b/src/libs/installer/fileutils.cpp
@@ -734,7 +734,7 @@ quint64 QInstaller::fileSize(const QFileInfo &info)
bool QInstaller::isInBundle(const QString &path, QString *bundlePath)
{
#ifdef Q_OS_MACOS
- QFileInfo fi = QFileInfo(path).absoluteFilePath();
+ QFileInfo fi(QFileInfo(path).absoluteFilePath());
while (!fi.isRoot()) {
if (fi.isBundle()) {
if (bundlePath)
diff --git a/src/libs/installer/genericdatacache.cpp b/src/libs/installer/genericdatacache.cpp
index fd264ce63..a1e31ccfe 100644
--- a/src/libs/installer/genericdatacache.cpp
+++ b/src/libs/installer/genericdatacache.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -120,6 +120,16 @@ CacheableItem::~CacheableItem()
*/
/*!
+ \enum GenericDataCache::RegisterMode
+ This enum holds the possible values for modes of registering items to cache.
+
+ \value Copy
+ The contents of the item are copied to the cache.
+ \value Move
+ The contents of the item are move to the cache.
+*/
+
+/*!
\fn template <typename T> QInstaller::GenericDataCache<T>::GenericDataCache()
Constructs a new empty cache. The cache is invalid until set with a
@@ -411,19 +421,20 @@ T *GenericDataCache<T>::itemByPath(const QString &path) const
}
/*!
- \fn template <typename T> QInstaller::GenericDataCache<T>::registerItem(T *item, bool replace)
+ \fn template <typename T> QInstaller::GenericDataCache<T>::registerItem(T *item, bool replace, RegisterMode mode)
Registers the \a item to the cache. If \a replace is set to \c true,
the new \a item replaces a previous item with the same checksum.
The cache takes ownership of the object pointed by \a item. The contents of the
- item are copied to the cache with a subdirectory name that matches the checksum
- of the item.
+ item are copied or moved to the cache with a subdirectory name that matches the checksum
+ of the item. The \a mode decides how the contents of the item are registered, either by
+ copying or moving.
Returns \c true on success or \c false if the item could not be registered.
*/
template <typename T>
-bool GenericDataCache<T>::registerItem(T *item, bool replace)
+bool GenericDataCache<T>::registerItem(T *item, bool replace, RegisterMode mode)
{
QMutexLocker _(&m_mutex);
if (m_invalidated) {
@@ -455,10 +466,27 @@ bool GenericDataCache<T>::registerItem(T *item, bool replace)
const QString newPath = m_path + QDir::separator() + QString::fromLatin1(item->checksum());
try {
// A directory is in the way but it isn't registered to the current cache, remove.
- if (QDir().exists(newPath))
+ QDir dir;
+ if (dir.exists(newPath))
QInstaller::removeDirectory(newPath);
- QInstaller::copyDirectoryContents(item->path(), newPath);
+ switch (mode) {
+ case Copy:
+ QInstaller::copyDirectoryContents(item->path(), newPath);
+ break;
+ case Move:
+ // First, try moving the top level directory
+ if (!dir.rename(item->path(), newPath)) {
+ qCDebug(lcDeveloperBuild) << "Failed to rename directory" << item->path()
+ << "to" << newPath << ". Trying again.";
+ // If that does not work, fallback to moving the contents one by one
+ QInstaller::moveDirectoryContents(item->path(), newPath);
+ }
+ break;
+ default:
+ throw Error(QCoreApplication::translate("GenericDataCache",
+ "Unknown register mode selected!"));
+ }
} catch (const Error &e) {
setErrorString(QCoreApplication::translate("GenericDataCache",
"Error while copying item to path \"%1\": %2").arg(newPath, e.message()));
@@ -587,8 +615,8 @@ bool GenericDataCache<T>::fromDisk()
for (const auto &itemJsonValue : itemsJsonArray) {
const QString checksum = itemJsonValue.toString();
- QScopedPointer<T> item(new T(m_path + QDir::separator() + checksum));
- m_items.insert(checksum.toLatin1(), item.take());
+ std::unique_ptr<T> item(new T(m_path + QDir::separator() + checksum));
+ m_items.insert(checksum.toLatin1(), item.release());
// The cache directory may contain other entries (unrelated directories or
// invalid old cache items) which we don't care about, unless registering
diff --git a/src/libs/installer/genericdatacache.h b/src/libs/installer/genericdatacache.h
index 2bdf6697e..94085502c 100644
--- a/src/libs/installer/genericdatacache.h
+++ b/src/libs/installer/genericdatacache.h
@@ -64,9 +64,14 @@ template <typename T>
class INSTALLER_EXPORT GenericDataCache
{
public:
+ enum RegisterMode {
+ Copy = 0,
+ Move = 1
+ };
+
GenericDataCache();
explicit GenericDataCache(const QString &path, const QString &type, const QString &version);
- ~GenericDataCache();
+ virtual ~GenericDataCache();
void setType(const QString &type);
void setVersion(const QString &version);
@@ -85,7 +90,7 @@ public:
T *itemByChecksum(const QByteArray &checksum) const;
T *itemByPath(const QString &path) const;
- bool registerItem(T *item, bool replace = false);
+ bool registerItem(T *item, bool replace = false, RegisterMode mode = Copy);
bool removeItem(const QByteArray &checksum);
QList<T *> obsoleteItems() const;
diff --git a/src/libs/installer/globals.cpp b/src/libs/installer/globals.cpp
index 5240138c4..3fd084768 100644
--- a/src/libs/installer/globals.cpp
+++ b/src/libs/installer/globals.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2023 The Qt Company Ltd.
+** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -30,6 +30,14 @@
#include "globals.h"
+#if defined(Q_OS_MACOS) || defined(Q_OS_LINUX)
+#include <termios.h>
+#include <unistd.h>
+#elif defined(Q_OS_WIN)
+#include <conio.h>
+#endif
+#include <iostream>
+
const char IFW_SERVER[] = "ifw.server";
const char IFW_INSTALLER_INSTALLLOG[] = "ifw.installer.installlog";
const char IFW_DEVELOPER_BUILD[] = "ifw.developer.build";
@@ -78,7 +86,9 @@ QStringList loggingCategories()
{
static QStringList categories = QStringList()
<< QLatin1String(IFW_INSTALLER_INSTALLLOG)
- << QLatin1String(IFW_SERVER);
+ << QLatin1String(IFW_SERVER)
+ << QLatin1String(IFW_DEVELOPER_BUILD)
+ << QLatin1String("js");
return categories;
}
@@ -117,5 +127,52 @@ QString enumToString(const QMetaObject& metaObject, const char *enumerator, int
return value;
}
+void askForCredentials(QString *username, QString *password, const QString &usernameTitle, const QString &passwordTitle)
+{
+ std::string usernameStdStr;
+ std::string passwordStdStr;
+
+ std::cout << qPrintable(usernameTitle);
+ std::cin >> usernameStdStr;
+
+ std::cout << qPrintable(passwordTitle);
+#if defined(Q_OS_MACOS) || defined(Q_OS_LINUX)
+ termios oldTerm;
+ termios term;
+
+ // Turn off echoing
+ tcgetattr(STDIN_FILENO, &oldTerm);
+ term = oldTerm;
+ term.c_lflag &= ~ECHO;
+ tcsetattr(STDIN_FILENO, TCSANOW, &term);
+
+ std::cin >> passwordStdStr;
+
+ // Clear input buffer
+ std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
+
+ // Restore old attributes
+ tcsetattr(STDIN_FILENO, TCSANOW, &oldTerm);
+#elif defined(Q_OS_WIN)
+ char ch;
+ while ((ch = _getch()) != '\r') { // Return key
+ if (ch == '\b') { // Backspace key
+ if (!passwordStdStr.empty())
+ passwordStdStr.pop_back();
+ } else {
+ passwordStdStr.push_back(ch);
+ }
+ }
+ // Clear input buffer
+ int c;
+ while ((c = getchar()) != '\n' && c != EOF);
+
+#endif
+ std::cout << "\n";
+
+ *username = username->fromStdString(usernameStdStr);
+ *password = password->fromStdString(passwordStdStr);
+}
+
} // namespace QInstaller
diff --git a/src/libs/installer/globals.h b/src/libs/installer/globals.h
index 3b3f4e3ab..2d119048b 100644
--- a/src/libs/installer/globals.h
+++ b/src/libs/installer/globals.h
@@ -59,6 +59,8 @@ QSet<T> toQSet(const C<T> &container)
return QSet<T>(container.begin(), container.end());
}
+void askForCredentials(QString *username, QString *password, const QString &usernameTitle, const QString &passwordTitle);
+
} // QInstaller
#endif // GLOBALS_H
diff --git a/src/libs/installer/globalsettingsoperation.cpp b/src/libs/installer/globalsettingsoperation.cpp
index 9608bba66..6ca50f96f 100644
--- a/src/libs/installer/globalsettingsoperation.cpp
+++ b/src/libs/installer/globalsettingsoperation.cpp
@@ -77,7 +77,7 @@ bool GlobalSettingsOperation::performOperation()
bool GlobalSettingsOperation::undoOperation()
{
- if (parseUndoOperationArguments().count() > 0)
+ if (skipUndoOperation())
return true;
const QStringList args = parsePerformOperationArguments();
diff --git a/src/libs/installer/installer.pro b/src/libs/installer/installer.pro
index 5a58968ee..ff7a0eed2 100644
--- a/src/libs/installer/installer.pro
+++ b/src/libs/installer/installer.pro
@@ -47,11 +47,13 @@ greaterThan(QT_MAJOR_VERSION, 5):QT += core5compat
HEADERS += packagemanagercore.h \
aspectratiolabel.h \
calculatorbase.h \
+ componentalias.h \
componentsortfilterproxymodel.h \
concurrentoperationrunner.h \
genericdatacache.h \
loggingutils.h \
metadata.h \
+ metadatacache.h \
packagemanagercore_p.h \
packagemanagergui.h \
binaryformat.h \
@@ -144,13 +146,15 @@ HEADERS += packagemanagercore.h \
abstractarchive.h \
directoryguard.h \
archivefactory.h \
- operationtracer.h
+ operationtracer.h \
+ customcombobox.h
SOURCES += packagemanagercore.cpp \
abstractarchive.cpp \
archivefactory.cpp \
aspectratiolabel.cpp \
calculatorbase.cpp \
+ componentalias.cpp \
concurrentoperationrunner.cpp \
directoryguard.cpp \
fileguard.cpp \
@@ -158,6 +162,7 @@ SOURCES += packagemanagercore.cpp \
genericdatacache.cpp \
loggingutils.cpp \
metadata.cpp \
+ metadatacache.cpp \
operationtracer.cpp \
packagemanagercore_p.cpp \
packagemanagergui.cpp \
@@ -231,7 +236,8 @@ SOURCES += packagemanagercore.cpp \
packagesource.cpp \
repositorycategory.cpp \
componentselectionpage_p.cpp \
- commandlineparser.cpp
+ commandlineparser.cpp \
+ customcombobox.cpp
macos:SOURCES += fileutils_mac.mm
diff --git a/src/libs/installer/installer_global.h b/src/libs/installer/installer_global.h
index ea6865042..285eff910 100644
--- a/src/libs/installer/installer_global.h
+++ b/src/libs/installer/installer_global.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -40,4 +40,10 @@
# define INSTALLER_EXPORT
#endif
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+typedef uint hashValue;
+#else
+typedef size_t hashValue;
+#endif
+
#endif //INSTALLER_GLOBAL_H
diff --git a/src/libs/installer/installercalculator.cpp b/src/libs/installer/installercalculator.cpp
index 105e99fd8..4c53824af 100644
--- a/src/libs/installer/installercalculator.cpp
+++ b/src/libs/installer/installercalculator.cpp
@@ -29,6 +29,8 @@
#include "installercalculator.h"
#include "component.h"
+#include "componentalias.h"
+#include "componentmodel.h"
#include "packagemanagercore.h"
#include "settings.h"
#include <globals.h>
@@ -51,6 +53,19 @@ InstallerCalculator::~InstallerCalculator()
{
}
+bool InstallerCalculator::solve()
+{
+ if (!solve(m_core->aliasesMarkedForInstallation()))
+ return false;
+
+ // Subtract components added by aliases
+ QList<Component *> components = m_core->componentsMarkedForInstallation();
+ for (auto *component : qAsConst(m_resolvedComponents))
+ components.removeAll(component);
+
+ return solve(components);
+}
+
QString InstallerCalculator::resolutionText(Component *component) const
{
const Resolution reason = resolutionType(component);
@@ -67,6 +82,9 @@ QString InstallerCalculator::resolutionText(Component *component) const
case Resolution::Selected:
return QCoreApplication::translate("InstallerCalculator",
"Selected components without dependencies:");
+ case Resolution::Alias:
+ return QCoreApplication::translate("InstallerCalculator",
+ "Components selected by alias \"%1\":").arg(referencedComponent(component));
default:
Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid install resolution detected!");
}
@@ -110,6 +128,44 @@ bool InstallerCalculator::solve(const QList<Component *> &components)
return true;
}
+bool InstallerCalculator::solve(const QList<ComponentAlias *> &aliases)
+{
+ if (aliases.isEmpty())
+ return true;
+
+ QList<ComponentAlias *> notAppendedAliases; // Aliases that require other aliases
+ for (auto *alias : aliases) {
+ if (!alias)
+ continue;
+
+ if (m_toInstallComponentAliases.contains(alias->name())) {
+ const QString errorMessage = QCoreApplication::translate("InstallerCalculator",
+ "Recursion detected, component alias \"%1\" already added.").arg(alias->name());
+ qCWarning(QInstaller::lcInstallerInstallLog).noquote() << errorMessage;
+ m_errorString.append(errorMessage);
+
+ Q_ASSERT_X(!m_toInstallComponentAliases.contains(alias->name()), Q_FUNC_INFO,
+ qPrintable(errorMessage));
+
+ return false;
+ }
+
+ if (alias->aliases().isEmpty()) {
+ if (!addComponentsFromAlias(alias))
+ return false;
+ } else {
+ notAppendedAliases.append(alias);
+ }
+ }
+
+ for (auto *alias : qAsConst(notAppendedAliases)) {
+ if (!solveAlias(alias))
+ return false;
+ }
+
+ return true;
+}
+
void InstallerCalculator::addComponentForInstall(Component *component, const QString &version)
{
if (!m_componentsForAutodepencencyCheck.contains(component))
@@ -121,12 +177,40 @@ void InstallerCalculator::addComponentForInstall(Component *component, const QSt
}
}
+bool InstallerCalculator::addComponentsFromAlias(ComponentAlias *alias)
+{
+ QList<Component *> componentsToAdd;
+ for (auto *component : alias->components()) {
+ if (m_toInstallComponentIds.contains(component->name()))
+ continue; // Already added
+
+ componentsToAdd.append(component);
+ // Updates the model, so that we also check the descendant
+ // components when calculating components to install
+ updateCheckState(component, Qt::Checked);
+ insertResolution(component, Resolution::Alias, alias->name());
+ }
+
+ m_toInstallComponentAliases.insert(alias->name());
+ return solve(componentsToAdd);
+}
+
QString InstallerCalculator::recursionError(Component *component) const
{
return QCoreApplication::translate("InstallerCalculator", "Recursion detected, component \"%1\" "
"already added with reason: \"%2\"").arg(component->name(), resolutionText(component));
}
+bool InstallerCalculator::updateCheckState(Component *component, Qt::CheckState state)
+{
+ ComponentModel *currentModel = m_core->isUpdater()
+ ? m_core->updaterComponentModel()
+ : m_core->defaultComponentModel();
+
+ const QModelIndex &idx = currentModel->indexFromComponentName(component->treeName());
+ return currentModel->setData(idx, state, Qt::CheckStateRole);
+}
+
bool InstallerCalculator::solveComponent(Component *component, const QString &version)
{
const QStringList dependenciesList = component->currentDependencies();
@@ -200,6 +284,19 @@ bool InstallerCalculator::solveComponent(Component *component, const QString &ve
return true;
}
+bool InstallerCalculator::solveAlias(ComponentAlias *alias)
+{
+ for (auto *requiredAlias : alias->aliases()) {
+ if (!solveAlias(requiredAlias))
+ return false;
+ }
+
+ if (m_toInstallComponentAliases.contains(alias->name()))
+ return true;
+
+ return addComponentsFromAlias(alias);
+}
+
QSet<Component *> InstallerCalculator::autodependencyComponents()
{
// All regular dependencies are resolved. Now we are looking for auto depend on components.
diff --git a/src/libs/installer/installercalculator.h b/src/libs/installer/installercalculator.h
index 339dbeffd..e542dc664 100644
--- a/src/libs/installer/installercalculator.h
+++ b/src/libs/installer/installercalculator.h
@@ -40,6 +40,7 @@
namespace QInstaller {
class Component;
+class ComponentAlias;
class PackageManagerCore;
class INSTALLER_EXPORT InstallerCalculator : public CalculatorBase
@@ -48,20 +49,28 @@ public:
InstallerCalculator(PackageManagerCore *core, const AutoDependencyHash &autoDependencyComponentHash);
~InstallerCalculator();
+ bool solve();
bool solve(const QList<Component *> &components) override;
+ bool solve(const QList<ComponentAlias *> &aliases);
+
QString resolutionText(Component *component) const override;
private:
bool solveComponent(Component *component, const QString &version = QString()) override;
+ bool solveAlias(ComponentAlias *alias);
void addComponentForInstall(Component *component, const QString &version = QString());
+ bool addComponentsFromAlias(ComponentAlias *alias);
QSet<Component *> autodependencyComponents();
QString recursionError(Component *component) const;
+ bool updateCheckState(Component *component, Qt::CheckState state);
+
private:
QHash<Component*, QSet<Component*> > m_visitedComponents;
QList<const Component*> m_componentsForAutodepencencyCheck;
QSet<QString> m_toInstallComponentIds; //for faster lookups
+ QSet<QString> m_toInstallComponentAliases;
//Helper hash for quicker search for autodependency components
AutoDependencyHash m_autoDependencyComponentHash;
};
diff --git a/src/libs/installer/installiconsoperation.cpp b/src/libs/installer/installiconsoperation.cpp
index 5927ebf74..b21634cd7 100644
--- a/src/libs/installer/installiconsoperation.cpp
+++ b/src/libs/installer/installiconsoperation.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2021 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -57,7 +57,7 @@ QString InstallIconsOperation::targetDirectory()
Qt::SkipEmptyParts);
XDG_DATA_HOME.push_back(QDir::home().absoluteFilePath(QLatin1String(".local/share"))); // default user-specific path
- if (AdminAuthorization::hasAdminRights() || RemoteClient::instance().isActive())
+ if (packageManager() && packageManager()->hasAdminRights())
XDG_DATA_HOME.push_front(QLatin1String("/usr/local/share")); // default system-wide path
QString directory;
diff --git a/src/libs/installer/libarchivewrapper_p.cpp b/src/libs/installer/libarchivewrapper_p.cpp
index e5c1e8598..b4325243d 100644
--- a/src/libs/installer/libarchivewrapper_p.cpp
+++ b/src/libs/installer/libarchivewrapper_p.cpp
@@ -41,12 +41,14 @@ namespace QInstaller {
*/
/*!
+ \internal
\fn QInstaller::LibArchiveWrapperPrivate::dataBlockRequested()
Emitted when the server process has requested another data block.
*/
/*!
+ \internal
\fn QInstaller::LibArchiveWrapperPrivate::remoteWorkerFinished()
Emitted when the server process has finished extracting an archive.
@@ -105,7 +107,7 @@ void LibArchiveWrapperPrivate::setFilename(const QString &filename)
{
if (connectToServer()) {
m_lock.lockForWrite();
- callRemoteMethod(QLatin1String(Protocol::AbstractArchiveSetFilename), filename, dummy);
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::AbstractArchiveSetFilename), filename);
m_lock.unlock();
}
m_archive.setFilename(filename);
@@ -145,7 +147,7 @@ bool LibArchiveWrapperPrivate::extract(const QString &dirPath, const quint64 tot
timer.start();
m_lock.lockForWrite();
- callRemoteMethod(QLatin1String(Protocol::AbstractArchiveExtract), dirPath, total);
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::AbstractArchiveExtract), dirPath, total);
m_lock.unlock();
{
QEventLoop loop;
@@ -203,7 +205,7 @@ void LibArchiveWrapperPrivate::setCompressionLevel(const AbstractArchive::Compre
{
if (connectToServer()) {
m_lock.lockForWrite();
- callRemoteMethod(QLatin1String(Protocol::AbstractArchiveSetCompressionLevel), level, dummy);
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::AbstractArchiveSetCompressionLevel), level);
m_lock.unlock();
return;
}
@@ -219,7 +221,7 @@ void LibArchiveWrapperPrivate::cancel()
{
if (connectToServer()) {
m_lock.lockForWrite();
- callRemoteMethod(QLatin1String(Protocol::AbstractArchiveCancel));
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::AbstractArchiveCancel));
m_lock.unlock();
return;
}
@@ -354,7 +356,7 @@ void LibArchiveWrapperPrivate::addDataBlock(const QByteArray &buffer)
{
if (connectToServer()) {
m_lock.lockForWrite();
- callRemoteMethod(QLatin1String(Protocol::AbstractArchiveAddDataBlock), buffer, dummy);
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::AbstractArchiveAddDataBlock), buffer);
m_lock.unlock();
}
}
@@ -367,7 +369,7 @@ void LibArchiveWrapperPrivate::setClientDataAtEnd()
{
if (connectToServer()) {
m_lock.lockForWrite();
- callRemoteMethod(QLatin1String(Protocol::AbstractArchiveSetClientDataAtEnd));
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::AbstractArchiveSetClientDataAtEnd));
m_lock.unlock();
}
}
@@ -379,7 +381,7 @@ void LibArchiveWrapperPrivate::setClientFilePosition(qint64 pos)
{
if (connectToServer()) {
m_lock.lockForWrite();
- callRemoteMethod(QLatin1String(Protocol::AbstractArchiveSetFilePosition), pos, dummy);
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::AbstractArchiveSetFilePosition), pos);
m_lock.unlock();
}
}
diff --git a/src/libs/installer/licenseoperation.cpp b/src/libs/installer/licenseoperation.cpp
index 6cf0c8e3e..0d30ab514 100644
--- a/src/libs/installer/licenseoperation.cpp
+++ b/src/libs/installer/licenseoperation.cpp
@@ -31,6 +31,7 @@
#include "packagemanagercore.h"
#include "settings.h"
#include "fileutils.h"
+#include "globals.h"
#include <QtCore/QDir>
#include <QtCore/QFile>
@@ -56,7 +57,7 @@ void LicenseOperation::backup()
bool LicenseOperation::performOperation()
{
- QVariantMap licenses = value(scLicenses).toMap();
+ QVariantMap licenses = value(scLicensesValue).toMap();
if (licenses.isEmpty()) {
setError(UserDefinedError);
setErrorString(tr("No license files found to copy."));
@@ -86,9 +87,11 @@ bool LicenseOperation::performOperation()
return false;
}
- QTextStream stream(&file);
- stream.setCodec("UTF-8");
+ QString outString;
+ QTextStream stream(&outString);
stream << it.value().toString();
+
+ file.write(outString.toUtf8());
}
return true;
@@ -96,11 +99,10 @@ bool LicenseOperation::performOperation()
bool LicenseOperation::undoOperation()
{
- const QVariantMap licenses = value(scLicenses).toMap();
+ const QVariantMap licenses = value(scLicensesValue).toMap();
if (licenses.isEmpty()) {
- setError(UserDefinedError);
- setErrorString(tr("No license files found to delete."));
- return false;
+ qCWarning(QInstaller::lcInstallerInstallLog) << "No license files found to delete.";
+ return true;
}
QString targetDir = arguments().value(0);
diff --git a/src/libs/installer/loggingutils.cpp b/src/libs/installer/loggingutils.cpp
index 42bbc0117..9a36720dd 100644
--- a/src/libs/installer/loggingutils.cpp
+++ b/src/libs/installer/loggingutils.cpp
@@ -29,6 +29,7 @@
#include "loggingutils.h"
#include "component.h"
+#include "componentalias.h"
#include "globals.h"
#include "fileutils.h"
#include "packagemanagercore.h"
@@ -367,6 +368,44 @@ void LoggingHandler::printPackageInformation(const PackagesList &matchedPackages
}
/*!
+ Prints basic or more detailed information about component \a aliases,
+ depending on the current verbosity level.
+*/
+void LoggingHandler::printAliasInformation(const QList<ComponentAlias *> &aliases)
+{
+ QList<ComponentAlias *> sortedAliases = aliases;
+ std::sort(sortedAliases.begin(), sortedAliases.end(),
+ [](const ComponentAlias *lhs, const ComponentAlias *rhs) {
+ return lhs->name() < rhs->name();
+ }
+ );
+
+ QString output;
+ QTextStream stream(&output);
+
+ stream << Qt::endl;
+ for (auto *alias : qAsConst(sortedAliases)) {
+ stream << "Name: " << alias->name() << Qt::endl;
+ stream << "Display name: " << alias->displayName() << Qt::endl;
+ stream << "Description: " << alias->description() << Qt::endl;
+ stream << "Version: " << alias->version() << Qt::endl;
+ if (verboseLevel() == VerbosityLevel::Detailed)
+ stream << "Virtual: " << alias->value(scVirtual) << Qt::endl;
+
+ stream << "Components: " << alias->value(scRequiredComponents) << Qt::endl;
+ stream << "Required aliases: " << alias->value(scRequiredAliases) << Qt::endl;
+
+ stream << "Optional components: " << alias->value(scOptionalComponents) << Qt::endl;
+ stream << "Optional aliases: " << alias->value(scOptionalAliases) << Qt::endl;
+
+ if (sortedAliases.indexOf(alias) != (sortedAliases.count() - 1))
+ stream << "========================================" << Qt::endl;
+ }
+
+ std::cout << qPrintable(output);
+}
+
+/*!
\internal
*/
VerboseWriter::VerboseWriter()
diff --git a/src/libs/installer/loggingutils.h b/src/libs/installer/loggingutils.h
index 8bd4217ee..18ff2d2c5 100644
--- a/src/libs/installer/loggingutils.h
+++ b/src/libs/installer/loggingutils.h
@@ -41,6 +41,7 @@
namespace QInstaller {
class Component;
+class ComponentAlias;
class INSTALLER_EXPORT LoggingHandler
{
@@ -67,6 +68,7 @@ public:
void printUpdateInformation(const QList<Component *> &components) const;
void printLocalPackageInformation(const QList<KDUpdater::LocalPackage> &packages) const;
void printPackageInformation(const PackagesList &matchedPackages, const LocalPackagesMap &installedPackages) const;
+ void printAliasInformation(const QList<ComponentAlias *> &aliases);
friend VerbosityLevel &operator++(VerbosityLevel &level, int);
friend VerbosityLevel &operator--(VerbosityLevel &level, int);
diff --git a/src/libs/installer/messageboxhandler.cpp b/src/libs/installer/messageboxhandler.cpp
index 78abc88fa..052709e51 100644
--- a/src/libs/installer/messageboxhandler.cpp
+++ b/src/libs/installer/messageboxhandler.cpp
@@ -368,7 +368,9 @@ static QMessageBox::StandardButton showNewMessageBox(QWidget *parent, QMessageBo
QMessageBox::StandardButton defaultButton)
{
QMessageBox msgBox(icon, title, text, QMessageBox::NoButton, parent);
- msgBox.setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
+ msgBox.setTextInteractionFlags(Qt::TextBrowserInteraction);
+ msgBox.setTextFormat(Qt::RichText);
+
QDialogButtonBox *buttonBox = msgBox.findChild<QDialogButtonBox *>();
Q_ASSERT(buttonBox != nullptr);
diff --git a/src/libs/installer/metadata.cpp b/src/libs/installer/metadata.cpp
index 9ae817127..2eccb020e 100644
--- a/src/libs/installer/metadata.cpp
+++ b/src/libs/installer/metadata.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -46,6 +46,52 @@ namespace QInstaller {
\brief The Metadata class represents fetched metadata from a repository.
*/
+
+/*!
+ \internal
+*/
+static bool verifyFileIntegrityFromElement(const QDomElement &element, const QString &childNodeName,
+ const QString &attribute, const QString &metaDirectory, bool testChecksum)
+{
+ const QDomNodeList nodes = element.childNodes();
+ for (int i = 0; i < nodes.count(); ++i) {
+ const QDomNode node = nodes.at(i);
+ if (node.nodeName() != childNodeName)
+ continue;
+
+ const QDir dir(metaDirectory);
+ const QString filename = attribute.isEmpty()
+ ? node.toElement().text()
+ : node.toElement().attribute(attribute);
+
+ if (filename.isEmpty())
+ continue;
+
+ QFile file(dir.absolutePath() + QDir::separator() + filename);
+ if (!file.open(QIODevice::ReadOnly)) {
+ qCWarning(QInstaller::lcInstallerInstallLog)
+ << "Cannot open" << file.fileName()
+ << "for reading:" << file.errorString();
+ return false;
+ }
+
+ if (!testChecksum)
+ continue;
+
+ QCryptographicHash hash(QCryptographicHash::Sha1);
+ hash.addData(&file);
+
+ const QByteArray checksum = hash.result().toHex();
+ if (!QFileInfo::exists(dir.absolutePath() + QDir::separator()
+ + QString::fromLatin1(checksum) + QLatin1String(".sha1"))) {
+ qCWarning(QInstaller::lcInstallerInstallLog)
+ << "Unexpected checksum for file" << file.fileName();
+ return false;
+ }
+ }
+ return true;
+}
+
/*!
Constructs a new metadata object.
*/
@@ -122,18 +168,23 @@ QDomDocument Metadata::updatesDocument() const
}
/*!
- Returns \c true if the \c Updates.xml document of this metadata
- exists, \c false otherwise.
+ Returns \c true if the \c Updates.xml document of this metadata exists, and that all
+ meta files referenced in the document exist. If the \c Updates.xml contains a \c Checksum
+ element with a value of \c true, the integrity of the files is also verified.
+
+ Returns \c false otherwise.
*/
bool Metadata::isValid() const
{
- const QString updateFile(path() + QLatin1String("/Updates.xml"));
- if (!QFileInfo::exists(updateFile)) {
+ QFile updateFile(path() + QLatin1String("/Updates.xml"));
+ if (!updateFile.open(QIODevice::ReadOnly)) {
qCWarning(QInstaller::lcInstallerInstallLog)
- << "File" << updateFile << "does not exist.";
+ << "Cannot open" << updateFile.fileName()
+ << "for reading:" << updateFile.errorString();
return false;
}
- return true;
+
+ return verifyMetaFiles(&updateFile);
}
/*!
@@ -282,4 +333,78 @@ bool Metadata::containsRepositoryUpdates() const
return false;
}
+/*!
+ Verifies that the files referenced in \a updateFile document exist
+ on disk. If the document contains a \c Checksum element with a value
+ of \c true, the integrity of the files is also verified.
+
+ Returns \c true if the meta files are valid, \c false otherwise.
+*/
+bool Metadata::verifyMetaFiles(QFile *updateFile) const
+{
+ QDomDocument doc;
+ QString errorString;
+ if (!doc.setContent(updateFile, &errorString)) {
+ qCWarning(QInstaller::lcInstallerInstallLog)
+ << "Cannot set document content:" << errorString;
+ return false;
+ }
+
+ const QDomElement rootElement = doc.documentElement();
+ const QDomNodeList childNodes = rootElement.childNodes();
+
+ bool testChecksum = true;
+ const QDomElement checksumElement = rootElement.firstChildElement(QLatin1String("Checksum"));
+ if (!checksumElement.isNull())
+ testChecksum = (checksumElement.text().toLower() == scTrue);
+
+ for (int i = 0; i < childNodes.count(); ++i) {
+ const QDomElement element = childNodes.at(i).toElement();
+ if (element.isNull() || element.tagName() != QLatin1String("PackageUpdate"))
+ continue;
+
+ const QDomNodeList c2 = element.childNodes();
+ QString packageName;
+ QString unused1;
+ QString unused2;
+
+ // Only need the package name, so values for "online" and "testCheckSum" do not matter
+ if (!MetadataJob::parsePackageUpdate(c2, packageName, unused1, unused2, true, true))
+ continue; // nothing to check for this package
+
+ const QString packagePath = QString::fromLatin1("%1/%2/").arg(path(), packageName);
+ for (auto &metaTagName : scMetaElements) {
+ const QDomElement metaElement = element.firstChildElement(metaTagName);
+ if (metaElement.isNull())
+ continue;
+
+ if (metaElement.tagName() == QLatin1String("Licenses")) {
+ if (!verifyFileIntegrityFromElement(metaElement, QLatin1String("License"),
+ QLatin1String("file"), packagePath, testChecksum)) {
+ return false;
+ }
+ } else if (metaElement.tagName() == QLatin1String("UserInterfaces")) {
+ if (!verifyFileIntegrityFromElement(metaElement, QLatin1String("UserInterface"),
+ QString(), packagePath, testChecksum)) {
+ return false;
+ }
+ } else if (metaElement.tagName() == QLatin1String("Translations")) {
+ if (!verifyFileIntegrityFromElement(metaElement, QLatin1String("Translation"),
+ QString(), packagePath, testChecksum)) {
+ return false;
+ }
+ } else if (metaElement.tagName() == QLatin1String("Script")) {
+ if (!verifyFileIntegrityFromElement(metaElement.parentNode().toElement(),
+ QLatin1String("Script"), QString(), packagePath, testChecksum)) {
+ return false;
+ }
+ } else {
+ Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown meta element.");
+ }
+ }
+ }
+
+ return true;
+}
+
} // namespace QInstaller
diff --git a/src/libs/installer/metadata.h b/src/libs/installer/metadata.h
index 3063be829..c7e4e857c 100644
--- a/src/libs/installer/metadata.h
+++ b/src/libs/installer/metadata.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -35,6 +35,8 @@
#include <QDomDocument>
+class QFile;
+
namespace QInstaller {
class INSTALLER_EXPORT Metadata : public CacheableItem
@@ -64,6 +66,9 @@ public:
bool containsRepositoryUpdates() const;
private:
+ bool verifyMetaFiles(QFile *updateFile) const;
+
+private:
Repository m_repository;
QString m_persistentRepositoryPath;
mutable QByteArray m_checksum;
@@ -71,13 +76,6 @@ private:
bool m_fromDefaultRepository;
};
-Q_GLOBAL_STATIC_WITH_ARGS(QStringList, scMetaElements, (QStringList(
- QLatin1String("Script")) <<
- QLatin1String("Licenses") <<
- QLatin1String("UserInterfaces") <<
- QLatin1String("Translations")
-));
-
} // namespace QInstaller
#endif // METADATA_H
diff --git a/src/libs/installer/metadatacache.cpp b/src/libs/installer/metadatacache.cpp
new file mode 100644
index 000000000..744e455f4
--- /dev/null
+++ b/src/libs/installer/metadatacache.cpp
@@ -0,0 +1,67 @@
+/**************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#include "metadatacache.h"
+
+#define QUOTE_(x) #x
+#define QUOTE(x) QUOTE_(x)
+
+namespace QInstaller {
+
+/*!
+ \inmodule QtInstallerFramework
+ \class QInstaller::MetadataCache
+ \brief The MetadataCache is a class for a checksum based storage of \c Metadata objects on disk.
+
+ MetadataCache manages a cache storage for a set \l{path()}, which contains
+ a subdirectory for each registered \c Metadata item. The cache has a manifest file in
+ its root directory, which lists the version and type of the cache, and all its items.
+ The file is updated automatically when the metadata cache object is destructed, or
+ it can be updated periodically by calling \l{sync()}.
+*/
+
+/*!
+ Constructs a new empty cache. The cache is invalid until set with a
+ path and initialized.
+*/
+MetadataCache::MetadataCache()
+ : GenericDataCache<Metadata>()
+{
+ setType(QLatin1String("Metadata"));
+ setVersion(QLatin1String(QUOTE(IFW_CACHE_FORMAT_VERSION)));
+}
+
+/*!
+ Constructs a cache to \a path. The cache is initialized automatically.
+*/
+MetadataCache::MetadataCache(const QString &path)
+ : GenericDataCache(path, QLatin1String("Metadata"), QLatin1String(QUOTE(IFW_CACHE_FORMAT_VERSION)))
+{
+}
+
+} // namespace QInstaller
diff --git a/src/libs/installer/metadatacache.h b/src/libs/installer/metadatacache.h
new file mode 100644
index 000000000..804d1b6db
--- /dev/null
+++ b/src/libs/installer/metadatacache.h
@@ -0,0 +1,46 @@
+/**************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#ifndef METADATACACHE_H
+#define METADATACACHE_H
+
+#include "genericdatacache.h"
+#include "metadata.h"
+
+namespace QInstaller {
+
+class MetadataCache : public GenericDataCache<Metadata>
+{
+public:
+ MetadataCache();
+ explicit MetadataCache(const QString &path);
+};
+
+} // namespace QInstaller
+
+#endif // METADATACACHE_H
diff --git a/src/libs/installer/metadatajob.cpp b/src/libs/installer/metadatajob.cpp
index ff15d7b0d..1bed304c6 100644
--- a/src/libs/installer/metadatajob.cpp
+++ b/src/libs/installer/metadatajob.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2023 The Qt Company Ltd.
+** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -41,9 +41,7 @@
#include <QtConcurrent>
#include <QtMath>
#include <QRandomGenerator>
-
-#define QUOTE_(x) #x
-#define QUOTE(x) QUOTE_(x)
+#include <QApplication>
namespace QInstaller {
@@ -52,7 +50,6 @@ namespace QInstaller {
\value All
\value CompressedPackage
- \value UpdatesXML
*/
/*!
@@ -145,9 +142,6 @@ QList<Metadata *> MetadataJob::metadata() const
QHash<RepositoryCategory, QSet<Repository>>::const_iterator it;
for (it = repositoryHash.constBegin(); it != repositoryHash.constEnd(); ++it) {
- if (m_core->isUpdater())
- return true;
-
if (!it.key().isEnabled())
continue; // Let's try the next one
@@ -192,8 +186,6 @@ bool MetadataJob::resetCache(bool init)
m_metaFromCache.clear();
m_metaFromCache.setPath(m_core->settings().localCachePath());
- m_metaFromCache.setType(QLatin1String("Metadata"));
- m_metaFromCache.setVersion(QLatin1String(QUOTE(IFW_REPOSITORY_FORMAT_VERSION)));
if (!init)
return true;
@@ -218,6 +210,11 @@ bool MetadataJob::clearCache()
return false;
}
+bool MetadataJob::isValidCache() const
+{
+ return m_metaFromCache.isValid();
+}
+
// -- private slots
void MetadataJob::doStart()
@@ -240,13 +237,15 @@ void MetadataJob::doStart()
if (m_downloadType != DownloadType::CompressedPackage) {
emit infoMessage(this, tr("Fetching latest update information..."));
const bool onlineInstaller = m_core->isInstaller() && !m_core->isOfflineOnly();
- if (onlineInstaller || m_core->isMaintainer()) {
+ const QSet<Repository> repositories = getRepositories();
+
+ if (onlineInstaller || m_core->isMaintainer()
+ || (m_core->settings().allowRepositoriesForOfflineInstaller() && !repositories.isEmpty())) {
static const QString updateFilePath(QLatin1Char('/') + scUpdatesXML + QLatin1Char('?'));
static const QString randomQueryString = QString::number(QRandomGenerator::global()->generate());
- QList<FileTaskItem> items;
- QSet<Repository> repositories = getRepositories();
quint64 cachedCount = 0;
+ setProgressTotalAmount(0); // Show only busy indicator during this loop as we have no progress to measure
foreach (const Repository &repo, repositories) {
// For not blocking the UI
qApp->processEvents();
@@ -289,17 +288,24 @@ void MetadataJob::doStart()
FileTaskItem item(url, tmp.path() + QLatin1String("/Updates.xml"));
item.insert(TaskRole::UserRole, QVariant::fromValue(repo));
item.insert(TaskRole::Authenticator, QVariant::fromValue(authenticator));
- items.append(item);
+ m_updatesXmlItems.append(item);
}
}
+ setProgressTotalAmount(100);
const quint64 totalCount = repositories.count();
if (cachedCount > 0) {
qCDebug(lcInstallerInstallLog).nospace() << "Loaded from cache "
<< cachedCount << "/" << totalCount << ". Downloading remaining "
- << items.count() << "/" << totalCount <<".";
+ << m_updatesXmlItems.count() << "/" << totalCount <<".";
+ } else {
+ qCDebug(lcInstallerInstallLog).nospace() <<"Downloading " << m_updatesXmlItems.count()
+ << " items to cache.";
}
- if (items.count() > 0) {
- startXMLTask(items);
+ if (m_updatesXmlItems.count() > 0) {
+ double taskCount = m_updatesXmlItems.length()/static_cast<double>(m_downloadableChunkSize);
+ m_totalTaskCount = qCeil(taskCount);
+ m_taskNumber = 0;
+ startXMLTask();
} else {
emitFinished();
}
@@ -338,13 +344,22 @@ void MetadataJob::doStart()
}
}
-void MetadataJob::startXMLTask(const QList<FileTaskItem> &items)
+bool MetadataJob::startXMLTask()
{
- DownloadFileTask *const xmlTask = new DownloadFileTask(items);
- xmlTask->setProxyFactory(m_core->proxyFactory());
- connect(&m_xmlTask, &QFutureWatcher<FileTaskResult>::progressValueChanged, this,
- &MetadataJob::progressChanged);
- m_xmlTask.setFuture(QtConcurrent::run(&DownloadFileTask::doTask, xmlTask));
+ int chunkSize = qMin(m_updatesXmlItems.length(), m_downloadableChunkSize);
+ QList<FileTaskItem> tempPackages = m_updatesXmlItems.mid(0, chunkSize);
+ m_updatesXmlItems = m_updatesXmlItems.mid(chunkSize, m_updatesXmlItems.length());
+ if (tempPackages.length() > 0) {
+ DownloadFileTask *const xmlTask = new DownloadFileTask(tempPackages);
+ xmlTask->setProxyFactory(m_core->proxyFactory());
+ connect(&m_xmlTask, &QFutureWatcher<FileTaskResult>::progressValueChanged, this,
+ &MetadataJob::progressChanged);
+ m_xmlTask.setFuture(QtConcurrent::run(&DownloadFileTask::doTask, xmlTask));
+
+ setInfoMessage(tr("Retrieving information from remote repositories..."));
+ return true;
+ }
+ return false;
}
void MetadataJob::doCancel()
@@ -431,7 +446,7 @@ void MetadataJob::unzipRepositoryTaskFinished()
FileTaskItem item(url, tmp.path() + QLatin1String("/Updates.xml"));
item.insert(TaskRole::UserRole, QVariant::fromValue(repo));
- m_unzipRepositoryitems.append(item);
+ m_updatesXmlItems.append(item);
} else {
//Repository is not valid, remove it
Settings &s = m_core->settings();
@@ -451,8 +466,8 @@ void MetadataJob::unzipRepositoryTaskFinished()
//One can specify many zipped repository items at once. As the repositories are
//unzipped one by one, we collect here all items before parsing xml files from those.
- if (m_unzipRepositoryitems.count() > 0 && m_unzipRepositoryTasks.isEmpty()) {
- startXMLTask(m_unzipRepositoryitems);
+ if (m_updatesXmlItems.count() > 0 && m_unzipRepositoryTasks.isEmpty()) {
+ startXMLTask();
} else {
if (error != Job::NoError) {
emitFinishedWithError(QInstaller::DownloadError, errorString);
@@ -476,19 +491,34 @@ void MetadataJob::xmlTaskFinished()
Status status = XmlDownloadFailure;
try {
m_xmlTask.waitForFinished();
- status = parseUpdatesXml(m_xmlTask.future().results());
+ m_updatesXmlResult.append(m_xmlTask.future().results());
+ if (!startXMLTask()) {
+ status = parseUpdatesXml(m_updatesXmlResult);
+ m_updatesXmlResult.clear();
+ } else {
+ return;
+ }
} catch (const AuthenticationRequiredException &e) {
if (e.type() == AuthenticationRequiredException::Type::Proxy) {
- const QNetworkProxy proxy = e.proxy();
- ProxyCredentialsDialog proxyCredentials(proxy);
qCWarning(QInstaller::lcInstallerInstallLog) << e.message();
-
- if (proxyCredentials.exec() == QDialog::Accepted) {
+ QString username;
+ QString password;
+ const QNetworkProxy proxy = e.proxy();
+ if (m_core->isCommandLineInstance()) {
+ qCDebug(QInstaller::lcInstallerInstallLog).noquote() << QString::fromLatin1("The proxy %1:%2 requires a username and password").arg(proxy.hostName(), proxy.port());
+ askForCredentials(&username, &password, QLatin1String("Username: "), QLatin1String("Password: "));
+ } else {
+ ProxyCredentialsDialog proxyCredentials(proxy);
+ if (proxyCredentials.exec() == QDialog::Accepted) {
+ username = proxyCredentials.userName();
+ password = proxyCredentials.password();
+ }
+ }
+ if (!username.isEmpty()) {
qCDebug(QInstaller::lcInstallerInstallLog) << "Retrying with new credentials ...";
PackageManagerProxyFactory *factory = m_core->proxyFactory();
- factory->setProxyCredentials(proxy, proxyCredentials.userName(),
- proxyCredentials.password());
+ factory->setProxyCredentials(proxy, username, password);
m_core->setProxyFactory(factory);
status = XmlDownloadRetry;
} else {
@@ -497,13 +527,25 @@ void MetadataJob::xmlTaskFinished()
}
} else if (e.type() == AuthenticationRequiredException::Type::Server) {
qCWarning(QInstaller::lcInstallerInstallLog) << e.message();
- ServerAuthenticationDialog dlg(e.message(), e.taskItem());
- if (dlg.exec() == QDialog::Accepted) {
+ QString username;
+ QString password;
+ if (m_core->isCommandLineInstance()) {
+ qCDebug(QInstaller::lcInstallerInstallLog) << "Server Requires Authentication";
+ qCDebug(QInstaller::lcInstallerInstallLog) << "You need to supply a username and password to access this site.";
+ askForCredentials(&username, &password, QLatin1String("Username: "), QLatin1String("Password: "));
+ } else {
+ ServerAuthenticationDialog dlg(e.message(), e.taskItem());
+ if (dlg.exec() == QDialog::Accepted) {
+ username = dlg.user();
+ password = dlg.password();
+ }
+ }
+ if (!username.isEmpty()) {
Repository original = e.taskItem().value(TaskRole::UserRole)
.value<Repository>();
Repository replacement = original;
- replacement.setUsername(dlg.user());
- replacement.setPassword(dlg.password());
+ replacement.setUsername(username);
+ replacement.setPassword(password);
Settings &s = m_core->settings();
QSet<Repository> temporaries = s.temporaryRepositories();
@@ -557,8 +599,9 @@ void MetadataJob::xmlTaskFinished()
// No new metadata packages to fetch, still need to update the cache
// for refreshed repositories.
startUpdateCacheTask();
- }
+ }
} else if (status == XmlDownloadRetry) {
+ reset();
QMetaObject::invokeMethod(this, "doStart", Qt::QueuedConnection);
} else {
reset();
@@ -630,6 +673,7 @@ void MetadataJob::metadataTaskFinished()
UnzipArchiveTask *task = new UnzipArchiveTask(result.target(),
item.value(TaskRole::UserRole).toString());
task->setRemoveArchive(true);
+ task->setStoreChecksums(true);
QFutureWatcher<void> *watcher = new QFutureWatcher<void>();
m_unzipTasks.insert(watcher, qobject_cast<QObject*> (task));
@@ -684,17 +728,11 @@ bool MetadataJob::fetchMetaDataPackages()
QList<FileTaskItem> tempPackages = m_packages.mid(0, chunkSize);
m_packages = m_packages.mid(chunkSize, m_packages.length());
if (tempPackages.length() > 0) {
- m_taskNumber++;
setProcessedAmount(0);
DownloadFileTask *const metadataTask = new DownloadFileTask(tempPackages);
metadataTask->setProxyFactory(m_core->proxyFactory());
m_metadataTask.setFuture(QtConcurrent::run(&DownloadFileTask::doTask, metadataTask));
- QString metaInformation;
- if (m_totalTaskCount > 1)
- metaInformation = tr("Retrieving meta information from remote repository... %1/%2 ").arg(m_taskNumber).arg(m_totalTaskCount);
- else
- metaInformation = tr("Retrieving meta information from remote repository... ");
- emit infoMessage(this, metaInformation);
+ setInfoMessage(tr("Retrieving meta information from remote repository..."));
return true;
}
return false;
@@ -703,6 +741,7 @@ bool MetadataJob::fetchMetaDataPackages()
void MetadataJob::reset()
{
m_packages.clear();
+ m_updatesXmlItems.clear();
m_defaultRepositoriesFetched = false;
m_fetchedCategorizedRepositories.clear();
@@ -721,6 +760,7 @@ void MetadataJob::reset()
} catch (...) {}
m_tempDirDeleter.releaseAndDeleteAll();
m_metadataResult.clear();
+ m_updatesXmlResult.clear();
m_taskNumber = 0;
}
@@ -728,7 +768,6 @@ void MetadataJob::resetCompressedFetch()
{
setError(Job::NoError);
setErrorString(QString());
- m_unzipRepositoryitems.clear();
try {
foreach (QFutureWatcher<void> *const watcher, m_unzipTasks.keys()) {
@@ -762,7 +801,7 @@ MetadataJob::Status MetadataJob::parseUpdatesXml(const QList<FileTaskResult> &re
}
QFileInfo fileInfo(result.target());
- QScopedPointer<Metadata> metadata(new Metadata(fileInfo.absolutePath()));
+ std::unique_ptr<Metadata> metadata(new Metadata(fileInfo.absolutePath()));
QFile file(result.target());
if (!file.open(QIODevice::ReadOnly)) {
qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot open Updates.xml for reading:"
@@ -770,13 +809,21 @@ MetadataJob::Status MetadataJob::parseUpdatesXml(const QList<FileTaskResult> &re
return XmlDownloadFailure;
}
const FileTaskItem item = result.value(TaskRole::TaskItem).value<FileTaskItem>();
+ const Repository repository = item.value(TaskRole::UserRole).value<Repository>();
- // Check if we have cached the metadata for this repository already
QCryptographicHash hash(QCryptographicHash::Sha1);
hash.addData(&file);
const QByteArray updatesChecksum = hash.result().toHex();
+ if (!repository.xmlChecksum().isEmpty() && updatesChecksum != repository.xmlChecksum()) {
+ qCWarning(lcDeveloperBuild).noquote().nospace() << "The checksum for Updates.xml "
+ "file downloaded from repository:\n" << repository.url().toString() << "\ndoes not "
+ "match the expected value:\n\tActual SHA1: " << updatesChecksum << "\n\tExpected SHA1: "
+ << repository.xmlChecksum() << Qt::endl;
+ }
+
bool refreshed;
+ // Check if we have cached the metadata for this repository already
Status status = refreshCacheItem(result, updatesChecksum, &refreshed);
if (status != XmlDownloadSuccess)
return status;
@@ -798,7 +845,7 @@ MetadataJob::Status MetadataJob::parseUpdatesXml(const QList<FileTaskResult> &re
}
file.close();
- metadata->setRepository(item.value(TaskRole::UserRole).value<Repository>());
+ metadata->setRepository(repository);
const bool online = !(metadata->repository().url().scheme()).isEmpty();
bool testCheckSum = true;
@@ -855,7 +902,7 @@ MetadataJob::Status MetadataJob::parseUpdatesXml(const QList<FileTaskResult> &re
m_fetchedCategorizedRepositories.insert(metadataPtr->repository()); // For faster lookups
const QString metadataPath = metadata->path();
- m_fetchedMetadata.insert(metadataPath, metadata.take());
+ m_fetchedMetadata.insert(metadataPath, metadata.release());
// search for additional repositories that we might need to check
status = parseRepositoryUpdates(root, result, metadataPtr);
@@ -885,6 +932,7 @@ MetadataJob::Status MetadataJob::refreshCacheItem(const FileTaskResult &result,
const FileTaskItem item = result.value(TaskRole::TaskItem).value<FileTaskItem>();
const Repository repository = item.value(TaskRole::UserRole).value<Repository>();
+
if (cachedMetadata->isValid() && !repository.isCompressed()) {
// Refresh repository information to cache. Same repository may appear in multiple
// categories and the metadata may be available from default repositories simultaneously.
@@ -973,9 +1021,8 @@ QSet<Repository> MetadataJob::getRepositories()
// Fetch repositories under archive which are selected in UI.
// If repository is already fetched, do not fetch it again.
- // In updater mode, fetch always all archive repositories to get updates
for (const RepositoryCategory &repositoryCategory : m_core->settings().repositoryCategories()) {
- if (!m_core->isUpdater() && !repositoryCategory.isEnabled())
+ if (!repositoryCategory.isEnabled())
continue;
for (const Repository &repository : repositoryCategory.repositories()) {
@@ -1015,7 +1062,7 @@ bool MetadataJob::parsePackageUpdate(const QDomNodeList &c2, QString &packageNam
else if ((element.tagName() == QLatin1String("SHA1")) && testCheckSum)
packageHash = element.text();
else {
- foreach (QString meta, *scMetaElements) {
+ foreach (QString meta, scMetaElements) {
if (element.tagName() == meta) {
metaFound = true;
break;
@@ -1122,4 +1169,14 @@ MetadataJob::Status MetadataJob::setAdditionalRepositories(QMultiHash<QString, Q
}
return status;
}
+
+void MetadataJob::setInfoMessage(const QString &message)
+{
+ m_taskNumber++;
+ QString metaInformation = message;
+ if (m_totalTaskCount > 1)
+ metaInformation = QLatin1String(" %1 %2/%3 ").arg(message).arg(m_taskNumber).arg(m_totalTaskCount);
+ emit infoMessage(this, metaInformation);
+
+}
} // namespace QInstaller
diff --git a/src/libs/installer/metadatajob.h b/src/libs/installer/metadatajob.h
index 37d9367e5..13ad3ea8c 100644
--- a/src/libs/installer/metadatajob.h
+++ b/src/libs/installer/metadatajob.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -33,7 +33,7 @@
#include "fileutils.h"
#include "job.h"
#include "metadata.h"
-#include "genericdatacache.h"
+#include "metadatacache.h"
#include "repository.h"
#include <QFutureWatcher>
@@ -74,6 +74,7 @@ public:
bool resetCache(bool init = false);
bool clearCache();
+ bool isValidCache() const;
private slots:
void doStart() override;
@@ -86,7 +87,7 @@ private slots:
void progressChanged(int progress);
void setProgressTotalAmount(int maximum);
void unzipRepositoryTaskFinished();
- void startXMLTask(const QList<FileTaskItem> &items);
+ bool startXMLTask();
private:
bool fetchMetaDataPackages();
@@ -108,6 +109,7 @@ private:
const FileTaskResult &result, const Metadata &metadata);
MetadataJob::Status setAdditionalRepositories(QMultiHash<QString, QPair<Repository, Repository> > repositoryUpdates,
const FileTaskResult &result, const Metadata& metadata);
+ void setInfoMessage(const QString &message);
private:
friend class Metadata;
@@ -116,6 +118,7 @@ private:
PackageManagerCore *m_core;
QList<FileTaskItem> m_packages;
+ QList<FileTaskItem> m_updatesXmlItems;
TempPathDeleter m_tempDirDeleter;
QFutureWatcher<FileTaskResult> m_xmlTask;
QFutureWatcher<FileTaskResult> m_metadataTask;
@@ -123,8 +126,8 @@ private:
QHash<QFutureWatcher<void> *, QObject*> m_unzipTasks;
QHash<QFutureWatcher<void> *, QObject*> m_unzipRepositoryTasks;
DownloadType m_downloadType;
- QList<FileTaskItem> m_unzipRepositoryitems;
QList<FileTaskResult> m_metadataResult;
+ QList<FileTaskResult> m_updatesXmlResult;
int m_downloadableChunkSize;
int m_taskNumber;
int m_totalTaskCount;
@@ -133,7 +136,7 @@ private:
QSet<Repository> m_fetchedCategorizedRepositories;
QHash<QString, Metadata *> m_fetchedMetadata;
- GenericDataCache<Metadata> m_metaFromCache;
+ MetadataCache m_metaFromCache;
};
} // namespace QInstaller
diff --git a/src/libs/installer/metadatajob_p.h b/src/libs/installer/metadatajob_p.h
index ef2729dbb..837a7e9ae 100644
--- a/src/libs/installer/metadatajob_p.h
+++ b/src/libs/installer/metadatajob_p.h
@@ -62,11 +62,16 @@ class UnzipArchiveTask : public AbstractTask<void>
public:
UnzipArchiveTask(const QString &arcive, const QString &target)
- : m_archive(arcive), m_targetDir(target), m_removeArchive(false)
+ : m_archive(arcive)
+ , m_targetDir(target)
+ , m_removeArchive(false)
+ , m_storeChecksums(false)
{}
+
QString target() { return m_targetDir; }
QString archive() { return m_archive; }
void setRemoveArchive(bool remove) { m_removeArchive = remove; }
+ void setStoreChecksums(bool store) { m_storeChecksums = store; }
void doTask(QFutureInterface<void> &fi) override
{
@@ -82,12 +87,43 @@ public:
if (!archive) {
fi.reportException(UnzipArchiveException(MetadataJob::tr("Unsupported archive \"%1\": no handler "
"registered for file suffix \"%2\".").arg(m_archive, QFileInfo(m_archive).suffix())));
+ return;
} else if (!archive->open(QIODevice::ReadOnly)) {
fi.reportException(UnzipArchiveException(MetadataJob::tr("Cannot open file \"%1\" for "
"reading: %2").arg(QDir::toNativeSeparators(m_archive), archive->errorString())));
+ return;
} else if (!archive->extract(m_targetDir)) {
fi.reportException(UnzipArchiveException(MetadataJob::tr("Error while extracting "
"archive \"%1\": %2").arg(QDir::toNativeSeparators(m_archive), archive->errorString())));
+ return;
+ }
+
+ if (m_storeChecksums) {
+ // Calculate and store checksums of extracted files for later use
+ const QVector<ArchiveEntry> entries = archive->list();
+ for (auto &entry : entries) {
+ if (entry.isDirectory)
+ continue;
+
+ QFile file(m_targetDir + QDir::separator() + entry.path);
+ if (!file.open(QIODevice::ReadOnly)) {
+ fi.reportException(UnzipArchiveException(MetadataJob::tr("Cannot open extracted file \"%1\" for "
+ "reading: %2").arg(QDir::toNativeSeparators(file.fileName()), file.errorString())));
+ break;
+ }
+ QCryptographicHash hash(QCryptographicHash::Sha1);
+ hash.addData(&file);
+
+ const QByteArray hexChecksum = hash.result().toHex();
+ QFileInfo fileInfo(file.fileName());
+ QFile hashFile(fileInfo.absolutePath() + QDir::separator()
+ + QString::fromLatin1(hexChecksum) + QLatin1String(".sha1"));
+ if (!hashFile.open(QIODevice::WriteOnly)) {
+ fi.reportException(UnzipArchiveException(MetadataJob::tr("Cannot open file \"%1\" for "
+ "writing: %2").arg(QDir::toNativeSeparators(hashFile.fileName()), hashFile.errorString())));
+ break;
+ }
+ }
}
archive->close();
@@ -101,6 +137,7 @@ private:
QString m_archive;
QString m_targetDir;
bool m_removeArchive;
+ bool m_storeChecksums;
};
class CacheTaskException : public QException
@@ -126,7 +163,7 @@ class UpdateCacheTask : public AbstractTask<void>
Q_DISABLE_COPY(UpdateCacheTask)
public:
- UpdateCacheTask(GenericDataCache<Metadata> &cache, QHash<QString, Metadata *> &updates)
+ UpdateCacheTask(MetadataCache &cache, QHash<QString, Metadata *> &updates)
: m_cache(&cache)
, m_updates(&updates)
{}
@@ -140,7 +177,7 @@ public:
QStringList registeredKeys;
bool success = true;
for (auto *meta : qAsConst(*m_updates)) {
- if (!m_cache->registerItem(meta, true)) {
+ if (!m_cache->registerItem(meta, true, MetadataCache::Move)) {
success = false;
break;
}
@@ -174,7 +211,7 @@ public:
}
private:
- GenericDataCache<Metadata> *const m_cache;
+ MetadataCache *const m_cache;
QHash<QString, Metadata *> *const m_updates;
};
diff --git a/src/libs/installer/observer.cpp b/src/libs/installer/observer.cpp
index 30afce719..57b67d8e1 100644
--- a/src/libs/installer/observer.cpp
+++ b/src/libs/installer/observer.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -121,9 +121,9 @@ QByteArray FileTaskObserver::checkSum() const
return m_hash.result();
}
-void FileTaskObserver::addCheckSumData(const char *data, int length)
+void FileTaskObserver::addCheckSumData(const QByteArray &data)
{
- m_hash.addData(data, length);
+ m_hash.addData(data);
}
void FileTaskObserver::addSample(qint64 sample)
diff --git a/src/libs/installer/observer.h b/src/libs/installer/observer.h
index 198a0f89c..d638d8ee4 100644
--- a/src/libs/installer/observer.h
+++ b/src/libs/installer/observer.h
@@ -60,7 +60,7 @@ public:
QString progressText() const override;
QByteArray checkSum() const;
- void addCheckSumData(const char *data, int length);
+ void addCheckSumData(const QByteArray &data);
void addSample(qint64 sample);
void timerEvent(QTimerEvent *event) override;
diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp
index b7d7d2a26..5c6f481f9 100644
--- a/src/libs/installer/packagemanagercore.cpp
+++ b/src/libs/installer/packagemanagercore.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2023 The Qt Company Ltd.
+** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -31,6 +31,7 @@
#include "adminauthorization.h"
#include "binarycontent.h"
#include "component.h"
+#include "componentalias.h"
#include "componentmodel.h"
#include "downloadarchivesjob.h"
#include "errors.h"
@@ -46,6 +47,7 @@
#include "installercalculator.h"
#include "uninstallercalculator.h"
#include "loggingutils.h"
+#include "componentsortfilterproxymodel.h"
#include <productkeycheck.h>
@@ -56,9 +58,15 @@
#include <QtCore/QMutex>
#include <QtCore/QSettings>
#include <QtCore/QTemporaryFile>
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+#include <QtCore5Compat/QTextCodec>
+#include <QtCore5Compat/QTextDecoder>
+#include <QtCore5Compat/QTextEncoder>
+#else
#include <QtCore/QTextCodec>
#include <QtCore/QTextDecoder>
#include <QtCore/QTextEncoder>
+#endif
#include <QtCore/QTextStream>
#include <QDesktopServices>
@@ -175,25 +183,6 @@ using namespace QInstaller;
Emitted when the new root component \a comp is added.
\sa {installer::componentAdded}{installer.componentAdded}
- \sa rootComponentsAdded(), updaterComponentsAdded()
-*/
-
-/*!
- \fn QInstaller::PackageManagerCore::rootComponentsAdded(QList<QInstaller::Component*> components)
-
- Emitted when the list of root components specified by \a components is added.
-
- \sa {installer::rootComponentsAdded}{installer.rootComponentsAdded}
- \sa componentAdded(), updaterComponentsAdded()
-*/
-
-/*!
- \fn QInstaller::PackageManagerCore::updaterComponentsAdded(QList<QInstaller::Component*> components)
-
- Emitted when a new list of updater components specified by \a components is added.
-
- \sa {installer::updaterComponentsAdded}{installer.updaterComponentsAdded}
- \sa componentAdded(), rootComponentsAdded()
*/
/*!
@@ -213,7 +202,7 @@ using namespace QInstaller;
*/
/*!
- \fn QInstaller::PackageManagerCore::defaultTranslationsLoadedForLanguage(QLocale::Language lang)
+ \fn QInstaller::PackageManagerCore::defaultTranslationsLoadedForLanguage(QLocale lang)
Emitted when the language \a lang has changed.
@@ -600,6 +589,14 @@ bool PackageManagerCore::clearLocalCache(QString *error)
}
/*!
+ Returns \c true if the metadata cache is initialized and valid, \c false otherwise.
+*/
+bool PackageManagerCore::isValidCache() const
+{
+ return d->m_metadataJob.isValidCache();
+}
+
+/*!
\internal
*/
template <typename T>
@@ -612,6 +609,22 @@ template bool PackageManagerCore::loadComponentScripts<QList<Component *>>(const
template bool PackageManagerCore::loadComponentScripts<QHash<QString, Component *>>(const QHash<QString, Component *> &, const bool);
/*!
+ Saves the installer \a args user has given when running installer. Command and option arguments
+ are not saved.
+*/
+void PackageManagerCore::saveGivenArguments(const QStringList &args)
+{
+ m_arguments = args;
+}
+
+/*!
+ Returns the commands and options user has given when running installer.
+*/
+QStringList PackageManagerCore::givenArguments() const
+{
+ return m_arguments;
+}
+/*!
\deprecated [4.5] Use recalculateAllComponents() instead.
\sa {installer::componentsToInstallNeedsRecalculation}{installer.componentsToInstallNeedsRecalculation}
@@ -639,6 +652,12 @@ void PackageManagerCore::componentsToInstallNeedsRecalculation()
*/
bool PackageManagerCore::recalculateAllComponents()
{
+ // Clear previous results first, as the check states are updated
+ // at the end of both calculate methods, which refer to the results
+ // from both calculators. Needed to keep the state correct.
+ d->clearInstallerCalculator();
+ d->clearUninstallerCalculator();
+
if (!calculateComponentsToInstall())
return false;
if (!isInstaller() && !calculateComponentsToUninstall())
@@ -792,12 +811,13 @@ quint64 PackageManagerCore::requiredDiskSpace() const
*/
quint64 PackageManagerCore::requiredTemporaryDiskSpace() const
{
- if (isOfflineOnly())
- return 0;
-
quint64 result = 0;
- foreach (QInstaller::Component *component, orderedComponentsToInstall())
+ foreach (QInstaller::Component *component, orderedComponentsToInstall()) {
+ if (!component->isFromOnlineRepository())
+ continue;
+
result += size(component, scCompressedSize);
+ }
return result;
}
@@ -833,7 +853,7 @@ int PackageManagerCore::downloadNeededArchives(double partProgressSize)
ProgressCoordinator::instance()->emitLabelAndDetailTextChanged(QLatin1Char('\n')
+ tr("Downloading packages..."));
- DownloadArchivesJob archivesJob(this);
+ DownloadArchivesJob archivesJob(this, QLatin1String("downloadArchiveJob"));
archivesJob.setAutoDelete(false);
archivesJob.setArchivesToDownload(archivesToDownload);
archivesJob.setExpectedTotalSize(archivesToDownloadTotalSize);
@@ -1026,8 +1046,7 @@ QString PackageManagerCore::readFile(const QString &filePath, const QString &cod
return QString();
QTextStream stream(&f);
- stream.setCodec(codec);
- return stream.readAll();
+ return QString::fromUtf8(codec->fromUnicode(stream.readAll()));
}
/*!
@@ -1516,7 +1535,7 @@ bool PackageManagerCore::fetchLocalPackagesTree()
continue;
}
- QScopedPointer<QInstaller::Component> component(new QInstaller::Component(this));
+ std::unique_ptr<QInstaller::Component> component(new QInstaller::Component(this));
component->loadDataFromPackage(package);
QString name = component->treeName();
if (components.contains(name)) {
@@ -1542,7 +1561,7 @@ bool PackageManagerCore::fetchLocalPackagesTree()
if (!treeName.isEmpty())
treeNameComponents.insert(component->name(), treeName);
- components.insert(name, component.take());
+ components.insert(name, component.release());
}
// Second pass with leftover packages
if (firstRun)
@@ -1587,10 +1606,11 @@ void PackageManagerCore::networkSettingsChanged()
cancelMetaInfoJob();
d->m_updates = false;
+ d->m_aliases = false;
d->m_repoFetched = false;
d->m_updateSourcesAdded = false;
- if (isMaintainer() ) {
+ if (!isInstaller()) {
bool gainedAdminRights = false;
if (!directoryWritable(d->targetDir())) {
gainAdminRights();
@@ -1663,11 +1683,42 @@ bool PackageManagerCore::fetchCompressedPackagesTree()
return fetchPackagesTree(packages, installedPackages);
}
+bool PackageManagerCore::fetchPackagesWithFallbackRepositories(const QStringList& components, bool &fallBackReposFetched)
+{
+ auto checkComponents = [&]() {
+ if (!fetchRemotePackagesTree(components))
+ return false;
+ return true;
+ };
+
+ if (!checkComponents()) {
+ // error when fetching packages tree
+ if (status() != NoPackagesFound)
+ return false;
+ //retry fetching packages with all categories enabled
+ fallBackReposFetched = true;
+ if (!d->enableAllCategories())
+ return false;
+
+ qCDebug(QInstaller::lcInstallerInstallLog).noquote()
+ << "Components not found with the current selection."
+ << "Searching from additional repositories";
+ if (!ProductKeyCheck::instance()->securityWarning().isEmpty()) {
+ qCWarning(QInstaller::lcInstallerInstallLog) << ProductKeyCheck::instance()->securityWarning();
+ }
+ if (!checkComponents()) {
+ return false;
+ }
+ }
+ return true;
+}
+
/*!
Checks for packages to install. Returns \c true if newer versions exist
- and they can be installed.
+ and they can be installed. Returns \c false if not \a components are found
+ for install, or if error occurred when fetching and generating package tree.
*/
-bool PackageManagerCore::fetchRemotePackagesTree()
+bool PackageManagerCore::fetchRemotePackagesTree(const QStringList& components)
{
d->setStatus(Running);
@@ -1695,8 +1746,14 @@ bool PackageManagerCore::fetchRemotePackagesTree()
return false;
const PackagesList &packages = d->remotePackages();
- if (packages.isEmpty())
+ if (packages.isEmpty()) {
+ d->setStatus(PackageManagerCore::NoPackagesFound);
return false;
+ }
+
+ if (!d->installablePackagesFound(components))
+ return false;
+
return fetchPackagesTree(packages, installedPackages);
}
@@ -1945,6 +2002,82 @@ void PackageManagerCore::setTemporaryRepositories(const QStringList &repositorie
settings().setTemporaryRepositories(repositorySet, replace);
}
+bool PackageManagerCore::addQBspRepositories(const QStringList &repositories)
+{
+ QSet<Repository> set;
+ foreach (QString fileName, repositories) {
+ Repository repository = Repository::fromUserInput(fileName, true);
+ repository.setEnabled(true);
+ set.insert(repository);
+ }
+ if (set.count() > 0) {
+ settings().addTemporaryRepositories(set, false);
+ return true;
+ }
+ return false;
+}
+
+bool PackageManagerCore::validRepositoriesAvailable() const
+{
+ foreach (const Repository &repo, settings().repositories()) {
+ if (repo.isEnabled() && repo.isValid()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void PackageManagerCore::setAllowCompressedRepositoryInstall(bool allow)
+{
+ d->m_allowCompressedRepositoryInstall = allow;
+}
+
+bool PackageManagerCore::allowCompressedRepositoryInstall() const
+{
+ return d->m_allowCompressedRepositoryInstall;
+}
+
+bool PackageManagerCore::showRepositoryCategories() const
+{
+ bool showCagetories = settings().repositoryCategories().count() > 0 && !isOfflineOnly() && !isUpdater();
+ if (showCagetories)
+ settings().setAllowUnstableComponents(true);
+ return showCagetories;
+}
+
+QVariantMap PackageManagerCore::organizedRepositoryCategories() const
+{
+ QVariantMap map;
+ QSet<RepositoryCategory> categories = settings().repositoryCategories();
+ foreach (const RepositoryCategory &category, categories)
+ map.insert(category.displayname(), QVariant::fromValue(category));
+ return map;
+}
+
+void PackageManagerCore::enableRepositoryCategory(const QString &repositoryName, bool enable)
+{
+ QMap<QString, RepositoryCategory> organizedRepositoryCategories = settings().organizedRepositoryCategories();
+
+ QMap<QString, RepositoryCategory>::iterator i = organizedRepositoryCategories.find(repositoryName);
+ while (i != organizedRepositoryCategories.end() && i.key() == repositoryName) {
+ d->enableRepositoryCategory(i.value(), enable);
+ i++;
+ }
+}
+
+void PackageManagerCore::runProgram()
+{
+ const QString program = replaceVariables(value(scRunProgram));
+
+ const QStringList args = replaceVariables(values(scRunProgramArguments));
+ if (program.isEmpty())
+ return;
+
+ qCDebug(QInstaller::lcInstallerInstallLog) << "starting" << program << args;
+ QProcess::startDetached(program, args);
+}
+
+
/*!
Returns the script engine that prepares and runs the component scripts.
@@ -2102,6 +2235,15 @@ Component *PackageManagerCore::componentByName(const QString &name) const
}
/*!
+ Searches for a component alias matching \a name and returns it.
+ If no alias matches the name, \c nullptr is returned.
+*/
+ComponentAlias *PackageManagerCore::aliasByName(const QString &name) const
+{
+ return d->m_componentAliases.value(name);
+}
+
+/*!
Searches \a components for a component matching \a name and returns it.
\a name can also contain a version requirement. For example, \c org.qt-project.sdk.qt
returns any component with that name, whereas \c{org.qt-project.sdk.qt->=4.5} requires
@@ -2127,6 +2269,18 @@ Component *PackageManagerCore::componentByName(const QString &name, const QList<
}
/*!
+ Returns an array of all components currently available. If the repository
+ metadata have not been fetched yet, the array will be empty. Optionally, a
+ \a regexp expression can be used to further filter the listed packages.
+
+ \sa {installer::components}{installer.components}
+ */
+QList<Component *> PackageManagerCore::components(const QString &regexp) const
+{
+ return components(PackageManagerCore::ComponentType::All, regexp);
+}
+
+/*!
Returns \c true if directory specified by \a path is writable by
the current user.
*/
@@ -2164,8 +2318,26 @@ QList<Component *> PackageManagerCore::componentsMarkedForInstallation() const
}
/*!
- Determines which components to install based on the current run mode, including dependencies
- and automatic dependencies. Returns \c true on success, \c false otherwise.
+ Returns a list of component aliases that are marked for installation.
+ The list can be empty.
+*/
+QList<ComponentAlias *> PackageManagerCore::aliasesMarkedForInstallation() const
+{
+ if (isUpdater()) // Aliases not supported on update at the moment
+ return QList<ComponentAlias *>();
+
+ QList<ComponentAlias *> markedForInstallation;
+ for (auto *alias : qAsConst(d->m_componentAliases)) {
+ if (alias && alias->isSelected())
+ markedForInstallation.append(alias);
+ }
+
+ return markedForInstallation;
+}
+
+/*!
+ Determines which components to install based on the current run mode, including component aliases,
+ dependencies and automatic dependencies. Returns \c true on success, \c false otherwise.
The aboutCalculateComponentsToInstall() signal is emitted
before the calculation starts, the finishedCalculateComponentsToInstall()
@@ -2179,15 +2351,13 @@ bool PackageManagerCore::calculateComponentsToInstall() const
emit aboutCalculateComponentsToInstall();
d->clearInstallerCalculator();
- const QList<Component*> selectedComponentsToInstall = componentsMarkedForInstallation();
- const bool componentsToInstallCalculated =
- d->installerCalculator()->solve(selectedComponentsToInstall);
+ const bool calculated = d->installerCalculator()->solve();
d->updateComponentInstallActions();
emit finishedCalculateComponentsToInstall();
- return componentsToInstallCalculated;
+ return calculated;
}
/*!
@@ -2455,12 +2625,13 @@ ComponentModel *PackageManagerCore::defaultComponentModel() const
if (!d->m_defaultModel) {
d->m_defaultModel = componentModel(const_cast<PackageManagerCore*> (this),
QLatin1String("AllComponentsModel"));
+
+ connect(this, &PackageManagerCore::startAllComponentsReset, [&] {
+ d->m_defaultModel->reset();
+ });
+ connect(this, &PackageManagerCore::finishAllComponentsReset, d->m_defaultModel,
+ &ComponentModel::reset);
}
- connect(this, &PackageManagerCore::startAllComponentsReset, [&] {
- d->m_defaultModel->reset();
- });
- connect(this, &PackageManagerCore::finishAllComponentsReset, d->m_defaultModel,
- &ComponentModel::reset);
return d->m_defaultModel;
}
@@ -2473,44 +2644,70 @@ ComponentModel *PackageManagerCore::updaterComponentModel() const
if (!d->m_updaterModel) {
d->m_updaterModel = componentModel(const_cast<PackageManagerCore*> (this),
QLatin1String("UpdaterComponentsModel"));
+
+ connect(this, &PackageManagerCore::startUpdaterComponentsReset, [&] {
+ d->m_updaterModel->reset();
+ });
+ connect(this, &PackageManagerCore::finishUpdaterComponentsReset, d->m_updaterModel,
+ &ComponentModel::reset);
}
- connect(this, &PackageManagerCore::startUpdaterComponentsReset, [&] {
- d->m_updaterModel->reset();
- });
- connect(this, &PackageManagerCore::finishUpdaterComponentsReset, d->m_updaterModel,
- &ComponentModel::reset);
return d->m_updaterModel;
}
/*!
+ Returns the proxy model
+*/
+
+ComponentSortFilterProxyModel *PackageManagerCore::componentSortFilterProxyModel()
+{
+ if (!d->m_componentSortFilterProxyModel) {
+ d->m_componentSortFilterProxyModel = new ComponentSortFilterProxyModel(this);
+ d->m_componentSortFilterProxyModel->setRecursiveFilteringEnabled(true);
+ d->m_componentSortFilterProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
+ }
+ return d->m_componentSortFilterProxyModel;
+}
+
+/*!
Lists available packages filtered with \a regexp without GUI. Virtual
components are not listed unless set visible. Optionally, a \a filters
hash containing package information elements and regular expressions
can be used to further filter listed packages.
+ Returns \c true if matching packages were found, \c false otherwise.
+
\sa setVirtualComponentsVisible()
*/
-void PackageManagerCore::listAvailablePackages(const QString &regexp, const QHash<QString, QString> &filters)
+bool PackageManagerCore::listAvailablePackages(const QString &regexp, const QHash<QString, QString> &filters)
{
setPackageViewer();
+ d->enableAllCategories();
qCDebug(QInstaller::lcInstallerInstallLog)
<< "Searching packages with regular expression:" << regexp;
ComponentModel *model = defaultComponentModel();
- d->fetchMetaInformationFromRepositories();
+ PackagesList packages;
+
+ if (!d->m_updates) {
+ d->fetchMetaInformationFromRepositories();
+ d->addUpdateResourcesFromRepositories();
+
+ packages = d->remotePackages();
+ if (!fetchAllPackages(packages, LocalPackagesMap())) {
+ qCWarning(QInstaller::lcInstallerInstallLog)
+ << "There was a problem with loading the package data.";
+ return false;
+ }
+ } else {
+ // No need to fetch metadata again
+ packages = d->remotePackages();
+ }
- d->addUpdateResourcesFromRepositories();
QRegularExpression re(regexp);
re.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
- const PackagesList &packages = d->remotePackages();
- if (!fetchAllPackages(packages, LocalPackagesMap())) {
- qCWarning(QInstaller::lcInstallerInstallLog)
- << "There was a problem with loading the package data.";
- return;
- }
PackagesList matchedPackages;
- foreach (Package *package, packages) {
+ foreach (Package *package, qAsConst(packages)) {
const QString name = package->data(scName).toString();
Component *component = componentByName(name);
if (!component)
@@ -2532,10 +2729,68 @@ void PackageManagerCore::listAvailablePackages(const QString &regexp, const QHas
matchedPackages.append(package);
}
}
- if (matchedPackages.count() == 0)
+ if (matchedPackages.count() == 0) {
qCDebug(QInstaller::lcInstallerInstallLog) << "No matching packages found.";
- else
- LoggingHandler::instance().printPackageInformation(matchedPackages, localInstalledPackages());
+ return false;
+ }
+
+ LoggingHandler::instance().printPackageInformation(matchedPackages, localInstalledPackages());
+ return true;
+}
+
+/*!
+ Lists available component aliases filtered with \a regexp without GUI. Virtual
+ aliases are not listed unless set visible.
+
+ Returns \c true if matching package aliases were found, \c false otherwise.
+
+ \sa setVirtualComponentsVisible()
+*/
+bool PackageManagerCore::listAvailableAliases(const QString &regexp)
+{
+ setPackageViewer();
+ d->enableAllCategories();
+ qCDebug(QInstaller::lcInstallerInstallLog)
+ << "Searching aliases with regular expression:" << regexp;
+
+ ComponentModel *model = defaultComponentModel();
+ Q_UNUSED(model);
+
+ if (!d->m_updates) {
+ d->fetchMetaInformationFromRepositories();
+ d->addUpdateResourcesFromRepositories();
+
+ const PackagesList &packages = d->remotePackages();
+ if (!fetchAllPackages(packages, LocalPackagesMap())) {
+ qCWarning(QInstaller::lcInstallerInstallLog)
+ << "There was a problem with loading the package data.";
+ return false;
+ }
+ }
+
+ QRegularExpression re(regexp);
+ re.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
+
+ QList<ComponentAlias *> matchedAliases;
+ for (auto *alias : qAsConst(d->m_componentAliases)) {
+ if (!alias)
+ continue;
+
+ if (re.match(alias->name()).hasMatch() && !alias->isUnstable()) {
+ if (alias->isVirtual() && !virtualComponentsVisible())
+ continue;
+
+ matchedAliases.append(alias);
+ }
+ }
+
+ if (matchedAliases.isEmpty()) {
+ qCDebug(QInstaller::lcInstallerInstallLog) << "No matching package aliases found.";
+ return false;
+ }
+
+ LoggingHandler::instance().printAliasInformation(matchedAliases);
+ return true;
}
bool PackageManagerCore::componentUninstallableFromCommandLine(const QString &componentName)
@@ -2549,7 +2804,7 @@ bool PackageManagerCore::componentUninstallableFromCommandLine(const QString &co
}
ComponentModel *model = defaultComponentModel();
const QModelIndex &idx = model->indexFromComponentName(component->treeName());
- if (model->data(idx, Qt::CheckStateRole) == QVariant::Invalid) {
+ if (model->data(idx, Qt::CheckStateRole) == QVariant()) {
// Component cannot be unselected, check why
if (component->forcedInstallation()) {
qCWarning(QInstaller::lcInstallerInstallLog).noquote().nospace()
@@ -2573,25 +2828,45 @@ bool PackageManagerCore::componentUninstallableFromCommandLine(const QString &co
/*!
\internal
- Tries to set \c Qt::CheckStateRole to \c Qt::Checked for given \a components in the
- default component model. Returns \c true if \a components contains at least one component
+ Tries to set \c Qt::CheckStateRole to \c Qt::Checked for given component \a names in the
+ default component model, and select given aliases in the \c names list.
+
+ Returns \c true if \a names contains at least one component or component alias
eligible for installation, otherwise returns \c false. An error message can be retrieved
with \a errorMessage.
*/
-bool PackageManagerCore::checkComponentsForInstallation(const QStringList &components, QString &errorMessage)
+bool PackageManagerCore::checkComponentsForInstallation(const QStringList &names, QString &errorMessage, bool &unstableAliasFound)
{
bool installComponentsFound = false;
ComponentModel *model = defaultComponentModel();
- foreach (const QString &name, components) {
+ foreach (const QString &name, names) {
Component *component = componentByName(name);
if (!component) {
- errorMessage.append(tr("Cannot install %1. Component not found.").arg(name) + QLatin1Char('\n'));
+ // No such component, check if we have an alias by the name
+ if (ComponentAlias *alias = aliasByName(name)) {
+ if (alias->isUnstable()) {
+ errorMessage.append(tr("Cannot select alias %1. There was a problem loading this alias, "
+ "so it is marked unstable and cannot be selected.").arg(name) + QLatin1Char('\n'));
+ unstableAliasFound = true;
+ continue;
+ } else if (alias->isVirtual()) {
+ errorMessage.append(tr("Cannot select %1. Alias is marked virtual, meaning it cannot "
+ "be selected manually.").arg(name) + QLatin1Char('\n'));
+ continue;
+ }
+
+ alias->setSelected(true);
+ installComponentsFound = true;
+ } else {
+ errorMessage.append(tr("Cannot install %1. Component not found.").arg(name) + QLatin1Char('\n'));
+ }
+
continue;
}
const QModelIndex &idx = model->indexFromComponentName(component->treeName());
if (idx.isValid()) {
- if ((model->data(idx, Qt::CheckStateRole) == QVariant::Invalid) && !component->forcedInstallation()) {
+ if ((model->data(idx, Qt::CheckStateRole) == QVariant()) && !component->forcedInstallation()) {
// User cannot select the component, check why
if (component->autoDependencies().count() > 0) {
errorMessage.append(tr("Cannot install component %1. Component is installed only as automatic "
@@ -2661,6 +2936,25 @@ void PackageManagerCore::listInstalledPackages(const QString &regexp)
LoggingHandler::instance().printLocalPackageInformation(packages);
}
+PackageManagerCore::Status PackageManagerCore::searchAvailableUpdates()
+{
+ setUpdater();
+ d->enableAllCategories();
+ if (!fetchRemotePackagesTree()) {
+ qCWarning(QInstaller::lcInstallerInstallLog) << error();
+ return status();
+ }
+
+ const QList<QInstaller::Component *> availableUpdates =
+ components(QInstaller::PackageManagerCore::ComponentType::Root);
+ if (availableUpdates.isEmpty()) {
+ qCWarning(QInstaller::lcInstallerInstallLog) << "There are currently no updates available.";
+ return status();
+ }
+ QInstaller::LoggingHandler::instance().printUpdateInformation(availableUpdates);
+ return status();
+}
+
/*!
Updates the selected components \a componentsToUpdate without GUI.
If essential components are found, then only those will be updated.
@@ -2668,13 +2962,25 @@ void PackageManagerCore::listInstalledPackages(const QString &regexp)
*/
PackageManagerCore::Status PackageManagerCore::updateComponentsSilently(const QStringList &componentsToUpdate)
{
- if (d->runningProcessesFound())
- throw Error(tr("Running processes found."));
setUpdater();
ComponentModel *model = updaterComponentModel();
- fetchRemotePackagesTree();
+ if (componentsToUpdate.isEmpty()) {
+ d->enableAllCategories();
+ fetchRemotePackagesTree();
+ } else {
+ bool fallbackReposFetched = false;
+ bool packagesFound = fetchPackagesWithFallbackRepositories(componentsToUpdate, fallbackReposFetched);
+
+ if (!packagesFound) {
+ qCDebug(QInstaller::lcInstallerInstallLog).noquote().nospace()
+ << "No components available for update with the current selection.";
+ d->setStatus(Canceled);
+ return status();
+ }
+ }
+
// List contains components containing update, if essential found contains only essential component
const QList<QInstaller::Component*> componentList = componentsMarkedForInstallation();
@@ -2780,6 +3086,20 @@ void PackageManagerCore::addLicenseItem(const QHash<QString, QVariantMap> &licen
}
}
+bool PackageManagerCore::hasLicenses() const
+{
+ foreach (Component* component, orderedComponentsToInstall()) {
+ if (isMaintainer() && component->isInstalled())
+ continue; // package manager or updater, hide as long as the component is installed
+
+ // The component is about to be installed and provides a license, so the page needs to
+ // be shown.
+ if (!component->licenses().isEmpty())
+ return true;
+ }
+ return false;
+}
+
/*!
* Adds \a component local \a dependencies to a hash table for quicker search for
* uninstall dependency components.
@@ -2804,9 +3124,6 @@ void PackageManagerCore::createAutoDependencyHash(const QString &component, cons
*/
PackageManagerCore::Status PackageManagerCore::uninstallComponentsSilently(const QStringList& components)
{
- if (d->runningProcessesFound())
- throw Error(tr("Running processes found."));
-
if (components.isEmpty()) {
qCDebug(QInstaller::lcInstallerInstallLog) << "No components selected for uninstallation.";
return PackageManagerCore::Canceled;
@@ -2845,8 +3162,6 @@ PackageManagerCore::Status PackageManagerCore::uninstallComponentsSilently(const
PackageManagerCore::Status PackageManagerCore::removeInstallationSilently()
{
setCompleteUninstallation(true);
- if (d->runningProcessesFound())
- throw Error(tr("Running processes found."));
qCDebug(QInstaller::lcInstallerInstallLog) << "Complete uninstallation was chosen.";
if (!(d->m_autoConfirmCommand || d->askUserConfirmCommand())) {
@@ -2868,23 +3183,7 @@ PackageManagerCore::Status PackageManagerCore::removeInstallationSilently()
PackageManagerCore::Status PackageManagerCore::createOfflineInstaller(const QStringList &componentsToAdd)
{
setOfflineGenerator();
- // init default model before fetching remote packages tree
- ComponentModel *model = defaultComponentModel();
- Q_UNUSED(model);
- if (!fetchRemotePackagesTree())
- return status();
-
- QString errorMessage;
- if (checkComponentsForInstallation(componentsToAdd, errorMessage)) {
- if (d->calculateComponentsAndRun()) {
- qCDebug(QInstaller::lcInstallerInstallLog)
- << "Created installer to:" << offlineBinaryName();
- }
- } else {
- qCDebug(QInstaller::lcInstallerInstallLog).noquote().nospace() << errorMessage
- << "\nNo components available with the current selection.";
- }
- return status();
+ return d->fetchComponentsAndInstall(componentsToAdd);
}
/*!
@@ -2896,9 +3195,6 @@ PackageManagerCore::Status PackageManagerCore::createOfflineInstaller(const QStr
PackageManagerCore::Status PackageManagerCore::installSelectedComponentsSilently(const QStringList& components)
{
if (!isInstaller()) {
- // Check if there are processes running in the install if maintenancetool is used.
- if (d->runningProcessesFound())
- throw Error(tr("Running processes found."));
setPackageManager();
//Check that packages are not already installed
@@ -2911,24 +3207,7 @@ PackageManagerCore::Status PackageManagerCore::installSelectedComponentsSilently
return PackageManagerCore::Canceled;
}
}
-
- // init default model before fetching remote packages tree
- ComponentModel *model = defaultComponentModel();
- Q_UNUSED(model);
- if (!fetchRemotePackagesTree())
- return status();
-
- QString errorMessage;
- if (checkComponentsForInstallation(components, errorMessage)) {
- if (!errorMessage.isEmpty())
- qCDebug(QInstaller::lcInstallerInstallLog).noquote().nospace() << errorMessage;
- if (d->calculateComponentsAndRun())
- qCDebug(QInstaller::lcInstallerInstallLog) << "Components installed successfully";
- } else {
- qCDebug(QInstaller::lcInstallerInstallLog).noquote().nospace() << errorMessage
- << "\nNo components available for installation with the current selection.";
- }
- return status();
+ return d->fetchComponentsAndInstall(components);
}
/*!
@@ -2994,6 +3273,21 @@ void PackageManagerCore::dropAdminRights()
}
/*!
+ Returns \c true if the installer has admin rights. For example, if the installer
+ was started with a root account, or the internal admin rights elevation is active.
+
+ Returns \c false otherwise.
+
+ \sa {installer::hasAdminRights}{installer.hasAdminRights}
+ \sa gainAdminRights()
+ \sa dropAdminRights()
+*/
+bool PackageManagerCore::hasAdminRights() const
+{
+ return AdminAuthorization::hasAdminRights() || RemoteClient::instance().isActive();
+}
+
+/*!
Sets checkAvailableSpace based on value of \a check.
*/
void PackageManagerCore::setCheckAvailableSpace(bool check)
@@ -3002,12 +3296,22 @@ void PackageManagerCore::setCheckAvailableSpace(bool check)
}
/*!
- Checks available disk space if the feature is not explicitly disabled. Informative
- text about space status can be retrieved by passing \a message parameter. Returns
+ * Returns informative text about disk space status
+ */
+QString PackageManagerCore::availableSpaceMessage() const
+{
+ return m_availableSpaceMessage;
+}
+
+/*!
+ Checks available disk space if the feature is not explicitly disabled. Returns
\c true if there is sufficient free space on installation and temporary volumes.
+
+ \sa availableSpaceMessage()
*/
-bool PackageManagerCore::checkAvailableSpace(QString &message) const
+bool PackageManagerCore::checkAvailableSpace()
{
+ m_availableSpaceMessage.clear();
const quint64 extraSpace = 256 * 1024 * 1024LL;
quint64 required(requiredDiskSpace());
quint64 tempRequired(requiredTemporaryDiskSpace());
@@ -3063,21 +3367,21 @@ bool PackageManagerCore::checkAvailableSpace(QString &message) const
}
if (cacheOnSameVolume && (installVolumeAvailableSize <= (required + tempRequired))) {
- message = tr("Not enough disk space to store temporary files and the "
+ m_availableSpaceMessage = tr("Not enough disk space to store temporary files and the "
"installation. %1 are available, while the minimum required is %2.").arg(
humanReadableSize(installVolumeAvailableSize), humanReadableSize(required + tempRequired));
return false;
}
if (installVolumeAvailableSize < required) {
- message = tr("Not enough disk space to store all selected components! %1 are "
+ m_availableSpaceMessage = tr("Not enough disk space to store all selected components! %1 are "
"available, while the minimum required is %2.").arg(humanReadableSize(installVolumeAvailableSize),
humanReadableSize(required));
return false;
}
if (cacheVolumeAvailableSize < tempRequired) {
- message = tr("Not enough disk space to store temporary files! %1 are available, "
+ m_availableSpaceMessage = tr("Not enough disk space to store temporary files! %1 are available, "
"while the minimum required is %2. You may select another location for the "
"temporary files by modifying the local cache path from the installer settings.")
.arg(humanReadableSize(cacheVolumeAvailableSize), humanReadableSize(tempRequired));
@@ -3086,22 +3390,25 @@ bool PackageManagerCore::checkAvailableSpace(QString &message) const
if (installVolumeAvailableSize - required < 0.01 * targetVolume.size()) {
// warn for less than 1% of the volume's space being free
- message = tr("The volume you selected for installation seems to have sufficient space for "
+ m_availableSpaceMessage = tr("The volume you selected for installation seems to have sufficient space for "
"installation, but there will be less than 1% of the volume's space available afterwards.");
} else if (installVolumeAvailableSize - required < 100 * 1024 * 1024LL) {
// warn for less than 100MB being free
- message = tr("The volume you selected for installation seems to have sufficient "
+ m_availableSpaceMessage = tr("The volume you selected for installation seems to have sufficient "
"space for installation, but there will be less than 100 MB available afterwards.");
}
#ifdef Q_OS_WIN
if (isOfflineGenerator() && (required > UINT_MAX)) {
- message = tr("The estimated installer size %1 would exceed the supported executable "
+ m_availableSpaceMessage = tr("The estimated installer size %1 would exceed the supported executable "
"size limit of %2. The application may not be able to run.")
.arg(humanReadableSize(required), humanReadableSize(UINT_MAX));
}
#endif
}
- message = QString::fromLatin1("%1 %2").arg(message, tr("Installation will use %1 of disk space.")
+ m_availableSpaceMessage = QString::fromLatin1("%1 %2").arg(m_availableSpaceMessage,
+ (isOfflineGenerator()
+ ? tr("Created installer will use %1 of disk space.")
+ : tr("Installation will use %1 of disk space."))
.arg(humanReadableSize(requiredDiskSpace()))).simplified();
return true;
@@ -3160,6 +3467,10 @@ bool PackageManagerCore::killProcess(const QString &absoluteFilePath) const
}
/*!
+ \deprecated [4.6] Maintenance tool no longer automatically checks for all running processes
+ in the installation directory for CLI runs. To manually check for a process to stop, use
+ \l {component::addStopProcessForUpdateRequest}{component.addStopProcessForUpdateRequest} instead.
+
Sets additional \a processes that can run when
updating with the maintenance tool.
@@ -3171,6 +3482,10 @@ void PackageManagerCore::setAllowedRunningProcesses(const QStringList &processes
}
/*!
+ \deprecated [4.6] Maintenance tool no longer automatically checks for all running processes
+ in the installation directory for CLI runs. To manually check for a process to stop, use
+ \l {component::addStopProcessForUpdateRequest}{component.addStopProcessForUpdateRequest} instead.
+
Returns processes that are allowed to run when
updating with the maintenance tool.
@@ -3686,6 +4001,14 @@ QString PackageManagerCore::offlineBinaryName() const
}
/*!
+ Add new \a source for looking component aliases.
+*/
+void PackageManagerCore::addAliasSource(const AliasSource &source)
+{
+ d->m_aliasSources.insert(source);
+}
+
+/*!
\sa {installer::setInstaller}{installer.setInstaller}
\sa isInstaller(), setUpdater(), setPackageManager()
*/
@@ -3787,6 +4110,7 @@ bool PackageManagerCore::isPackageManager() const
void PackageManagerCore::setOfflineGenerator()
{
d->m_magicMarkerSupplement = BinaryContent::OfflineGenerator;
+ emit installerBinaryMarkerChanged(d->m_magicBinaryMarker);
}
/*!
@@ -3805,6 +4129,7 @@ bool PackageManagerCore::isOfflineGenerator() const
void PackageManagerCore::setPackageViewer()
{
d->m_magicMarkerSupplement = BinaryContent::PackageViewer;
+ emit installerBinaryMarkerChanged(d->m_magicBinaryMarker);
}
/*!
@@ -3818,6 +4143,17 @@ bool PackageManagerCore::isPackageViewer() const
}
/*!
+ Resets the binary marker supplement of the installer to \c Default.
+ The supplement enables or disables additional features on top of the binary
+ marker state (\c Installer, \c Updater, \c PackageManager, \c Uninstaller).
+*/
+void PackageManagerCore::resetBinaryMarkerSupplement()
+{
+ d->m_magicMarkerSupplement = BinaryContent::Default;
+ emit installerBinaryMarkerChanged(d->m_magicBinaryMarker);
+}
+
+/*!
Sets the installer magic binary marker based on \a magicMarker and
userSetBinaryMarker to \c true.
*/
@@ -3992,13 +4328,6 @@ bool PackageManagerCore::updateComponentData(struct Data &data, Component *compo
component->setUninstalled();
const QString localPath = component->localTempPath();
- if (LoggingHandler::instance().verboseLevel() == LoggingHandler::Detailed) {
- static QString lastLocalPath;
- if (lastLocalPath != localPath)
- qCDebug(QInstaller::lcDeveloperBuild()) << "Url is:" << localPath;
- lastLocalPath = localPath;
- }
-
const Repository repo = d->m_metadataJob.repositoryForCacheDirectory(localPath);
if (repo.isValid()) {
@@ -4130,10 +4459,10 @@ bool PackageManagerCore::fetchAllPackages(const PackagesList &remotes, const Loc
continue;
}
- QScopedPointer<QInstaller::Component> remoteComponent(new QInstaller::Component(this));
+ std::unique_ptr<QInstaller::Component> remoteComponent(new QInstaller::Component(this));
data.package = package;
remoteComponent->loadDataFromPackage(*package);
- if (updateComponentData(data, remoteComponent.data())) {
+ if (updateComponentData(data, remoteComponent.get())) {
// Create a list where is name and treename. Repo can contain a package with
// a different treename of component which is already installed. We don't want
// to move already installed local packages.
@@ -4141,7 +4470,7 @@ bool PackageManagerCore::fetchAllPackages(const PackagesList &remotes, const Loc
if (!treeName.isEmpty())
remoteTreeNameComponents.insert(remoteComponent->name(), treeName);
const QString name = remoteComponent->treeName();
- allComponents.insert(name, remoteComponent.take());
+ allComponents.insert(name, remoteComponent.release());
}
}
// Second pass with leftover packages
@@ -4164,7 +4493,7 @@ bool PackageManagerCore::fetchAllPackages(const PackagesList &remotes, const Loc
d->m_localVirtualComponents.append(package.name);
}
- QScopedPointer<QInstaller::Component> localComponent(new QInstaller::Component(this));
+ std::unique_ptr<QInstaller::Component> localComponent(new QInstaller::Component(this));
localComponent->loadDataFromPackage(package);
const QString name = localComponent->treeName();
@@ -4219,7 +4548,7 @@ bool PackageManagerCore::fetchAllPackages(const PackagesList &remotes, const Loc
const QString treeName = localComponent->value(scTreeName);
if (!treeName.isEmpty())
allTreeNameComponents.insert(localComponent->name(), treeName);
- allComponents.insert(name, localComponent.take());
+ allComponents.insert(name, localComponent.release());
}
// store all components that got a replacement
@@ -4233,6 +4562,9 @@ bool PackageManagerCore::fetchAllPackages(const PackagesList &remotes, const Loc
d->commitPendingUnstableComponents();
+ if (!d->buildComponentAliases())
+ return false;
+
} catch (const Error &error) {
d->clearAllComponentLists();
d->setStatus(PackageManagerCore::Failure, error.message());
@@ -4270,12 +4602,12 @@ bool PackageManagerCore::fetchUpdaterPackages(const PackagesList &remotes, const
if (!ProductKeyCheck::instance()->isValidPackage(update->data(scName).toString()))
continue;
- QScopedPointer<QInstaller::Component> component(new QInstaller::Component(this));
+ std::unique_ptr<QInstaller::Component> component(new QInstaller::Component(this));
data.package = update;
component->loadDataFromPackage(*update);
- if (updateComponentData(data, component.data())) {
+ if (updateComponentData(data, component.get())) {
// Keep a reference so we can resolve dependencies during update.
- d->m_updaterComponentsDeps.append(component.take());
+ d->m_updaterComponentsDeps.append(component.release());
// const QString isNew = update->data(scNewComponent).toString();
// if (isNew.toLower() != scTrue)
diff --git a/src/libs/installer/packagemanagercore.h b/src/libs/installer/packagemanagercore.h
index e5236112e..170ddf557 100644
--- a/src/libs/installer/packagemanagercore.h
+++ b/src/libs/installer/packagemanagercore.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2023 The Qt Company Ltd.
+** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -29,6 +29,7 @@
#define PACKAGEMANAGERCORE_H
#include "binaryformat.h"
+#include "binarycontent.h"
#include "component.h"
#include "protocol.h"
#include "repository.h"
@@ -45,11 +46,14 @@
namespace QInstaller {
+struct AliasSource;
class ComponentModel;
+class ComponentAlias;
class ScriptEngine;
class PackageManagerCorePrivate;
class PackageManagerProxyFactory;
class Settings;
+class ComponentSortFilterProxyModel;
// -- PackageManagerCore
@@ -80,7 +84,8 @@ public:
Canceled = 3,
Unfinished = 4,
ForceUpdate = 5,
- EssentialUpdated = 6
+ EssentialUpdated = 6,
+ NoPackagesFound = 7
};
Status status() const;
QString error() const;
@@ -145,8 +150,9 @@ public:
void setProxyFactory(PackageManagerProxyFactory *factory);
PackagesList remotePackages();
- bool fetchRemotePackagesTree();
+ bool fetchRemotePackagesTree(const QStringList& components = QStringList());
bool fetchCompressedPackagesTree();
+ bool fetchPackagesWithFallbackRepositories(const QStringList& components, bool &fallBackReposFetched);
bool run();
void reset();
@@ -202,9 +208,20 @@ public:
void setOfflineBinaryName(const QString &name);
QString offlineBinaryName() const;
+ void addAliasSource(const AliasSource &source);
+
Q_INVOKABLE void addUserRepositories(const QStringList &repositories);
Q_INVOKABLE void setTemporaryRepositories(const QStringList &repositories,
bool replace = false, bool compressed = false);
+ bool addQBspRepositories(const QStringList &repositories);
+ bool validRepositoriesAvailable() const;
+ Q_INVOKABLE void setAllowCompressedRepositoryInstall(bool allow);
+ bool allowCompressedRepositoryInstall() const;
+ bool showRepositoryCategories() const;
+ QVariantMap organizedRepositoryCategories() const;
+ void enableRepositoryCategory(const QString &repositoryName, bool enable);
+ void runProgram();
+
Q_INVOKABLE void autoAcceptMessageBoxes();
Q_INVOKABLE void autoRejectMessageBoxes();
Q_INVOKABLE void setMessageBoxAutomaticAnswer(const QString &identifier, int button);
@@ -241,7 +258,10 @@ public:
void appendUpdaterComponent(Component *components);
QList<Component *> components(ComponentTypes mask, const QString &regexp = QString()) const;
- Component *componentByName(const QString &identifier) const;
+ Q_INVOKABLE QInstaller::Component *componentByName(const QString &identifier) const;
+ Q_INVOKABLE QList<QInstaller::Component *> components(const QString &regexp = QString()) const;
+
+ ComponentAlias *aliasByName(const QString &name) const;
Q_INVOKABLE bool calculateComponentsToInstall() const;
QList<Component*> orderedComponentsToInstall() const;
@@ -252,6 +272,9 @@ public:
Q_INVOKABLE bool calculateComponentsToUninstall() const;
QList<Component*> componentsToUninstall() const;
+ QList<Component *> componentsMarkedForInstallation() const;
+ QList<ComponentAlias *> aliasesMarkedForInstallation() const;
+
QString componentsToInstallError() const;
QString componentsToUninstallError() const;
QString installReason(Component *component) const;
@@ -263,9 +286,14 @@ public:
ComponentModel *defaultComponentModel() const;
ComponentModel *updaterComponentModel() const;
+ ComponentSortFilterProxyModel *componentSortFilterProxyModel();
+
void listInstalledPackages(const QString &regexp = QString());
- void listAvailablePackages(const QString &regexp = QString(),
+ bool listAvailablePackages(const QString &regexp = QString(),
const QHash<QString, QString> &filters = QHash<QString, QString>());
+ bool listAvailableAliases(const QString &regexp = QString());
+
+ PackageManagerCore::Status searchAvailableUpdates();
PackageManagerCore::Status updateComponentsSilently(const QStringList &componentsToUpdate);
PackageManagerCore::Status installSelectedComponentsSilently(const QStringList& components);
PackageManagerCore::Status installDefaultComponentsSilently();
@@ -293,6 +321,8 @@ public:
void setPackageViewer();
Q_INVOKABLE bool isPackageViewer() const;
+ void resetBinaryMarkerSupplement();
+
void setUserSetBinaryMarker(qint64 magicMarker);
Q_INVOKABLE bool isUserSetBinaryMarker() const;
@@ -307,9 +337,11 @@ public:
Q_INVOKABLE bool gainAdminRights();
Q_INVOKABLE void dropAdminRights();
+ Q_INVOKABLE bool hasAdminRights() const;
void setCheckAvailableSpace(bool check);
- bool checkAvailableSpace(QString &message) const;
+ bool checkAvailableSpace();
+ QString availableSpaceMessage() const;
Q_INVOKABLE quint64 requiredDiskSpace() const;
Q_INVOKABLE quint64 requiredTemporaryDiskSpace() const;
@@ -353,14 +385,20 @@ public:
void clearLicenses();
QHash<QString, QMap<QString, QString>> sortedLicenses();
void addLicenseItem(const QHash<QString, QVariantMap> &licenses);
+ bool hasLicenses() const;
void createLocalDependencyHash(const QString &component, const QString &dependencies) const;
void createAutoDependencyHash(const QString &component, const QString &oldDependencies, const QString &newDependencies) const;
bool resetLocalCache(bool init = false);
bool clearLocalCache(QString *error = nullptr);
+ bool isValidCache() const;
+
template <typename T>
bool loadComponentScripts(const T &components, const bool postScript = false);
+ void saveGivenArguments(const QStringList &args);
+ QStringList givenArguments() const;
+
public Q_SLOTS:
bool runInstaller();
bool runUninstaller();
@@ -380,11 +418,9 @@ Q_SIGNALS:
void aboutCalculateComponentsToUninstall() const;
void finishedCalculateComponentsToUninstall() const;
void componentAdded(QInstaller::Component *comp);
- void rootComponentsAdded(QList<QInstaller::Component*> components);
- void updaterComponentsAdded(QList<QInstaller::Component*> components);
void valueChanged(const QString &key, const QString &value);
void statusChanged(QInstaller::PackageManagerCore::Status);
- void defaultTranslationsLoadedForLanguage(QLocale::Language lang);
+ void defaultTranslationsLoadedForLanguage(QLocale lang);
void currentPageChanged(int page);
void finishButtonClicked();
@@ -447,17 +483,18 @@ private:
QString findDisplayVersion(const QString &componentName, const QHash<QString, QInstaller::Component*> &components,
const QString& versionKey, QHash<QString, bool> &visited);
ComponentModel *componentModel(PackageManagerCore *core, const QString &objectName) const;
- QList<Component *> componentsMarkedForInstallation() const;
bool fetchPackagesTree(const PackagesList &packages, const LocalPackagesMap installedPackages);
bool componentUninstallableFromCommandLine(const QString &componentName);
- bool checkComponentsForInstallation(const QStringList &components, QString &errorMessage);
+ bool checkComponentsForInstallation(const QStringList &names, QString &errorMessage, bool &unstableAliasFound);
private:
PackageManagerCorePrivate *const d;
friend class PackageManagerCorePrivate;
QHash<QString, QString> m_fileDialogAutomaticAnswers;
QHash<QString, QStringList> m_localVirtualWithDependants;
+ QString m_availableSpaceMessage;
+ QStringList m_arguments;
private:
// remove once we deprecate isSelected, setSelected etc...
diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp
index 259aafeb6..10ca27d00 100644
--- a/src/libs/installer/packagemanagercore_p.cpp
+++ b/src/libs/installer/packagemanagercore_p.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2023 The Qt Company Ltd.
+** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -45,6 +45,7 @@
#include "qsettingswrapper.h"
#include "installercalculator.h"
#include "uninstallercalculator.h"
+#include "componentalias.h"
#include "componentchecker.h"
#include "globals.h"
#include "binarycreator.h"
@@ -56,11 +57,13 @@
#include "selfrestarter.h"
#include "filedownloaderfactory.h"
#include "updateoperationfactory.h"
+#include "constants.h"
#include <productkeycheck.h>
#include <QSettings>
#include <QtConcurrentRun>
+#include <QtConcurrent>
#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtCore/QDirIterator>
@@ -151,25 +154,56 @@ static void deferredRename(const QString &oldName, const QString &newName, bool
#endif
}
+static bool filterMissingAliasesToInstall(const QString& component, const QList<ComponentAlias *> packages)
+{
+ bool packageFound = false;
+ for (qsizetype i = 0; i < packages.size(); ++i) {
+ packageFound = (packages.at(i)->name() == component);
+ if (packageFound)
+ break;
+ }
+ return !packageFound;
+}
+
+static bool filterMissingPackagesToInstall(const QString& component, const PackagesList& packages)
+{
+ bool packageFound = false;
+ for (qsizetype i = 0; i < packages.size(); ++i) {
+ packageFound = (packages.at(i)->data(scName).toString() == component);
+ if (packageFound)
+ break;
+ }
+ return !packageFound;
+}
// -- PackageManagerCorePrivate
PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core)
: m_updateFinder(nullptr)
+ , m_aliasFinder(nullptr)
, m_localPackageHub(std::make_shared<LocalPackageHub>())
, m_status(PackageManagerCore::Unfinished)
, m_needsHardRestart(false)
, m_testChecksum(false)
, m_launchedAsRoot(AdminAuthorization::hasAdminRights())
+ , m_commandLineInstance(false)
+ , m_defaultInstall(false)
+ , m_userSetBinaryMarker(false)
+ , m_checkAvailableSpace(true)
, m_completeUninstall(false)
, m_needToWriteMaintenanceTool(false)
, m_dependsOnLocalInstallerBinary(false)
+ , m_autoAcceptLicenses(false)
+ , m_disableWriteMaintenanceTool(false)
+ , m_autoConfirmCommand(false)
, m_core(core)
, m_updates(false)
+ , m_aliases(false)
, m_repoFetched(false)
, m_updateSourcesAdded(false)
, m_magicBinaryMarker(0) // initialize with pseudo marker
, m_magicMarkerSupplement(BinaryContent::Default)
+ , m_foundEssentialUpdate(false)
, m_componentScriptEngine(nullptr)
, m_controlScriptEngine(nullptr)
, m_installerCalculator(nullptr)
@@ -177,37 +211,46 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core)
, m_proxyFactory(nullptr)
, m_defaultModel(nullptr)
, m_updaterModel(nullptr)
+ , m_componentSortFilterProxyModel(nullptr)
, m_guiObject(nullptr)
, m_remoteFileEngineHandler(nullptr)
- , m_foundEssentialUpdate(false)
- , m_commandLineInstance(false)
- , m_defaultInstall(false)
- , m_userSetBinaryMarker(false)
- , m_checkAvailableSpace(true)
- , m_autoAcceptLicenses(false)
- , m_disableWriteMaintenanceTool(false)
- , m_autoConfirmCommand(false)
, m_datFileName(QString())
+#ifdef INSTALLCOMPRESSED
+ , m_allowCompressedRepositoryInstall(true)
+#else
+ , m_allowCompressedRepositoryInstall(false)
+#endif
+ , m_connectedOperations(0)
{
}
PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core, qint64 magicInstallerMaker,
const QList<OperationBlob> &performedOperations, const QString &datFileName)
: m_updateFinder(nullptr)
+ , m_aliasFinder(nullptr)
, m_localPackageHub(std::make_shared<LocalPackageHub>())
, m_status(PackageManagerCore::Unfinished)
, m_needsHardRestart(false)
, m_testChecksum(false)
, m_launchedAsRoot(AdminAuthorization::hasAdminRights())
+ , m_commandLineInstance(false)
+ , m_defaultInstall(false)
+ , m_userSetBinaryMarker(false)
+ , m_checkAvailableSpace(true)
, m_completeUninstall(false)
, m_needToWriteMaintenanceTool(false)
, m_dependsOnLocalInstallerBinary(false)
+ , m_autoAcceptLicenses(false)
+ , m_disableWriteMaintenanceTool(false)
+ , m_autoConfirmCommand(false)
, m_core(core)
, m_updates(false)
+ , m_aliases(false)
, m_repoFetched(false)
, m_updateSourcesAdded(false)
, m_magicBinaryMarker(magicInstallerMaker)
, m_magicMarkerSupplement(BinaryContent::Default)
+ , m_foundEssentialUpdate(false)
, m_componentScriptEngine(nullptr)
, m_controlScriptEngine(nullptr)
, m_installerCalculator(nullptr)
@@ -215,22 +258,21 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core, q
, m_proxyFactory(nullptr)
, m_defaultModel(nullptr)
, m_updaterModel(nullptr)
+ , m_componentSortFilterProxyModel(nullptr)
, m_guiObject(nullptr)
, m_remoteFileEngineHandler(new RemoteFileEngineHandler)
- , m_foundEssentialUpdate(false)
- , m_commandLineInstance(false)
- , m_defaultInstall(false)
- , m_userSetBinaryMarker(false)
- , m_checkAvailableSpace(true)
- , m_autoAcceptLicenses(false)
- , m_disableWriteMaintenanceTool(false)
- , m_autoConfirmCommand(false)
, m_datFileName(datFileName)
+#ifdef INSTALLCOMPRESSED
+ , m_allowCompressedRepositoryInstall(true)
+#else
+ , m_allowCompressedRepositoryInstall(false)
+#endif
+ , m_connectedOperations(0)
{
foreach (const OperationBlob &operation, performedOperations) {
- QScopedPointer<QInstaller::Operation> op(KDUpdater::UpdateOperationFactory::instance()
+ std::unique_ptr<QInstaller::Operation> op(KDUpdater::UpdateOperationFactory::instance()
.create(operation.name, core));
- if (op.isNull()) {
+ if (!op) {
qCWarning(QInstaller::lcInstallerInstallLog) << "Failed to load unknown operation"
<< operation.name;
continue;
@@ -241,7 +283,7 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core, q
<< operation.name;
continue;
}
- m_performedOperationsOld.append(op.take());
+ m_performedOperationsOld.append(op.release());
}
connect(this, &PackageManagerCorePrivate::installationStarted,
@@ -270,6 +312,7 @@ PackageManagerCorePrivate::~PackageManagerCorePrivate()
qDeleteAll(m_performedOperationsCurrentSession);
delete m_updateFinder;
+ delete m_aliasFinder;
delete m_proxyFactory;
delete m_defaultModel;
@@ -430,6 +473,90 @@ bool PackageManagerCorePrivate::buildComponentTree(QHash<QString, Component*> &c
return true;
}
+bool PackageManagerCorePrivate::buildComponentAliases()
+{
+ // For now, aliases are only used for command line runs
+ if (!m_core->isCommandLineInstance())
+ return true;
+
+ {
+ const QList<ComponentAlias *> aliasList = componentAliases();
+ if (aliasList.isEmpty())
+ return true;
+
+ for (const auto *alias : aliasList) {
+ // Create a new alias object for package manager core to take ownership of
+ ComponentAlias *newAlias = new ComponentAlias(m_core);
+ for (const QString &key : alias->keys())
+ newAlias->setValue(key, alias->value(key));
+
+ m_componentAliases.insert(alias->name(), newAlias);
+ }
+ }
+ // After aliases are loaded, perform sanity checks:
+
+ // 1. Component check state is changed by alias selection, so store the initial state
+ storeCheckState();
+
+ Graph<QString> aliasGraph;
+ for (auto *alias : qAsConst(m_componentAliases)) {
+ aliasGraph.addNode(alias->name());
+ aliasGraph.addEdges(alias->name(),
+ QInstaller::splitStringWithComma(alias->value(scRequiredAliases)) <<
+ QInstaller::splitStringWithComma(alias->value(scOptionalAliases)));
+
+ if (!m_core->componentByName(alias->name())) {
+ // Name ok, select for sanity check calculation
+ alias->setSelected(true);
+ } else {
+ alias->setUnstable(ComponentAlias::ComponentNameConfict,
+ tr("Alias declares name that conflicts with an existing component \"%1\"")
+ .arg(alias->name()));
+ }
+ }
+
+ const QList<QString> sortedAliases = aliasGraph.sort();
+ // 2. Check for cyclic dependency errors
+ if (aliasGraph.hasCycle()) {
+ setStatus(PackageManagerCore::Failure, installerCalculator()->error());
+ MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("Error"),
+ tr("Unresolved component aliases"),
+ tr("Cyclic dependency between aliases \"%1\" and \"%2\" detected.")
+ .arg(aliasGraph.cycle().first, aliasGraph.cycle().second));
+
+ return false;
+ }
+
+ // 3. Test for required aliases and components, this triggers setting the
+ // alias unstable in case of a broken reference.
+ for (const auto &aliasName : sortedAliases) {
+ ComponentAlias *alias = m_componentAliases.value(aliasName);
+ if (!alias) // sortedAliases may contain dependencies that don't exist, we don't know it yet
+ continue;
+
+ alias->components();
+ alias->aliases();
+ }
+
+ clearInstallerCalculator();
+ // 4. Check for other errors preventing resolving components to install
+ if (!installerCalculator()->solve(m_componentAliases.values())) {
+ setStatus(PackageManagerCore::Failure, installerCalculator()->error());
+ MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("Error"),
+ tr("Unresolved component aliases"), installerCalculator()->error());
+
+ return false;
+ }
+
+ for (auto *alias : qAsConst(m_componentAliases))
+ alias->setSelected(false);
+
+ // 5. Restore original state
+ restoreCheckState();
+
+ return true;
+}
+
template <typename T>
bool PackageManagerCorePrivate::loadComponentScripts(const T &components, const bool postScript)
{
@@ -468,6 +595,10 @@ void PackageManagerCorePrivate::cleanUpComponentEnvironment()
// so we need to remove the current component script engine
delete m_componentScriptEngine;
m_componentScriptEngine = nullptr;
+
+ // Calculators become invalid after clearing components
+ clearInstallerCalculator();
+ clearUninstallerCalculator();
}
ScriptEngine *PackageManagerCorePrivate::componentScriptEngine() const
@@ -486,6 +617,9 @@ ScriptEngine *PackageManagerCorePrivate::controlScriptEngine() const
void PackageManagerCorePrivate::clearAllComponentLists()
{
+ qDeleteAll(m_componentAliases);
+ m_componentAliases.clear();
+
QList<QInstaller::Component*> toDelete;
toDelete << m_rootComponents << m_deletedReplacedComponents;
@@ -645,6 +779,10 @@ void PackageManagerCorePrivate::initialize(const QHash<QString, QString> &params
if (isInstaller())
m_packageSources.insert(PackageSource(QUrl(QLatin1String("resource://metadata/")), 1));
+ const QString aliasFilePath = m_core->settings().aliasDefinitionsFile();
+ if (!aliasFilePath.isEmpty())
+ m_aliasSources.insert(AliasSource(AliasSource::SourceFileFormat::Xml, aliasFilePath, -1));
+
m_metadataJob.disconnect();
m_metadataJob.setAutoDelete(false);
m_metadataJob.setPackageManagerCore(m_core);
@@ -773,7 +911,7 @@ QString PackageManagerCorePrivate::maintenanceToolAliasPath() const
if (aliasName.isEmpty())
return QString();
- const bool isRoot = (AdminAuthorization::hasAdminRights() || RemoteClient::instance().isActive());
+ const bool isRoot = m_core->hasAdminRights();
const QString applicationsDir = m_core->value(
isRoot ? QLatin1String("ApplicationsDir") : QLatin1String("ApplicationsDirUser")
);
@@ -864,7 +1002,7 @@ void PackageManagerCorePrivate::writeMaintenanceConfigFiles()
if (key == scRunProgramDescription || key == scRunProgram || key == scRunProgramArguments)
continue;
QVariant value = m_data.value(key);
- if (value.canConvert(QVariant::String))
+ if (value.canConvert<QString>())
value = replacePath(value.toString(), targetDir(), QLatin1String(scRelocatable));
variables.insert(key, value);
}
@@ -888,8 +1026,8 @@ void PackageManagerCorePrivate::writeMaintenanceConfigFiles()
QFile file(targetDir() + QLatin1Char('/') + QLatin1String("network.xml"));
if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
- QXmlStreamWriter writer(&file);
- writer.setCodec("UTF-8");
+ QString outputStr;
+ QXmlStreamWriter writer(&outputStr);
writer.setAutoFormatting(true);
writer.writeStartDocument();
@@ -922,6 +1060,8 @@ void PackageManagerCorePrivate::writeMaintenanceConfigFiles()
writer.writeEndElement();
writer.writeTextElement(QLatin1String("LocalCachePath"), m_data.settings().localCachePath());
writer.writeEndElement();
+
+ file.write(outputStr.toUtf8());
}
setDefaultFilePermissions(&file, DefaultFilePermissions::NonExecutable);
}
@@ -1070,8 +1210,11 @@ void PackageManagerCorePrivate::connectOperationToInstaller(Operation *const ope
connect(m_core, SIGNAL(installationInterrupted()), operationObject, SLOT(cancelOperation()));
if (mo->indexOfSignal(QMetaObject::normalizedSignature("progressChanged(double)")) > -1) {
+ // create unique object names for progress information track
+ operationObject->setObjectName(QLatin1String("operation_%1").arg(QString::number(m_connectedOperations)));
ProgressCoordinator::instance()->registerPartProgress(operationObject,
SIGNAL(progressChanged(double)), operationPartSize);
+ m_connectedOperations++;
}
}
}
@@ -1296,7 +1439,7 @@ void PackageManagerCorePrivate::writeMaintenanceToolAppBundle(OperationList &per
const QString after = QLatin1String("<string>") + QFileInfo(maintenanceToolName()).baseName()
+ QLatin1String("</string>");
while (!in.atEnd())
- out << in.readLine().replace(before, after) << endl;
+ out << in.readLine().replace(before, after) << Qt::endl;
// copy qt_menu.nib if it exists
op = createOwnedOperation(QLatin1String("Mkdir"));
@@ -1740,7 +1883,7 @@ bool PackageManagerCorePrivate::runInstaller()
throw Error(tr("It is not possible to install from network location"));
}
- if (!adminRightsGained) {
+ if (!m_core->hasAdminRights()) {
foreach (Component *component, componentsToInstall) {
if (component->value(scRequiresAdminRights, scFalse) == scFalse)
continue;
@@ -1774,7 +1917,7 @@ bool PackageManagerCorePrivate::runInstaller()
double progressOperationSize = componentsInstallPartProgressSize / progressOperationCount;
// Now install the requested components
- unpackAndInstallComponents(componentsToInstall, progressOperationSize, adminRightsGained);
+ unpackAndInstallComponents(componentsToInstall, progressOperationSize);
if (m_core->isOfflineOnly() && PackageManagerCore::createLocalRepositoryFromBinary()) {
emit m_core->titleMessageChanged(tr("Creating local repository"));
@@ -1972,7 +2115,7 @@ bool PackageManagerCorePrivate::runPackageUpdater()
}
// we did not request admin rights till we found out that a component/ undo needs admin rights
- if (updateAdminRights && !adminRightsGained) {
+ if (updateAdminRights && !m_core->hasAdminRights()) {
m_core->gainAdminRights();
m_core->dropAdminRights();
}
@@ -1993,7 +2136,7 @@ bool PackageManagerCorePrivate::runPackageUpdater()
if (undoOperations.count() > 0) {
ProgressCoordinator::instance()->emitLabelAndDetailTextChanged(tr("Removing deselected components..."));
- runUndoOperations(undoOperations, undoOperationProgressSize, adminRightsGained, true);
+ runUndoOperations(undoOperations, undoOperationProgressSize, true);
}
m_performedOperationsOld = nonRevertedOperations; // these are all operations left: those not reverted
@@ -2001,7 +2144,7 @@ bool PackageManagerCorePrivate::runPackageUpdater()
const double progressOperationSize = componentsInstallPartProgressSize / progressOperationCount;
// Now install the requested new components
- unpackAndInstallComponents(componentsToInstall, progressOperationSize, adminRightsGained);
+ unpackAndInstallComponents(componentsToInstall, progressOperationSize);
emit m_core->titleMessageChanged(tr("Creating Maintenance Tool"));
@@ -2070,7 +2213,7 @@ bool PackageManagerCorePrivate::runUninstaller()
}
// We did not yet request elevated permissions but they are required.
- if (updateAdminRights && !adminRightsGained) {
+ if (updateAdminRights && !m_core->hasAdminRights()) {
m_core->gainAdminRights();
m_core->dropAdminRights();
}
@@ -2078,7 +2221,7 @@ bool PackageManagerCorePrivate::runUninstaller()
const int uninstallOperationCount = countProgressOperations(undoOperations);
const double undoOperationProgressSize = double(1) / double(uninstallOperationCount);
- runUndoOperations(undoOperations, undoOperationProgressSize, adminRightsGained, false);
+ runUndoOperations(undoOperations, undoOperationProgressSize, false);
// No operation delete here, as all old undo operations are deleted in the destructor.
deleteMaintenanceTool(); // this will also delete the TargetDir on Windows
@@ -2087,7 +2230,7 @@ bool PackageManagerCorePrivate::runUninstaller()
// If not on Windows, we need to remove TargetDir manually.
#ifndef Q_OS_WIN
if (QVariant(m_core->value(scRemoveTargetDir)).toBool() && !targetDir().isEmpty()) {
- if (updateAdminRights && !adminRightsGained)
+ if (updateAdminRights && !m_core->hasAdminRights())
adminRightsGained = m_core->gainAdminRights();
removeDirectoryThreaded(targetDir(), true);
qCDebug(QInstaller::lcInstallerInstallLog) << "Complete uninstallation was chosen.";
@@ -2249,7 +2392,7 @@ bool PackageManagerCorePrivate::runOfflineGenerator()
}
void PackageManagerCorePrivate::unpackComponents(const QList<Component *> &components,
- double progressOperationSize, bool adminRightsGained)
+ double progressOperationSize)
{
OperationList unpackOperations;
bool becameAdmin = false;
@@ -2273,7 +2416,7 @@ void PackageManagerCorePrivate::unpackComponents(const QList<Component *> &compo
// There's currently no way to control this on a per-operation basis, so
// any op requesting execution as admin means all extracts are done as admin.
- if (!adminRightsGained && !becameAdmin && op->value(QLatin1String("admin")).toBool())
+ if (!m_core->hasAdminRights() && op->value(QLatin1String("admin")).toBool())
becameAdmin = m_core->gainAdminRights();
}
}
@@ -2321,7 +2464,7 @@ void PackageManagerCorePrivate::unpackComponents(const QList<Component *> &compo
continue;
}
// Backup may request performing operation as admin
- if (!adminRightsGained && !becameAdmin && operation->value(QLatin1String("admin")).toBool())
+ if (!m_core->hasAdminRights() && operation->value(QLatin1String("admin")).toBool())
becameAdmin = m_core->gainAdminRights();
}
@@ -2390,8 +2533,7 @@ void PackageManagerCorePrivate::unpackComponents(const QList<Component *> &compo
ProgressCoordinator::instance()->emitDetailTextChanged(tr("Done"));
}
-void PackageManagerCorePrivate::installComponent(Component *component, double progressOperationSize,
- bool adminRightsGained)
+void PackageManagerCorePrivate::installComponent(Component *component, double progressOperationSize)
{
OperationList operations = component->operations(Operation::Install);
if (!component->operationsCreatedSuccessfully())
@@ -2412,7 +2554,7 @@ void PackageManagerCorePrivate::installComponent(Component *component, double pr
// maybe this operations wants us to be admin...
bool becameAdmin = false;
- if (!adminRightsGained && operation->value(QLatin1String("admin")).toBool()) {
+ if (!m_core->hasAdminRights() && operation->value(QLatin1String("admin")).toBool()) {
becameAdmin = m_core->gainAdminRights();
qCDebug(QInstaller::lcInstallerInstallLog) << operation->name() << "as admin:" << becameAdmin;
}
@@ -2501,23 +2643,54 @@ void PackageManagerCorePrivate::installComponent(Component *component, double pr
ProgressCoordinator::instance()->emitDetailTextChanged(tr("Done"));
}
-bool PackageManagerCorePrivate::runningProcessesFound()
+PackageManagerCore::Status PackageManagerCorePrivate::fetchComponentsAndInstall(const QStringList& components)
{
- //Check if there are processes running in the install
- QStringList excludeFiles = m_allowedRunningProcesses;
- excludeFiles.append(maintenanceToolName());
+ // init default model before fetching remote packages tree
+ ComponentModel *model = m_core->defaultComponentModel();
+ Q_UNUSED(model);
- const QString performModeWarning = m_completeUninstall
- ? QLatin1String("Unable to remove components.")
- : QLatin1String("Unable to update components.");
+ bool fallbackReposFetched = false;
+ auto fetchComponents = [&]() {
+ bool packagesFound = m_core->fetchPackagesWithFallbackRepositories(components, fallbackReposFetched);
- QStringList runningProcesses = runningInstallerProcesses(excludeFiles);
- if (!runningProcesses.isEmpty()) {
- qCWarning(QInstaller::lcInstallerInstallLog).noquote().nospace() << performModeWarning
- << " Please stop these processes: " << runningProcesses << " and try again.";
+ if (!packagesFound) {
+ qCDebug(QInstaller::lcInstallerInstallLog).noquote().nospace()
+ << "No components available with the current selection.";
+ setStatus(PackageManagerCore::Canceled);
+ return false;
+ }
+ QString errorMessage;
+ bool unstableAliasFound = false;
+ if (m_core->checkComponentsForInstallation(components, errorMessage, unstableAliasFound)) {
+ if (!errorMessage.isEmpty())
+ qCDebug(QInstaller::lcInstallerInstallLog).noquote().nospace() << errorMessage;
+ if (calculateComponentsAndRun()) {
+ if (m_core->isOfflineGenerator())
+ qCDebug(QInstaller::lcInstallerInstallLog) << "Created installer to:" << offlineBinaryName();
+ else
+ qCDebug(QInstaller::lcInstallerInstallLog) << "Components installed successfully";
+ }
+ } else {
+ // We found unstable alias and all repos were not fetched. Alias might have dependency to component
+ // which exists in non-default repository. Fetch all repositories now.
+ if (unstableAliasFound && !fallbackReposFetched) {
+ return false;
+ }
+ else {
+ qCDebug(QInstaller::lcInstallerInstallLog).noquote().nospace() << errorMessage
+ << "No components available with the current selection.";
+ }
+ }
return true;
+ };
+
+ if (!fetchComponents() && !fallbackReposFetched) {
+ setStatus(PackageManagerCore::Running);
+ enableAllCategories();
+ fetchComponents();
}
- return false;
+
+ return m_core->status();
}
void PackageManagerCorePrivate::setComponentSelection(const QString &id, Qt::CheckState state)
@@ -2637,9 +2810,12 @@ void PackageManagerCorePrivate::registerMaintenanceTool()
settings.setValue(QLatin1String("Comments"), m_data.value(scTitle));
settings.setValue(QLatin1String("InstallDate"), QDateTime::currentDateTime().toString());
settings.setValue(QLatin1String("InstallLocation"), QDir::toNativeSeparators(targetDir()));
- settings.setValue(QLatin1String("UninstallString"), quoted(maintenanceTool));
- settings.setValue(QLatin1String("ModifyPath"), QString(quoted(maintenanceTool)
- + QLatin1String(" --manage-packages")));
+ settings.setValue(QLatin1String("UninstallString"), QString(quoted(maintenanceTool)
+ + QLatin1String(" --") + CommandLineOptions::scStartUninstallerLong));
+ if (!isOfflineOnly()) {
+ settings.setValue(QLatin1String("ModifyPath"), QString(quoted(maintenanceTool)
+ + QLatin1String(" --") + CommandLineOptions::scStartPackageManagerLong));
+ }
// required disk space of the installed components
quint64 estimatedSizeKB = m_core->requiredDiskSpace() / 1024;
// add required space for the maintenance tool
@@ -2676,8 +2852,8 @@ void PackageManagerCorePrivate::unregisterMaintenanceTool()
#endif
}
-void PackageManagerCorePrivate::runUndoOperations(const OperationList &undoOperations, double progressSize,
- bool adminRightsGained, bool deleteOperation)
+void PackageManagerCorePrivate::runUndoOperations(const OperationList &undoOperations,
+ double progressSize, bool deleteOperation)
{
try {
const int operationsCount = undoOperations.size();
@@ -2688,7 +2864,7 @@ void PackageManagerCorePrivate::runUndoOperations(const OperationList &undoOpera
throw Error(tr("Installation canceled by user"));
bool becameAdmin = false;
- if (!adminRightsGained && undoOperation->value(QLatin1String("admin")).toBool())
+ if (!m_core->hasAdminRights() && undoOperation->value(QLatin1String("admin")).toBool())
becameAdmin = m_core->gainAdminRights();
connectOperationToInstaller(undoOperation, progressSize);
@@ -2796,6 +2972,25 @@ LocalPackagesMap PackageManagerCorePrivate::localInstalledPackages()
return m_localPackageHub->localPackages();
}
+QList<ComponentAlias *> PackageManagerCorePrivate::componentAliases()
+{
+ if (m_aliases && m_aliasFinder)
+ return m_aliasFinder->aliases();
+
+ m_aliases = false;
+ delete m_aliasFinder;
+
+ m_aliasFinder = new AliasFinder(m_core);
+ m_aliasFinder->setAliasSources(m_aliasSources);
+ if (!m_aliasFinder->run()) {
+ qCDebug(lcDeveloperBuild) << "No component aliases found." << Qt::endl;
+ return QList<ComponentAlias *>();
+ }
+
+ m_aliases = true;
+ return m_aliasFinder->aliases();
+}
+
bool PackageManagerCorePrivate::fetchMetaInformationFromRepositories(DownloadType type)
{
m_updates = false;
@@ -2858,9 +3053,9 @@ bool PackageManagerCorePrivate::addUpdateResourcesFromRepositories(bool compress
continue;
if (data->repository().isCompressed())
- m_compressedPackageSources.insert(PackageSource(QUrl::fromLocalFile(data->path()), 2));
+ m_compressedPackageSources.insert(PackageSource(QUrl::fromLocalFile(data->path()), 2, data->repository().postLoadComponentScript()));
else
- m_packageSources.insert(PackageSource(QUrl::fromLocalFile(data->path()), 0));
+ m_packageSources.insert(PackageSource(QUrl::fromLocalFile(data->path()), 0, data->repository().postLoadComponentScript()));
ProductKeyCheck::instance()->addPackagesFromXml(data->path() + QLatin1String("/Updates.xml"));
}
@@ -2913,6 +3108,63 @@ void PackageManagerCorePrivate::updateComponentInstallActions()
component->setInstallAction(ComponentModelHelper::Install);
}
+bool PackageManagerCorePrivate::enableAllCategories()
+{
+ QSet<RepositoryCategory> repoCategories = m_data.settings().repositoryCategories();
+ bool additionalRepositoriesEnabled = false;
+ for (const auto &category : repoCategories) {
+ if (!category.isEnabled()) {
+ additionalRepositoriesEnabled = true;
+ enableRepositoryCategory(category, true);
+ }
+ }
+ return additionalRepositoriesEnabled;
+}
+
+void PackageManagerCorePrivate::enableRepositoryCategory(const RepositoryCategory &repoCategory, const bool enable)
+{
+ RepositoryCategory replacement = repoCategory;
+ replacement.setEnabled(enable);
+ QSet<RepositoryCategory> tmpRepoCategories = m_data.settings().repositoryCategories();
+ if (tmpRepoCategories.contains(repoCategory)) {
+ tmpRepoCategories.remove(repoCategory);
+ tmpRepoCategories.insert(replacement);
+ m_data.settings().addRepositoryCategories(tmpRepoCategories);
+ }
+}
+
+bool PackageManagerCorePrivate::installablePackagesFound(const QStringList& components)
+{
+ if (components.isEmpty())
+ return true;
+
+ PackagesList remotes = remotePackages();
+
+ auto componentsNotFoundForInstall = QtConcurrent::blockingFiltered(
+ components,
+ [remotes](const QString& installerPackage) {
+ return filterMissingPackagesToInstall(installerPackage, remotes);
+ }
+ );
+
+ if (componentsNotFoundForInstall.count() > 0) {
+ QList<ComponentAlias *> aliasList = componentAliases();
+ auto aliasesNotFoundForInstall = QtConcurrent::blockingFiltered(
+ components,
+ [aliasList](const QString& installerPackage) {
+ return filterMissingAliasesToInstall(installerPackage, aliasList);
+ }
+ );
+
+ if (aliasesNotFoundForInstall.count() > 0) {
+ qCDebug(QInstaller::lcInstallerInstallLog).noquote().nospace() << "Cannot select " << aliasesNotFoundForInstall.join(QLatin1String(", ")) << ". Component(s) not found.";
+ setStatus(PackageManagerCore::NoPackagesFound);
+ return false;
+ }
+ }
+ return true;
+}
+
void PackageManagerCorePrivate::connectOperationCallMethodRequest(Operation *const operation)
{
QObject *const operationObject = dynamic_cast<QObject *> (operation);
@@ -2973,16 +3225,16 @@ void PackageManagerCorePrivate::addPathForDeletion(const QString &path)
}
void PackageManagerCorePrivate::unpackAndInstallComponents(const QList<Component *> &components,
- const double progressOperationSize, const bool adminRightsGained)
+ const double progressOperationSize)
{
// Perform extract operations
- unpackComponents(components, progressOperationSize, adminRightsGained);
+ unpackComponents(components, progressOperationSize);
// Perform rest of the operations and mark component as installed
const int componentsToInstallCount = components.size();
int installedComponents = 0;
foreach (Component *component, components) {
- installComponent(component, progressOperationSize, adminRightsGained);
+ installComponent(component, progressOperationSize);
++installedComponents;
ProgressCoordinator::instance()->emitAdditionalProgressStatus(tr("%1 of %2 components installed.")
@@ -3008,24 +3260,6 @@ void PackageManagerCorePrivate::processFilesForDelayedDeletion()
}
}
-void PackageManagerCorePrivate::findExecutablesRecursive(const QString &path, const QStringList &excludeFiles, QStringList *result)
-{
- QDirIterator it(path, QDir::NoDotAndDotDot | QDir::Executable | QDir::Files | QDir::System, QDirIterator::Subdirectories );
-
- while (it.hasNext())
- result->append(QDir::toNativeSeparators(it.next().toLower()));
-
- foreach (const QString &process, excludeFiles)
- result->removeAll(QDir::toNativeSeparators(process.toLower()));
-}
-
-QStringList PackageManagerCorePrivate::runningInstallerProcesses(const QStringList &excludeFiles)
-{
- QStringList resultFiles;
- findExecutablesRecursive(QCoreApplication::applicationDirPath(), excludeFiles, &resultFiles);
- return checkRunningProcessesFromList(resultFiles);
-}
-
bool PackageManagerCorePrivate::calculateComponentsAndRun()
{
bool componentsOk = m_core->recalculateAllComponents();
@@ -3042,9 +3276,8 @@ bool PackageManagerCorePrivate::calculateComponentsAndRun()
qCDebug(QInstaller::lcInstallerInstallLog).noquote()
<< htmlToString(m_core->componentResolveReasons());
- QString spaceInfo;
- const bool spaceOk = m_core->checkAvailableSpace(spaceInfo);
- qCDebug(QInstaller::lcInstallerInstallLog) << spaceInfo;
+ const bool spaceOk = m_core->checkAvailableSpace();
+ qCDebug(QInstaller::lcInstallerInstallLog) << m_core->availableSpaceMessage();
if (!spaceOk || !(m_autoConfirmCommand || askUserConfirmCommand())) {
qCDebug(QInstaller::lcInstallerInstallLog) << "Installation aborted.";
@@ -3071,6 +3304,13 @@ bool PackageManagerCorePrivate::acceptLicenseAgreements() const
m_core->addLicenseItem(component->licenses());
}
+ const QString acceptanceText = ProductKeyCheck::instance()->licenseAcceptanceText();
+ if (!acceptanceText.isEmpty()) {
+ qCDebug(QInstaller::lcInstallerInstallLog).noquote() << acceptanceText;
+ if (!m_autoAcceptLicenses && !acceptRejectCliQuery())
+ return false;
+ }
+
QHash<QString, QMap<QString, QString>> priorityHash = m_core->sortedLicenses();
QStringList priorities = priorityHash.keys();
priorities.sort();
@@ -3119,6 +3359,23 @@ bool PackageManagerCorePrivate::askUserAcceptLicense(const QString &name, const
}
}
+bool PackageManagerCorePrivate::acceptRejectCliQuery() const
+{
+ forever {
+ const QString input = m_core->readConsoleLine(QLatin1String("Accept|Reject"));
+
+ if (QString::compare(input, QLatin1String("Accept"), Qt::CaseInsensitive) == 0
+ || QString::compare(input, QLatin1String("A"), Qt::CaseInsensitive) == 0) {
+ return true;
+ } else if (QString::compare(input, QLatin1String("Reject"), Qt::CaseInsensitive) == 0
+ || QString::compare(input, QLatin1String("R"), Qt::CaseInsensitive) == 0) {
+ return false;
+ } else {
+ qCDebug(QInstaller::lcInstallerInstallLog) << "Unknown answer:" << input;
+ }
+ }
+}
+
bool PackageManagerCorePrivate::askUserConfirmCommand() const
{
qCDebug(QInstaller::lcInstallerInstallLog) << "Do you want to continue?";
diff --git a/src/libs/installer/packagemanagercore_p.h b/src/libs/installer/packagemanagercore_p.h
index 74cb0667c..c0c55c4cc 100644
--- a/src/libs/installer/packagemanagercore_p.h
+++ b/src/libs/installer/packagemanagercore_p.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2023 The Qt Company Ltd.
+** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -54,11 +54,15 @@ using namespace KDUpdater;
namespace QInstaller {
struct BinaryLayout;
+struct AliasSource;
+class AliasFinder;
class ScriptEngine;
class ComponentModel;
+class ComponentAlias;
class InstallerCalculator;
class UninstallerCalculator;
class RemoteFileEngineHandler;
+class ComponentSortFilterProxyModel;
class PackageManagerCorePrivate : public QObject
{
@@ -106,6 +110,7 @@ public:
QString configurationFileName() const;
bool buildComponentTree(QHash<QString, Component*> &components, bool loadScript);
+ bool buildComponentAliases();
template <typename T>
bool loadComponentScripts(const T &components, const bool postScript = false);
@@ -169,13 +174,11 @@ public:
m_performedOperationsCurrentSession.clear();
}
- void unpackComponents(const QList<Component *> &components, double progressOperationSize,
- bool adminRightsGained = false);
+ void unpackComponents(const QList<Component *> &components, double progressOperationSize);
- void installComponent(Component *component, double progressOperationSize,
- bool adminRightsGained = false);
+ void installComponent(Component *component, double progressOperationSize);
+ PackageManagerCore::Status fetchComponentsAndInstall(const QStringList& components);
- bool runningProcessesFound();
void setComponentSelection(const QString &id, Qt::CheckState state);
signals:
@@ -188,8 +191,10 @@ signals:
public:
UpdateFinder *m_updateFinder;
+ AliasFinder *m_aliasFinder;
QSet<PackageSource> m_packageSources;
QSet<PackageSource> m_compressedPackageSources;
+ QSet<AliasSource> m_aliasSources;
std::shared_ptr<LocalPackageHub> m_localPackageHub;
QStringList m_filesForDelayedDeletion;
@@ -217,6 +222,8 @@ public:
QList<QInstaller::Component*> m_updaterComponentsDeps;
QList<QInstaller::Component*> m_updaterDependencyReplacements;
+ QHash<QString, QInstaller::ComponentAlias *> m_componentAliases;
+
OperationList m_ownedOperations;
OperationList m_performedOperationsOld;
OperationList m_performedOperationsCurrentSession;
@@ -244,7 +251,7 @@ private slots:
private:
void unpackAndInstallComponents(const QList<Component *> &components,
- const double progressOperationSize, const bool adminRightsGained);
+ const double progressOperationSize);
void deleteMaintenanceTool();
void deleteMaintenanceToolAlias();
@@ -257,18 +264,19 @@ private:
void writeMaintenanceToolAppBundle(OperationList &performedOperations);
void runUndoOperations(const OperationList &undoOperations, double undoOperationProgressSize,
- bool adminRightsGained, bool deleteOperation);
+ bool deleteOperation);
PackagesList remotePackages();
LocalPackagesMap localInstalledPackages();
+ QList<ComponentAlias *> componentAliases();
+
bool fetchMetaInformationFromRepositories(DownloadType type = DownloadType::All);
bool addUpdateResourcesFromRepositories(bool compressedRepository = false);
void processFilesForDelayedDeletion();
- void findExecutablesRecursive(const QString &path, const QStringList &excludeFiles, QStringList *result);
- QStringList runningInstallerProcesses(const QStringList &exludeFiles);
bool calculateComponentsAndRun();
bool acceptLicenseAgreements() const;
bool askUserAcceptLicense(const QString &name, const QString &content) const;
+ bool acceptRejectCliQuery() const;
bool askUserConfirmCommand() const;
bool packageNeedsUpdate(const LocalPackage &localPackage, const Package *update) const;
void commitPendingUnstableComponents();
@@ -276,6 +284,11 @@ private:
void createLocalDependencyHash(const QString &componentName, const QString &dependencies);
void updateComponentInstallActions();
+ bool enableAllCategories();
+ void enableRepositoryCategory(const RepositoryCategory &repoCategory, const bool enable);
+
+ bool installablePackagesFound(const QStringList& components);
+
// remove once we deprecate isSelected, setSelected etc...
void restoreCheckState();
void storeCheckState();
@@ -286,6 +299,7 @@ private:
TempPathDeleter m_tmpPathDeleter;
bool m_updates;
+ bool m_aliases;
bool m_repoFetched;
bool m_updateSourcesAdded;
qint64 m_magicBinaryMarker;
@@ -308,6 +322,7 @@ private:
ComponentModel *m_defaultModel;
ComponentModel *m_updaterModel;
+ ComponentSortFilterProxyModel *m_componentSortFilterProxyModel;
QObject *m_guiObject;
QScopedPointer<RemoteFileEngineHandler> m_remoteFileEngineHandler;
@@ -325,6 +340,8 @@ private:
QHash<QString, QStringList > m_componentReplaces;
QString m_datFileName;
+ bool m_allowCompressedRepositoryInstall;
+ int m_connectedOperations;
};
} // namespace QInstaller
diff --git a/src/libs/installer/packagemanagercoredata.cpp b/src/libs/installer/packagemanagercoredata.cpp
index 1d5b9f713..1113908bd 100644
--- a/src/libs/installer/packagemanagercoredata.cpp
+++ b/src/libs/installer/packagemanagercoredata.cpp
@@ -36,6 +36,7 @@
#include <QDir>
#include <QRegularExpression>
#include <QSettings>
+#include <QStandardPaths>
#ifdef Q_OS_WIN
# include <windows.h>
@@ -95,7 +96,7 @@ PackageManagerCoreData::PackageManagerCoreData(const QHash<QString, QString> &va
if (isInstaller) {
addNewVariable(scTargetDir, replaceVariables(m_settings.targetDir()));
addNewVariable(scTargetConfigurationFile, m_settings.configurationFileName());
- addNewVariable(scStartMenuDir, m_settings.startMenuDir());
+ addNewVariable(scStartMenuDir, replaceVariables(m_settings.startMenuDir()));
} else {
#ifdef Q_OS_MACOS
addNewVariable(scTargetDir, QFileInfo(QCoreApplication::applicationDirPath() + QLatin1String("/../../..")).absoluteFilePath());
@@ -257,6 +258,8 @@ QVariant PackageManagerCoreData::value(const QString &key, const QVariant &_defa
if (!filename.isEmpty() && !regKey.isEmpty() && registry.contains(regKey))
return registry.value(regKey).toString();
}
+#else
+ Q_UNUSED(format)
#endif
if (m_variables.contains(key))
diff --git a/src/libs/installer/packagemanagergui.cpp b/src/libs/installer/packagemanagergui.cpp
index c3642e4ee..1f0462eea 100644
--- a/src/libs/installer/packagemanagergui.cpp
+++ b/src/libs/installer/packagemanagergui.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2023 The Qt Company Ltd.
+** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -412,10 +412,13 @@ PackageManagerGui::PackageManagerGui(PackageManagerCore *core, QWidget *parent)
connect(this, &QDialog::rejected, m_core, &PackageManagerCore::setCanceled);
connect(this, &PackageManagerGui::interrupted, m_core, &PackageManagerCore::interrupt);
- // both queued to show the finished page once everything is done
+ // all queued to show the finished page once everything is done
connect(m_core, &PackageManagerCore::installationFinished,
this, &PackageManagerGui::showFinishedPage,
Qt::QueuedConnection);
+ connect(m_core, &PackageManagerCore::offlineGenerationFinished,
+ this, &PackageManagerGui::showFinishedPage,
+ Qt::QueuedConnection);
connect(m_core, &PackageManagerCore::uninstallationFinished,
this, &PackageManagerGui::showFinishedPage,
Qt::QueuedConnection);
@@ -689,6 +692,22 @@ bool PackageManagerGui::isButtonEnabled(int wb)
}
/*!
+ Sets \a buttonText for button specified by \a buttonId to a installer page \a pageId.
+
+ \note In some pages, installer will change the button text when entering
+ the page. In that case, you need to connect to \c entered() -signal of the
+ page to change the \a buttonText.
+
+ \sa {gui::setWizardPageButtonText}{gui.setWizardPageButtonText}
+*/
+void PackageManagerGui::setWizardPageButtonText(int pageId, int buttonId, const QString &buttonText)
+{
+ PackageManagerPage *const p = qobject_cast<PackageManagerPage*> (page(pageId));
+ if (p)
+ p->setButtonText(static_cast<QWizard::WizardButton>(buttonId), buttonText);
+}
+
+/*!
Sets a validator for the custom page specified by \a name and
\a callbackName requested by \a component.
*/
@@ -1245,10 +1264,10 @@ void PackageManagerGui::currentPageChanged(int newId)
PackageManagerPage::PackageManagerPage(PackageManagerCore *core)
: m_complete(true)
, m_titleColor(QString())
+ , m_showOnPageList(true)
, m_needsSettingsButton(false)
, m_core(core)
, validatorComponent(nullptr)
- , m_showOnPageList(true)
{
if (!m_core->settings().titleColor().isEmpty())
m_titleColor = m_core->settings().titleColor();
@@ -1452,19 +1471,12 @@ int PackageManagerPage::nextId() const
if (next == PackageManagerCore::LicenseCheck) {
// calculate the page after the license page
const int nextNextId = gui()->pageIds().value(gui()->pageIds().indexOf(next) + 1, -1);
- const PackageManagerCore *const core = packageManagerCore();
+ PackageManagerCore *const core = packageManagerCore();
if (core->isUninstaller())
return nextNextId; // forcibly hide the license page if we run as uninstaller
-
- foreach (Component* component, core->orderedComponentsToInstall()) {
- if (core->isMaintainer() && component->isInstalled())
- continue; // package manager or updater, hide as long as the component is installed
-
- // The component is about to be installed and provides a license, so the page needs to
- // be shown.
- if (!component->licenses().isEmpty())
- return next;
- }
+ core->recalculateAllComponents();
+ if (core->hasLicenses())
+ return next;
return nextNextId; // no component with a license or all components with license installed
}
return next; // default, show the next page
@@ -1503,7 +1515,7 @@ IntroductionPage::IntroductionPage(PackageManagerCore *core)
, m_removeAllComponents(nullptr)
{
setObjectName(QLatin1String("IntroductionPage"));
- setColoredTitle(tr("Setup - %1").arg(productName()));
+ setColoredTitle(tr("Welcome"));
QVBoxLayout *layout = new QVBoxLayout(this);
setLayout(layout);
@@ -1551,6 +1563,8 @@ IntroductionPage::IntroductionPage(PackageManagerCore *core)
m_errorLabel = new QLabel(this);
m_errorLabel->setWordWrap(true);
+ m_errorLabel->setTextFormat(Qt::RichText);
+ m_errorLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
boxLayout->addWidget(m_errorLabel);
m_errorLabel->setObjectName(QLatin1String("ErrorLabel"));
@@ -1607,7 +1621,7 @@ bool IntroductionPage::validatePage()
bool isOfflineOnlyInstaller = core->isInstaller() && core->isOfflineOnly();
// If not offline only installer, at least one valid repository needs to be available
- if (!isOfflineOnlyInstaller && !validRepositoriesAvailable()) {
+ if (!isOfflineOnlyInstaller && !core->validRepositoriesAvailable()) {
setErrorMessage(QLatin1String("<font color=\"red\">") + tr("At least one valid and enabled "
"repository required for this action to succeed.") + QLatin1String("</font>"));
return isComplete();
@@ -1654,21 +1668,12 @@ bool IntroductionPage::validatePage()
// fetch common packages
if (core->isInstaller() || core->isPackageManager()) {
- bool localPackagesTreeFetched = false;
if (!m_allPackagesFetched) {
// first try to fetch the server side packages tree
m_allPackagesFetched = core->fetchRemotePackagesTree();
if (!m_allPackagesFetched) {
QString error = core->error();
- if (core->isPackageManager() && core->status() != PackageManagerCore::ForceUpdate) {
- // if that fails and we're in maintenance mode, try to fetch local installed tree
- localPackagesTreeFetched = core->fetchLocalPackagesTree();
- if (localPackagesTreeFetched) {
- // if that succeeded, adjust error message
- error = QLatin1String("<font color=\"red\">") + error + tr(" Only local package "
- "management available.") + QLatin1String("</font>");
- }
- } else if (core->status() == PackageManagerCore::ForceUpdate) {
+ if (core->status() == PackageManagerCore::ForceUpdate) {
// replaces the error string from packagemanagercore
error = tr("There is an important update available. Please select '%1' first")
.arg(m_updateComponents->text().remove(QLatin1Char('&')));
@@ -1686,7 +1691,7 @@ bool IntroductionPage::validatePage()
}
}
- if (m_allPackagesFetched || localPackagesTreeFetched)
+ if (m_allPackagesFetched)
setComplete(true);
}
@@ -1833,22 +1838,6 @@ void IntroductionPage::setErrorMessage(const QString &error)
#endif
}
-/*!
- Returns \c true if at least one valid and enabled repository is available.
-*/
-bool IntroductionPage::validRepositoriesAvailable() const
-{
- const PackageManagerCore *const core = packageManagerCore();
- bool valid = false;
-
- foreach (const Repository &repo, core->settings().repositories()) {
- if (repo.isEnabled() && repo.isValid()) {
- valid = true;
- break;
- }
- }
- return valid;
-}
// -- private slots
@@ -1892,9 +1881,9 @@ void IntroductionPage::setPackageManager(bool value)
*/
void IntroductionPage::initializePage()
{
- const bool repositoriesAvailable = validRepositoriesAvailable();
-
PackageManagerCore *core = packageManagerCore();
+ const bool repositoriesAvailable = core->validRepositoriesAvailable();
+
if (core->isPackageManager()) {
m_packageManager->setChecked(true);
} else if (core->isUpdater()) {
@@ -1927,7 +1916,7 @@ void IntroductionPage::onCoreNetworkSettingsChanged()
PackageManagerCore *core = packageManagerCore();
if (core->isUninstaller() || core->isMaintainer()) {
- m_offlineMaintenanceTool = !validRepositoriesAvailable();
+ m_offlineMaintenanceTool = !core->validRepositoriesAvailable();
setMaintainerToolsEnabled(!m_offlineMaintenanceTool);
m_removeAllComponents->setChecked(m_offlineMaintenanceTool);
@@ -2117,7 +2106,7 @@ void LicenseAgreementPage::entering()
*/
bool LicenseAgreementPage::isComplete() const
{
- return m_acceptCheckBox->isChecked();
+ return m_acceptCheckBox->isChecked() && ProductKeyCheck::instance()->hasAcceptedAllLicenses();
}
void LicenseAgreementPage::openLicenseUrl(const QUrl &url)
@@ -2210,7 +2199,7 @@ void ComponentSelectionPage::entering()
QT_TR_NOOP("Please select the components you want to update."),
QT_TR_NOOP("Please select the components you want to install."),
QT_TR_NOOP("Please select the components you want to uninstall."),
- QT_TR_NOOP("Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated."),
+ QT_TR_NOOP("Select the components to install. Deselect installed components to uninstall them.<br>Any components already installed will not be updated."),
QT_TR_NOOP("Mandatory components need to be updated first before you can select other components to update.")
};
@@ -2228,14 +2217,13 @@ void ComponentSelectionPage::entering()
d->onModelStateChanged(d->m_currentModel->checkedState());
setModified(isComplete());
- if (core->settings().repositoryCategories().count() > 0 && !core->isOfflineOnly()
- && !core->isUpdater()) {
- d->showCategoryLayout(true);
- core->settings().setAllowUnstableComponents(true);
- } else {
- d->showCategoryLayout(false);
- }
+ d->showCategoryLayout(core->showRepositoryCategories());
d->showCompressedRepositoryButton();
+ d->showCreateOfflineInstallerButton(true);
+
+ // Reset to default supplement state. The page may set it to OfflineGenerator
+ // which needs to be reset after navigating back to the page.
+ core->resetBinaryMarkerSupplement();
}
/*!
@@ -2245,6 +2233,7 @@ void ComponentSelectionPage::entering()
void ComponentSelectionPage::leaving()
{
d->hideCompressedRepositoryButton();
+ d->showCreateOfflineInstallerButton(false);
}
/*!
@@ -2328,16 +2317,6 @@ void ComponentSelectionPage::deselectComponent(const QString &id)
}
/*!
- Adds the possibility to install a compressed repository on component selection
- page. A new button which opens a file browser is added for compressed
- repository selection.
-*/
-void ComponentSelectionPage::allowCompressedRepositoryInstall()
-{
- d->allowCompressedRepositoryInstall();
-}
-
-/*!
Adds an additional virtual component with the \a name to be installed.
Returns \c true if the virtual component is found and not installed.
@@ -2357,6 +2336,11 @@ bool ComponentSelectionPage::addVirtualComponentToUninstall(const QString &name)
return false;
}
+void ComponentSelectionPage::setAllowCreateOfflineInstaller(bool allow)
+{
+ d->setAllowCreateOfflineInstaller(allow);
+}
+
void ComponentSelectionPage::setModified(bool modified)
{
setComplete(modified);
@@ -2370,18 +2354,7 @@ bool ComponentSelectionPage::isComplete() const
if (!d->componentsResolved())
return false;
- if (packageManagerCore()->isInstaller() || packageManagerCore()->isUpdater())
- return d->m_currentModel->checked().count();
-
- if (d->m_currentModel->checkedState().testFlag(ComponentModel::DefaultChecked) == false)
- return true;
-
- const QSet<Component *> uncheckable = d->m_currentModel->uncheckable();
- for (auto &component : uncheckable) {
- if (component->forcedInstallation() && !component->isInstalled())
- return true; // allow installation for new forced components
- }
- return false;
+ return d->m_currentModel->componentsSelected();
}
@@ -2719,6 +2692,10 @@ void ReadyForInstallationPage::entering()
setButtonText(QWizard::CommitButton, tr("U&pdate"));
setColoredTitle(tr("Ready to Update Packages"));
m_msgLabel->setText(tr("All required information is now available to begin updating your installation."));
+ } else if (packageManagerCore()->isOfflineGenerator()) {
+ setButtonText(QWizard::CommitButton, tr("Create Offline Installer"));
+ setColoredTitle(tr("Ready to Create Offline Installer"));
+ m_msgLabel->setText(tr("All required information is now available to create an offline installer for selected components."));
} else {
Q_ASSERT(packageManagerCore()->isInstaller());
setButtonText(QWizard::CommitButton, tr("&Install"));
@@ -2735,11 +2712,10 @@ void ReadyForInstallationPage::entering()
m_taskDetailsBrowser->setVisible(!componentsOk || LoggingHandler::instance().isVerbose());
setComplete(componentsOk);
- QString spaceInfo;
- if (packageManagerCore()->checkAvailableSpace(spaceInfo)) {
- m_msgLabel->setText(QString::fromLatin1("%1 %2").arg(m_msgLabel->text(), spaceInfo));
+ if (packageManagerCore()->checkAvailableSpace()) {
+ m_msgLabel->setText(QString::fromLatin1("%1 %2").arg(m_msgLabel->text(), packageManagerCore()->availableSpaceMessage()));
} else {
- m_msgLabel->setText(spaceInfo);
+ m_msgLabel->setText(packageManagerCore()->availableSpaceMessage());
setComplete(false);
}
}
@@ -2759,7 +2735,9 @@ void ReadyForInstallationPage::leaving()
void ReadyForInstallationPage::updatePageListTitle()
{
PackageManagerCore *core = packageManagerCore();
- if (core->isInstaller())
+ if (core->isOfflineGenerator())
+ setPageListTitle(tr("Ready to Create Offline Installer"));
+ else if (core->isInstaller())
setPageListTitle(tr("Ready to Install"));
else if (core->isMaintainer())
setPageListTitle(tr("Ready to Update"));
@@ -2817,6 +2795,11 @@ PerformInstallationPage::PerformInstallationPage(PackageManagerCore *core)
connect(core, &PackageManagerCore::installationFinished,
this, &PerformInstallationPage::installationFinished);
+ connect(core, &PackageManagerCore::offlineGenerationStarted,
+ this, &PerformInstallationPage::installationStarted);
+ connect(core, &PackageManagerCore::offlineGenerationFinished,
+ this, &PerformInstallationPage::installationFinished);
+
connect(core, &PackageManagerCore::uninstallationStarted,
this, &PerformInstallationPage::uninstallationStarted);
connect(core, &PackageManagerCore::uninstallationFinished,
@@ -2886,6 +2869,11 @@ void PerformInstallationPage::entering()
setColoredTitle(tr("Updating components of %1").arg(productName()));
QTimer::singleShot(30, packageManagerCore(), SLOT(runPackageUpdater()));
+ } else if (packageManagerCore()->isOfflineGenerator()) {
+ setButtonText(QWizard::CommitButton, tr("&Create Offline Installer"));
+ setColoredTitle(tr("Creating Offline Installer for %1").arg(productName()));
+
+ QTimer::singleShot(30, packageManagerCore(), SLOT(runOfflineGenerator()));
} else {
setButtonText(QWizard::CommitButton, tr("&Install"));
setColoredTitle(tr("Installing %1").arg(productName()));
@@ -2910,7 +2898,9 @@ void PerformInstallationPage::leaving()
void PerformInstallationPage::updatePageListTitle()
{
PackageManagerCore *core = packageManagerCore();
- if (core->isInstaller())
+ if (core->isOfflineGenerator())
+ setPageListTitle(tr("Creating Offline Installer"));
+ else if (core->isInstaller())
setPageListTitle(tr("Installing"));
else if (core->isMaintainer())
setPageListTitle(tr("Updating"));
@@ -3014,7 +3004,7 @@ FinishedPage::FinishedPage(PackageManagerCore *core)
, m_commitButton(nullptr)
{
setObjectName(QLatin1String("FinishedPage"));
- setColoredTitle(tr("Completing the %1 Setup").arg(productName()));
+ setColoredTitle(tr("Finished the %1 Setup").arg(productName()));
setPageListTitle(tr("Finished"));
m_msgLabel = new QLabel(this);
@@ -3039,7 +3029,7 @@ FinishedPage::FinishedPage(PackageManagerCore *core)
*/
void FinishedPage::entering()
{
- m_msgLabel->setText(tr("Click %1 to exit the %2 Wizard.")
+ m_msgLabel->setText(tr("Click %1 to exit the %2 Setup.")
.arg(gui()->defaultButtonText(QWizard::FinishButton).remove(QLatin1Char('&')))
.arg(productName()));
@@ -3132,16 +3122,8 @@ void FinishedPage::leaving()
*/
void FinishedPage::handleFinishClicked()
{
- const QString program =
- packageManagerCore()->replaceVariables(packageManagerCore()->value(scRunProgram));
-
- const QStringList args = packageManagerCore()->replaceVariables(packageManagerCore()
- ->values(scRunProgramArguments));
- if (!m_runItCheckBox->isChecked() || program.isEmpty())
- return;
-
- qCDebug(QInstaller::lcInstallerInstallLog) << "starting" << program << args;
- QProcess::startDetached(program, args);
+ if (m_runItCheckBox->isChecked())
+ packageManagerCore()->runProgram();
}
/*!
@@ -3186,7 +3168,7 @@ RestartPage::RestartPage(PackageManagerCore *core)
: PackageManagerPage(core)
{
setObjectName(QLatin1String("RestartPage"));
- setColoredTitle(tr("Completing the %1 Setup").arg(productName()));
+ setColoredTitle(tr("Finished the %1 Setup").arg(productName()));
// Never show this page on the page list
setShowOnPageList(false);
diff --git a/src/libs/installer/packagemanagergui.h b/src/libs/installer/packagemanagergui.h
index ba27c4af6..d83643005 100644
--- a/src/libs/installer/packagemanagergui.h
+++ b/src/libs/installer/packagemanagergui.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -82,6 +82,7 @@ public:
void clickButton(int wizardButton, int delayInMs = 0);
void clickButton(const QString &objectName, int delayInMs = 0) const;
bool isButtonEnabled(int wizardButton);
+ void setWizardPageButtonText(int pageId, int buttonId, const QString &buttonText);
void showSettingsButton(bool show);
void requestSettingsButtonByInstaller(bool request);
@@ -261,7 +262,6 @@ private:
void leaving() override;
void showWidgets(bool show);
- bool validRepositoriesAvailable() const;
private:
bool m_updatesFetched;
@@ -330,9 +330,10 @@ public:
Q_INVOKABLE void selectDefault();
Q_INVOKABLE void selectComponent(const QString &id);
Q_INVOKABLE void deselectComponent(const QString &id);
- Q_INVOKABLE void allowCompressedRepositoryInstall();
Q_INVOKABLE bool addVirtualComponentToUninstall(const QString &name);
+ void setAllowCreateOfflineInstaller(bool allow);
+
protected:
void entering() override;
void leaving() override;
diff --git a/src/libs/installer/packagesource.cpp b/src/libs/installer/packagesource.cpp
index 3b9fbe813..0f87e0def 100644
--- a/src/libs/installer/packagesource.cpp
+++ b/src/libs/installer/packagesource.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -50,7 +50,7 @@ namespace QInstaller {
*/
/*!
- \fn QInstaller::PackageSource::PackageSource(const QUrl &u, int p)
+ \fn QInstaller::PackageSource::PackageSource(const QUrl &u, int p, bool pl)
Constructs a package source info object. The object's url is set to \a u, while the priority
is set to \a p.
@@ -69,7 +69,7 @@ namespace QInstaller {
/*!
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-uint qHash(const PackageSource &key, uint seed)
+hashValue qHash(const PackageSource &key, hashValue seed)
{
return qHash(key.url, seed) ^ key.priority;
}
diff --git a/src/libs/installer/packagesource.h b/src/libs/installer/packagesource.h
index 1193c1f76..f63b53cd8 100644
--- a/src/libs/installer/packagesource.h
+++ b/src/libs/installer/packagesource.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -40,16 +40,18 @@ struct INSTALLER_EXPORT PackageSource
PackageSource()
: priority(-1)
{}
- PackageSource(const QUrl &u, int p)
+ PackageSource(const QUrl &u, int p, bool pl = false)
: url(u)
, priority(p)
+ , postLoadComponentScript(pl)
{}
QUrl url;
int priority;
+ bool postLoadComponentScript;
};
-INSTALLER_EXPORT uint qHash(const PackageSource &key, uint seed);
+INSTALLER_EXPORT hashValue qHash(const PackageSource &key, hashValue seed);
INSTALLER_EXPORT bool operator==(const PackageSource &lhs, const PackageSource &rhs);
} // namespace QInstaller
diff --git a/src/libs/installer/permissionsettings.cpp b/src/libs/installer/permissionsettings.cpp
index 68e4ab427..d70cf5625 100644
--- a/src/libs/installer/permissionsettings.cpp
+++ b/src/libs/installer/permissionsettings.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -37,38 +37,6 @@ using namespace QInstaller;
\internal
*/
-PermissionSettings::PermissionSettings(const QString &organization, const QString &application, QObject *parent)
- : QSettings(organization, application, parent)
-{
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- setIniCodec("UTF-8"); // to workaround QTBUG-102334
-#endif
-}
-
-PermissionSettings::PermissionSettings(Scope scope, const QString &organization, const QString &application, QObject *parent)
- : QSettings(scope, organization, application, parent)
-{
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- setIniCodec("UTF-8"); // QTBUG-102334
-#endif
-}
-
-PermissionSettings::PermissionSettings(Format format, Scope scope, const QString &organization, const QString &application, QObject *parent)
- : QSettings(format, scope, organization, application, parent)
-{
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- setIniCodec("UTF-8"); // QTBUG-102334
-#endif
-}
-
-PermissionSettings::PermissionSettings(const QString &fileName, Format format, QObject *parent)
- : QSettings(fileName, format, parent)
-{
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- setIniCodec("UTF-8"); // QTBUG-102334
-#endif
-}
-
PermissionSettings::~PermissionSettings()
{
if (!fileName().isEmpty()) {
diff --git a/src/libs/installer/permissionsettings.h b/src/libs/installer/permissionsettings.h
index 2621624c2..c950d9c17 100644
--- a/src/libs/installer/permissionsettings.h
+++ b/src/libs/installer/permissionsettings.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -37,12 +37,19 @@ class PermissionSettings : public QSettings
{
public:
explicit PermissionSettings(const QString &organization,
- const QString &application = QString(), QObject *parent = 0);
+ const QString &application = QString(), QObject *parent = 0)
+ : QSettings(organization, application, parent) {}
+
PermissionSettings(Scope scope, const QString &organization,
- const QString &application = QString(), QObject *parent = 0);
+ const QString &application = QString(), QObject *parent = 0)
+ : QSettings(scope, organization, application, parent) {}
+
PermissionSettings(Format format, Scope scope, const QString &organization,
- const QString &application = QString(), QObject *parent = 0);
- PermissionSettings(const QString &fileName, Format format, QObject *parent = 0);
+ const QString &application = QString(), QObject *parent = 0)
+ : QSettings(format, scope, organization, application, parent) {}
+ PermissionSettings(const QString &fileName, Format format, QObject *parent = 0)
+ : QSettings(fileName, format, parent) {}
+
~PermissionSettings();
};
diff --git a/src/libs/installer/productkeycheck.cpp b/src/libs/installer/productkeycheck.cpp
index c1dfe83d6..ed128fa61 100644
--- a/src/libs/installer/productkeycheck.cpp
+++ b/src/libs/installer/productkeycheck.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -29,6 +29,8 @@
#include "productkeycheck.h"
#include "packagemanagercore.h"
+#include <QtUiTools/QUiLoader>
+
class ProductKeyCheckPrivate
{
};
@@ -49,6 +51,12 @@ ProductKeyCheck *ProductKeyCheck::instance()
return &instance;
}
+QUiLoader *ProductKeyCheck::uiLoader()
+{
+ static QUiLoader loader;
+ return &loader;
+}
+
void ProductKeyCheck::init(QInstaller::PackageManagerCore *core)
{
Q_UNUSED(core)
@@ -106,3 +114,22 @@ bool ProductKeyCheck::hasValidLicense() const
{
return true;
}
+
+bool ProductKeyCheck::hasAcceptedAllLicenses() const
+{
+ return true;
+}
+
+QString ProductKeyCheck::licenseAcceptanceText() const
+{
+ return QString();
+}
+QString ProductKeyCheck::securityWarning() const
+{
+ return QString();
+}
+
+QString ProductKeyCheck::additionalMetaDownloadWarning() const
+{
+ return QString();
+}
diff --git a/src/libs/installer/productkeycheck.h b/src/libs/installer/productkeycheck.h
index b7e8c6d52..8e7d6724f 100644
--- a/src/libs/installer/productkeycheck.h
+++ b/src/libs/installer/productkeycheck.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -32,6 +32,7 @@
#include "installer_global.h"
#include <QString>
+#include <QUiLoader>
namespace QInstaller {
@@ -49,6 +50,8 @@ public:
static ProductKeyCheck *instance();
void init(QInstaller::PackageManagerCore *core);
+ static QUiLoader *uiLoader();
+
// was validLicense
bool hasValidKey();
QString lastErrorString();
@@ -67,6 +70,10 @@ public:
QList<int> registeredPages() const;
bool hasValidLicense() const;
+ bool hasAcceptedAllLicenses() const;
+ QString licenseAcceptanceText() const;
+ QString securityWarning() const;
+ QString additionalMetaDownloadWarning() const;
private:
ProductKeyCheck();
diff --git a/src/libs/installer/progresscoordinator.cpp b/src/libs/installer/progresscoordinator.cpp
index 8b02711b1..6413efe28 100644
--- a/src/libs/installer/progresscoordinator.cpp
+++ b/src/libs/installer/progresscoordinator.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2021 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -40,7 +40,7 @@
using namespace QInstaller;
QT_BEGIN_NAMESPACE
-uint qHash(QPointer<QObject> key)
+hashValue qHash(QPointer<QObject> key)
{
return qHash(key.data());
}
@@ -76,7 +76,8 @@ ProgressCoordinator *ProgressCoordinator::instance()
void ProgressCoordinator::reset()
{
- disconnectAllSenders();
+ m_senderPartProgressSizeHash.clear();
+ m_senderPendingCalculatedPercentageHash.clear();
m_installationLabelText.clear();
m_currentCompletePercentage = 0;
m_currentBasePercentage = 0;
@@ -90,10 +91,11 @@ void ProgressCoordinator::reset()
void ProgressCoordinator::registerPartProgress(QObject *sender, const char *signal, double partProgressSize)
{
Q_ASSERT(sender);
+ Q_ASSERT(!sender->objectName().isEmpty());
Q_ASSERT(QString::fromLatin1(signal).contains(QLatin1String("(double)")));
Q_ASSERT(partProgressSize <= 1);
- m_senderPartProgressSizeHash.insert(sender, partProgressSize);
+ m_senderPartProgressSizeHash.insert(sender->objectName(), partProgressSize);
bool isConnected = connect(sender, signal, this, SLOT(partProgressChanged(double)));
Q_UNUSED(isConnected);
Q_ASSERT(isConnected);
@@ -116,16 +118,17 @@ void ProgressCoordinator::partProgressChanged(double fraction)
}
// no fraction no change
- if (fraction == 0)
+ if (fraction == 0 || !sender())
return;
+ QString senderObjectName = sender()->objectName();
// ignore senders sending 100% multiple times
- if (fraction == 1 && m_senderPendingCalculatedPercentageHash.contains(sender())
- && m_senderPendingCalculatedPercentageHash.value(sender()) == 0) {
+ if (fraction == 1 && m_senderPendingCalculatedPercentageHash.contains(senderObjectName)
+ && m_senderPendingCalculatedPercentageHash.value(senderObjectName) == 0) {
return;
}
- double partProgressSize = m_senderPartProgressSizeHash.value(sender(), 0);
+ double partProgressSize = m_senderPartProgressSizeHash.value(senderObjectName, 0);
if (partProgressSize == 0) {
qCWarning(QInstaller::lcInstallerInstallLog) << "It seems that this sender was not registered "
"in the right way:" << sender();
@@ -138,7 +141,7 @@ void ProgressCoordinator::partProgressChanged(double fraction)
// allPendingCalculatedPartPercentages has negative values
double newCurrentCompletePercentage = m_currentBasePercentage - pendingCalculatedPartPercentage
- + allPendingCalculatedPartPercentages(sender());
+ + allPendingCalculatedPartPercentages(senderObjectName);
//we can't check this here, because some round issues can make it little bit under 0 or over 100
//Q_ASSERT(newCurrentCompletePercentage >= 0);
@@ -163,9 +166,9 @@ void ProgressCoordinator::partProgressChanged(double fraction)
m_currentCompletePercentage = newCurrentCompletePercentage;
if (fraction == 1) {
m_currentBasePercentage = m_currentBasePercentage - pendingCalculatedPartPercentage;
- m_senderPendingCalculatedPercentageHash.insert(sender(), 0);
+ m_senderPendingCalculatedPercentageHash.insert(senderObjectName, 0);
} else {
- m_senderPendingCalculatedPercentageHash.insert(sender(), pendingCalculatedPartPercentage);
+ m_senderPendingCalculatedPercentageHash.insert(senderObjectName, pendingCalculatedPartPercentage);
}
} else { //if (m_undoMode)
@@ -174,7 +177,7 @@ void ProgressCoordinator::partProgressChanged(double fraction)
//double checkValue = allPendingCalculatedPartPercentages(sender());
double newCurrentCompletePercentage = m_manualAddedPercentage + m_currentBasePercentage
- + pendingCalculatedPartPercentage + allPendingCalculatedPartPercentages(sender());
+ + pendingCalculatedPartPercentage + allPendingCalculatedPartPercentages(senderObjectName);
//we can't check this here, because some round issues can make it little bit under 0 or over 100
//Q_ASSERT(newCurrentCompletePercentage >= 0);
@@ -199,9 +202,9 @@ void ProgressCoordinator::partProgressChanged(double fraction)
if (fraction == 1) {
m_currentBasePercentage = m_currentBasePercentage + pendingCalculatedPartPercentage;
- m_senderPendingCalculatedPercentageHash.insert(sender(), 0);
+ m_senderPendingCalculatedPercentageHash.insert(senderObjectName, 0);
} else {
- m_senderPendingCalculatedPercentageHash.insert(sender(), pendingCalculatedPartPercentage);
+ m_senderPendingCalculatedPercentageHash.insert(senderObjectName, pendingCalculatedPartPercentage);
}
} //if (m_undoMode)
printProgressPercentage(progressInPercentage());
@@ -219,25 +222,13 @@ int ProgressCoordinator::progressInPercentage() const
return currentValue;
}
-void ProgressCoordinator::disconnectAllSenders()
-{
- foreach (QPointer<QObject> sender, m_senderPartProgressSizeHash.keys()) {
- if (!sender.isNull()) {
- bool isDisconnected = sender->disconnect(this);
- Q_UNUSED(isDisconnected);
- Q_ASSERT(isDisconnected);
- }
- }
- m_senderPartProgressSizeHash.clear();
- m_senderPendingCalculatedPercentageHash.clear();
-}
-
void ProgressCoordinator::setUndoMode()
{
Q_ASSERT(!m_undoMode);
m_undoMode = true;
- disconnectAllSenders();
+ m_senderPartProgressSizeHash.clear();
+ m_senderPendingCalculatedPercentageHash.clear();
m_reachedPercentageBeforeUndo = progressInPercentage();
m_currentBasePercentage = m_reachedPercentageBeforeUndo;
}
@@ -294,10 +285,10 @@ void ProgressCoordinator::emitLabelAndDetailTextChanged(const QString &text)
qApp->processEvents(); //makes the result available in the ui
}
-double ProgressCoordinator::allPendingCalculatedPartPercentages(QObject *excludeKeyObject)
+double ProgressCoordinator::allPendingCalculatedPartPercentages(const QString &excludeKeyObject)
{
double result = 0;
- QHash<QPointer<QObject>, double>::iterator it = m_senderPendingCalculatedPercentageHash.begin();
+ QHash<QString, double>::iterator it = m_senderPendingCalculatedPercentageHash.begin();
while (it != m_senderPendingCalculatedPercentageHash.end()) {
if (it.key() != excludeKeyObject)
result += it.value();
diff --git a/src/libs/installer/progresscoordinator.h b/src/libs/installer/progresscoordinator.h
index 3540b5d16..75d5a5d30 100644
--- a/src/libs/installer/progresscoordinator.h
+++ b/src/libs/installer/progresscoordinator.h
@@ -85,12 +85,12 @@ protected:
explicit ProgressCoordinator(QObject *parent);
private:
- double allPendingCalculatedPartPercentages(QObject *excludeKeyObject = 0);
+ double allPendingCalculatedPartPercentages(const QString &excludeKeyObject = QString());
void disconnectAllSenders();
private:
- QHash<QPointer<QObject>, double> m_senderPendingCalculatedPercentageHash;
- QHash<QPointer<QObject>, double> m_senderPartProgressSizeHash;
+ QHash<QString, double> m_senderPendingCalculatedPercentageHash;
+ QHash<QString, double> m_senderPartProgressSizeHash;
ProgressSpinner *m_progressSpinner;
QString m_installationLabelText;
double m_currentCompletePercentage;
diff --git a/src/libs/installer/protocol.h b/src/libs/installer/protocol.h
index 2dd1a5b1c..8b2288a89 100644
--- a/src/libs/installer/protocol.h
+++ b/src/libs/installer/protocol.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -90,7 +90,7 @@ const char GetQProcessSignals[] = "GetQProcessSignals";
const char QProcessSignalBytesWritten[] = "QProcess::bytesWritten";
const char QProcessSignalAboutToClose[] = "QProcess::aboutToClose";
const char QProcessSignalReadChannelFinished[] = "QProcess::readChannelFinished";
-const char QProcessSignalError[] = "QProcess::error";
+const char QProcessSignalError[] = "QProcess::errorOccurred";
const char QProcessSignalReadyReadStandardOutput[] = "QProcess::readyReadStandardOutput";
const char QProcessSignalReadyReadStandardError[] = "QProcess::readyReadStandardError";
const char QProcessSignalStarted[] = "QProcess::started";
diff --git a/src/libs/installer/qprocesswrapper.cpp b/src/libs/installer/qprocesswrapper.cpp
index 6f34e36da..44117eefb 100644
--- a/src/libs/installer/qprocesswrapper.cpp
+++ b/src/libs/installer/qprocesswrapper.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -54,7 +54,7 @@ QProcessWrapper::QProcessWrapper(QObject *parent)
connect(&process, &QIODevice::bytesWritten, this, &QProcessWrapper::bytesWritten);
connect(&process, &QIODevice::aboutToClose, this, &QProcessWrapper::aboutToClose);
connect(&process, &QIODevice::readChannelFinished, this, &QProcessWrapper::readChannelFinished);
- connect(&process, SIGNAL(error(QProcess::ProcessError)), SIGNAL(error(QProcess::ProcessError)));
+ connect(&process, SIGNAL(errorOccurred(QProcess::ProcessError)), SIGNAL(errorOccurred(QProcess::ProcessError)));
connect(&process, &QProcess::readyReadStandardOutput, this, &QProcessWrapper::readyReadStandardOutput);
connect(&process, &QProcess::readyReadStandardError, this, &QProcessWrapper::readyReadStandardError);
connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)), SIGNAL(finished(int,QProcess::ExitStatus)));
@@ -88,7 +88,7 @@ void QProcessWrapper::processSignals()
} else if (name == QLatin1String(Protocol::QProcessSignalReadChannelFinished)) {
emit readChannelFinished();
} else if (name == QLatin1String(Protocol::QProcessSignalError)) {
- emit error(static_cast<QProcess::ProcessError> (receivedSignals.takeFirst().toInt()));
+ emit errorOccurred(static_cast<QProcess::ProcessError> (receivedSignals.takeFirst().toInt()));
} else if (name == QLatin1String(Protocol::QProcessSignalReadyReadStandardOutput)) {
emit readyReadStandardOutput();
} else if (name == QLatin1String(Protocol::QProcessSignalReadyReadStandardError)) {
@@ -191,8 +191,8 @@ void QProcessWrapper::setProcessChannelMode(QProcessWrapper::ProcessChannelMode
{
if (connectToServer()) {
m_lock.lockForWrite();
- callRemoteMethod(QLatin1String(Protocol::QProcessSetProcessChannelMode),
- static_cast<QProcess::ProcessChannelMode>(mode), dummy);
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::QProcessSetProcessChannelMode),
+ static_cast<QProcess::ProcessChannelMode>(mode));
m_lock.unlock();
} else {
process.setProcessChannelMode(static_cast<QProcess::ProcessChannelMode>(mode));
@@ -216,8 +216,8 @@ void QProcessWrapper::setReadChannel(QProcessWrapper::ProcessChannel chan)
{
if (connectToServer()) {
m_lock.lockForWrite();
- callRemoteMethod(QLatin1String(Protocol::QProcessSetReadChannel),
- static_cast<QProcess::ProcessChannel>(chan), dummy);
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::QProcessSetReadChannel),
+ static_cast<QProcess::ProcessChannel>(chan));
m_lock.unlock();
} else {
process.setReadChannel(static_cast<QProcess::ProcessChannel>(chan));
@@ -263,7 +263,7 @@ void QProcessWrapper::closeWriteChannel()
{
if (connectToServer()) {
m_lock.lockForWrite();
- callRemoteMethod(QLatin1String(Protocol::QProcessCloseWriteChannel));
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::QProcessCloseWriteChannel));
m_lock.unlock();
} else {
process.closeWriteChannel();
@@ -296,7 +296,7 @@ void QProcessWrapper::kill()
{
if (connectToServer()) {
m_lock.lockForWrite();
- callRemoteMethod(QLatin1String(Protocol::QProcessKill));
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::QProcessKill));
m_lock.unlock();
} else {
process.kill();
@@ -343,7 +343,7 @@ void QProcessWrapper::start(const QString &param1, const QStringList &param2,
{
if (connectToServer()) {
m_lock.lockForWrite();
- callRemoteMethod(QLatin1String(Protocol::QProcessStart3Arg), param1, param2, param3);
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::QProcessStart3Arg), param1, param2, param3);
m_lock.unlock();
} else {
process.start(param1, param2, param3);
@@ -354,7 +354,7 @@ void QProcessWrapper::start(const QString &param1, QIODevice::OpenMode param2)
{
if (connectToServer()) {
m_lock.lockForWrite();
- callRemoteMethod(QLatin1String(Protocol::QProcessStart2Arg), param1, param2);
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::QProcessStart2Arg), param1, param2);
m_lock.unlock();
} else {
process.start(param1, {}, param2);
@@ -376,7 +376,7 @@ void QProcessWrapper::terminate()
{
if (connectToServer()) {
m_lock.lockForWrite();
- callRemoteMethod(QLatin1String(Protocol::QProcessTerminate));
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::QProcessTerminate));
m_lock.unlock();
} else {
process.terminate();
@@ -443,7 +443,7 @@ void QProcessWrapper::setEnvironment(const QStringList &param1)
{
if (connectToServer()) {
m_lock.lockForWrite();
- callRemoteMethod(QLatin1String(Protocol::QProcessSetEnvironment), param1, dummy);
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::QProcessSetEnvironment), param1);
m_lock.unlock();
} else {
process.setEnvironment(param1);
@@ -455,7 +455,7 @@ void QProcessWrapper::setNativeArguments(const QString &param1)
{
if (connectToServer()) {
m_lock.lockForWrite();
- callRemoteMethod(QLatin1String(Protocol::QProcessSetNativeArguments), param1, dummy);
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::QProcessSetNativeArguments), param1);
m_lock.unlock();
} else {
process.setNativeArguments(param1);
@@ -467,7 +467,7 @@ void QProcessWrapper::setWorkingDirectory(const QString &param1)
{
if (connectToServer()) {
m_lock.lockForWrite();
- callRemoteMethod(QLatin1String(Protocol::QProcessSetWorkingDirectory), param1, dummy);
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::QProcessSetWorkingDirectory), param1);
m_lock.unlock();
} else {
process.setWorkingDirectory(param1);
diff --git a/src/libs/installer/qprocesswrapper.h b/src/libs/installer/qprocesswrapper.h
index 1a68bbf92..b34d6f82c 100644
--- a/src/libs/installer/qprocesswrapper.h
+++ b/src/libs/installer/qprocesswrapper.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -119,7 +119,7 @@ Q_SIGNALS:
void bytesWritten(qint64);
void aboutToClose();
void readChannelFinished();
- void error(QProcess::ProcessError);
+ void errorOccurred(QProcess::ProcessError);
void readyReadStandardOutput();
void readyReadStandardError();
void finished(int exitCode, QProcess::ExitStatus exitStatus);
diff --git a/src/libs/installer/qsettingswrapper.cpp b/src/libs/installer/qsettingswrapper.cpp
index f2dd53767..d322728f5 100644
--- a/src/libs/installer/qsettingswrapper.cpp
+++ b/src/libs/installer/qsettingswrapper.cpp
@@ -141,27 +141,39 @@ QString QSettingsWrapper::applicationName() const
return d->settings.applicationName();
}
-void QSettingsWrapper::beginGroup(const QString &param1)
+#if QT_VERSION < QT_VERSION_CHECK(6, 4, 0)
+ void QSettingsWrapper::beginGroup(const QString &prefix)
+#else
+ void QSettingsWrapper::beginGroup(QAnyStringView prefix)
+#endif
{
if (createSocket())
- callRemoteMethod(QLatin1String(Protocol::QSettingsBeginGroup), param1, dummy);
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::QSettingsBeginGroup), prefix);
else
- d->settings.beginGroup(param1);
+ d->settings.beginGroup(prefix);
}
-int QSettingsWrapper::beginReadArray(const QString &param1)
+#if QT_VERSION < QT_VERSION_CHECK(6, 4, 0)
+ int QSettingsWrapper::beginReadArray(const QString &prefix)
+#else
+ int QSettingsWrapper::beginReadArray(QAnyStringView prefix)
+#endif
{
if (createSocket())
- return callRemoteMethod<qint32>(QLatin1String(Protocol::QSettingsBeginReadArray), param1);
- return d->settings.beginReadArray(param1);
+ return callRemoteMethod<qint32>(QLatin1String(Protocol::QSettingsBeginReadArray), prefix);
+ return d->settings.beginReadArray(prefix);
}
-void QSettingsWrapper::beginWriteArray(const QString &param1, int param2)
+#if QT_VERSION < QT_VERSION_CHECK(6, 4, 0)
+ void QSettingsWrapper::beginWriteArray(const QString &prefix, int size)
+#else
+ void QSettingsWrapper::beginWriteArray(QAnyStringView prefix, int size)
+#endif
{
if (createSocket())
- callRemoteMethod(QLatin1String(Protocol::QSettingsBeginWriteArray), param1, qint32(param2));
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::QSettingsBeginWriteArray), prefix, qint32(size));
else
- d->settings.beginWriteArray(param1, param2);
+ d->settings.beginWriteArray(prefix, size);
}
QStringList QSettingsWrapper::childGroups() const
@@ -181,21 +193,25 @@ QStringList QSettingsWrapper::childKeys() const
void QSettingsWrapper::clear()
{
if (createSocket())
- callRemoteMethod(QLatin1String(Protocol::QSettingsClear));
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::QSettingsClear));
else d->settings.clear();
}
-bool QSettingsWrapper::contains(const QString &param1) const
+#if QT_VERSION < QT_VERSION_CHECK(6, 4, 0)
+ bool QSettingsWrapper::contains(const QString &key) const
+#else
+ bool QSettingsWrapper::contains(QAnyStringView key) const
+#endif
{
if (createSocket())
- return callRemoteMethod<bool>(QLatin1String(Protocol::QSettingsContains), param1);
- return d->settings.contains(param1);
+ return callRemoteMethod<bool>(QLatin1String(Protocol::QSettingsContains), key);
+ return d->settings.contains(key);
}
void QSettingsWrapper::endArray()
{
if (createSocket())
- callRemoteMethod(QLatin1String(Protocol::QSettingsEndArray));
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::QSettingsEndArray));
else
d->settings.endArray();
}
@@ -203,7 +219,7 @@ void QSettingsWrapper::endArray()
void QSettingsWrapper::endGroup()
{
if (createSocket())
- callRemoteMethod(QLatin1String(Protocol::QSettingsEndGroup));
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::QSettingsEndGroup));
else
d->settings.endGroup();
}
@@ -249,12 +265,16 @@ QString QSettingsWrapper::organizationName() const
return d->settings.organizationName();
}
-void QSettingsWrapper::remove(const QString &param1)
+#if QT_VERSION < QT_VERSION_CHECK(6, 4, 0)
+ void QSettingsWrapper::remove(const QString &key)
+#else
+ void QSettingsWrapper::remove(QAnyStringView key)
+#endif
{
if (createSocket())
- callRemoteMethod(QLatin1String(Protocol::QSettingsRemove), param1, dummy);
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::QSettingsRemove), key);
else
- d->settings.remove(param1);
+ d->settings.remove(key);
}
QSettingsWrapper::Scope QSettingsWrapper::scope() const
@@ -266,7 +286,7 @@ QSettingsWrapper::Scope QSettingsWrapper::scope() const
void QSettingsWrapper::setArrayIndex(int param1)
{
if (createSocket())
- callRemoteMethod(QLatin1String(Protocol::QSettingsSetArrayIndex), qint32(param1), dummy);
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::QSettingsSetArrayIndex), qint32(param1));
else
d->settings.setArrayIndex(param1);
}
@@ -274,17 +294,20 @@ void QSettingsWrapper::setArrayIndex(int param1)
void QSettingsWrapper::setFallbacksEnabled(bool param1)
{
if (createSocket())
- callRemoteMethod(QLatin1String(Protocol::QSettingsSetFallbacksEnabled), param1, dummy);
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::QSettingsSetFallbacksEnabled), param1);
else
d->settings.setFallbacksEnabled(param1);
}
-
-void QSettingsWrapper::setValue(const QString &param1, const QVariant &param2)
+#if QT_VERSION < QT_VERSION_CHECK(6, 4, 0)
+void QSettingsWrapper::setValue(const QString &key, const QVariant &value)
+#else
+void QSettingsWrapper::setValue(QAnyStringView key, const QVariant &value)
+#endif
{
if (createSocket())
- callRemoteMethod(QLatin1String(Protocol::QSettingsSetValue), param1, param2);
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::QSettingsSetValue), key, value);
else
- d->settings.setValue(param1, param2);
+ d->settings.setValue(key, value);
}
QSettingsWrapper::Status QSettingsWrapper::status() const
@@ -299,17 +322,30 @@ QSettingsWrapper::Status QSettingsWrapper::status() const
void QSettingsWrapper::sync()
{
if (createSocket())
- callRemoteMethod(QLatin1String(Protocol::QSettingsSync));
+ callRemoteMethodDefaultReply(QLatin1String(Protocol::QSettingsSync));
else
d->settings.sync();
}
-QVariant QSettingsWrapper::value(const QString &param1, const QVariant &param2) const
+#if QT_VERSION < QT_VERSION_CHECK(6, 4, 0)
+QVariant QSettingsWrapper::value(const QString &key, const QVariant &value) const
+#else
+QVariant QSettingsWrapper::value(QAnyStringView key, const QVariant &value) const
+#endif
+{
+ if (createSocket())
+ return callRemoteMethod<QVariant>(QLatin1String(Protocol::QSettingsValue), key, value);
+ return d->settings.value(key, value);
+}
+
+#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
+QVariant QSettingsWrapper::value(QAnyStringView key) const
{
if (createSocket())
- return callRemoteMethod<QVariant>(QLatin1String(Protocol::QSettingsValue), param1, param2);
- return d->settings.value(param1, param2);
+ return callRemoteMethod<QVariant>(QLatin1String(Protocol::QSettingsValue), key);
+ return d->settings.value(key);
}
+#endif
// -- private
diff --git a/src/libs/installer/qsettingswrapper.h b/src/libs/installer/qsettingswrapper.h
index 92221c117..f5d428b1e 100644
--- a/src/libs/installer/qsettingswrapper.h
+++ b/src/libs/installer/qsettingswrapper.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -36,6 +36,8 @@
#include <QSettings>
+QT_FORWARD_DECLARE_CLASS(QTextCodec)
+
namespace QInstaller {
class INSTALLER_EXPORT QSettingsWrapper : public RemoteObject
@@ -68,12 +70,21 @@ public:
void sync();
Status status() const;
+#if QT_VERSION < QT_VERSION_CHECK(6, 4, 0)
void beginGroup(const QString &prefix);
+#else
+ void beginGroup(QAnyStringView prefix);
+#endif
void endGroup();
QString group() const;
+#if QT_VERSION < QT_VERSION_CHECK(6, 4, 0)
int beginReadArray(const QString &prefix);
void beginWriteArray(const QString &prefix, int size = -1);
+#else
+ int beginReadArray(QAnyStringView prefix);
+ void beginWriteArray(QAnyStringView prefix, int size = -1);
+#endif
void endArray();
void setArrayIndex(int i);
@@ -82,12 +93,22 @@ public:
QStringList childGroups() const;
bool isWritable() const;
+#if QT_VERSION < QT_VERSION_CHECK(6, 4, 0)
void setValue(const QString &key, const QVariant &value);
QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;
+#else
+ void setValue(QAnyStringView key, const QVariant &value);
+ QVariant value(QAnyStringView key, const QVariant &defaultValue) const;
+ QVariant value(QAnyStringView key) const;
+#endif
+#if QT_VERSION < QT_VERSION_CHECK(6, 4, 0)
void remove(const QString &key);
bool contains(const QString &key) const;
-
+#else
+ void remove(QAnyStringView key);
+ bool contains(QAnyStringView key) const;
+#endif
void setFallbacksEnabled(bool b);
bool fallbacksEnabled() const;
@@ -105,14 +126,13 @@ private: // we cannot support the following functionality
: RemoteObject(QLatin1String(Protocol::QSettings), parent)
{}
+#if QT_VERSION < QT_VERSION_CHECK(6, 4, 0)
void setIniCodec(QTextCodec * /*codec*/);
void setIniCodec(const char * /*codecName*/);
QTextCodec *iniCodec() const { return 0; }
-
+#endif
static void setDefaultFormat(QSettings::Format /*format*/);
static QSettings::Format defaultFormat() { return QSettings::NativeFormat; }
- static void setSystemIniPath(const QString & /*dir*/);
- static void setUserIniPath(const QString & /*dir*/);
static void setPath(QSettings::Format /*format*/, Scope /*scope*/, const QString & /*path*/);
typedef QMap<QString, QVariant> SettingsMap;
diff --git a/src/libs/installer/registerfiletypeoperation.cpp b/src/libs/installer/registerfiletypeoperation.cpp
index 1754b664d..852714dfb 100644
--- a/src/libs/installer/registerfiletypeoperation.cpp
+++ b/src/libs/installer/registerfiletypeoperation.cpp
@@ -153,7 +153,7 @@ bool RegisterFileTypeOperation::undoOperation()
{
#ifdef Q_OS_WIN
ensureOptionalArgumentsRead();
- if (parseUndoOperationArguments().count() > 0)
+ if (skipUndoOperation())
return true;
QStringList args = arguments();
diff --git a/src/libs/installer/remotefileengine.cpp b/src/libs/installer/remotefileengine.cpp
index b600da618..7a5e91682 100644
--- a/src/libs/installer/remotefileengine.cpp
+++ b/src/libs/installer/remotefileengine.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -55,10 +55,10 @@ QAbstractFileEngine* RemoteFileEngineHandler::create(const QString &fileName) co
if (fileName.isEmpty() || fileName.startsWith(QLatin1String(":")))
return 0; // empty filename or Qt resource
- QScopedPointer<RemoteFileEngine> client(new RemoteFileEngine());
+ std::unique_ptr<RemoteFileEngine> client(new RemoteFileEngine());
client->setFileName(fileName);
if (client->isConnectedToServer())
- return client.take();
+ return client.release();
return 0;
}
@@ -313,6 +313,7 @@ bool RemoteFileEngine::link(const QString &newName)
/*!
\reimp
*/
+#if QT_VERSION < QT_VERSION_CHECK(6, 3, 0)
bool RemoteFileEngine::mkdir(const QString &dirName, bool createParentDirectories) const
{
if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) {
@@ -320,18 +321,38 @@ bool RemoteFileEngine::mkdir(const QString &dirName, bool createParentDirectorie
dirName, createParentDirectories);
}
return m_fileEngine.mkdir(dirName, createParentDirectories);
+
+}
+#else
+bool RemoteFileEngine::mkdir(const QString &dirName, bool createParentDirectories,
+ std::optional<QFile::Permissions> permissions) const
+{
+ if ((const_cast<RemoteFileEngine *>(this))->connectToServer()) {
+ return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineMkdir),
+ dirName, createParentDirectories);
+ }
+ return m_fileEngine.mkdir(dirName, createParentDirectories, permissions);
}
+#endif
/*!
\reimp
*/
+#if QT_VERSION < QT_VERSION_CHECK(6, 3, 0)
bool RemoteFileEngine::open(QIODevice::OpenMode mode)
+#else
+bool RemoteFileEngine::open(QIODevice::OpenMode mode, std::optional<QFile::Permissions> permissions)
+#endif
{
if (connectToServer()) {
return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineOpen),
static_cast<qint32>(mode | QIODevice::Unbuffered));
}
+#if QT_VERSION < QT_VERSION_CHECK(6, 3, 0)
return m_fileEngine.open(mode | QIODevice::Unbuffered);
+#else
+ return m_fileEngine.open(mode | QIODevice::Unbuffered, permissions);
+#endif
}
/*!
@@ -418,8 +439,7 @@ bool RemoteFileEngine::seek(qint64 offset)
void RemoteFileEngine::setFileName(const QString &fileName)
{
if (connectToServer()) {
- callRemoteMethod(QString::fromLatin1(Protocol::QAbstractFileEngineSetFileName), fileName,
- dummy);
+ callRemoteMethodDefaultReply(QString::fromLatin1(Protocol::QAbstractFileEngineSetFileName), fileName);
}
m_fileEngine.setFileName(fileName);
}
diff --git a/src/libs/installer/remotefileengine.h b/src/libs/installer/remotefileengine.h
index 35ebf7742..31ae67d77 100644
--- a/src/libs/installer/remotefileengine.h
+++ b/src/libs/installer/remotefileengine.h
@@ -53,7 +53,12 @@ public:
RemoteFileEngine();
~RemoteFileEngine();
+#if QT_VERSION < QT_VERSION_CHECK(6, 3, 0)
bool open(QIODevice::OpenMode mode) override;
+#else
+ bool open(QIODevice::OpenMode mode,
+ std::optional<QFile::Permissions> permissions = std::nullopt) override;
+#endif
bool close() override;
bool flush() override;
bool syncToDisk() override;
@@ -66,7 +71,12 @@ public:
bool rename(const QString &newName) override;
bool renameOverwrite(const QString &newName) override;
bool link(const QString &newName) override;
+#if QT_VERSION < QT_VERSION_CHECK(6, 3, 0)
bool mkdir(const QString &dirName, bool createParentDirectories) const override;
+#else
+ bool mkdir(const QString &dirName, bool createParentDirectories,
+ std::optional<QFile::Permissions> permissions = std::nullopt) const override;
+#endif
bool rmdir(const QString &dirName, bool recurseParentDirectories) const override;
bool setSize(qint64 size) override;
bool caseSensitive() const override;
diff --git a/src/libs/installer/remoteobject.cpp b/src/libs/installer/remoteobject.cpp
index 70ab48af3..b4dd0cbb7 100644
--- a/src/libs/installer/remoteobject.cpp
+++ b/src/libs/installer/remoteobject.cpp
@@ -46,7 +46,6 @@ namespace QInstaller {
RemoteObject::RemoteObject(const QString &wrappedType, QObject *parent)
: QObject(parent)
- , dummy(nullptr)
, m_type(wrappedType)
, m_socket(nullptr)
{
@@ -140,10 +139,4 @@ bool RemoteObject::isConnectedToServer() const
return false;
}
-void RemoteObject::callRemoteMethod(const QString &name)
-{
- const QString reply = sendReceivePacket<QString>(name, dummy, dummy, dummy);
- Q_ASSERT(reply == QLatin1String(Protocol::DefaultReply));
-}
-
} // namespace QInstaller
diff --git a/src/libs/installer/remoteobject.h b/src/libs/installer/remoteobject.h
index c423de943..ddd512588 100644
--- a/src/libs/installer/remoteobject.h
+++ b/src/libs/installer/remoteobject.h
@@ -52,93 +52,58 @@ public:
virtual ~RemoteObject() = 0;
bool isConnectedToServer() const;
- void callRemoteMethod(const QString &name);
- template<typename T1, typename T2>
- void callRemoteMethod(const QString &name, const T1 &arg, const T2 &arg2)
+ template<typename... Args>
+ void callRemoteMethodDefaultReply(const QString &name, const Args&... args)
{
- const QString reply = sendReceivePacket<QString>(name, arg, arg2, dummy);
+ const QString reply = sendReceivePacket<QString>(name, args...);
Q_ASSERT(reply == QLatin1String(Protocol::DefaultReply));
}
- template<typename T1, typename T2, typename T3>
- void callRemoteMethod(const QString &name, const T1 &arg, const T2 &arg2, const T3 & arg3)
+ template<typename T, typename... Args>
+ T callRemoteMethod(const QString &name, const Args&... args) const
{
- const QString reply = sendReceivePacket<QString>(name, arg, arg2, arg3);
- Q_ASSERT(reply == QLatin1String(Protocol::DefaultReply));
- }
-
- template<typename T>
- T callRemoteMethod(const QString &name) const
- {
- return sendReceivePacket<T>(name, dummy, dummy, dummy);
- }
-
- template<typename T, typename T1>
- T callRemoteMethod(const QString &name, const T1 &arg) const
- {
- return sendReceivePacket<T>(name, arg, dummy, dummy);
- }
-
- template<typename T, typename T1, typename T2>
- T callRemoteMethod(const QString &name, const T1 & arg, const T2 &arg2) const
- {
- return sendReceivePacket<T>(name, arg, arg2, dummy);
- }
-
- template<typename T, typename T1, typename T2, typename T3>
- T callRemoteMethod(const QString &name, const T1 &arg, const T2 &arg2, const T3 &arg3) const
- {
- return sendReceivePacket<T>(name, arg, arg2, arg3);
+ return sendReceivePacket<T>(name, args...);
}
protected:
bool authorize();
bool connectToServer(const QVariantList &arguments = QVariantList());
- // Use this structure to allow derived classes to manipulate the template
- // function signature of the callRemoteMethod templates, since most of the
- // generated functions will differ in return type rather given arguments.
- struct Dummy {}; Dummy *dummy;
-
private:
- template<typename T> bool isValueType(T) const
- {
- return true;
- }
- template<typename T> bool isValueType(T *dummy) const
+ template<typename T, typename... Args>
+ T sendReceivePacket(const QString &name, const Args&... args) const
{
- // Force compiler error while passing anything different then Dummy* to the function.
- // It really doesn't make sense to send any pointer over to the server, so bail early.
- Q_UNUSED(static_cast<Dummy*> (dummy))
- return false;
- }
-
- template<typename T, typename T1, typename T2, typename T3>
- T sendReceivePacket(const QString &name, const T1 &arg, const T2 &arg2, const T3 &arg3) const
- {
- writeData(name, arg, arg2, arg3);
+ writeData(name, args...);
while (m_socket->bytesToWrite())
m_socket->waitForBytesWritten();
return readData<T>(name);
}
+ template <class T> int writeObject(QDataStream& out, const T& t) const
+ {
+ static_assert(!std::is_pointer<T>::value, "Pointer passed to remote server");
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ out << t;
+#else
+ if constexpr (std::is_same<T, QAnyStringView>::value)
+ out << t.toString();
+ else
+ out << t;
+#endif
+
+ return 0;
+ }
- template<typename T1, typename T2, typename T3>
- void writeData(const QString &name, const T1 &arg, const T2 &arg2, const T3 &arg3) const
+ template<typename... Args>
+ void writeData(const QString &name, const Args&... args) const
{
QByteArray data;
QDataStream out(&data, QIODevice::WriteOnly);
- if (isValueType(arg))
- out << arg;
- if (isValueType(arg2))
- out << arg2;
- if (isValueType(arg3))
- out << arg3;
-
+ (void)std::initializer_list<int>{writeObject(out, args)...};
sendPacket(m_socket, name.toLatin1(), data);
m_socket->flush();
}
diff --git a/src/libs/installer/remoteserverconnection.cpp b/src/libs/installer/remoteserverconnection.cpp
index ed3d343fe..51619983e 100644
--- a/src/libs/installer/remoteserverconnection.cpp
+++ b/src/libs/installer/remoteserverconnection.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -429,7 +429,8 @@ void RemoteServerConnection::handleQSettings(RemoteServerReply *reply, const QSt
QString key;
QVariant defaultValue;
data >> key;
- data >> defaultValue;
+ if (!data.atEnd())
+ data >> defaultValue;
reply->send(settings->value(key, defaultValue));
} else if (command == QLatin1String(Protocol::QSettingsOrganizationName)) {
reply->send(settings->organizationName());
@@ -497,11 +498,20 @@ void RemoteServerConnection::handleQFSFileEngine(RemoteServerReply *reply, const
bool createParentDirectories;
data >>dirName;
data >>createParentDirectories;
+#if QT_VERSION < QT_VERSION_CHECK(6, 3, 0)
reply->send(m_engine->mkdir(dirName, createParentDirectories));
+#else
+ reply->send(m_engine->mkdir(dirName, createParentDirectories, std::nullopt));
+#endif
+
} else if (command == QLatin1String(Protocol::QAbstractFileEngineOpen)) {
qint32 openMode;
data >>openMode;
+#if QT_VERSION < QT_VERSION_CHECK(6, 3, 0)
reply->send(m_engine->open(static_cast<QIODevice::OpenMode> (openMode)));
+#else
+ reply->send(m_engine->open(static_cast<QIODevice::OpenMode> (openMode), std::nullopt));
+#endif
} else if (command == QLatin1String(Protocol::QAbstractFileEngineOwner)) {
qint32 owner;
data >>owner;
diff --git a/src/libs/installer/remoteserverconnection_p.h b/src/libs/installer/remoteserverconnection_p.h
index 977a64711..09e6de7d7 100644
--- a/src/libs/installer/remoteserverconnection_p.h
+++ b/src/libs/installer/remoteserverconnection_p.h
@@ -52,7 +52,7 @@ private:
connect(process, &QIODevice::bytesWritten, this, &QProcessSignalReceiver::onBytesWritten);
connect(process, &QIODevice::aboutToClose, this, &QProcessSignalReceiver::onAboutToClose);
connect(process, &QIODevice::readChannelFinished, this, &QProcessSignalReceiver::onReadChannelFinished);
- connect(process, SIGNAL(error(QProcess::ProcessError)),
+ connect(process, SIGNAL(errorOccurred(QProcess::ProcessError)),
SLOT(onError(QProcess::ProcessError)));
connect(process, &QProcess::readyReadStandardOutput,
this, &QProcessSignalReceiver::onReadyReadStandardOutput);
diff --git a/src/libs/installer/repository.cpp b/src/libs/installer/repository.cpp
index 4ef8f9f25..f7035e732 100644
--- a/src/libs/installer/repository.cpp
+++ b/src/libs/installer/repository.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -35,7 +35,7 @@
#include <QDir>
/*!
- \fn inline uint QInstaller::qHash(const Repository &repository)
+ \fn inline hashValue QInstaller::qHash(const Repository &repository)
Returns a hash of the \a repository.
*/
@@ -49,6 +49,7 @@ Repository::Repository()
: m_default(false)
, m_enabled(false)
, m_compressed(false)
+ , m_postLoadComponentScript(false)
{
}
@@ -62,9 +63,10 @@ Repository::Repository(const Repository &other)
, m_username(other.m_username)
, m_password(other.m_password)
, m_displayname(other.m_displayname)
- , m_compressed(other.m_compressed)
, m_categoryname(other.m_categoryname)
+ , m_compressed(other.m_compressed)
, m_xmlChecksum(other.m_xmlChecksum)
+ , m_postLoadComponentScript(other.m_postLoadComponentScript)
{
}
@@ -77,6 +79,7 @@ Repository::Repository(const QUrl &url, bool isDefault, bool compressed)
, m_default(isDefault)
, m_enabled(true)
, m_compressed(compressed)
+ , m_postLoadComponentScript(false)
{
}
@@ -252,6 +255,22 @@ bool Repository::isCompressed() const
}
/*!
+ \internal
+*/
+bool Repository::postLoadComponentScript() const
+{
+ return m_postLoadComponentScript;
+}
+
+/*!
+ \internal
+*/
+void Repository::setPostLoadComponentScript(const bool postLoad)
+{
+ m_postLoadComponentScript = postLoad;
+}
+
+/*!
Compares the values of this repository to \a other and returns true if they are equal (same server,
default state, enabled state as well as username and password). \sa operator!=()
*/
@@ -259,7 +278,8 @@ bool Repository::operator==(const Repository &other) const
{
return m_url == other.m_url && m_default == other.m_default && m_enabled == other.m_enabled
&& m_username == other.m_username && m_password == other.m_password
- && m_displayname == other.m_displayname && m_xmlChecksum == other.m_xmlChecksum;
+ && m_displayname == other.m_displayname && m_xmlChecksum == other.m_xmlChecksum
+ && m_postLoadComponentScript == other.m_postLoadComponentScript;
}
/*!
@@ -288,6 +308,7 @@ const Repository &Repository::operator=(const Repository &other)
m_compressed = other.m_compressed;
m_categoryname = other.m_categoryname;
m_xmlChecksum = other.m_xmlChecksum;
+ m_postLoadComponentScript = other.m_postLoadComponentScript;
return *this;
}
@@ -307,7 +328,7 @@ QDataStream &operator>>(QDataStream &istream, Repository &repository)
{
QByteArray url, username, password, displayname, compressed;
istream >> url >> repository.m_default >> repository.m_enabled >> username >> password
- >> displayname >> repository.m_categoryname >> repository.m_xmlChecksum;
+ >> displayname >> repository.m_categoryname >> repository.m_xmlChecksum >> repository.m_postLoadComponentScript;
repository.setUrl(QUrl::fromEncoded(QByteArray::fromBase64(url)));
repository.setUsername(QString::fromUtf8(QByteArray::fromBase64(username)));
repository.setPassword(QString::fromUtf8(QByteArray::fromBase64(password)));
@@ -323,7 +344,7 @@ QDataStream &operator<<(QDataStream &ostream, const Repository &repository)
return ostream << repository.m_url.toEncoded().toBase64() << repository.m_default << repository.m_enabled
<< repository.m_username.toUtf8().toBase64() << repository.m_password.toUtf8().toBase64()
<< repository.m_displayname.toUtf8().toBase64() << repository.m_categoryname.toUtf8().toBase64()
- << repository.m_xmlChecksum.toBase64();
+ << repository.m_xmlChecksum.toBase64() << repository.m_postLoadComponentScript;
}
}
diff --git a/src/libs/installer/repository.h b/src/libs/installer/repository.h
index 1edb83449..0a589a43e 100644
--- a/src/libs/installer/repository.h
+++ b/src/libs/installer/repository.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -71,10 +71,13 @@ public:
void setXmlChecksum(const QByteArray &checksum);
bool isCompressed() const;
+ bool postLoadComponentScript() const;
+ void setPostLoadComponentScript(const bool postLoad);
+
bool operator==(const Repository &other) const;
bool operator!=(const Repository &other) const;
- uint qHash(const Repository &repository);
+ hashValue qHash(const Repository &repository);
const Repository &operator=(const Repository &other);
friend INSTALLER_EXPORT QDataStream &operator>>(QDataStream &istream, Repository &repository);
@@ -90,9 +93,10 @@ private:
QString m_categoryname;
bool m_compressed;
QByteArray m_xmlChecksum;
+ bool m_postLoadComponentScript;
};
-inline uint qHash(const Repository &repository)
+inline hashValue qHash(const Repository &repository)
{
return qHash(repository.url());
}
diff --git a/src/libs/installer/repositorycategory.cpp b/src/libs/installer/repositorycategory.cpp
index 6be292330..c9bee6e3a 100644
--- a/src/libs/installer/repositorycategory.cpp
+++ b/src/libs/installer/repositorycategory.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -35,7 +35,7 @@
#include <QStringList>
/*!
- \fn inline uint QInstaller::qHash(const RepositoryCategory &repository)
+ \fn inline hashValue QInstaller::qHash(const RepositoryCategory &repository)
Returns a hash of the repository category \a repository.
*/
@@ -65,8 +65,8 @@ RepositoryCategory::RepositoryCategory()
Constructs a new category by using all fields of the given category \a other.
*/
RepositoryCategory::RepositoryCategory(const RepositoryCategory &other)
- : m_displayname(other.m_displayname), m_data(other.m_data), m_enabled(other.m_enabled),
- m_tooltip(other.m_tooltip)
+ : m_data(other.m_data), m_displayname(other.m_displayname), m_tooltip(other.m_tooltip),
+ m_enabled(other.m_enabled)
{
registerMetaType();
}
diff --git a/src/libs/installer/repositorycategory.h b/src/libs/installer/repositorycategory.h
index dc45527eb..993ae78aa 100644
--- a/src/libs/installer/repositorycategory.h
+++ b/src/libs/installer/repositorycategory.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -31,6 +31,7 @@
#include "installer_global.h"
#include "repository.h"
+#include "qinstallerglobal.h"
#include <QtCore/QMetaType>
#include <QtCore/QUrl>
@@ -63,7 +64,7 @@ public:
bool operator==(const RepositoryCategory &other) const;
bool operator!=(const RepositoryCategory &other) const;
- uint qHash(const RepositoryCategory &repository);
+ hashValue qHash(const RepositoryCategory &repository);
friend INSTALLER_EXPORT QDataStream &operator>>(QDataStream &istream, RepositoryCategory &repository);
friend INSTALLER_EXPORT QDataStream &operator<<(QDataStream &ostream, const RepositoryCategory &repository);
@@ -75,7 +76,7 @@ private:
bool m_enabled;
};
-inline uint qHash(const RepositoryCategory &repository)
+inline hashValue qHash(const RepositoryCategory &repository)
{
return qHash(repository.displayname());
}
diff --git a/src/libs/installer/resources/installer.qrc b/src/libs/installer/resources/installer.qrc
index 48a7c65bd..a3855b5c4 100644
--- a/src/libs/installer/resources/installer.qrc
+++ b/src/libs/installer/resources/installer.qrc
@@ -7,5 +7,6 @@
<file>uninstall.png</file>
<file>keepinstalled.png</file>
<file>keepuninstalled.png</file>
+ <file>qt/etc/qt.conf</file>
</qresource>
</RCC>
diff --git a/src/libs/installer/resources/qt/etc/qt.conf b/src/libs/installer/resources/qt/etc/qt.conf
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/libs/installer/resources/qt/etc/qt.conf
diff --git a/src/libs/installer/scriptengine.cpp b/src/libs/installer/scriptengine.cpp
index baf348868..7e3e69eb2 100644
--- a/src/libs/installer/scriptengine.cpp
+++ b/src/libs/installer/scriptengine.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2023 The Qt Company Ltd.
+** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -56,18 +56,6 @@ namespace QInstaller {
/*!
\inmodule QtInstallerFramework
- \class QInstaller::ConsoleProxy
- \internal
-*/
-
-/*!
- \inmodule QtInstallerFramework
- \class QInstaller::InstallerProxy
- \internal
-*/
-
-/*!
- \inmodule QtInstallerFramework
\class QInstaller::QDesktopServicesProxy
\internal
*/
@@ -78,28 +66,6 @@ namespace QInstaller {
\internal
*/
-QJSValue InstallerProxy::components(const QString &regexp) const
-{
- if (m_core) {
- const QList<Component*> all = m_core->components(PackageManagerCore::ComponentType::All, regexp);
- QJSValue scriptComponentsObject = m_engine->newArray(all.count());
- for (int i = 0; i < all.count(); ++i) {
- Component *const component = all.at(i);
- QQmlEngine::setObjectOwnership(component, QQmlEngine::CppOwnership);
- scriptComponentsObject.setProperty(i, m_engine->newQObject(component));
- }
- return scriptComponentsObject;
- }
- return m_engine->newArray();
-}
-
-QJSValue InstallerProxy::componentByName(const QString &componentName)
-{
- if (m_core)
- return m_engine->newQObject(m_core->componentByName(componentName), false);
- return QJSValue();
-}
-
QJSValue QDesktopServicesProxy::findFiles(const QString &path, const QString &pattern)
{
QStringList result;
@@ -223,6 +189,12 @@ bool GuiProxy::isButtonEnabled(int wizardButton)
return m_gui->isButtonEnabled(wizardButton);
}
+void GuiProxy::setWizardPageButtonText(int pageId, int buttonId, const QString &buttonText)
+{
+ if (m_gui)
+ m_gui->setWizardPageButtonText(pageId, buttonId, buttonText);
+}
+
void GuiProxy::showSettingsButton(bool show)
{
if (m_gui)
@@ -382,14 +354,10 @@ ScriptEngine::ScriptEngine(PackageManagerCore *core) : QObject(core)
, m_guiProxy(new GuiProxy(this, this))
, m_core(core)
{
- m_engine.installExtensions(QJSEngine::TranslationExtension);
+ m_engine.installExtensions(QJSEngine::TranslationExtension | QJSEngine::ConsoleExtension);
QJSValue global = m_engine.globalObject();
- global.setProperty(QLatin1String("console"), m_engine.newQObject(new ConsoleProxy));
+
global.setProperty(QLatin1String("QFileDialog"), m_engine.newQObject(new QFileDialogProxy(core)));
- const QJSValue proxy = m_engine.newQObject(new InstallerProxy(this, core));
- global.setProperty(QLatin1String("InstallerProxy"), proxy);
- global.setProperty(QLatin1String("print"), m_engine.newQObject(new ConsoleProxy)
- .property(QLatin1String("log")));
global.setProperty(QLatin1String("systemInfo"), m_engine.newQObject(new SystemInfo));
global.setProperty(QLatin1String("QInstaller"), generateQInstallerObject());
@@ -409,11 +377,6 @@ ScriptEngine::ScriptEngine(PackageManagerCore *core) : QObject(core)
global.setProperty(QLatin1String("installer"), m_engine.newQObject(new QObject));
}
global.setProperty(QLatin1String("gui"), m_engine.newQObject(m_guiProxy));
-
- global.property(QLatin1String("installer")).setProperty(QLatin1String("components"),
- proxy.property(QLatin1String("components")));
- global.property(QLatin1String("installer")).setProperty(QLatin1String("componentByName"),
- proxy.property(QLatin1String("componentByName")));
}
/*!
@@ -661,14 +624,19 @@ QJSValue ScriptEngine::generateDesktopServicesObject()
SETPROPERTY(desktopServices, PicturesLocation, QStandardPaths)
SETPROPERTY(desktopServices, TempLocation, QStandardPaths)
SETPROPERTY(desktopServices, HomeLocation, QStandardPaths)
- SETPROPERTY(desktopServices, AppDataLocation, QStandardPaths)
+ SETPROPERTY(desktopServices, AppLocalDataLocation, QStandardPaths)
SETPROPERTY(desktopServices, CacheLocation, QStandardPaths)
+ SETPROPERTY(desktopServices, GenericCacheLocation, QStandardPaths)
SETPROPERTY(desktopServices, GenericDataLocation, QStandardPaths)
SETPROPERTY(desktopServices, RuntimeLocation, QStandardPaths)
SETPROPERTY(desktopServices, ConfigLocation, QStandardPaths)
SETPROPERTY(desktopServices, DownloadLocation, QStandardPaths)
SETPROPERTY(desktopServices, GenericCacheLocation, QStandardPaths)
SETPROPERTY(desktopServices, GenericConfigLocation, QStandardPaths)
+ SETPROPERTY(desktopServices, AppDataLocation, QStandardPaths)
+ SETPROPERTY(desktopServices, AppConfigLocation, QStandardPaths)
+ SETPROPERTY(desktopServices, PublicShareLocation, QStandardPaths)
+ SETPROPERTY(desktopServices, TemplatesLocation, QStandardPaths)
QJSValue object = m_engine.newQObject(new QDesktopServicesProxy(this));
object.setPrototype(desktopServices); // attach the properties
diff --git a/src/libs/installer/scriptengine_p.h b/src/libs/installer/scriptengine_p.h
index a0936fe75..101d4f303 100644
--- a/src/libs/installer/scriptengine_p.h
+++ b/src/libs/installer/scriptengine_p.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -43,36 +43,6 @@ class PackageManagerCore;
class PackageManagerGui;
class ScriptEngine;
-class ConsoleProxy : public QObject
-{
- Q_OBJECT
- Q_DISABLE_COPY(ConsoleProxy)
-
-public:
- ConsoleProxy() {}
-
-public slots :
- void log(const QString &log) { qCDebug(QInstaller::lcInstallerInstallLog).noquote() << log; }
-};
-
-class InstallerProxy : public QObject
-{
- Q_OBJECT
- Q_DISABLE_COPY(InstallerProxy)
-
-public:
- InstallerProxy(ScriptEngine *engine, PackageManagerCore *core)
- : m_engine(engine), m_core(core) {}
-
-public slots:
- QJSValue components(const QString &regexp = QString()) const;
- QJSValue componentByName(const QString &componentName);
-
-private:
- ScriptEngine *m_engine;
- PackageManagerCore *m_core;
-};
-
class QFileDialogProxy : public QObject
{
Q_OBJECT
@@ -146,6 +116,7 @@ public:
Q_INVOKABLE void clickButton(int wizardButton, int delayInMs = 0);
Q_INVOKABLE void clickButton(const QString &objectName, int delayInMs = 0) const;
Q_INVOKABLE bool isButtonEnabled(int wizardButton);
+ Q_INVOKABLE void setWizardPageButtonText(int pageId, int buttonId, const QString &buttonText);
Q_INVOKABLE void showSettingsButton(bool show);
Q_INVOKABLE void setSettingsButtonEnabled(bool enable);
@@ -178,8 +149,6 @@ private:
} // namespace QInstaller
-Q_DECLARE_METATYPE(QInstaller::ConsoleProxy*)
-Q_DECLARE_METATYPE(QInstaller::InstallerProxy*)
Q_DECLARE_METATYPE(QInstaller::QFileDialogProxy*)
Q_DECLARE_METATYPE(QInstaller::QDesktopServicesProxy*)
diff --git a/src/libs/installer/settings.cpp b/src/libs/installer/settings.cpp
index 85ab0dece..e18f63689 100644
--- a/src/libs/installer/settings.cpp
+++ b/src/libs/installer/settings.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -318,13 +318,13 @@ Settings Settings::fromFileAndPrefix(const QString &path, const QString &prefix,
elementList << scName << scVersion << scTitle << scPublisher << scProductUrl
<< scTargetDir << scAdminTargetDir
<< scInstallerApplicationIcon << scInstallerWindowIcon
- << scLogo << scWatermark << scBanner << scBackground << scPageListPixmap
+ << scLogo << scWatermark << scBanner << scBackground << scPageListPixmap << scAliasDefinitionsFile
<< scStartMenuDir << scMaintenanceToolName << scMaintenanceToolIniFile << scMaintenanceToolAlias
<< scRemoveTargetDir << scLocalCacheDir << scPersistentLocalCache
<< scRunProgram << scRunProgramArguments << scRunProgramDescription
<< scDependsOnLocalInstallerBinary
- << scAllowSpaceInPath << scAllowNonAsciiCharacters << scDisableAuthorizationFallback
- << scDisableCommandLineInterface
+ << scAllowSpaceInPath << scAllowNonAsciiCharacters << scAllowRepositoriesForOfflineInstaller
+ << scDisableAuthorizationFallback << scDisableCommandLineInterface
<< scWizardStyle << scStyleSheet << scTitleColor
<< scWizardDefaultWidth << scWizardDefaultHeight << scWizardMinimumWidth << scWizardMinimumHeight
<< scWizardShowPageList << scProductImages
@@ -485,11 +485,11 @@ static int lengthToInt(const QVariant &variant)
QString length = variant.toString().trimmed();
if (length.endsWith(QLatin1String("em"), Qt::CaseInsensitive)) {
length.chop(2);
- return qRound(length.toDouble() * QApplication::fontMetrics().height());
+ return qRound(length.toDouble() * QFontMetricsF(QApplication::font()).height());
}
if (length.endsWith(QLatin1String("ex"), Qt::CaseInsensitive)) {
length.chop(2);
- return qRound(length.toDouble() * QApplication::fontMetrics().xHeight());
+ return qRound(length.toDouble() * QFontMetricsF(QApplication::font()).xHeight());
}
if (length.endsWith(QLatin1String("px"), Qt::CaseInsensitive)) {
length.chop(2);
@@ -539,6 +539,11 @@ void Settings::setProductImages(const QMap<QString, QVariant> &images)
d->m_data.insert(scProductImages, QVariant::fromValue(images));
}
+QString Settings::aliasDefinitionsFile() const
+{
+ return d->absolutePathFromKey(scAliasDefinitionsFile);
+}
+
QString Settings::installerApplicationIcon() const
{
return d->absolutePathFromKey(scInstallerApplicationIcon, systemIconSuffix());
@@ -644,6 +649,11 @@ bool Settings::allowNonAsciiCharacters() const
return d->m_data.value(scAllowNonAsciiCharacters, false).toBool();
}
+bool Settings::allowRepositoriesForOfflineInstaller() const
+{
+ return d->m_data.value(scAllowRepositoriesForOfflineInstaller, true).toBool();
+}
+
bool Settings::disableAuthorizationFallback() const
{
return d->m_data.value(scDisableAuthorizationFallback, false).toBool();
diff --git a/src/libs/installer/settings.h b/src/libs/installer/settings.h
index f98319110..85b59869c 100644
--- a/src/libs/installer/settings.h
+++ b/src/libs/installer/settings.h
@@ -95,6 +95,8 @@ public:
QMap<QString, QVariant> productImages() const;
void setProductImages(const QMap<QString, QVariant> &images);
+ QString aliasDefinitionsFile() const;
+
QString applicationName() const;
QString version() const;
@@ -143,6 +145,8 @@ public:
bool allowSpaceInPath() const;
bool allowNonAsciiCharacters() const;
+ bool allowRepositoriesForOfflineInstaller() const;
+
bool disableAuthorizationFallback() const;
bool disableCommandLineInterface() const;
diff --git a/src/libs/installer/simplemovefileoperation.cpp b/src/libs/installer/simplemovefileoperation.cpp
index 5f3000be0..5bbbdabb4 100644
--- a/src/libs/installer/simplemovefileoperation.cpp
+++ b/src/libs/installer/simplemovefileoperation.cpp
@@ -93,7 +93,7 @@ bool SimpleMoveFileOperation::performOperation()
bool SimpleMoveFileOperation::undoOperation()
{
- if (parseUndoOperationArguments().count() > 0)
+ if (skipUndoOperation())
return true;
const QString source = arguments().at(0);
const QString target = arguments().at(1);
diff --git a/src/libs/installer/sysinfo_win.cpp b/src/libs/installer/sysinfo_win.cpp
index e74eb1d4e..e5df8e35f 100644
--- a/src/libs/installer/sysinfo_win.cpp
+++ b/src/libs/installer/sysinfo_win.cpp
@@ -64,7 +64,7 @@ VolumeInfo updateVolumeSizeInformation(const VolumeInfo &info)
return update;
}
-/*!
+/*
Returns a list of volume info objects that are mounted as network drive shares.
*/
QList<VolumeInfo> networkVolumeInfosFromMountPoints()
@@ -95,7 +95,7 @@ QList<VolumeInfo> networkVolumeInfosFromMountPoints()
return volumes;
}
-/*!
+/*
Returns a list of volume info objects based on the given \a volumeGUID. The function also solves mounted
volume folder paths. It does not return any network drive shares.
*/
diff --git a/src/libs/installer/systeminfo.cpp b/src/libs/installer/systeminfo.cpp
index 6a1976c4a..aed02c569 100644
--- a/src/libs/installer/systeminfo.cpp
+++ b/src/libs/installer/systeminfo.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -55,6 +55,7 @@ SystemInfo::SystemInfo(QObject *parent) : QObject(parent)
\list
\li "i386"
\li "x86_64"
+ \li "arm64"
\endlist
\note This function depends on what the OS will report and may not detect the actual CPU
@@ -62,7 +63,7 @@ SystemInfo::SystemInfo(QObject *parent) : QObject(parent)
OS running on a 64-bit CPU is usually unable to determine whether the CPU is actually capable
of running 64-bit programs.
- \sa QSysInfo::currentCpuArchitecture()
+ \sa QSysInfo::currentCpuArchitecture() buildCpuArchitecture()
*/
QString SystemInfo::currentCpuArchitecture() const
{
@@ -70,6 +71,29 @@ QString SystemInfo::currentCpuArchitecture() const
}
/*!
+ \property SystemInfo::buildCpuArchitecture
+
+ The architecture of the CPU that the application was compiled for, in text format.
+
+ Possible values include:
+ \list
+ \li "i386"
+ \li "x86_64"
+ \li "arm64"
+ \endlist
+
+ \note Note that this may not match the actual CPU that the application is running on if
+ there's an emulation layer or if the CPU supports multiple architectures (like x86-64
+ processors supporting i386 applications). To detect that, use \c installer.currentCpuArchitecture()
+
+ \sa QSysInfo::buildCpuArchitecture() currentCpuArchitecture()
+*/
+QString SystemInfo::buildCpuArchitecture() const
+{
+ return QSysInfo::buildCpuArchitecture();
+}
+
+/*!
\property SystemInfo::kernelType
The type of the operating system kernel the installer was compiled for. It is also the
@@ -124,7 +148,7 @@ QString SystemInfo::kernelVersion() const
\list
\li "windows"
\li "opensuse" (for the Linux openSUSE distribution)
- \li "osx"
+ \li "macos"
\endlist
\sa QSysInfo::productType()
diff --git a/src/libs/installer/systeminfo.h b/src/libs/installer/systeminfo.h
index c5451605e..a1393397a 100644
--- a/src/libs/installer/systeminfo.h
+++ b/src/libs/installer/systeminfo.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -39,6 +39,7 @@ class SystemInfo : public QObject
Q_DISABLE_COPY(SystemInfo)
Q_PROPERTY(QString currentCpuArchitecture READ currentCpuArchitecture CONSTANT)
+ Q_PROPERTY(QString buildCpuArchitecture READ buildCpuArchitecture CONSTANT)
Q_PROPERTY(QString kernelType READ kernelType CONSTANT)
Q_PROPERTY(QString kernelVersion READ kernelVersion CONSTANT)
Q_PROPERTY(QString productType READ productType CONSTANT)
@@ -49,7 +50,7 @@ public:
explicit SystemInfo(QObject *parent = 0);
QString currentCpuArchitecture() const;
-
+ QString buildCpuArchitecture() const;
QString kernelType() const;
QString kernelVersion() const;
QString productType() const;
diff --git a/src/libs/installer/utils.cpp b/src/libs/installer/utils.cpp
index 154a66553..9b64ade37 100644
--- a/src/libs/installer/utils.cpp
+++ b/src/libs/installer/utils.cpp
@@ -171,7 +171,7 @@ QByteArray QInstaller::calculateHash(QIODevice *device, QCryptographicHash::Algo
const qint64 numRead = device->read(buffer.data(), buffer.size());
if (numRead <= 0)
return hash.result();
- hash.addData(buffer.constData(), numRead);
+ hash.addData(buffer.left(numRead));
}
return QByteArray(); // never reached
}
diff --git a/src/libs/kdtools/filedownloader.cpp b/src/libs/kdtools/filedownloader.cpp
index 6152811aa..4d4002b7a 100644
--- a/src/libs/kdtools/filedownloader.cpp
+++ b/src/libs/kdtools/filedownloader.cpp
@@ -658,14 +658,6 @@ void KDUpdater::FileDownloader::addCheckSumData(const QByteArray &data)
}
/*!
- Adds the \a length of characters of \a data to the cryptographic hash of the downloaded file.
-*/
-void KDUpdater::FileDownloader::addCheckSumData(const char *data, int length)
-{
- d->m_hash.addData(data, length);
-}
-
-/*!
Resets SHA-1 checksum data of the downloaded file.
*/
void KDUpdater::FileDownloader::resetCheckSumData()
@@ -921,7 +913,7 @@ void KDUpdater::LocalFileDownloader::timerEvent(QTimerEvent *event)
toWrite -= numWritten;
}
addSample(numRead);
- addCheckSumData(buffer.data(), numRead);
+ addCheckSumData(buffer.left(numRead));
if (numRead > 0) {
setProgress(d->source->pos(), d->source->size());
emit downloadProgress(calcProgress(d->source->pos(), d->source->size()));
@@ -1113,7 +1105,7 @@ void KDUpdater::ResourceFileDownloader::timerEvent(QTimerEvent *event)
const qint64 numRead = d->destFile.read(buffer.data(), buffer.size());
addSample(numRead);
- addCheckSumData(buffer.data(), numRead);
+ addCheckSumData(buffer.left(numRead));
if (numRead > 0) {
setProgress(d->destFile.pos(), d->destFile.size());
@@ -1192,9 +1184,8 @@ struct KDUpdater::HttpDownloader::Private
disconnect(http, &QNetworkReply::finished, q, &HttpDownloader::httpReqFinished);
disconnect(http, &QNetworkReply::downloadProgress,
q, &HttpDownloader::httpReadProgress);
- void (QNetworkReply::*errorSignal)(QNetworkReply::NetworkError) = &QNetworkReply::error;
- disconnect(http, errorSignal, q, &HttpDownloader::httpError);
+ disconnect(http, &QNetworkReply::errorOccurred, q, &HttpDownloader::httpError);
http->deleteLater();
}
http = 0;
@@ -1220,8 +1211,14 @@ KDUpdater::HttpDownloader::HttpDownloader(QObject *parent)
#endif
connect(&d->manager, &QNetworkAccessManager::authenticationRequired,
this, &HttpDownloader::onAuthenticationRequired);
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
connect(&d->manager, &QNetworkAccessManager::networkAccessibleChanged,
this, &HttpDownloader::onNetworkAccessibleChanged);
+#else
+ auto netInfo = QNetworkInformation::instance();
+ connect(netInfo, &QNetworkInformation::reachabilityChanged,
+ this, &HttpDownloader::onReachabilityChanged);
+#endif
}
@@ -1314,7 +1311,7 @@ void KDUpdater::HttpDownloader::httpReadyRead()
written += numWritten;
}
addSample(written);
- addCheckSumData(buffer.data(), read);
+ addCheckSumData(buffer.left(read));
updateBytesDownloadedBeforeResume(written);
}
}
@@ -1476,13 +1473,17 @@ void KDUpdater::HttpDownloader::startDownload(const QUrl &url)
d->m_authenticationCount = 0;
d->manager.setProxyFactory(proxyFactory());
clearBytesDownloadedBeforeResume();
- d->http = d->manager.get(QNetworkRequest(url));
+
+ QNetworkRequest request(url);
+ request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::ManualRedirectPolicy);
+ request.setAttribute(QNetworkRequest::Http2AllowedAttribute, false);
+
+ d->http = d->manager.get(request);
connect(d->http, &QIODevice::readyRead, this, &HttpDownloader::httpReadyRead);
connect(d->http, &QNetworkReply::downloadProgress,
this, &HttpDownloader::httpReadProgress);
connect(d->http, &QNetworkReply::finished, this, &HttpDownloader::httpReqFinished);
- void (QNetworkReply::*errorSignal)(QNetworkReply::NetworkError) = &QNetworkReply::error;
- connect(d->http, errorSignal, this, &HttpDownloader::httpError);
+ connect(d->http, &QNetworkReply::errorOccurred, this, &HttpDownloader::httpError);
bool fileOpened = false;
if (d->destFileName.isEmpty()) {
@@ -1509,9 +1510,9 @@ void KDUpdater::HttpDownloader::startDownload(const QUrl &url)
qCWarning(QInstaller::lcInstallerInstallLog) << "File exists but installer is unable to open it.";
else
qCWarning(QInstaller::lcInstallerInstallLog) << "File does not exist.";
- d->shutDown();
setDownloadAborted(tr("Cannot download %1. Cannot create file \"%2\": %3").arg(
url.toString(), d->destination->fileName(), d->destination->errorString()));
+ d->shutDown();
}
}
}
@@ -1532,8 +1533,7 @@ void KDUpdater::HttpDownloader::resumeDownload()
connect(d->http, &QNetworkReply::downloadProgress,
this, &HttpDownloader::httpReadProgress);
connect(d->http, &QNetworkReply::finished, this, &HttpDownloader::httpReqFinished);
- void (QNetworkReply::*errorSignal)(QNetworkReply::NetworkError) = &QNetworkReply::error;
- connect(d->http, errorSignal, this, &HttpDownloader::httpError);
+ connect(d->http, &QNetworkReply::errorOccurred, this, &HttpDownloader::httpError);
runDownloadSpeedTimer();
runDownloadDeadlineTimer();
}
@@ -1575,6 +1575,7 @@ void KDUpdater::HttpDownloader::onAuthenticationRequired(QNetworkReply *reply, Q
}
}
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
void KDUpdater::HttpDownloader::onNetworkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility accessible)
{
if (accessible == QNetworkAccessManager::NotAccessible) {
@@ -1589,6 +1590,22 @@ void KDUpdater::HttpDownloader::onNetworkAccessibleChanged(QNetworkAccessManager
}
}
}
+#else
+void KDUpdater::HttpDownloader::onReachabilityChanged(QNetworkInformation::Reachability newReachability)
+{
+ if (newReachability == QNetworkInformation::Reachability::Online) {
+ if (isDownloadPaused()) {
+ setDownloadPaused(false);
+ resumeDownload();
+ }
+ } else {
+ d->shutDown(false);
+ setDownloadPaused(true);
+ setDownloadResumed(false);
+ stopDownloadDeadlineTimer();
+ }
+}
+#endif
#ifndef QT_NO_SSL
@@ -1626,7 +1643,7 @@ void KDUpdater::HttpDownloader::onSslErrors(QNetworkReply* reply, const QList<QS
"the error may be temporary and you can try again.")));
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
- msgBox.setButtonText(QMessageBox::Yes, tr("Try again"));
+ msgBox.addButton(tr("Try again"), QMessageBox::YesRole);
msgBox.setDefaultButton(QMessageBox::Cancel);
if (msgBox.exec() == QMessageBox::Cancel) {
diff --git a/src/libs/kdtools/filedownloader.h b/src/libs/kdtools/filedownloader.h
index 3990d849a..e71f7d62f 100644
--- a/src/libs/kdtools/filedownloader.h
+++ b/src/libs/kdtools/filedownloader.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -142,7 +143,6 @@ protected:
void emitEstimatedDownloadTime();
void addCheckSumData(const QByteArray &data);
- void addCheckSumData(const char *data, int length);
void resetCheckSumData();
private Q_SLOTS:
diff --git a/src/libs/kdtools/filedownloader_p.h b/src/libs/kdtools/filedownloader_p.h
index ec47e31ca..23eff08d7 100644
--- a/src/libs/kdtools/filedownloader_p.h
+++ b/src/libs/kdtools/filedownloader_p.h
@@ -35,6 +35,10 @@
#include <QtNetwork/QNetworkReply>
#include <QNetworkAccessManager>
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+#include <QNetworkInformation>
+#endif
+
// these classes are not a part of the public API
namespace KDUpdater {
@@ -130,7 +134,11 @@ private Q_SLOTS:
void httpDone(bool error);
void httpReqFinished();
void onAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator);
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
void onNetworkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility accessible);
+#else
+ void onReachabilityChanged(QNetworkInformation::Reachability newReachability);
+#endif
#ifndef QT_NO_SSL
void onSslErrors(QNetworkReply* reply, const QList<QSslError> &errors);
#endif
diff --git a/src/libs/kdtools/updatefinder.cpp b/src/libs/kdtools/updatefinder.cpp
index 120dcb952..dbe7825df 100644
--- a/src/libs/kdtools/updatefinder.cpp
+++ b/src/libs/kdtools/updatefinder.cpp
@@ -301,9 +301,9 @@ bool UpdateFinder::downloadUpdateXMLFiles()
connect(downloader, SIGNAL(downloadCanceled()), this, SLOT(slotDownloadDone()));
connect(downloader, SIGNAL(downloadCompleted()), this, SLOT(slotDownloadDone()));
connect(downloader, SIGNAL(downloadAborted(QString)), this, SLOT(slotDownloadDone()));
- m_updatesInfoList.insert(new UpdatesInfo, Data(info, downloader));
+ m_updatesInfoList.insert(new UpdatesInfo(info.postLoadComponentScript), Data(info, downloader));
} else {
- UpdatesInfo *updatesInfo = new UpdatesInfo;
+ UpdatesInfo *updatesInfo = new UpdatesInfo(info.postLoadComponentScript);
updatesInfo->setFileName(QInstaller::pathFromUrl(url));
m_updatesInfoList.insert(updatesInfo, Data(info));
}
diff --git a/src/libs/kdtools/updateoperation.cpp b/src/libs/kdtools/updateoperation.cpp
index 6a7e62f2b..af89382a8 100644
--- a/src/libs/kdtools/updateoperation.cpp
+++ b/src/libs/kdtools/updateoperation.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -292,23 +292,18 @@ QStringList UpdateOperation::parsePerformOperationArguments()
}
/*!
- Returns undo operation argument list. If the installation is
- cancelled or failed, returns an empty list so that full undo
- operation can be performed.
+ Returns \c true if operation undo should not be performed.
+ Returns \c false if the installation is cancelled or failed, or
+ \c UNDOOPERATION is not set in operation call.
*/
-QStringList UpdateOperation::parseUndoOperationArguments()
+bool UpdateOperation::skipUndoOperation()
{
//Install has failed, allow a normal undo
if (m_core && (m_core->status() == QInstaller::PackageManagerCore::Canceled
|| m_core->status() == QInstaller::PackageManagerCore::Failure)) {
- return QStringList();
- }
- int index = arguments().indexOf(QLatin1String("UNDOOPERATION"));
- QStringList args;
- if ((index != -1) && (arguments().length() > index + 1)) {
- args = arguments().mid(index + 1);
+ return false;
}
- return args;
+ return arguments().contains(QLatin1String("UNDOOPERATION"));
}
/*!
@@ -577,14 +572,21 @@ QDomDocument UpdateOperation::toXml() const
value.setAttribute(QLatin1String("name"), it.key());
value.setAttribute(QLatin1String("type"), QLatin1String(variant.typeName()));
- if (variant.type() != QVariant::List && variant.type() != QVariant::StringList
- && variant.canConvert(QVariant::String)) {
- // it can convert to string? great!
- value.appendChild(doc.createTextNode(QInstaller::replacePath(variant.toString(),
- target, QLatin1String(QInstaller::scRelocatable))));
+ int variantType;
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ variantType = variant.typeId();
+#else
+ variantType = variant.type();
+#endif
+
+ if (variantType != QMetaType::QStringList
+ && variant.canConvert<QString>()) {
+ // it can convert to string? great!
+ value.appendChild(doc.createTextNode(QInstaller::replacePath(variant.toString(),
+ target, QLatin1String(QInstaller::scRelocatable))));
} else {
// no? then we have to go the hard way...
- if (variant.type() == QVariant::StringList) {
+ if (variantType == QMetaType::QStringList) {
QStringList list = variant.toStringList();
for (int i = 0; i < list.count(); ++i) {
list[i] = QInstaller::replacePath(list.at(i), target,
@@ -651,25 +653,31 @@ bool UpdateOperation::fromXml(const QDomDocument &doc)
const QString type = v.attribute(QLatin1String("type"));
const QString value = v.text();
+ int variantType;
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ const QMetaType t = QMetaType::fromName(type.toLatin1().data());
+ variantType = t.id();
+#else
const QVariant::Type t = QVariant::nameToType(type.toLatin1().data());
+ variantType = t;
+#endif
QVariant var = QVariant::fromValue(value);
- if (t == QVariant::List || t == QVariant::StringList || !var.convert(t)) {
- QDataStream stream(QByteArray::fromBase64( value.toLatin1()));
+ if (variantType == QMetaType::QStringList || !var.canConvert(t)) {
+ QDataStream stream(QByteArray::fromBase64(value.toLatin1()));
stream >> var;
- if (t == QVariant::StringList) {
+ if (variantType == QMetaType::QStringList) {
QStringList list = var.toStringList();
for (int i = 0; i < list.count(); ++i) {
list[i] = QInstaller::replacePath(list.at(i),
- relocatable, target);
+ relocatable, target);
}
var = QVariant::fromValue(list);
}
- } else if (t == QVariant::String) {
- const QString str = QInstaller::replacePath(value,
- relocatable, target);
- var = QVariant::fromValue(str);
+ } else if (variantType == QMetaType::QString) {
+ const QString str = QInstaller::replacePath(value,
+ relocatable, target);
+ var = QVariant::fromValue(str);
}
-
m_values[name] = var;
}
diff --git a/src/libs/kdtools/updateoperation.h b/src/libs/kdtools/updateoperation.h
index 4a431f107..e25846cd3 100644
--- a/src/libs/kdtools/updateoperation.h
+++ b/src/libs/kdtools/updateoperation.h
@@ -112,7 +112,7 @@ protected:
bool checkArgumentCount(int minArgCount, int maxArgCount, const QString &argDescription = QString());
bool checkArgumentCount(int argCount);
QStringList parsePerformOperationArguments();
- QStringList parseUndoOperationArguments();
+ bool skipUndoOperation();
void setRequiresUnreplacedVariables(bool isRequired);
bool variableReplacement(QString *variableValue);
diff --git a/src/libs/kdtools/updateoperations.cpp b/src/libs/kdtools/updateoperations.cpp
index 9301d4f13..5f6135103 100644
--- a/src/libs/kdtools/updateoperations.cpp
+++ b/src/libs/kdtools/updateoperations.cpp
@@ -127,7 +127,7 @@ QString CopyOperation::sourcePath()
QString CopyOperation::destinationPath()
{
- QString destination = arguments().last();
+ QString destination = arguments().at(1);
// if the target is a directory use the source filename to complete the destination path
if (QFileInfo(destination).isDir())
@@ -135,7 +135,6 @@ QString CopyOperation::destinationPath()
return destination;
}
-
void CopyOperation::backup()
{
QString destination = destinationPath();
@@ -156,8 +155,8 @@ void CopyOperation::backup()
bool CopyOperation::performOperation()
{
// We need two args to complete the copy operation. First arg provides the complete file name of source
- // Second arg provides the complete file name of dest
- if (!checkArgumentCount(2))
+ // Second arg provides the complete file name of dest. Optionally UNDOOPERATION can be added as well
+ if (!checkArgumentCount(2, 4, QLatin1String("<source filename> <destination filename> [UNDOOPERATION, \"\"]")))
return false;
QString source = sourcePath();
@@ -193,6 +192,8 @@ bool CopyOperation::performOperation()
bool CopyOperation::undoOperation()
{
+ if (skipUndoOperation())
+ return true;
QString source = sourcePath();
QString destination = destinationPath();
@@ -270,7 +271,7 @@ MoveOperation::~MoveOperation()
void MoveOperation::backup()
{
- const QString dest = arguments().last();
+ const QString dest = arguments().at(1);
if (!QFile::exists(dest)) {
clearValue(QLatin1String("backupOfExistingDestination"));
return;
@@ -286,9 +287,10 @@ void MoveOperation::backup()
bool MoveOperation::performOperation()
{
- // We need two args to complete the copy operation. // First arg provides the complete file name of
- // source, second arg provides the complete file name of dest
- if (!checkArgumentCount(2))
+ // We need two args to complete the copy operation. First arg provides the complete file name of
+ // source, second arg provides the complete file name of dest. Optionally UNDOOPERATION can be added as well
+ if (!checkArgumentCount(2, 4, QLatin1String("<complete source file name> <complete destination "
+ "file name> [UNDOOPERATION, \"\"]")))
return false;
const QStringList args = arguments();
@@ -318,8 +320,10 @@ bool MoveOperation::performOperation()
bool MoveOperation::undoOperation()
{
+ if (skipUndoOperation())
+ return true;
const QStringList args = arguments();
- const QString dest = args.last();
+ const QString dest = args.at(1);
// first: copy back the destination to source
QFile destF(dest);
if (!destF.copy(args.first())) {
@@ -391,7 +395,8 @@ void DeleteOperation::backup()
bool DeleteOperation::performOperation()
{
// Requires only one parameter. That is the name of the file to remove.
- if (!checkArgumentCount(1))
+ // Optionally UNDOOPERATION can be added as well
+ if (!checkArgumentCount(1, 3, QLatin1String("<file to remove> [UNDOOPERATION, \"\"]")))
return false;
return deleteFileNowOrLater(arguments().at(0));
@@ -399,7 +404,7 @@ bool DeleteOperation::performOperation()
bool DeleteOperation::undoOperation()
{
- if (!hasValue(QLatin1String("backupOfExistingFile")))
+ if (skipUndoOperation())
return true;
const QString fileName = arguments().first();
@@ -478,7 +483,8 @@ void MkdirOperation::backup()
bool MkdirOperation::performOperation()
{
// Requires only one parameter. That is the path which should be created
- if (!checkArgumentCount(1))
+ // Optionally UNDOOPERATION can be added as well
+ if (!checkArgumentCount(1, 3, QLatin1String("<file to remove> [UNDOOPERATION, \"\"]")))
return false;
const QString dirName = arguments().at(0);
@@ -493,7 +499,8 @@ bool MkdirOperation::performOperation()
bool MkdirOperation::undoOperation()
{
- Q_ASSERT(arguments().count() == 1);
+ if (skipUndoOperation())
+ return true;
QString createdDirValue = value(QLatin1String("createddir")).toString();
if (packageManager()) {
@@ -572,7 +579,8 @@ void RmdirOperation::backup()
bool RmdirOperation::performOperation()
{
// Requires only one parameter. That is the name of the file to remove.
- if (!checkArgumentCount(1))
+ // Optionally UNDOOPERATION can be added as well
+ if (!checkArgumentCount(1, 3, QLatin1String("<file to remove> [UNDOOPERATION, \"\"]")))
return false;
const QString firstArg = arguments().at(0);
@@ -597,7 +605,7 @@ bool RmdirOperation::performOperation()
bool RmdirOperation::undoOperation()
{
- if (!value(QLatin1String("removed")).toBool())
+ if (!value(QLatin1String("removed")).toBool() || skipUndoOperation())
return true;
errno = 0;
@@ -633,6 +641,12 @@ AppendFileOperation::AppendFileOperation(QInstaller::PackageManagerCore *core)
setName(QLatin1String("AppendFile"));
}
+AppendFileOperation::~AppendFileOperation()
+{
+ if (skipUndoOperation())
+ deleteFileNowOrLater(value(QLatin1String("backupOfFile")).toString());
+}
+
void AppendFileOperation::backup()
{
const QString filename = arguments().first();
@@ -653,10 +667,10 @@ bool AppendFileOperation::performOperation()
{
// This operation takes two arguments. First argument is the name of the file into which a text has to be
// appended. Second argument is the text to append.
- if (!checkArgumentCount(2))
+ if (!checkArgumentCount(2, 4, QLatin1String("<filename> <text to apply> [UNDOOPERATION, \"\"]")))
return false;
- const QStringList args = this->arguments();
+ const QStringList args = arguments();
const QString fName = args.at(0);
QFile file(fName);
if (!file.open(QFile::Append)) {
@@ -695,6 +709,9 @@ bool AppendFileOperation::performOperation()
bool AppendFileOperation::undoOperation()
{
+ if (skipUndoOperation())
+ return true;
+
// backupOfFile being empty -> file didn't exist before -> no error
const QString filename = arguments().first();
const QString backupOfFile = value(QLatin1String("backupOfFile")).toString();
@@ -746,6 +763,12 @@ PrependFileOperation::PrependFileOperation(QInstaller::PackageManagerCore *core)
setName(QLatin1String("PrependFile"));
}
+PrependFileOperation::~PrependFileOperation()
+{
+ if (skipUndoOperation())
+ deleteFileNowOrLater(value(QLatin1String("backupOfFile")).toString());
+}
+
void PrependFileOperation::backup()
{
const QString filename = arguments().first();
@@ -767,10 +790,10 @@ bool PrependFileOperation::performOperation()
// This operation takes two arguments. First argument is the name
// of the file into which a text has to be appended. Second argument
// is the text to append.
- if (!checkArgumentCount(2))
+ if (!checkArgumentCount(2, 4, QLatin1String("<filename> <text to prepend> [UNDOOPERATION, \"\"]")))
return false;
- const QStringList args = this->arguments();
+ const QStringList args = arguments();
const QString fName = args.at(0);
// Load the file first.
QFile file(fName);
@@ -810,7 +833,9 @@ bool PrependFileOperation::performOperation()
bool PrependFileOperation::undoOperation()
{
- // bockupOfFile being empty -> file didn't exist before -> no error
+ if (skipUndoOperation())
+ return true;
+
const QString filename = arguments().first();
const QString backupOfFile = value(QLatin1String("backupOfFile")).toString();
if (!backupOfFile.isEmpty() && !QFile::exists(backupOfFile)) {
diff --git a/src/libs/kdtools/updateoperations.h b/src/libs/kdtools/updateoperations.h
index c789975e2..adbfc7de1 100644
--- a/src/libs/kdtools/updateoperations.h
+++ b/src/libs/kdtools/updateoperations.h
@@ -109,6 +109,7 @@ class KDTOOLS_EXPORT AppendFileOperation : public UpdateOperation
Q_DECLARE_TR_FUNCTIONS(KDUpdater::AppendFileOperation)
public:
explicit AppendFileOperation(QInstaller::PackageManagerCore *core = 0);
+ ~AppendFileOperation();
void backup() override;
bool performOperation() override;
@@ -121,6 +122,7 @@ class KDTOOLS_EXPORT PrependFileOperation : public UpdateOperation
Q_DECLARE_TR_FUNCTIONS(KDUpdater::PrependFileOperation)
public:
explicit PrependFileOperation(QInstaller::PackageManagerCore *core = 0);
+ ~PrependFileOperation();
void backup() override;
bool performOperation() override;
diff --git a/src/libs/kdtools/updatesinfo.cpp b/src/libs/kdtools/updatesinfo.cpp
index 707daf11f..e82c1c1fb 100644
--- a/src/libs/kdtools/updatesinfo.cpp
+++ b/src/libs/kdtools/updatesinfo.cpp
@@ -40,8 +40,9 @@
using namespace KDUpdater;
-UpdatesInfoData::UpdatesInfoData()
+UpdatesInfoData::UpdatesInfoData(const bool postLoadComponentScript)
: error(UpdatesInfo::NotYetReadError)
+ , m_postLoadComponentScript(postLoadComponentScript)
{
}
@@ -135,7 +136,14 @@ bool UpdatesInfoData::parsePackageUpdateElement(QXmlStreamReader &reader, const
parseOperations(reader, info.data);
} else if (elementName == QLatin1String("Script")) {
const QXmlStreamAttributes attr = reader.attributes();
- const bool postLoad = attr.value(QLatin1String("postLoad")).toString().toLower() == QInstaller::scTrue ? true : false;
+ bool postLoad = false;
+ // postLoad can be set either to individual components or to whole repositories.
+ // If individual components has the postLoad attribute, it overwrites the repository value.
+ if (attr.hasAttribute(QLatin1String("postLoad")))
+ postLoad = attr.value(QLatin1String("postLoad")).toString().toLower() == QInstaller::scTrue ? true : false;
+ else if (m_postLoadComponentScript)
+ postLoad = true;
+
if (postLoad)
scriptHash.insert(QLatin1String("postLoadScript"), reader.readElementText());
else
@@ -238,8 +246,8 @@ void UpdatesInfoData::parseLicenses(QXmlStreamReader &reader, QHash<QString, QVa
//
// UpdatesInfo
//
-UpdatesInfo::UpdatesInfo()
- : d(new UpdatesInfoData)
+UpdatesInfo::UpdatesInfo(const bool postLoadComponentScript)
+ : d(new UpdatesInfoData(postLoadComponentScript))
{
}
diff --git a/src/libs/kdtools/updatesinfo_p.h b/src/libs/kdtools/updatesinfo_p.h
index bd9885327..a3768232a 100644
--- a/src/libs/kdtools/updatesinfo_p.h
+++ b/src/libs/kdtools/updatesinfo_p.h
@@ -59,7 +59,7 @@ public:
InvalidContentError
};
- UpdatesInfo();
+ UpdatesInfo(const bool postLoadComponentScript = false);
~UpdatesInfo();
bool isValid() const;
diff --git a/src/libs/kdtools/updatesinfodata_p.h b/src/libs/kdtools/updatesinfodata_p.h
index 9229f8577..c71a85193 100644
--- a/src/libs/kdtools/updatesinfodata_p.h
+++ b/src/libs/kdtools/updatesinfodata_p.h
@@ -43,7 +43,7 @@ struct UpdatesInfoData : public QSharedData
Q_DECLARE_TR_FUNCTIONS(KDUpdater::UpdatesInfoData)
public:
- UpdatesInfoData();
+ UpdatesInfoData(const bool postLoadComponentScript);
~UpdatesInfoData();
int error;
@@ -53,6 +53,7 @@ public:
QString applicationVersion;
QString checkSha1CheckSum;
QList<UpdateInfo> updateInfoList;
+ bool m_postLoadComponentScript;
void parseFile(const QString &updateXmlFile);
bool parsePackageUpdateElement(QXmlStreamReader &reader, const QString &checkSha1CheckSum);
diff --git a/src/sdk/commandlineinterface.cpp b/src/sdk/commandlineinterface.cpp
index afc5c2f42..44f028fd5 100644
--- a/src/sdk/commandlineinterface.cpp
+++ b/src/sdk/commandlineinterface.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2021 The Qt Company Ltd.
+** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -63,6 +63,7 @@ bool CommandLineInterface::initialize()
return false;
}
// Filter the arguments list by removing any key=value pair occurrences.
+ QString command;
m_positionalArguments = m_parser.positionalArguments();
foreach (const QString &argument, m_positionalArguments) {
if (argument.contains(QLatin1Char('=')))
@@ -76,9 +77,10 @@ bool CommandLineInterface::initialize()
} else {
// Sanity and order of arguments already checked in main(), we should be
// quite safe to assume that command is the first positional argument.
+ command = m_positionalArguments.first();
m_positionalArguments.removeFirst();
}
-
+ m_core->saveGivenArguments(QStringList() << command << m_parser.optionNames());
QString ctrlScript = controlScript();
if (!ctrlScript.isEmpty()) {
m_core->controlScriptEngine()->loadInContext(
@@ -96,20 +98,15 @@ int CommandLineInterface::checkUpdates()
qCWarning(QInstaller::lcInstallerInstallLog) << "Cannot check updates with installer.";
return EXIT_FAILURE;
}
- m_core->setUpdater();
- if (!m_core->fetchRemotePackagesTree()) {
- qCWarning(QInstaller::lcInstallerInstallLog) << m_core->error();
- return EXIT_FAILURE;
- }
-
- const QList<QInstaller::Component *> components =
- m_core->components(QInstaller::PackageManagerCore::ComponentType::Root);
- if (components.isEmpty()) {
- qCWarning(QInstaller::lcInstallerInstallLog) << "There are currently no updates available.";
+ try {
+ if (m_core->searchAvailableUpdates() != QInstaller::PackageManagerCore::Success) {
+ return EXIT_FAILURE;
+ }
return EXIT_SUCCESS;
+ } catch (const QInstaller::Error &err) {
+ qCCritical(QInstaller::lcInstallerInstallLog) << err.message();
+ return EXIT_FAILURE;
}
- QInstaller::LoggingHandler::instance().printUpdateInformation(components);
- return EXIT_SUCCESS;
}
int CommandLineInterface::listInstalledPackages()
@@ -139,7 +136,19 @@ int CommandLineInterface::searchAvailablePackages()
QString regexp;
if (!m_positionalArguments.isEmpty())
regexp = m_positionalArguments.first();
- m_core->listAvailablePackages(regexp, parsePackageFilters());
+
+ if (m_parser.isSet(CommandLineOptions::scTypeLong)) {
+ // If type is specified, only list relevant contents
+ if (m_parser.value(CommandLineOptions::scTypeLong) == QLatin1String("package"))
+ m_core->listAvailablePackages(regexp, parsePackageFilters());
+ else if (m_parser.value(CommandLineOptions::scTypeLong) == QLatin1String("alias"))
+ m_core->listAvailableAliases(regexp);
+ } else {
+ // No type - we can try again with packages search if there were no matching aliases
+ if (!m_core->listAvailableAliases(regexp))
+ m_core->listAvailablePackages(regexp, parsePackageFilters());
+ }
+
return EXIT_SUCCESS;
}
diff --git a/src/sdk/installerbase.cpp b/src/sdk/installerbase.cpp
index 20a4f312b..ac2c9d367 100644
--- a/src/sdk/installerbase.cpp
+++ b/src/sdk/installerbase.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -97,6 +97,8 @@ int InstallerBase::run()
if (status != QInstaller::PackageManagerCore::Success)
return status;
+ m_core->saveGivenArguments(m_parser.optionNames());
+
#ifdef ENABLE_SQUISH
if (m_parser.isSet(CommandLineOptions::scSquishPortLong)) {
const int maxSquishPortNumber = 65535;
diff --git a/src/sdk/main.cpp b/src/sdk/main.cpp
index efaf44582..abfc9dc5a 100644
--- a/src/sdk/main.cpp
+++ b/src/sdk/main.cpp
@@ -106,13 +106,13 @@ static void cleanupUpdate(const CommandLineParser &parser, bool *exit)
int main(int argc, char *argv[])
{
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
if (!qEnvironmentVariableIsSet("QT_AUTO_SCREEN_SCALE_FACTOR")
&& !qEnvironmentVariableIsSet("QT_SCALE_FACTOR")
&& !qEnvironmentVariableIsSet("QT_SCREEN_SCALE_FACTORS")) {
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
}
#if defined(Q_OS_WIN)
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton);
#endif
#endif
diff --git a/src/sdk/sdk.pro b/src/sdk/sdk.pro
index fac8f4f49..ee4e8fb1d 100644
--- a/src/sdk/sdk.pro
+++ b/src/sdk/sdk.pro
@@ -40,7 +40,9 @@ exists($$LRELEASE) {
"<RCC>" \
" <qresource prefix=\"/\">"
for (file, IB_TRANSLATIONS) {
- lang = $$replace(file, .*_([^/]*)\\.ts, \\1)
+ lang = $$basename(file)
+ lang = $$replace(lang, .ts, "")
+ lang = $$replace(lang, ifw_, "")
qlang = $${lang}
qfile = $$[QT_INSTALL_TRANSLATIONS]/qtbase_$${lang}.qm
!exists($$qfile) {
diff --git a/src/sdk/sdkapp.h b/src/sdk/sdkapp.h
index ba542691e..eef0110ec 100644
--- a/src/sdk/sdkapp.h
+++ b/src/sdk/sdkapp.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -60,6 +60,10 @@
#include <QMetaEnum>
#include <QTranslator>
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+#include <QNetworkInformation>
+#endif
+
template<class T>
class SDKApp : public T
{
@@ -71,6 +75,9 @@ public:
, m_core(nullptr)
{
m_parser.parse(QCoreApplication::arguments());
+#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
+ QNetworkInformation::loadDefaultBackend();
+#endif
}
virtual ~SDKApp()
@@ -202,7 +209,7 @@ public:
if (translations.isEmpty()) {
for (const QString &language : QLocale().uiLanguages()) {
const QLocale locale(language);
- QScopedPointer<QTranslator> qtTranslator(new QTranslator(QCoreApplication::instance()));
+ std::unique_ptr<QTranslator> qtTranslator(new QTranslator(QCoreApplication::instance()));
bool qtLoaded = qtTranslator->load(locale, QLatin1String("qt"),
QLatin1String("_"), newDirectory);
if (!qtLoaded)
@@ -211,14 +218,14 @@ public:
if (qtLoaded || locale.language() == QLocale::English) {
if (qtLoaded)
- QCoreApplication::instance()->installTranslator(qtTranslator.take());
+ QCoreApplication::instance()->installTranslator(qtTranslator.release());
- QScopedPointer<QTranslator> ifwTranslator(new QTranslator(QCoreApplication::instance()));
+ std::unique_ptr <QTranslator> ifwTranslator(new QTranslator(QCoreApplication::instance()));
bool ifwLoaded = ifwTranslator->load(locale, QLatin1String("ifw"), QLatin1String("_"), newDirectory);
if (!ifwLoaded)
ifwLoaded = ifwTranslator->load(locale, QLatin1String("ifw"), QLatin1String("_"), directory);
if (ifwLoaded) {
- QCoreApplication::instance()->installTranslator(ifwTranslator.take());
+ QCoreApplication::instance()->installTranslator(ifwTranslator.release());
} else {
qCWarning(QInstaller::lcDeveloperBuild) << "Could not load IFW translation for language"
<< QLocale::languageToString(locale.language());
@@ -235,9 +242,9 @@ public:
}
} else {
foreach (const QString &translation, translations) {
- QScopedPointer<QTranslator> translator(new QTranslator(QCoreApplication::instance()));
+ std::unique_ptr<QTranslator> translator(new QTranslator(QCoreApplication::instance()));
if (translator->load(translation, QLatin1String(":/translations")))
- QCoreApplication::instance()->installTranslator(translator.take());
+ QCoreApplication::instance()->installTranslator(translator.release());
}
QLocale currentLocale(translations.at(0).section(QLatin1Char('_'), 1));
lang = currentLocale;
@@ -421,7 +428,7 @@ public:
}
m_core->setValue(QInstaller::scUILanguage, lang.name());
- emit m_core->defaultTranslationsLoadedForLanguage(lang.language());
+ emit m_core->defaultTranslationsLoadedForLanguage(lang);
ProductKeyCheck::instance()->addPackagesFromXml(QLatin1String(":/metadata/Updates.xml"));
return true;
@@ -549,7 +556,7 @@ public:
foreach (const QString &argument, positionalArguments) {
if (argument.contains(QLatin1Char('='))) {
const QString name = argument.section(QLatin1Char('='), 0, 0);
- const QString value = argument.section(QLatin1Char('='), 1, 1);
+ const QString value = argument.section(QLatin1Char('='), 1);
params.insert(name, value);
}
}
diff --git a/src/sdk/settingsdialog.cpp b/src/sdk/settingsdialog.cpp
index acd364b2f..0a16377b3 100644
--- a/src/sdk/settingsdialog.cpp
+++ b/src/sdk/settingsdialog.cpp
@@ -242,8 +242,19 @@ SettingsDialog::SettingsDialog(PackageManagerCore *core, QWidget *parent)
connect(m_ui->m_clearPushButton, &QAbstractButton::clicked,
this, &SettingsDialog::clearLocalCacheClicked);
- connect(m_ui->m_clearPushButton, &QAbstractButton::clicked,
- this, [&] { m_cacheCleared = true; });
+ connect(m_ui->m_clearPushButton, &QAbstractButton::clicked, this, [&] {
+ // Disable the button as the new settings will only take effect after
+ // closing the dialog.
+ m_ui->m_clearPushButton->setEnabled(false);
+ m_cacheCleared = true;
+ });
+ connect(m_ui->m_cachePathLineEdit, &QLineEdit::textChanged, this, [&] {
+ if (!m_cacheCleared) {
+ // Disable the button if the path is modified between applying settings
+ m_ui->m_clearPushButton->setEnabled(
+ settings.localCachePath() == m_ui->m_cachePathLineEdit->text());
+ }
+ });
useTmpRepositoriesOnly(settings.hasReplacementRepos());
m_ui->m_useTmpRepositories->setChecked(settings.hasReplacementRepos());
@@ -256,8 +267,9 @@ SettingsDialog::SettingsDialog(PackageManagerCore *core, QWidget *parent)
m_ui->m_repositories->setVisible(settings.repositorySettingsPageVisible());
}
- m_ui->m_cachePathLineEdit->setText(settings.localCachePath());
- showClearCacheProgress(false);
+ m_ui->m_cachePathLineEdit->setText(settings.localCachePath());
+ m_ui->m_clearPushButton->setEnabled(m_core->isValidCache());
+ showClearCacheProgress(false);
}
void SettingsDialog::showClearCacheProgress(bool show)
diff --git a/src/sdk/settingsdialog.ui b/src/sdk/settingsdialog.ui
index 9d4ba9577..90580877d 100644
--- a/src/sdk/settingsdialog.ui
+++ b/src/sdk/settingsdialog.ui
@@ -335,7 +335,7 @@
<number>-1</number>
</property>
<property name="format">
- <string>%p%</string>
+ <string notr="true">%p%</string>
</property>
</widget>
</item>
diff --git a/src/sdk/tabcontroller.cpp b/src/sdk/tabcontroller.cpp
index f82664126..8c15243f8 100644
--- a/src/sdk/tabcontroller.cpp
+++ b/src/sdk/tabcontroller.cpp
@@ -173,6 +173,7 @@ void TabController::restartWizard()
void TabController::onSettingsButtonClicked()
{
SettingsDialog dialog(d->m_core);
+ dialog.adjustSize();
connect(&dialog, &SettingsDialog::networkSettingsChanged,
this, &TabController::onNetworkSettingsChanged);
connect(&dialog, &SettingsDialog::clearLocalCacheClicked,
@@ -216,8 +217,13 @@ void TabController::onClearCacheClicked()
loop.quit();
});
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ futureWatcher.setFuture(QtConcurrent::run(&PackageManagerCore::clearLocalCache,
+ d->m_core, &errorMessage));
+#else
futureWatcher.setFuture(QtConcurrent::run(d->m_core,
&PackageManagerCore::clearLocalCache, &errorMessage));
+#endif
if (!futureWatcher.isFinished())
loop.exec();
diff --git a/src/sdk/translations/ifw_ar.ts b/src/sdk/translations/ifw_ar.ts
index 0d9f700e4..ee995f3d5 100644
--- a/src/sdk/translations/ifw_ar.ts
+++ b/src/sdk/translations/ifw_ar.ts
@@ -232,6 +232,10 @@
<source>Clear cache</source>
<translation>مسح ذاكرة التخزين المؤقت</translation>
</message>
+ <message>
+ <source>Clearing cache...</source>
+ <translation>جاري مسح ذاكرة التخزين المؤقت ...</translation>
+ </message>
</context>
<context>
<name>QObject</name>
@@ -410,6 +414,10 @@
<source>Invalid content in &quot;%1&quot;.</source>
<translation>محتوى غير صالح في &quot;%1&quot;.</translation>
</message>
+ <message>
+ <source>This may be solved by restarting the application after clearing the cache from:</source>
+ <translation>يمكن حل هذا عن طريق إعادة تشغيل التطبيق بعد مسح ذاكرة التخزين المؤقت من:</translation>
+ </message>
</context>
<context>
<name>BinaryLayout</name>
@@ -470,18 +478,6 @@
<translation>لا يمكن للمكونات أن تحتوي على أطفال في وضع التحديث.</translation>
</message>
<message>
- <source>Cannot open the requested UI file &quot;%1&quot;: %2</source>
- <translation>لا يمكن فتح ملف واجهة المستخدم المطلوب &quot;%1&quot;: %2</translation>
- </message>
- <message>
- <source>Cannot load the requested UI file &quot;%1&quot;: %2</source>
- <translation>لا يمكن تحميل ملف واجهة المتسخدم المطلوب &quot;%1&quot;: %2</translation>
- </message>
- <message>
- <source>Cannot open the requested license file &quot;%1&quot;: %2</source>
- <translation>لا يمكن فتح ملف الرخصة المطلوب &quot;%1&quot;: %2</translation>
- </message>
- <message>
<source>Error</source>
<translation>خطأ</translation>
</message>
@@ -501,6 +497,26 @@
<source>There was an error loading the selected component. This component cannot be installed.</source>
<translation>كان هناك خطأ أثناء تحميل المكون المحدد. هذا المكون لا يمكن تثبيته.</translation>
</message>
+ <message>
+ <source>Cannot open the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>لا يمكن فتح ملف واجهة المستخدم المطلوب &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot load the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>لا يمكن تحميل ملف واجهة المتسخدم المطلوب &quot;%1&quot;: %2.%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot open the requested license file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>لا يمكن فتح ملف الرخصة المطلوب &quot;%1&quot;: %2.%3 &quot;%4&quot;</translation>
+ </message>
</context>
<context>
<name>QInstaller::ComponentModel</name>
@@ -580,10 +596,6 @@
<translation>قم بإلغاء تحديد المكونات الافتراضية في عرض الشجري.</translation>
</message>
<message>
- <source>&amp;Browse QBSP files</source>
- <translation>&amp;تصفح ملفات QBSP</translation>
- </message>
- <message>
<source>Select a Qt Board Support Package file to install additional content that is not directly available from the online repositories.</source>
<translation>حدد ملف حزمة دعم لوحة Qt لتثبيت محتوى إضافي غير متاح مباشرة في المستودعات التي عبر الإنترنت.</translation>
</message>
@@ -616,7 +628,7 @@
<translation>يرجى تحديد المكونات التي تريد إزالتها.</translation>
</message>
<message>
- <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source>
+ <source>Select the components to install. Deselect installed components to uninstall them.&lt;br&gt;Any components already installed will not be updated.</source>
<translation>حدّد المكونات التي تريد تثبيتها. ألغِ تحديد المكونات المثبتة لإزالتها. أي مكونات مثبتة بالفعل لن يتم تحديثها.</translation>
</message>
<message>
@@ -627,6 +639,26 @@
<source>Search</source>
<translation>بحث</translation>
</message>
+ <message>
+ <source>Browse &amp;QBSP files</source>
+ <translation>تصفح ملفات &amp;QBSP</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>اختيار</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>خطأ</translation>
+ </message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation>إنشاء المثبت دون اتصال</translation>
+ </message>
+ <message>
+ <source>Create offline installer from selected components, instead of installing now.</source>
+ <translation>إنشاء برنامج تثبيت دون اتصال من المكونات المحددة، بدلاً من التثبيت الآن.</translation>
+ </message>
</context>
<context>
<name>QInstaller::ComponentSelectionPagePrivate</name>
@@ -640,7 +672,7 @@
</message>
<message>
<source>Information</source>
- <translation type="unfinished">معلومات المكون</translation>
+ <translation>معلومات المكون</translation>
</message>
</context>
<context>
@@ -839,14 +871,6 @@
<translation>خطأ في التنزيل</translation>
</message>
<message>
- <source>Hash verification while downloading failed. This is a temporary error, please retry.</source>
- <translation>فشل التحقق من التجزئة أثناء التنزيل. هذا خطأ مؤقت، يرجى إعادة المحاولة.</translation>
- </message>
- <message>
- <source>Cannot verify Hash</source>
- <translation>لا يمكن التحقق من التحزئة</translation>
- </message>
- <message>
<source>Cannot download archive %1: %2</source>
<translation>لا يمكن تنزيل الأرشيف %1: %2</translation>
</message>
@@ -936,6 +960,29 @@ Error while loading %2</source>
<source>Total: </source>
<translation>المجموع: </translation>
</message>
+ <message>
+ <source>Retry count (%1) exceeded</source>
+ <translation>تم تجاوز عدد مرات إعادة المحاولة (%1).
+</translation>
+ </message>
+ <message>
+ <source>Hash verification while downloading failed. This is a temporary error, please retry.
+
+Expected: %1
+Downloaded: %2</source>
+ <translation>فشل التحقق من التجزئة أثناء التنزيل. هذا خطأ مؤقت، يرجى إعادة المحاولة.
+
+المتوقع: %1
+تم التنزيل: %2</translation>
+ </message>
+ <message>
+ <source>Cannot verify Hash
+Expected: %1
+Downloaded: %2</source>
+ <translation>لا يمكن التحقق من التجزئة
+المتوقع: %1
+تم التنزيل: %2</translation>
+ </message>
</context>
<context>
<name>QInstaller::Downloader</name>
@@ -1147,6 +1194,18 @@ Error while loading %2</source>
<source>Cannot find missing dependency &quot;%1&quot; for &quot;%2&quot;.</source>
<translation>لا يمكن العثور على الاعتمادية المفقودة &quot;%1&quot; لـ &quot;%2&quot;.</translation>
</message>
+ <message>
+ <source>Impossible dependency resolution detected. Forced install component &quot;%1&quot; would be uninstalled because its dependency &quot;%2&quot; is marked for uninstallation with reason: &quot;%3&quot;.</source>
+ <translation>تم الكشف عن تحليل تبعية مستحيلة. سيتم إلغاء تثبيت مكون التثبيت الإجباري &quot;%1&quot; بسبب أن التبعية &quot;%2&quot; تم تعليمها لإلغاء التثبيت بسبب: &quot;%3&quot;.</translation>
+ </message>
+ <message>
+ <source>Components selected by alias &quot;%1&quot;:</source>
+ <translation>المكونات المحددة بواسطة الاسم المستعار &quot;%1&quot;:</translation>
+ </message>
+ <message>
+ <source>Recursion detected, component alias &quot;%1&quot; already added.</source>
+ <translation>تم اكتشاف التكرار، الاسم المستعار للمكون &quot;%1&quot; تم الاضافة مسبقا.</translation>
+ </message>
</context>
<context>
<name>QInstaller::InstallIconsOperation</name>
@@ -1306,10 +1365,6 @@ Error while loading %2</source>
<source>Can not write license file &quot;%1&quot;.</source>
<translation>لا يمكن كتابة ملف الرخصة &quot;%1&quot;.</translation>
</message>
- <message>
- <source>No license files found to delete.</source>
- <translation>لم يُعثر على ملفات ترخيص لحذفها.</translation>
- </message>
</context>
<context>
<name>QInstaller::LineReplaceOperation</name>
@@ -1369,14 +1424,6 @@ Error while loading %2</source>
<translation>اكتُشف عدم تطابق تدقيق المجموع لـ &quot;%1&quot;.</translation>
</message>
<message>
- <source>Retrieving meta information from remote repository... %1/%2 </source>
- <translation>جارٍ الحصول على معلومات التعريف من المستودع البعيد... %1/%2 </translation>
- </message>
- <message>
- <source>Retrieving meta information from remote repository... </source>
- <translation>جارٍ الحصول على معلومات التعريف من المستودع البعيد... </translation>
- </message>
- <message>
<source>Error while extracting archive &quot;%1&quot;: %2</source>
<translation>حدث خطأ أثناء إستخراج الأرشيف &quot;%1&quot;: %2</translation>
</message>
@@ -1407,6 +1454,26 @@ Error while loading %2</source>
<source>Clearing the cache directory and restarting the application may solve this.</source>
<translation>قد يؤدي مسح دليل ذاكرة التخزين المؤقت وإعادة تشغيل التطبيق إلى حل هذه المشكلة.</translation>
</message>
+ <message>
+ <source>Unknown exception during updating cache.</source>
+ <translation>حدث خطأ غير معروف أثناء تحديث ذاكرة التخزين المؤقت.</translation>
+ </message>
+ <message>
+ <source>Cannot open extracted file &quot;%1&quot; for reading: %2</source>
+ <translation>لا يمكن فتح الملف المستخرج &quot;%1&quot; للقراءة: %2</translation>
+ </message>
+ <message>
+ <source>Cannot open file &quot;%1&quot; for writing: %2</source>
+ <translation>لا يمكن فتح الملف &quot;%1&quot; للكتابة: %2</translation>
+ </message>
+ <message>
+ <source>Retrieving information from remote repositories...</source>
+ <translation>الحصول على المعلومات من المستودع البعيد...</translation>
+ </message>
+ <message>
+ <source>Retrieving meta information from remote repository...</source>
+ <translation>جارٍ الحصول على معلومات التعريف من المستودع البعيد...</translation>
+ </message>
</context>
<context>
<name>QInstaller::FileTaskObserver</name>
@@ -1616,10 +1683,6 @@ Do you want to continue?</source>
<translation>المكون افتراضي.</translation>
</message>
<message>
- <source>Running processes found.</source>
- <translation>وجدت العمليات الجارية.</translation>
- </message>
- <message>
<source>Cannot elevate access rights while running from command line. Please restart the application as administrator.</source>
<translation>الرجاء إعادة تشغيل التطبيق كمسؤول.</translation>
</message>
@@ -1675,6 +1738,22 @@ Do you want to continue?</source>
<source>Not enough disk space to store temporary files! %1 are available, while the minimum required is %2. You may select another location for the temporary files by modifying the local cache path from the installer settings.</source>
<translation>لا توجد مساحة كافية على القرص لتخزين الملفات المؤقتة! يتوفر%1 ، بينما الحد الأدنى المطلوب هو%2. يمكنك تحديد موقع آخر للملفات المؤقتة عن طريق تعديل مسار ذاكرة التخزين المؤقت المحلية من إعدادات المثبت.</translation>
</message>
+ <message>
+ <source>Cannot resolve components to uninstall.</source>
+ <translation>لا يمكن تحديد المكونات المطلوب إزالتها.</translation>
+ </message>
+ <message>
+ <source>Cannot select alias %1. There was a problem loading this alias, so it is marked unstable and cannot be selected.</source>
+ <translation>لا يمكن تحديد الاسم المستعار %1. حدثت مشكلة أثناء تحميل هذا الاسم المستعار، لذا تم وضع علامة عليه كغير مستقر ولا يمكن تحديده.</translation>
+ </message>
+ <message>
+ <source>Cannot select %1. Alias is marked virtual, meaning it cannot be selected manually.</source>
+ <translation>لا يمكن تحديد %1. تم وضع علامة على الاسم المستعار افتراضيًا، مما يعني أنه لا يمكن تحديده يدويًا.</translation>
+ </message>
+ <message>
+ <source>Created installer will use %1 of disk space.</source>
+ <translation>سيستخدم المثبت الذي تم إنشاؤه %1 من مساحة القرص.</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCorePrivate</name>
@@ -1895,10 +1974,6 @@ Do you want to continue?</source>
<translation>لا يمكن الحصول على بيانات التعريف: %1</translation>
</message>
<message>
- <source>Cannot add temporary update source information.</source>
- <translation>لا تمكن إضافة معلومات مصدر التحديث المؤقت.</translation>
- </message>
- <message>
<source>Cannot find any update source information.</source>
<translation>لا يمكن العثور على أي معلومات مصدر تحديث.</translation>
</message>
@@ -1944,6 +2019,18 @@ Do you want to continue?</source>
<source>Loading component scripts...</source>
<translation>جاري تحميل البرامج النصية للمكونات...</translation>
</message>
+ <message>
+ <source>Alias declares name that conflicts with an existing component &quot;%1&quot;</source>
+ <translation>الاسم المستعار يعلن عن اسم يتعارض مع مكون موجود &quot;%1&quot;</translation>
+ </message>
+ <message>
+ <source>Unresolved component aliases</source>
+ <translation>لم يتم التمكن من تحديد الأسماء المستعارة للمكونات</translation>
+ </message>
+ <message>
+ <source>Cyclic dependency between aliases &quot;%1&quot; and &quot;%2&quot; detected.</source>
+ <translation>تم اكتشاف تبعية دورية بين الأسماء المستعارة &quot;%1&quot; و &quot;%2&quot;.</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerGui</name>
@@ -2001,8 +2088,8 @@ Please copy the installer to a local drive</source>
<context>
<name>QInstaller::IntroductionPage</name>
<message>
- <source>Setup - %1</source>
- <translation>الإعداد - %1</translation>
+ <source>Welcome</source>
+ <translation>مَرْحَبًا</translation>
</message>
<message>
<source>Welcome to the %1 Setup.</source>
@@ -2033,10 +2120,6 @@ Please copy the installer to a local drive</source>
<translation>لا تحديثات متوفرة.</translation>
</message>
<message>
- <source> Only local package management available.</source>
- <translation> إدارة الحزم المحلية هي المتاحة فقط.</translation>
- </message>
- <message>
<source>&amp;Quit</source>
<translation>&amp;اخرج</translation>
</message>
@@ -2154,6 +2237,18 @@ Please copy the installer to a local drive</source>
<source>Ready to Update</source>
<translation>جاهز للتحديث</translation>
</message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation>إنشاء المثبت دون اتصال</translation>
+ </message>
+ <message>
+ <source>Ready to Create Offline Installer</source>
+ <translation>جاهز لإنشاء برنامج التثبيت دون اتصال</translation>
+ </message>
+ <message>
+ <source>All required information is now available to create an offline installer for selected components.</source>
+ <translation>جميع المعلومات المطلوبة متاحة الآن لإنشاء برنامج تثبيت دون اتصال للمكونات المحددة.</translation>
+ </message>
</context>
<context>
<name>QInstaller::PerformInstallationPage</name>
@@ -2193,11 +2288,23 @@ Please copy the installer to a local drive</source>
<source>Uninstalling</source>
<translation>إلغاء التثبيت</translation>
</message>
+ <message>
+ <source>&amp;Create Offline Installer</source>
+ <translation>&amp; إنشاء برنامج التثبيت دون اتصال</translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer for %1</source>
+ <translation>إنشاء برنامج تثبيت دون اتصال لـ %1</translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer</source>
+ <translation>إنشاء المثبت دون اتصال</translation>
+ </message>
</context>
<context>
<name>QInstaller::FinishedPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>إكمال معالج %1</translation>
</message>
<message>
@@ -2205,7 +2312,7 @@ Please copy the installer to a local drive</source>
<translation>مكتمل</translation>
</message>
<message>
- <source>Click %1 to exit the %2 Wizard.</source>
+ <source>Click %1 to exit the %2 Setup.</source>
<translation>اضغط %1 للخروج من معالج %2.</translation>
</message>
<message>
@@ -2224,7 +2331,7 @@ Please copy the installer to a local drive</source>
<context>
<name>QInstaller::RestartPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>إكمال معالج إعداد %1</translation>
</message>
</context>
@@ -2348,7 +2455,7 @@ or accept the elevation of access rights if being asked.</source>
</message>
<message>
<source>Categories</source>
- <translation type="unfinished">حدد الاقسام</translation>
+ <translation>حدد الاقسام</translation>
</message>
</context>
<context>
@@ -2555,6 +2662,10 @@ or accept the elevation of access rights if being asked.</source>
<source>Try again</source>
<translation>حاول مرة آخرى</translation>
</message>
+ <message>
+ <source>Cannot download %1. Cannot create directory for &quot;%2&quot;</source>
+ <translation>لا يمكن تحميل %1. لا يمكن إنشاء دليل لـ &quot;%2&quot;</translation>
+ </message>
</context>
<context>
<name>Job</name>
@@ -2830,10 +2941,6 @@ or accept the elevation of access rights if being asked.</source>
<translation>لا يمكن قراءة &quot;%1&apos;</translation>
</message>
<message>
- <source>Parse error in %1 at %2, %3: %4</source>
- <translation>خطأ في فرز %1 في %2، %3:%4</translation>
- </message>
- <message>
<source>Root element %1 unexpected, should be &quot;Updates&quot;.</source>
<translation>عنصر الجذر %1 غير متوقع، يجب أن يكون &quot;Updates&quot;.</translation>
</message>
@@ -3045,6 +3152,10 @@ or accept the elevation of access rights if being asked.</source>
<source>Cannot synchronize invalidated cache.</source>
<translation>لا يمكن مزامنة ذاكرة التخزين المؤقت غير الصالحة.</translation>
</message>
+ <message>
+ <source>Unknown register mode selected!</source>
+ <translation>تم اختبار وضع تسجيل غير معروف!</translation>
+ </message>
</context>
<context>
<name>TabController</name>
diff --git a/src/sdk/translations/ifw_ca.ts b/src/sdk/translations/ifw_ca.ts
index acf1b9b32..ddd7efc13 100644
--- a/src/sdk/translations/ifw_ca.ts
+++ b/src/sdk/translations/ifw_ca.ts
@@ -136,6 +136,18 @@
<source>Cannot find missing dependency &quot;%1&quot; for &quot;%2&quot;.</source>
<translation>No s&apos;ha pogut trobar la dependència «%1» que falta per a «%2».</translation>
</message>
+ <message>
+ <source>Impossible dependency resolution detected. Forced install component &quot;%1&quot; would be uninstalled because its dependency &quot;%2&quot; is marked for uninstallation with reason: &quot;%3&quot;.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Components selected by alias &quot;%1&quot;:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Recursion detected, component alias &quot;%1&quot; already added.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>Job</name>
@@ -306,6 +318,10 @@
<source>Try again</source>
<translation>Torna a intentar-ho</translation>
</message>
+ <message>
+ <source>Cannot download %1. Cannot create directory for &quot;%2&quot;</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>KDUpdater::LocalFileDownloader</name>
@@ -489,10 +505,6 @@
<translation>No s&apos;ha pogut llegir «%1»</translation>
</message>
<message>
- <source>Parse error in %1 at %2, %3: %4</source>
- <translation>Error d&apos;anàlisi en %1 a %2, %3: %4</translation>
- </message>
- <message>
<source>Root element %1 unexpected, should be &quot;Updates&quot;.</source>
<translation>Element arrel %1 inesperat, hauria de ser «Updates».</translation>
</message>
@@ -744,6 +756,10 @@
<source>Invalid content in &quot;%1&quot;.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>This may be solved by restarting the application after clearing the cache from:</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::Component</name>
@@ -752,18 +768,6 @@
<translation>Els components no poden tenir elements secundaris en el mode actualitzador.</translation>
</message>
<message>
- <source>Cannot open the requested UI file &quot;%1&quot;: %2</source>
- <translation>No s&apos;ha pogut obrir el fitxer UI «%1» sol·licitat: %2</translation>
- </message>
- <message>
- <source>Cannot load the requested UI file &quot;%1&quot;: %2</source>
- <translation>No s&apos;ha pogut carregar el fitxer UI «%1» sol·licitat: %2</translation>
- </message>
- <message>
- <source>Cannot open the requested license file &quot;%1&quot;: %2</source>
- <translation>No s&apos;ha pogut obrir el fitxer de llicència «%1» sol·licitat: %2</translation>
- </message>
- <message>
<source>Error</source>
<translation>Error</translation>
</message>
@@ -783,6 +787,26 @@
<source>There was an error loading the selected component. This component cannot be installed.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Cannot open the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>No s&apos;ha pogut obrir el fitxer UI «%1» sol·licitat: %2. %3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot load the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>No s&apos;ha pogut carregar el fitxer UI «%1» sol·licitat: %2. %3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot open the requested license file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>No s&apos;ha pogut obrir el fitxer de llicència «%1» sol·licitat: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
</context>
<context>
<name>QInstaller::ComponentModel</name>
@@ -862,10 +886,6 @@
<translation type="unfinished"></translation>
</message>
<message>
- <source>&amp;Browse QBSP files</source>
- <translation>Explora els fitxers Q&amp;BSP</translation>
- </message>
- <message>
<source>Select a Qt Board Support Package file to install additional content that is not directly available from the online repositories.</source>
<translation type="unfinished"></translation>
</message>
@@ -894,39 +914,39 @@
<translation>Seleccioneu els components que voleu desinstal·lar.</translation>
</message>
<message>
- <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source>
- <translation>Seleccioneu els components que voleu instal·lar. Desseleccioneu els components instal·lats per a desinstal·lar-los. No s&apos;actualitzaran els components ja instal·lats.</translation>
+ <source>Select the components to install. Deselect installed components to uninstall them.&lt;br&gt;Any components already installed will not be updated.</source>
+ <translation>Seleccioneu els components que voleu instal·lar. Desseleccioneu els components instal·lats per a desinstal·lar-los.&lt;br&gt;No s&apos;actualitzaran els components ja instal·lats.</translation>
</message>
<message>
<source>Mandatory components need to be updated first before you can select other components to update.</source>
<translation>Cal que actualitzeu els components obligatoris abans de poder seleccionar altres components per actualitzar-los.</translation>
</message>
<message>
- <source>Alt+A</source>
- <comment>Select default components</comment>
- <translation type="unfinished">Alt+A</translation>
+ <source>Filter the enabled repository categories</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Alt+R</source>
- <comment>Reset to already installed components</comment>
+ <source>Search</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Browse &amp;QBSP files</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Alt+S</source>
- <comment>Select all components</comment>
- <translation type="unfinished">Alt+S</translation>
+ <source>Select</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Alt+D</source>
- <comment>Deselect all components</comment>
- <translation type="unfinished">Alt+D</translation>
+ <source>Error</source>
+ <translation type="unfinished">Error</translation>
</message>
<message>
- <source>Filter the enabled repository categories</source>
+ <source>Create Offline Installer</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Search</source>
+ <source>Create offline installer from selected components, instead of installing now.</source>
<translation type="unfinished"></translation>
</message>
</context>
@@ -942,7 +962,7 @@
</message>
<message>
<source>Information</source>
- <translation type="unfinished"></translation>
+ <translation>Informació</translation>
</message>
</context>
<context>
@@ -1222,6 +1242,10 @@ Error en descarregar %2</translation>
<source>Total: </source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Retry count (%1) exceeded</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::Downloader</name>
@@ -1382,7 +1406,7 @@ Error en descarregar %2</translation>
<context>
<name>QInstaller::FinishedPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>S&apos;ha completat l&apos;Assistent de %1</translation>
</message>
<message>
@@ -1390,7 +1414,7 @@ Error en descarregar %2</translation>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Click %1 to exit the %2 Wizard.</source>
+ <source>Click %1 to exit the %2 Setup.</source>
<translation>Feu clic a %1 per a sortir de l&apos;Assistent de %2.</translation>
</message>
<message>
@@ -1451,8 +1475,8 @@ Error en descarregar %2</translation>
<context>
<name>QInstaller::IntroductionPage</name>
<message>
- <source>Setup - %1</source>
- <translation>Programa d&apos;instal·lació: %1</translation>
+ <source>Welcome</source>
+ <translation type="unfinished"></translation>
</message>
<message>
<source>Welcome to the %1 Setup.</source>
@@ -1483,10 +1507,6 @@ Error en descarregar %2</translation>
<translation>No hi ha disponible cap actualització.</translation>
</message>
<message>
- <source> Only local package management available.</source>
- <translation> Només està disponible la gestió dels paquets locals.</translation>
- </message>
- <message>
<source>&amp;Quit</source>
<translation>Su&amp;rt</translation>
</message>
@@ -1537,10 +1557,6 @@ Error en descarregar %2</translation>
<source>Can not write license file &quot;%1&quot;.</source>
<translation>No s&apos;ha pogut escriure en el fitxer de llicència «%1».</translation>
</message>
- <message>
- <source>No license files found to delete.</source>
- <translation>No s&apos;han trobat fitxers de llicència per a suprimir.</translation>
- </message>
</context>
<context>
<name>QInstaller::LineReplaceOperation</name>
@@ -1596,14 +1612,6 @@ Error en descarregar %2</translation>
<translation>S&apos;ha detectat una discrepància en la suma de verificació per a «%1».</translation>
</message>
<message>
- <source>Retrieving meta information from remote repository... %1/%2 </source>
- <translation>S&apos;està recuperant la informació de les metadades des del repositori remot... %1/%2 </translation>
- </message>
- <message>
- <source>Retrieving meta information from remote repository... </source>
- <translation>S&apos;està recuperant la informació de les metadades des del repositori remot... </translation>
- </message>
- <message>
<source>Error while extracting archive &quot;%1&quot;: %2</source>
<translation>Error en extreure l&apos;arxiu «%1»: %2</translation>
</message>
@@ -1634,6 +1642,26 @@ Error en descarregar %2</translation>
<source>Clearing the cache directory and restarting the application may solve this.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Unknown exception during updating cache.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot open extracted file &quot;%1&quot; for reading: %2</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot open file &quot;%1&quot; for writing: %2</source>
+ <translation>No s&apos;ha pogut obrir el fitxer «%1» per a escriptura: %2</translation>
+ </message>
+ <message>
+ <source>Retrieving information from remote repositories...</source>
+ <translation>S&apos;està recuperant la informació des de repositoris remots...</translation>
+ </message>
+ <message>
+ <source>Retrieving meta information from remote repository...</source>
+ <translation>S&apos;està recuperant la informació de les metadades des del repositori remot...</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCore</name>
@@ -1764,10 +1792,6 @@ Voleu continuar?</translation>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Running processes found.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
<source>Cannot elevate access rights while running from command line. Please restart the application as administrator.</source>
<translation type="unfinished"></translation>
</message>
@@ -1835,6 +1859,22 @@ Voleu continuar?</translation>
<source>Not enough disk space to store temporary files! %1 are available, while the minimum required is %2. You may select another location for the temporary files by modifying the local cache path from the installer settings.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Cannot resolve components to uninstall.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot select alias %1. There was a problem loading this alias, so it is marked unstable and cannot be selected.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot select %1. Alias is marked virtual, meaning it cannot be selected manually.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Created installer will use %1 of disk space.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCorePrivate</name>
@@ -2041,10 +2081,6 @@ Voleu continuar?</translation>
<translation>No s&apos;ha pogut recuperar la informació de les metadades: %1</translation>
</message>
<message>
- <source>Cannot add temporary update source information.</source>
- <translation>No s&apos;ha pogut afegir la informació temporal de la font d&apos;actualització.</translation>
- </message>
- <message>
<source>Cannot find any update source information.</source>
<translation>No s&apos;ha pogut trobar cap informació de la font d&apos;actualització.</translation>
</message>
@@ -2105,6 +2141,18 @@ Voleu continuar?</translation>
<source>Loading component scripts...</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Alias declares name that conflicts with an existing component &quot;%1&quot;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unresolved component aliases</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cyclic dependency between aliases &quot;%1&quot; and &quot;%2&quot; detected.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerGui</name>
@@ -2208,6 +2256,18 @@ Copieu l&apos;instal·lador en una unitat local</translation>
<source>Uninstalling</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>&amp;Create Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer for %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::ProxyCredentialsDialog</name>
@@ -2282,6 +2342,18 @@ Copieu l&apos;instal·lador en una unitat local</translation>
<source>Ready to Update</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Ready to Create Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>All required information is now available to create an offline installer for selected components.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::RegisterFileTypeOperation</name>
@@ -2338,7 +2410,7 @@ Copieu l&apos;instal·lador en una unitat local</translation>
<context>
<name>QInstaller::RestartPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>S&apos;està completant l&apos;Assistent d&apos;instal·lació de %1</translation>
</message>
</context>
@@ -2614,7 +2686,7 @@ or accept the elevation of access rights if being asked.</source>
</message>
<message>
<source>Categories</source>
- <translation type="unfinished">Selecciona les categories dels paquets</translation>
+ <translation>Categories</translation>
</message>
</context>
<context>
@@ -2771,6 +2843,10 @@ or accept the elevation of access rights if being asked.</source>
<source>Clear cache</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Clearing cache...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UpdateOperation</name>
@@ -3001,6 +3077,10 @@ or accept the elevation of access rights if being asked.</source>
<source>Cannot synchronize invalidated cache.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Unknown register mode selected!</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>TabController</name>
diff --git a/src/sdk/translations/ifw_da.ts b/src/sdk/translations/ifw_da.ts
index 1b7ad5c1b..a6325fb01 100644
--- a/src/sdk/translations/ifw_da.ts
+++ b/src/sdk/translations/ifw_da.ts
@@ -136,6 +136,18 @@
<source>Cannot find missing dependency &quot;%1&quot; for &quot;%2&quot;.</source>
<translation>Kan ikke finde manglende afhængighed &quot;%1&quot; til &quot;%2&quot;.</translation>
</message>
+ <message>
+ <source>Components selected by alias &quot;%1&quot;:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Recursion detected, component alias &quot;%1&quot; already added.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Impossible dependency resolution detected. Forced install component &quot;%1&quot; would be uninstalled because its dependency &quot;%2&quot; is marked for uninstallation with reason: &quot;%3&quot;.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>Job</name>
@@ -306,6 +318,10 @@
<source>Try again</source>
<translation>Prøv igen</translation>
</message>
+ <message>
+ <source>Cannot download %1. Cannot create directory for &quot;%2&quot;</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>KDUpdater::LocalFileDownloader</name>
@@ -489,10 +505,6 @@
<translation>Kan ikke læse &quot;%1&quot;</translation>
</message>
<message>
- <source>Parse error in %1 at %2, %3: %4</source>
- <translation>Parse-fejl i %1 ved %2, %3: %4</translation>
- </message>
- <message>
<source>Root element %1 unexpected, should be &quot;Updates&quot;.</source>
<translation>Rod-elementet %1 uventet, skulle være &quot;Updates&quot;.</translation>
</message>
@@ -744,6 +756,10 @@
<source>Invalid content in &quot;%1&quot;.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>This may be solved by restarting the application after clearing the cache from:</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::Component</name>
@@ -752,18 +768,6 @@
<translation>Komponenter må ikke have børn i opdateringstilstand.</translation>
</message>
<message>
- <source>Cannot open the requested UI file &quot;%1&quot;: %2</source>
- <translation>Kan ikke åbne den anmodede UI-fil &quot;%1&quot;: %2</translation>
- </message>
- <message>
- <source>Cannot load the requested UI file &quot;%1&quot;: %2</source>
- <translation>Kan ikke indlæse den anmodede UI-fil &quot;%1&quot;: %2</translation>
- </message>
- <message>
- <source>Cannot open the requested license file &quot;%1&quot;: %2</source>
- <translation>Kan ikke åbne den anmodede licensfil &quot;%1&quot;: %2</translation>
- </message>
- <message>
<source>Error</source>
<translation>Fejl</translation>
</message>
@@ -783,6 +787,30 @@
<source>There was an error loading the selected component. This component cannot be installed.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Cannot open the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Kan ikke åbne den anmodede UI-fil &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot load the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Kan ikke indlæse den anmodede UI-fil &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot open the requested license file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Kan ikke åbne den anmodede licensfil &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
</context>
<context>
<name>QInstaller::ComponentModel</name>
@@ -866,12 +894,8 @@
<translation type="unfinished"></translation>
</message>
<message>
- <source>&amp;Browse QBSP files</source>
- <translation>&amp;Gennemse QBSP-filer</translation>
- </message>
- <message>
- <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source>
- <translation>Vælg de komponenter du vil installere. Fravælg installeret komponenter for at afinstallere dem. Komponenter som allerede er installeret vil ikke blive opdateret.</translation>
+ <source>Select the components to install. Deselect installed components to uninstall them.&lt;br&gt;Any components already installed will not be updated.</source>
+ <translation>Vælg de komponenter du vil installere. Fravælg installeret komponenter for at afinstallere dem.&lt;br&gt;Komponenter som allerede er installeret vil ikke blive opdateret.</translation>
</message>
<message>
<source>This component will occupy approximately %1 on your hard disk drive.</source>
@@ -902,33 +926,33 @@
<translation type="unfinished"></translation>
</message>
<message>
- <source>Alt+A</source>
- <comment>Select default components</comment>
+ <source>Filter the enabled repository categories</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Alt+R</source>
- <comment>Reset to already installed components</comment>
+ <source>Search</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Alt+S</source>
- <comment>Select all components</comment>
- <translation type="unfinished">Alt+V</translation>
+ <source>Create Offline Installer</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Alt+D</source>
- <comment>Deselect all components</comment>
- <translation type="unfinished">Alt+F</translation>
+ <source>Create offline installer from selected components, instead of installing now.</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Filter the enabled repository categories</source>
+ <source>Browse &amp;QBSP files</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Search</source>
+ <source>Select</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">Fejl</translation>
+ </message>
</context>
<context>
<name>QInstaller::ConsumeOutputOperation</name>
@@ -1207,6 +1231,10 @@ Fejl under indlæsning af %2</translation>
<source>Total: </source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Retry count (%1) exceeded</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::Downloader</name>
@@ -1344,7 +1372,7 @@ Fejl under indlæsning af %2</translation>
<context>
<name>QInstaller::FinishedPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>Fuldfører %1-assistenten</translation>
</message>
<message>
@@ -1352,7 +1380,7 @@ Fejl under indlæsning af %2</translation>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Click %1 to exit the %2 Wizard.</source>
+ <source>Click %1 to exit the %2 Setup.</source>
<translation>Klik på %1 for at afslutte %2-assistenten.</translation>
</message>
<message>
@@ -1413,8 +1441,8 @@ Fejl under indlæsning af %2</translation>
<context>
<name>QInstaller::IntroductionPage</name>
<message>
- <source>Setup - %1</source>
- <translation>Opsætning - %1</translation>
+ <source>Welcome</source>
+ <translation type="unfinished"></translation>
</message>
<message>
<source>Welcome to the %1 Setup.</source>
@@ -1433,10 +1461,6 @@ Fejl under indlæsning af %2</translation>
<translation>Ingen tilgængelige opdateringer.</translation>
</message>
<message>
- <source> Only local package management available.</source>
- <translation> Kun lokal pakkehåndtering tilgængeligt.</translation>
- </message>
- <message>
<source>&amp;Add or remove components</source>
<translation>&amp;Tilføj eller fjern komponenter</translation>
</message>
@@ -1499,10 +1523,6 @@ Fejl under indlæsning af %2</translation>
<source>Can not write license file &quot;%1&quot;.</source>
<translation>Kan ikke skrive licensfilen &quot;%1&quot;.</translation>
</message>
- <message>
- <source>No license files found to delete.</source>
- <translation>Ingen licensfil fundet til sletning.</translation>
- </message>
</context>
<context>
<name>QInstaller::LineReplaceOperation</name>
@@ -1566,14 +1586,6 @@ Fejl under indlæsning af %2</translation>
<translation>Tjeksum uoverensstemmelse registreret for &quot;%1&quot;.</translation>
</message>
<message>
- <source>Retrieving meta information from remote repository... %1/%2 </source>
- <translation>Henter metainformation fra fjern-repository... %1/%2 </translation>
- </message>
- <message>
- <source>Retrieving meta information from remote repository... </source>
- <translation>Henter metainformation fra fjern-repository... </translation>
- </message>
- <message>
<source>Metadata download canceled.</source>
<translation type="unfinished"></translation>
</message>
@@ -1596,6 +1608,26 @@ Fejl under indlæsning af %2</translation>
<source>Clearing the cache directory and restarting the application may solve this.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Unknown exception during updating cache.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot open extracted file &quot;%1&quot; for reading: %2</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot open file &quot;%1&quot; for writing: %2</source>
+ <translation type="unfinished">Kan ikke åbne filen &quot;%1&quot; til skrivning: %2</translation>
+ </message>
+ <message>
+ <source>Retrieving information from remote repositories...</source>
+ <translation>Henter information fra fjern-repository...</translation>
+ </message>
+ <message>
+ <source>Retrieving meta information from remote repository...</source>
+ <translation>Henter metainformation fra fjern-repository...</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCore</name>
@@ -1726,10 +1758,6 @@ Vil du fortsætte?</translation>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Running processes found.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
<source>Cannot elevate access rights while running from command line. Please restart the application as administrator.</source>
<translation type="unfinished"></translation>
</message>
@@ -1797,6 +1825,22 @@ Vil du fortsætte?</translation>
<source>Not enough disk space to store temporary files! %1 are available, while the minimum required is %2. You may select another location for the temporary files by modifying the local cache path from the installer settings.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Cannot resolve components to uninstall.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot select alias %1. There was a problem loading this alias, so it is marked unstable and cannot be selected.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot select %1. Alias is marked virtual, meaning it cannot be selected manually.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Created installer will use %1 of disk space.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCorePrivate</name>
@@ -2003,10 +2047,6 @@ Vil du fortsætte?</translation>
<translation>Kan ikke hente metainformation: %1</translation>
</message>
<message>
- <source>Cannot add temporary update source information.</source>
- <translation>Kan ikke tilføje kildeinformation for midlertidig opdatering.</translation>
- </message>
- <message>
<source>Cannot find any update source information.</source>
<translation>Kan ikke finde nogen kildeinformation for opdatering.</translation>
</message>
@@ -2067,6 +2107,18 @@ Vil du fortsætte?</translation>
<source>Loading component scripts...</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Alias declares name that conflicts with an existing component &quot;%1&quot;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unresolved component aliases</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cyclic dependency between aliases &quot;%1&quot; and &quot;%2&quot; detected.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerGui</name>
@@ -2170,6 +2222,18 @@ Kopiér venligst installeren til et lokalt drev</translation>
<source>Uninstalling</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>&amp;Create Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer for %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::ProxyCredentialsDialog</name>
@@ -2244,6 +2308,18 @@ Kopiér venligst installeren til et lokalt drev</translation>
<source>Ready to Update</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Ready to Create Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>All required information is now available to create an offline installer for selected components.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::RegisterFileTypeOperation</name>
@@ -2300,7 +2376,7 @@ Kopiér venligst installeren til et lokalt drev</translation>
<context>
<name>QInstaller::RestartPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>Fuldfører opsætningsassistenten for %1</translation>
</message>
</context>
@@ -2702,11 +2778,11 @@ or accept the elevation of access rights if being asked.</source>
</message>
<message>
<source>Select All</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">Vælg alle</translation>
</message>
<message>
<source>Deselect All</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">Fravælg alle</translation>
</message>
<message>
<source>The server&apos;s URL that contains a valid repository.</source>
@@ -2732,6 +2808,10 @@ or accept the elevation of access rights if being asked.</source>
<source>Clear cache</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Clearing cache...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UpdateOperation</name>
@@ -3000,6 +3080,10 @@ or accept the elevation of access rights if being asked.</source>
<source>Cannot synchronize invalidated cache.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Unknown register mode selected!</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>TabController</name>
diff --git a/src/sdk/translations/ifw_de.ts b/src/sdk/translations/ifw_de.ts
index 9e17ffbac..ad80c6624 100644
--- a/src/sdk/translations/ifw_de.ts
+++ b/src/sdk/translations/ifw_de.ts
@@ -136,6 +136,18 @@
<source>Cannot find missing dependency &quot;%1&quot; for &quot;%2&quot;.</source>
<translation>Konnte fehlende Abhängigkeit &apos;%1&apos; für &apos;%2&apos; nicht finden.</translation>
</message>
+ <message>
+ <source>Impossible dependency resolution detected. Forced install component &quot;%1&quot; would be uninstalled because its dependency &quot;%2&quot; is marked for uninstallation with reason: &quot;%3&quot;.</source>
+ <translation>Die Abhängigkeiten sind nicht auflösbar. Die zur forcierten Installation vorgesehene Komponente &quot;%1&quot; würde deinstalliert werden, weil sie von Komponente &quot;%2&quot; abhängt, welche auf Grund von &quot;%3&quot; zur Deinstallation vorgesehen ist.</translation>
+ </message>
+ <message>
+ <source>Components selected by alias &quot;%1&quot;:</source>
+ <translation>Durch den Alias &quot;%1&quot; ausgewählte Komponenten</translation>
+ </message>
+ <message>
+ <source>Recursion detected, component alias &quot;%1&quot; already added.</source>
+ <translation>Es wurde eine Rekursion festegestellt; der Alias &quot;%1&quot; wurde bereits hinzugefügt.</translation>
+ </message>
</context>
<context>
<name>Job</name>
@@ -306,6 +318,10 @@
<source>Try again</source>
<translation>Erneut versuchen</translation>
</message>
+ <message>
+ <source>Cannot download %1. Cannot create directory for &quot;%2&quot;</source>
+ <translation>Kann %1 nicht herunterladen. Es kann kein Verzeichnis für &quot;%2&quot; erstellt werden</translation>
+ </message>
</context>
<context>
<name>KDUpdater::LocalFileDownloader</name>
@@ -489,10 +505,6 @@
<translation>Konnte Datei &quot;%1&quot; nicht lesen</translation>
</message>
<message>
- <source>Parse error in %1 at %2, %3: %4</source>
- <translation>Ungültiges XML in Datei %1, Zeile %2, Spalte %3: %4</translation>
- </message>
- <message>
<source>Root element %1 unexpected, should be &quot;Updates&quot;.</source>
<translation>Unerwartetes Wurzelelement %1, erwartet wird &quot;UpdateSources&quot;.</translation>
</message>
@@ -744,6 +756,10 @@
<source>Invalid content in &quot;%1&quot;.</source>
<translation>Ungültiger Inhalt in &quot;%1&quot;.</translation>
</message>
+ <message>
+ <source>This may be solved by restarting the application after clearing the cache from:</source>
+ <translation>Das kann durch Neustart der Anwendung behoben werden; nach Löschen des Caches von:</translation>
+ </message>
</context>
<context>
<name>QInstaller::Component</name>
@@ -752,18 +768,6 @@
<translation>Komponenten können im Updater-Modus keine Kinder haben.</translation>
</message>
<message>
- <source>Cannot open the requested UI file &quot;%1&quot;: %2</source>
- <translation>Konnte angeforderte UI-Datei &apos;%1&apos; nicht öffnen: %2</translation>
- </message>
- <message>
- <source>Cannot load the requested UI file &quot;%1&quot;: %2</source>
- <translation>Konnte angeforderte UI-Datei &apos;%1&apos; nicht laden: %2</translation>
- </message>
- <message>
- <source>Cannot open the requested license file &quot;%1&quot;: %2</source>
- <translation>Konnte angeforderte Lizenzdatei &apos;%1&apos; nicht öffnen: %2</translation>
- </message>
- <message>
<source>Error</source>
<translation>Fehler</translation>
</message>
@@ -783,6 +787,30 @@
<source>There was an error loading the selected component. This component cannot be installed.</source>
<translation>Es ist ein Fehler beim Laden der ausgewählten Komponente aufgetreten. Diese Komponente kann nicht installiert werden.</translation>
</message>
+ <message>
+ <source>Cannot open the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Konnte angeforderte UI-Datei &quot;%1&quot; nicht öffnen: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot load the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Konnte angeforderte UI-Datei &quot;%1&quot; nicht laden: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot open the requested license file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Konnte angeforderte Lizenzdatei &quot;%1&quot; nicht öffnen: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
</context>
<context>
<name>QInstaller::ComponentModel</name>
@@ -870,10 +898,6 @@
<translation>Datei öffnen</translation>
</message>
<message>
- <source>&amp;Browse QBSP files</source>
- <translation>Durchsuche QBSP Dateien</translation>
- </message>
- <message>
<source>Select a Qt Board Support Package file to install additional content that is not directly available from the online repositories.</source>
<translation>Wählen Sie eine Qt Board Support Package-Datei, um zusätzliche Inhalte zu installieren, die nicht direkt in den Online-Repositories verfügbar sind.</translation>
</message>
@@ -902,13 +926,33 @@
<translation>Bitte wählen Sie die Komponenten aus, die Sie entfernen möchten.</translation>
</message>
<message>
- <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source>
- <translation>Bitte wählen Sie die Komponenten aus, die Sie installieren möchten. Wählen Sie die Komponenten ab, die Sie entfernen möchten.</translation>
- </message>
- <message>
<source>Mandatory components need to be updated first before you can select other components to update.</source>
<translation>Obligatorische Komponenten müssen zuerst aktualisiert werden, bevor andere Komponenten zur Aktualisierung ausgewählt werden können.</translation>
</message>
+ <message>
+ <source>Browse &amp;QBSP files</source>
+ <translation>Durchsuche QBSP Dateien</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Auswählen</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Fehler</translation>
+ </message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation>Offline-Installer Erstellen</translation>
+ </message>
+ <message>
+ <source>Create offline installer from selected components, instead of installing now.</source>
+ <translation>Erstellt einen Offline-Installer von den ausgewählten Komponenten anstatt zu installieren</translation>
+ </message>
+ <message>
+ <source>Select the components to install. Deselect installed components to uninstall them.&lt;br&gt;Any components already installed will not be updated.</source>
+ <translation>Bitte wählen Sie die Komponenten aus, die Sie installieren möchten. Wählen Sie die Komponenten ab, die Sie entfernen möchten.</translation>
+ </message>
</context>
<context>
<name>QInstaller::ComponentSelectionPagePrivate</name>
@@ -922,7 +966,7 @@
</message>
<message>
<source>Information</source>
- <translation type="unfinished">Komponenteninformationen</translation>
+ <translation>Informationen</translation>
</message>
</context>
<context>
@@ -1121,14 +1165,6 @@
<translation>Fehler beim Herunterladen</translation>
</message>
<message>
- <source>Hash verification while downloading failed. This is a temporary error, please retry.</source>
- <translation>Prüfsumme ungültig beim Herunterladen. Dies ist ein kurzzeitiger Fehler, bitte erneut versuchen.</translation>
- </message>
- <message>
- <source>Cannot verify Hash</source>
- <translation>Prüfsumme konnte nicht geprüft werden</translation>
- </message>
- <message>
<source>Cannot download archive %1: %2</source>
<translation>Konnte Archiv %1 nicht herunterladen: %2</translation>
</message>
@@ -1202,6 +1238,28 @@ Fehler beim Laden von %2</translation>
<source>Archive: </source>
<translation>Archiv: </translation>
</message>
+ <message>
+ <source>Retry count (%1) exceeded</source>
+ <translation>Anzahl der Wiederholungen (%1) überschritten</translation>
+ </message>
+ <message>
+ <source>Hash verification while downloading failed. This is a temporary error, please retry.
+
+Expected: %1
+Downloaded: %2</source>
+ <translation>Prüfsumme ungültig beim Herunterladen. Dies ist ein kurzzeitiger Fehler, bitte erneut versuchen.
+
+Erwartet: %1
+Heruntergeladen: %2</translation>
+ </message>
+ <message>
+ <source>Cannot verify Hash
+Expected: %1
+Downloaded: %2</source>
+ <translation>Prüfsumme konnte nicht geprüft werden
+Erwartet: %1
+Heruntergeladen: %2</translation>
+ </message>
</context>
<context>
<name>QInstaller::Downloader</name>
@@ -1362,7 +1420,7 @@ Fehler beim Laden von %2</translation>
<context>
<name>QInstaller::FinishedPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>Den %1-Assistent abschließen</translation>
</message>
<message>
@@ -1370,7 +1428,7 @@ Fehler beim Laden von %2</translation>
<translation>Abschließen</translation>
</message>
<message>
- <source>Click %1 to exit the %2 Wizard.</source>
+ <source>Click %1 to exit the %2 Setup.</source>
<translation>Klicken Sie %1, um den %2 Assistenten zu beenden.</translation>
</message>
<message>
@@ -1431,8 +1489,8 @@ Fehler beim Laden von %2</translation>
<context>
<name>QInstaller::IntroductionPage</name>
<message>
- <source>Setup - %1</source>
- <translation>Einrichten - %1</translation>
+ <source>Welcome</source>
+ <translation>Willkommen</translation>
</message>
<message>
<source>Welcome to the %1 Setup.</source>
@@ -1463,10 +1521,6 @@ Fehler beim Laden von %2</translation>
<translation>Keine Aktualisierungen verfügbar.</translation>
</message>
<message>
- <source> Only local package management available.</source>
- <translation> Nur lokale Paketverwaltung verfügbar.</translation>
- </message>
- <message>
<source>&amp;Quit</source>
<translation>Beenden</translation>
</message>
@@ -1518,10 +1572,6 @@ Fehler beim Laden von %2</translation>
<source>Can not write license file &quot;%1&quot;.</source>
<translation>Konnte Lizenzdatei &quot;%1&quot; nicht schreiben.</translation>
</message>
- <message>
- <source>No license files found to delete.</source>
- <translation>Keine Lizenzdateien zum Löschen gefunden.</translation>
- </message>
</context>
<context>
<name>QInstaller::LineReplaceOperation</name>
@@ -1581,14 +1631,6 @@ Fehler beim Laden von %2</translation>
<translation>Checksummen stimmen nicht überein &apos;%1&apos;.</translation>
</message>
<message>
- <source>Retrieving meta information from remote repository... %1/%2 </source>
- <translation>Metainformationen werden vom Installationsserver empfangen... %1/%2 </translation>
- </message>
- <message>
- <source>Retrieving meta information from remote repository... </source>
- <translation>Metainformationen werden vom Installationsserver empfangen ... </translation>
- </message>
- <message>
<source>Unsupported archive &quot;%1&quot;: no handler registered for file suffix &quot;%2&quot;.</source>
<translation>Nicht unterstütztes Archivformat: &quot;%1&quot;: Für die Dateiendung &quot;%2&quot; ist keine Behandlungsroutine registriert.</translation>
</message>
@@ -1615,6 +1657,26 @@ Fehler beim Laden von %2</translation>
<source>Clearing the cache directory and restarting the application may solve this.</source>
<translation>Das Löschen des Cache-Verzeichnisses and Neustarten der Anwendung kann das beheben.</translation>
</message>
+ <message>
+ <source>Unknown exception during updating cache.</source>
+ <translation>Unbekannte Ausnahmebedingung beim Aktualisieren des Caches</translation>
+ </message>
+ <message>
+ <source>Cannot open extracted file &quot;%1&quot; for reading: %2</source>
+ <translation>Die extrahierte Datei &quot;%1&quot; konnte nicht zum Lesen geöffnet werden: %2</translation>
+ </message>
+ <message>
+ <source>Cannot open file &quot;%1&quot; for writing: %2</source>
+ <translation>Die Datei &quot;%1&quot; konnte nicht zum Schreiben geöffnet werden: %2</translation>
+ </message>
+ <message>
+ <source>Retrieving information from remote repositories...</source>
+ <translation>Informationen werden vom Installationsserver empfangen...</translation>
+ </message>
+ <message>
+ <source>Retrieving meta information from remote repository...</source>
+ <translation>Metainformationen werden vom Installationsserver empfangen...</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCore</name>
@@ -1757,10 +1819,6 @@ Möchten Sie trotzdem fortsetzen?</translation>
<translation>%1 kann nicht installiert werden. Komponente nicht gefunden.</translation>
</message>
<message>
- <source>Running processes found.</source>
- <translation>Laufende Prozesse gefunden.</translation>
- </message>
- <message>
<source>Cannot elevate access rights while running from command line. Please restart the application as administrator.</source>
<translation>Bei der Ausführung über die Befehlszeile konnten die Zugriffsrechte nicht erhöht werden. Bitte starten Sie die Anwendung als Administrator neu.</translation>
</message>
@@ -1816,6 +1874,22 @@ Möchten Sie trotzdem fortsetzen?</translation>
<source>Not enough disk space to store temporary files! %1 are available, while the minimum required is %2. You may select another location for the temporary files by modifying the local cache path from the installer settings.</source>
<translation>Es gibt nicht ausreichend Plattenplatz, um die temporären Dateien zu speichern! %1 sind verfügbar, aber das erforderliche Minimum ist %2. Sie können einen anderen Speicherort für die temporären Dateien auswählen, indem Sie den lokalen Cache-Pfad in den Installationseinstellungen ändern.</translation>
</message>
+ <message>
+ <source>Cannot resolve components to uninstall.</source>
+ <translation>Die zu deinstallierenden Komponenten konnten nicht aufgelöst werden.</translation>
+ </message>
+ <message>
+ <source>Cannot select alias %1. There was a problem loading this alias, so it is marked unstable and cannot be selected.</source>
+ <translation>Der Alias %1 kann nicht ausgewählt werden. Beim Laden trat ein Problem auf; er wurde daher als instabil gekennzeichnet und kann nicht ausgewählt werden.</translation>
+ </message>
+ <message>
+ <source>Cannot select %1. Alias is marked virtual, meaning it cannot be selected manually.</source>
+ <translation>Der Alias %1 kann nicht ausgewählt werden. Er ist als virtuell gekennzeichnet und kann nicht daher nicht manuell ausgewählt werden.</translation>
+ </message>
+ <message>
+ <source>Created installer will use %1 of disk space.</source>
+ <translation>Der erstellte Installer wird %1 Festplattenplatz verwenden.</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCorePrivate</name>
@@ -2044,10 +2118,6 @@ Möchten Sie trotzdem fortsetzen?</translation>
<translation>Konnte die Metainformationen nicht empfangen: %1</translation>
</message>
<message>
- <source>Cannot add temporary update source information.</source>
- <translation>Konnte Informationen nicht zu temporären Aktualisierungsquellen hinzufügen.</translation>
- </message>
- <message>
<source>Cannot find any update source information.</source>
<translation>Konnte keine Informationen zu Aktualisierungsquellen finden.</translation>
</message>
@@ -2087,6 +2157,18 @@ Möchten Sie trotzdem fortsetzen?</translation>
<source>Loading component scripts...</source>
<translation>Lade Komponenten-Skripte...</translation>
</message>
+ <message>
+ <source>Alias declares name that conflicts with an existing component &quot;%1&quot;</source>
+ <translation>Der Alias verwendet einen Namen, der mit der bereits existierenden Komponte &quot;%1&quot; kollidiert</translation>
+ </message>
+ <message>
+ <source>Unresolved component aliases</source>
+ <translation>Unaufgelöste Komponenten-Aliasse</translation>
+ </message>
+ <message>
+ <source>Cyclic dependency between aliases &quot;%1&quot; and &quot;%2&quot; detected.</source>
+ <translation>Es wurde eine zyklische Abhängigkeit zwischen den Aliassen &quot;%1&quot; und &quot;%2&quot; festgestellt.</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerGui</name>
@@ -2190,6 +2272,18 @@ Bitte kopieren Sie den Installer auf ein lokales Laufwerk</translation>
<source>Uninstalling</source>
<translation>Wird deinstalliert</translation>
</message>
+ <message>
+ <source>&amp;Create Offline Installer</source>
+ <translation>Offline-Installer &amp;Erstellen</translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer for %1</source>
+ <translation>Erstelle Offline-Installer für %1</translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer</source>
+ <translation>Erstelle Offline-Installer</translation>
+ </message>
</context>
<context>
<name>QInstaller::ProxyCredentialsDialog</name>
@@ -2271,6 +2365,18 @@ Bitte kopieren Sie den Installer auf ein lokales Laufwerk</translation>
<source>Ready to Update</source>
<translation>Bereit für Aktualisierung</translation>
</message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation>Offline-Installer Erstellen</translation>
+ </message>
+ <message>
+ <source>Ready to Create Offline Installer</source>
+ <translation>Bereit zum Erstellen des Offline-Installers</translation>
+ </message>
+ <message>
+ <source>All required information is now available to create an offline installer for selected components.</source>
+ <translation>Die erforderlichen Informationen zum Erstellen eines Offline-Installers für die ausgewählten Komponenten stehen bereit.</translation>
+ </message>
</context>
<context>
<name>QInstaller::RegisterFileTypeOperation</name>
@@ -2327,7 +2433,7 @@ Bitte kopieren Sie den Installer auf ein lokales Laufwerk</translation>
<context>
<name>QInstaller::RestartPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>Der %1-Assistent wird abgeschlossen</translation>
</message>
</context>
@@ -2603,7 +2709,7 @@ or accept the elevation of access rights if being asked.</source>
</message>
<message>
<source>Categories</source>
- <translation type="unfinished">Kategorien auswählen</translation>
+ <translation>Kategorien</translation>
</message>
</context>
<context>
@@ -2760,6 +2866,10 @@ or accept the elevation of access rights if being asked.</source>
<source>Clear cache</source>
<translation>Cache löschen</translation>
</message>
+ <message>
+ <source>Clearing cache...</source>
+ <translation>Lösche Cache...</translation>
+ </message>
</context>
<context>
<name>UpdateOperation</name>
@@ -2983,6 +3093,10 @@ or accept the elevation of access rights if being asked.</source>
<source>Cannot synchronize invalidated cache.</source>
<translation>Ungültiger Cache kann nicht synchronisiert werden.</translation>
</message>
+ <message>
+ <source>Unknown register mode selected!</source>
+ <translation>Unbekannter Registrierungsmodus ausgewählt!</translation>
+ </message>
</context>
<context>
<name>TabController</name>
diff --git a/src/sdk/translations/ifw_es.ts b/src/sdk/translations/ifw_es.ts
index 721fed1df..69369064f 100644
--- a/src/sdk/translations/ifw_es.ts
+++ b/src/sdk/translations/ifw_es.ts
@@ -136,6 +136,18 @@
<source>Cannot find missing dependency &quot;%1&quot; for &quot;%2&quot;.</source>
<translation>No se puede encontrar la dependencia &quot;%1&quot; que falta para &quot;%2&quot;.</translation>
</message>
+ <message>
+ <source>Impossible dependency resolution detected. Forced install component &quot;%1&quot; would be uninstalled because its dependency &quot;%2&quot; is marked for uninstallation with reason: &quot;%3&quot;.</source>
+ <translation>Resolución de dependencia imposible detectada. El componente de instalación forzada &quot;%1&quot; se desinstalaría porque su dependencia &quot;%2&quot; está marcada para desinstalación con el motivo: &quot;%3&quot;.</translation>
+ </message>
+ <message>
+ <source>Components selected by alias &quot;%1&quot;:</source>
+ <translation>Compoentes seleccionados por el alias &quot;%1&quot;:</translation>
+ </message>
+ <message>
+ <source>Recursion detected, component alias &quot;%1&quot; already added.</source>
+ <translation>Recursión detectada, el alias del componente &quot;%1&quot; ya se agregó.</translation>
+ </message>
</context>
<context>
<name>Job</name>
@@ -306,6 +318,10 @@
<source>Try again</source>
<translation>Volver a intentar</translation>
</message>
+ <message>
+ <source>Cannot download %1. Cannot create directory for &quot;%2&quot;</source>
+ <translation>No se puede descargar %1. No se puede crear el directorio para &quot;%2&quot;</translation>
+ </message>
</context>
<context>
<name>KDUpdater::LocalFileDownloader</name>
@@ -489,10 +505,6 @@
<translation>No se puede leer &quot;%1&quot;</translation>
</message>
<message>
- <source>Parse error in %1 at %2, %3: %4</source>
- <translation>Error de análisis en %1 en %2, %3: %4</translation>
- </message>
- <message>
<source>Root element %1 unexpected, should be &quot;Updates&quot;.</source>
<translation>Elemento raíz %1 inesperado, debería ser &quot;Updates&quot;.</translation>
</message>
@@ -744,6 +756,10 @@
<source>Invalid content in &quot;%1&quot;.</source>
<translation>Contenido inválido en &quot;%1&quot;.</translation>
</message>
+ <message>
+ <source>This may be solved by restarting the application after clearing the cache from:</source>
+ <translation>Esto puede solucionarse reiniciando la aplicación después de borrar el caché de:</translation>
+ </message>
</context>
<context>
<name>QInstaller::Component</name>
@@ -752,18 +768,6 @@
<translation>Los componentes no pueden tener elementos secundarios en el modo actualizador.</translation>
</message>
<message>
- <source>Cannot open the requested UI file &quot;%1&quot;: %2</source>
- <translation>No se puede abrir el archivo de UI &quot;%1&quot; solicitado: %2</translation>
- </message>
- <message>
- <source>Cannot load the requested UI file &quot;%1&quot;: %2</source>
- <translation>No se puede cargar el archivo de UI &quot;%1&quot; solicitado: %2</translation>
- </message>
- <message>
- <source>Cannot open the requested license file &quot;%1&quot;: %2</source>
- <translation>No se puede abrir el archivo de licencia &quot;%1&quot; solicitado: %2</translation>
- </message>
- <message>
<source>Error</source>
<translation>Error</translation>
</message>
@@ -783,6 +787,30 @@
<source>There was an error loading the selected component. This component cannot be installed.</source>
<translation>Se ha producido un error cargando el componente seleccionado. Este componente no se puede instalar.</translation>
</message>
+ <message>
+ <source>Cannot open the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>No se puede abrir el archivo de UI &quot;%1&quot; solicitado: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot load the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>No se puede cargar el archivo de UI &quot;%1&quot; solicitado: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot open the requested license file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>No se puede abrir el archivo de licencia &quot;%1&quot; solicitado: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
</context>
<context>
<name>QInstaller::ComponentModel</name>
@@ -862,10 +890,6 @@
<translation>Anula la selección de todos los componentes en la vista de árbol.</translation>
</message>
<message>
- <source>&amp;Browse QBSP files</source>
- <translation>&amp;Examinar archivos QBSP</translation>
- </message>
- <message>
<source>Select a Qt Board Support Package file to install additional content that is not directly available from the online repositories.</source>
<translation>Selecciona un archivo de paquete de soporte de Qt Board para instalar contenido adicional que no esté disponible directamente en los repositorios en línea.</translation>
</message>
@@ -898,8 +922,8 @@
<translation>Seleccione los componentes que desea desinstalar.</translation>
</message>
<message>
- <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source>
- <translation>Seleccione los componentes que desea instalar. Anule la selección de los componentes instalados para desinstalarlos. No se actualizarán los componentes ya instalados.</translation>
+ <source>Select the components to install. Deselect installed components to uninstall them.&lt;br&gt;Any components already installed will not be updated.</source>
+ <translation>Seleccione los componentes que desea instalar. Anule la selección de los componentes instalados para desinstalarlos.&lt;br&gt;No se actualizarán los componentes ya instalados.</translation>
</message>
<message>
<source>Mandatory components need to be updated first before you can select other components to update.</source>
@@ -909,6 +933,26 @@
<source>Search</source>
<translation>Buscar</translation>
</message>
+ <message>
+ <source>Browse &amp;QBSP files</source>
+ <translation>Examinar archivos &amp;QBSP</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Seleccionar</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Error</translation>
+ </message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation>Crear instalador sin conexión</translation>
+ </message>
+ <message>
+ <source>Create offline installer from selected components, instead of installing now.</source>
+ <translation>Crea un instalador sin conexión a partir de componentes seleccionados, en lugar de instalarlo ahora.</translation>
+ </message>
</context>
<context>
<name>QInstaller::ConsumeOutputOperation</name>
@@ -1106,14 +1150,6 @@
<translation>Error de descarga</translation>
</message>
<message>
- <source>Hash verification while downloading failed. This is a temporary error, please retry.</source>
- <translation>Error de verificación del hash durante la descarga. Es un error temporal, vuelva a intentarlo.</translation>
- </message>
- <message>
- <source>Cannot verify Hash</source>
- <translation>No se puede verificar el hash</translation>
- </message>
- <message>
<source>Cannot download archive %1: %2</source>
<translation>No se puede descargar el archivo %1: %2</translation>
</message>
@@ -1187,6 +1223,28 @@ Error al descargar %2</translation>
<source>Total: </source>
<translation>Total: </translation>
</message>
+ <message>
+ <source>Retry count (%1) exceeded</source>
+ <translation>Se superó el recuento de reintentos (%1)</translation>
+ </message>
+ <message>
+ <source>Hash verification while downloading failed. This is a temporary error, please retry.
+
+Expected: %1
+Downloaded: %2</source>
+ <translation>Error de verificación del hash durante la descarga. Es un error temporal, vuelva a intentarlo.
+
+Esperados: %1
+Descargado: %2</translation>
+ </message>
+ <message>
+ <source>Cannot verify Hash
+Expected: %1
+Downloaded: %2</source>
+ <translation>No se puede verificar el hash
+Esperados: %1
+Descargado: %2</translation>
+ </message>
</context>
<context>
<name>QInstaller::Downloader</name>
@@ -1324,7 +1382,7 @@ Error al descargar %2</translation>
<context>
<name>QInstaller::FinishedPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>Completando el Asistente de %1</translation>
</message>
<message>
@@ -1332,7 +1390,7 @@ Error al descargar %2</translation>
<translation>Terminado</translation>
</message>
<message>
- <source>Click %1 to exit the %2 Wizard.</source>
+ <source>Click %1 to exit the %2 Setup.</source>
<translation>Haga clic en %1 para salir del asistente de %2.</translation>
</message>
<message>
@@ -1393,8 +1451,8 @@ Error al descargar %2</translation>
<context>
<name>QInstaller::IntroductionPage</name>
<message>
- <source>Setup - %1</source>
- <translation>Programa de instalación - %1</translation>
+ <source>Welcome</source>
+ <translation>Bienvenido</translation>
</message>
<message>
<source>Welcome to the %1 Setup.</source>
@@ -1425,10 +1483,6 @@ Error al descargar %2</translation>
<translation>No hay actualizaciones disponibles.</translation>
</message>
<message>
- <source> Only local package management available.</source>
- <translation> Solo está disponible la administración de paquetes locales.</translation>
- </message>
- <message>
<source>&amp;Quit</source>
<translation>Salir</translation>
</message>
@@ -1479,10 +1533,6 @@ Error al descargar %2</translation>
<source>Can not write license file &quot;%1&quot;.</source>
<translation>No se puede escribir en el archivo de licencia &quot;%1&quot;.</translation>
</message>
- <message>
- <source>No license files found to delete.</source>
- <translation>No se han encontrado archivos de licencia para eliminar.</translation>
- </message>
</context>
<context>
<name>QInstaller::LineReplaceOperation</name>
@@ -1542,14 +1592,6 @@ Error al descargar %2</translation>
<translation>Discrepancia de suma de comprobación detectada para &quot;%1&quot;.</translation>
</message>
<message>
- <source>Retrieving meta information from remote repository... %1/%2 </source>
- <translation>Recuperando información de metadatos del repositorio remoto... %1/%2 </translation>
- </message>
- <message>
- <source>Retrieving meta information from remote repository... </source>
- <translation>Recuperando información de metadatos del repositorio remoto... </translation>
- </message>
- <message>
<source>Error while extracting archive &quot;%1&quot;: %2</source>
<translation>Error al extraer el archivo &quot;%1&quot;: %2</translation>
</message>
@@ -1576,6 +1618,26 @@ Error al descargar %2</translation>
<source>Clearing the cache directory and restarting the application may solve this.</source>
<translation>Borrando el directorio de caché y reiniciando la aplicación puede resolver esto.</translation>
</message>
+ <message>
+ <source>Unknown exception during updating cache.</source>
+ <translation>Excepción desconocida durante la actualización de caché.</translation>
+ </message>
+ <message>
+ <source>Cannot open extracted file &quot;%1&quot; for reading: %2</source>
+ <translation>No se puede abrir el archivo extraído &quot;%1&quot; para leer: %2</translation>
+ </message>
+ <message>
+ <source>Cannot open file &quot;%1&quot; for writing: %2</source>
+ <translation>No se puede abrir el archivo &apos;%1&apos; para la escritura: %2</translation>
+ </message>
+ <message>
+ <source>Retrieving information from remote repositories...</source>
+ <translation>Recuperando información de repositorios remotos...</translation>
+ </message>
+ <message>
+ <source>Retrieving meta information from remote repository...</source>
+ <translation>Recuperando información de metadatos del repositorio remoto...</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCore</name>
@@ -1714,10 +1776,6 @@ No es recomendable instalar en este directorio, ya que la instalación podría g
<translation>No se puede instalar %1. No se encuentra el componente.</translation>
</message>
<message>
- <source>Running processes found.</source>
- <translation>Se han encontrado procesos en ejecución.</translation>
- </message>
- <message>
<source>Cannot elevate access rights while running from command line. Please restart the application as administrator.</source>
<translation>No se pueden elevar los derechos de acceso mientras se ejecuta desde la línea de comandos. Por favor, reinicie la aplicación como administrador.</translation>
</message>
@@ -1777,6 +1835,22 @@ No es recomendable instalar en este directorio, ya que la instalación podría g
<source>Not enough disk space to store temporary files! %1 are available, while the minimum required is %2. You may select another location for the temporary files by modifying the local cache path from the installer settings.</source>
<translation>¡No hay suficiente espacio en disco para almacenar archivos temporales! %1 están disponibles, mientras que el mínimo requerido es %2. Puede seleccionar otra ubicación para los archivos temporales modificando la ruta de caché local desde la configuración del instalador.</translation>
</message>
+ <message>
+ <source>Cannot resolve components to uninstall.</source>
+ <translation>No se pueden resolver los componentes para desinstalar.</translation>
+ </message>
+ <message>
+ <source>Cannot select alias %1. There was a problem loading this alias, so it is marked unstable and cannot be selected.</source>
+ <translation>No se puede seleccionar el alias %1. Hubo un problema al cargar este alias, por lo que está marcado como inestable y no se puede seleccionar.</translation>
+ </message>
+ <message>
+ <source>Cannot select %1. Alias is marked virtual, meaning it cannot be selected manually.</source>
+ <translation>No se puede seleccionar %1. El alias está marcado como virtual, lo que significa que no se puede seleccionar manualmente.</translation>
+ </message>
+ <message>
+ <source>Created installer will use %1 of disk space.</source>
+ <translation>El instalador creado utilizará %1 del espacio en disco.</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCorePrivate</name>
@@ -2005,10 +2079,6 @@ No es recomendable instalar en este directorio, ya que la instalación podría g
<translation>No se puede recuperar la información de los metadatos: %1</translation>
</message>
<message>
- <source>Cannot add temporary update source information.</source>
- <translation>No se puede agregar la información de la fuente de actualización temporal.</translation>
- </message>
- <message>
<source>Cannot find any update source information.</source>
<translation>No se puede encontrar ninguna información de fuente de actualización.</translation>
</message>
@@ -2048,6 +2118,18 @@ No es recomendable instalar en este directorio, ya que la instalación podría g
<source>Loading component scripts...</source>
<translation>Cargando scripts de componentes...</translation>
</message>
+ <message>
+ <source>Alias declares name that conflicts with an existing component &quot;%1&quot;</source>
+ <translation>El alias declara un nombre que entra en conflicto con un componente existente &quot;%1&quot;</translation>
+ </message>
+ <message>
+ <source>Unresolved component aliases</source>
+ <translation>Alias de componentes no resueltos</translation>
+ </message>
+ <message>
+ <source>Cyclic dependency between aliases &quot;%1&quot; and &quot;%2&quot; detected.</source>
+ <translation>Se detectó dependencia cíclica entre los alias &quot;%1&quot; y &quot;%2&quot;.</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerGui</name>
@@ -2151,6 +2233,18 @@ Copie el instalador en una unidad local</translation>
<source>Uninstalling</source>
<translation>Desinstalando</translation>
</message>
+ <message>
+ <source>&amp;Create Offline Installer</source>
+ <translation>&amp;Crear instalador sin conexión</translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer for %1</source>
+ <translation>Creando un instalador sin conexión para %1</translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer</source>
+ <translation>Creando un instalador sin conexión</translation>
+ </message>
</context>
<context>
<name>QInstaller::ProxyCredentialsDialog</name>
@@ -2225,6 +2319,18 @@ Copie el instalador en una unidad local</translation>
<source>Ready to Update</source>
<translation>Listo para la actualización</translation>
</message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation>Crear instalador sin conexión</translation>
+ </message>
+ <message>
+ <source>Ready to Create Offline Installer</source>
+ <translation>Listo para crear instalador sin conexión</translation>
+ </message>
+ <message>
+ <source>All required information is now available to create an offline installer for selected components.</source>
+ <translation>Toda la información requerida ahora está disponible para crear un instalador sin conexión para los componentes seleccionados.</translation>
+ </message>
</context>
<context>
<name>QInstaller::RegisterFileTypeOperation</name>
@@ -2281,7 +2387,7 @@ Copie el instalador en una unidad local</translation>
<context>
<name>QInstaller::RestartPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>Completando el Asistente de instalación de %1</translation>
</message>
</context>
@@ -2559,7 +2665,7 @@ O bien acepte la elevación de los derechos de acceso si se le pide.</translatio
</message>
<message>
<source>Categories</source>
- <translation type="unfinished">Seleccione las categorías</translation>
+ <translation>Categorías</translation>
</message>
</context>
<context>
@@ -2716,6 +2822,10 @@ O bien acepte la elevación de los derechos de acceso si se le pide.</translatio
<source>Clear cache</source>
<translation>Limpiar cache</translation>
</message>
+ <message>
+ <source>Clearing cache...</source>
+ <translation>Limpiando caché...</translation>
+ </message>
</context>
<context>
<name>UpdateOperation</name>
@@ -2778,7 +2888,7 @@ O bien acepte la elevación de los derechos de acceso si se le pide.</translatio
</message>
<message>
<source>Information</source>
- <translation type="unfinished">Información de componentes</translation>
+ <translation>Información</translation>
</message>
</context>
<context>
@@ -2984,6 +3094,10 @@ O bien acepte la elevación de los derechos de acceso si se le pide.</translatio
<source>Cannot synchronize invalidated cache.</source>
<translation>No se puede sincronizar el caché invalidado.</translation>
</message>
+ <message>
+ <source>Unknown register mode selected!</source>
+ <translation>¡Modo de registro desconocido seleccionado!</translation>
+ </message>
</context>
<context>
<name>TabController</name>
diff --git a/src/sdk/translations/ifw_fr.ts b/src/sdk/translations/ifw_fr.ts
index 683540c79..2f2bd5bf5 100644
--- a/src/sdk/translations/ifw_fr.ts
+++ b/src/sdk/translations/ifw_fr.ts
@@ -136,6 +136,18 @@
<source>Cannot find missing dependency &quot;%1&quot; for &quot;%2&quot;.</source>
<translation>La dépendance manquante &quot;%1&quot; est introuvable pour &quot;%2&quot;.</translation>
</message>
+ <message>
+ <source>Impossible dependency resolution detected. Forced install component &quot;%1&quot; would be uninstalled because its dependency &quot;%2&quot; is marked for uninstallation with reason: &quot;%3&quot;.</source>
+ <translation>Résolution de dépendance impossible détectée. Le composant dont l&apos;installation est forcée &quot;%1&quot; serait désinstallé car sa dépendance &quot;%2&quot; est marquée pour désinstallation avec la raison : &quot;%3&quot;.</translation>
+ </message>
+ <message>
+ <source>Components selected by alias &quot;%1&quot;:</source>
+ <translation>Composants sélectionnés par alias &quot;%1&quot; :</translation>
+ </message>
+ <message>
+ <source>Recursion detected, component alias &quot;%1&quot; already added.</source>
+ <translation>Récursion détectée, componsant alias &quot;%1&quot; déjà ajouté.</translation>
+ </message>
</context>
<context>
<name>Job</name>
@@ -306,6 +318,10 @@
<source>Try again</source>
<translation>Réessayez</translation>
</message>
+ <message>
+ <source>Cannot download %1. Cannot create directory for &quot;%2&quot;</source>
+ <translation>Impossible de télécharger %1. Impossible de créer le répertoire pour &quot;%2&quot;</translation>
+ </message>
</context>
<context>
<name>KDUpdater::LocalFileDownloader</name>
@@ -489,10 +505,6 @@
<translation>Impossible de lire &quot;%1&quot;</translation>
</message>
<message>
- <source>Parse error in %1 at %2, %3: %4</source>
- <translation>Erreur d’analyse dans %1 sur %2, %3 : %4</translation>
- </message>
- <message>
<source>Root element %1 unexpected, should be &quot;Updates&quot;.</source>
<translation>Élément racine %1 inattendu, il doit s’agir de &quot;Updates&quot;.</translation>
</message>
@@ -744,6 +756,10 @@
<source>Invalid content in &quot;%1&quot;.</source>
<translation>Contenu invalide dans &quot;%1&quot;.</translation>
</message>
+ <message>
+ <source>This may be solved by restarting the application after clearing the cache from:</source>
+ <translation>Le problème peut être résolu en redémarrant l&apos;application après avoir vidé le cache de :</translation>
+ </message>
</context>
<context>
<name>QInstaller::Component</name>
@@ -752,18 +768,6 @@
<translation>Les composants ne peuvent pas comporter d’enfants en mode de mise à jour.</translation>
</message>
<message>
- <source>Cannot open the requested UI file &quot;%1&quot;: %2</source>
- <translation>Impossible d’ouvrir le fichier d’interface utilisateur demandé &quot;%1&quot; : %2</translation>
- </message>
- <message>
- <source>Cannot load the requested UI file &quot;%1&quot;: %2</source>
- <translation>Impossible de charger le fichier d’interface utilisateur demandé &quot;%1&quot; : %2</translation>
- </message>
- <message>
- <source>Cannot open the requested license file &quot;%1&quot;: %2</source>
- <translation>Impossible d’ouvrir le fichier de licence demandé &quot;%1&quot; : %2</translation>
- </message>
- <message>
<source>Error</source>
<translation>Erreur</translation>
</message>
@@ -783,6 +787,30 @@
<source>There was an error loading the selected component. This component cannot be installed.</source>
<translation>Une erreur s&amp;apos;est produite lors du chargement du composant sélectionné. Ce composant ne peut pas être installé.</translation>
</message>
+ <message>
+ <source>Cannot open the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Impossible d’ouvrir le fichier d’interface utilisateur demandé &quot;%1&quot; : %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot load the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Impossible de charger le fichier d’interface utilisateur demandé &quot;%1&quot; : %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot open the requested license file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Impossible d’ouvrir le fichier de licence demandé &quot;%1&quot; : %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
</context>
<context>
<name>QInstaller::ComponentModel</name>
@@ -862,10 +890,6 @@
<translation>Désélectionner tous les composants dans l&apos;arborescence.</translation>
</message>
<message>
- <source>&amp;Browse QBSP files</source>
- <translation>&amp;Parcourir les fichiers QBSP</translation>
- </message>
- <message>
<source>Select a Qt Board Support Package file to install additional content that is not directly available from the online repositories.</source>
<translation>Sélectionner un fichier Qt Board Support Package pour installer du contenu supplémentaire qui n&apos;est pas directement disponible à partir des référentiels en ligne.</translation>
</message>
@@ -898,8 +922,8 @@
<translation>Sélectionnez les composants que vous souhaitez désinstaller.</translation>
</message>
<message>
- <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source>
- <translation>Sélectionnez les composants à installer. Désélectionnez les composants installés pour les désinstaller. Les composants déjà installés ne seront pas mis à jour.</translation>
+ <source>Select the components to install. Deselect installed components to uninstall them.&lt;br&gt;Any components already installed will not be updated.</source>
+ <translation>Sélectionnez les composants à installer. Désélectionnez les composants installés pour les désinstaller.&lt;br&gt;Les composants déjà installés ne seront pas mis à jour.</translation>
</message>
<message>
<source>Mandatory components need to be updated first before you can select other components to update.</source>
@@ -909,6 +933,26 @@
<source>Search</source>
<translation>Recherche</translation>
</message>
+ <message>
+ <source>Browse &amp;QBSP files</source>
+ <translation>Parcourir les fichiers QBSP</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Sélectionner</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Erreur</translation>
+ </message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation>Créer un programme d’installation hors ligne</translation>
+ </message>
+ <message>
+ <source>Create offline installer from selected components, instead of installing now.</source>
+ <translation>Créer un programme d’installation hors ligne à partir des composants sélectionnés, au lieu d&apos;installer maintenant.</translation>
+ </message>
</context>
<context>
<name>QInstaller::ConsumeOutputOperation</name>
@@ -1106,14 +1150,6 @@
<translation>Erreur de téléchargement</translation>
</message>
<message>
- <source>Hash verification while downloading failed. This is a temporary error, please retry.</source>
- <translation>La vérification du hachage lors du téléchargement a échoué. Cette erreur est temporaire, réessayez.</translation>
- </message>
- <message>
- <source>Cannot verify Hash</source>
- <translation>Impossible de vérifier le hachage</translation>
- </message>
- <message>
<source>Cannot download archive %1: %2</source>
<translation>Impossible de télécharger l’archive %1 : %2</translation>
</message>
@@ -1187,6 +1223,28 @@ Erreur lors du chargement de %2</translation>
<source>Total: </source>
<translation>Total: </translation>
</message>
+ <message>
+ <source>Retry count (%1) exceeded</source>
+ <translation>Nombre de tentatives (%1) dépassé</translation>
+ </message>
+ <message>
+ <source>Hash verification while downloading failed. This is a temporary error, please retry.
+
+Expected: %1
+Downloaded: %2</source>
+ <translation>La vérification du hachage lors du téléchargement a échoué. Cette erreur est temporaire, réessayez.
+
+Attendu: %1
+Téléchargé: %2</translation>
+ </message>
+ <message>
+ <source>Cannot verify Hash
+Expected: %1
+Downloaded: %2</source>
+ <translation>Impossible de vérifier le hachage
+Attendu: %1
+Téléchargé: %2</translation>
+ </message>
</context>
<context>
<name>QInstaller::Downloader</name>
@@ -1324,7 +1382,7 @@ Erreur lors du chargement de %2</translation>
<context>
<name>QInstaller::FinishedPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>Exécution de l’assistant de %1</translation>
</message>
<message>
@@ -1332,7 +1390,7 @@ Erreur lors du chargement de %2</translation>
<translation>Terminé</translation>
</message>
<message>
- <source>Click %1 to exit the %2 Wizard.</source>
+ <source>Click %1 to exit the %2 Setup.</source>
<translation>Cliquez sur %1 pour quitter l’assistant de %2.</translation>
</message>
<message>
@@ -1393,8 +1451,8 @@ Erreur lors du chargement de %2</translation>
<context>
<name>QInstaller::IntroductionPage</name>
<message>
- <source>Setup - %1</source>
- <translation>Installation - %1</translation>
+ <source>Welcome</source>
+ <translation type="unfinished"></translation>
</message>
<message>
<source>Welcome to the %1 Setup.</source>
@@ -1425,10 +1483,6 @@ Erreur lors du chargement de %2</translation>
<translation>Aucune mise à jour disponible.</translation>
</message>
<message>
- <source> Only local package management available.</source>
- <translation> Seule la gestion des paquetages locaux est disponible.</translation>
- </message>
- <message>
<source>&amp;Quit</source>
<translation>Quitter</translation>
</message>
@@ -1479,10 +1533,6 @@ Erreur lors du chargement de %2</translation>
<source>Can not write license file &quot;%1&quot;.</source>
<translation>Impossible d’écrire le fichier de licence &quot;%1&quot;.</translation>
</message>
- <message>
- <source>No license files found to delete.</source>
- <translation>Aucun fichier de licence à supprimer.</translation>
- </message>
</context>
<context>
<name>QInstaller::LineReplaceOperation</name>
@@ -1542,14 +1592,6 @@ Erreur lors du chargement de %2</translation>
<translation>Non-concordance des sommes de contrôle détectée pour &quot;%1&quot;.</translation>
</message>
<message>
- <source>Retrieving meta information from remote repository... %1/%2 </source>
- <translation>Extraction des métadonnées depuis le référentiel distant... %1/%2 </translation>
- </message>
- <message>
- <source>Retrieving meta information from remote repository... </source>
- <translation>Extraction des métadonnées depuis le référentiel distant... </translation>
- </message>
- <message>
<source>Error while extracting archive &quot;%1&quot;: %2</source>
<translation>Erreur lors de l’extraction de l’archive &quot;%1&quot; : %2</translation>
</message>
@@ -1576,6 +1618,26 @@ Erreur lors du chargement de %2</translation>
<source>Clearing the cache directory and restarting the application may solve this.</source>
<translation>Effacer le répertoire de cache et redémarrer l&apos;application peut résoudre ce problème.</translation>
</message>
+ <message>
+ <source>Unknown exception during updating cache.</source>
+ <translation>Exception inconnue lors de la mise à jour du cache.</translation>
+ </message>
+ <message>
+ <source>Cannot open extracted file &quot;%1&quot; for reading: %2</source>
+ <translation>Impossible d&apos;ouvrir le fichier extrait &quot;%1&quot; en lecture : %2</translation>
+ </message>
+ <message>
+ <source>Cannot open file &quot;%1&quot; for writing: %2</source>
+ <translation>Impossible d’ouvrir le fichier &quot;%1&quot; en écriture : %2</translation>
+ </message>
+ <message>
+ <source>Retrieving information from remote repositories...</source>
+ <translation>Extraction des informations depuis le référentiels distants...</translation>
+ </message>
+ <message>
+ <source>Retrieving meta information from remote repository...</source>
+ <translation>Extraction des métadonnées depuis le référentiel distant...</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCore</name>
@@ -1714,10 +1776,6 @@ Souhaitez-vous continuer ?</translation>
<translation>Impossible d&apos;installer le composant %1. Composant introuvable.</translation>
</message>
<message>
- <source>Running processes found.</source>
- <translation>Processus en cours trouvés.</translation>
- </message>
- <message>
<source>Cannot elevate access rights while running from command line. Please restart the application as administrator.</source>
<translation>Impossible d&apos;élever les droits d&apos;accès lors de l&apos;exécution à partir de la ligne de commande. Veuillez redémarrer l&apos;application en tant qu&apos;administrateur.</translation>
</message>
@@ -1777,6 +1835,22 @@ Souhaitez-vous continuer ?</translation>
<source>Not enough disk space to store temporary files! %1 are available, while the minimum required is %2. You may select another location for the temporary files by modifying the local cache path from the installer settings.</source>
<translation>L’espace disque est insuffisant pour stocker les fichiers temporaires ! %1 sont disponibles, alors qu’au moins %2 sont nécessaires. Vous pouvez sélectionner un autre emplacement pour les fichiers temporaires en modifiant le chemin du cache local à partir des paramètres du programme d&apos;installation.</translation>
</message>
+ <message>
+ <source>Cannot resolve components to uninstall.</source>
+ <translation>Impossible de résoudre les composants à désinstaller.</translation>
+ </message>
+ <message>
+ <source>Cannot select alias %1. There was a problem loading this alias, so it is marked unstable and cannot be selected.</source>
+ <translation>Impossible de sélectionner l&apos;alias %1. Un problème est survenu lors du chargement de cet alaias, il est donc marqué comme instable et ne peut pas être sélectionné</translation>
+ </message>
+ <message>
+ <source>Cannot select %1. Alias is marked virtual, meaning it cannot be selected manually.</source>
+ <translation>Impossible de sélectionner %1. L&apos;alias est marqué virtuel, ce qui signifie qu&apos;il ne peut pas être sélectionné manuellement.</translation>
+ </message>
+ <message>
+ <source>Created installer will use %1 of disk space.</source>
+ <translation>Le programme d&apos;installation créé utilisera %1 d&apos;espace disque.</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCorePrivate</name>
@@ -2005,10 +2079,6 @@ Souhaitez-vous continuer ?</translation>
<translation>Impossible d’extraire les métadonnées : %1</translation>
</message>
<message>
- <source>Cannot add temporary update source information.</source>
- <translation>Impossible d’ajouter des informations sur la source de mise à jour temporaire.</translation>
- </message>
- <message>
<source>Cannot find any update source information.</source>
<translation>Informations introuvables sur la source de mise à jour.</translation>
</message>
@@ -2048,6 +2118,18 @@ Souhaitez-vous continuer ?</translation>
<source>Loading component scripts...</source>
<translation>Chargement des scripts du composant...</translation>
</message>
+ <message>
+ <source>Alias declares name that conflicts with an existing component &quot;%1&quot;</source>
+ <translation>L&apos;alias déclare un nom en conflit avec un composant existant : &quot;%1&quot;</translation>
+ </message>
+ <message>
+ <source>Unresolved component aliases</source>
+ <translation>Alias ​​de composants non résolus</translation>
+ </message>
+ <message>
+ <source>Cyclic dependency between aliases &quot;%1&quot; and &quot;%2&quot; detected.</source>
+ <translation>Dépendance cyclique entre les alias &quot;%1&quot; et &quot;%2&quot; détectée.</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerGui</name>
@@ -2151,6 +2233,18 @@ Copiez le programme d’installation sur un disque local</translation>
<source>Uninstalling</source>
<translation>Désinstallation</translation>
</message>
+ <message>
+ <source>&amp;Create Offline Installer</source>
+ <translation>&amp;Créer un programme d’installation hors ligne</translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer for %1</source>
+ <translation>Création d&apos;un programme d’installation hors ligne pour %1</translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer</source>
+ <translation>Création d&apos;un programme d’installation hors ligne</translation>
+ </message>
</context>
<context>
<name>QInstaller::ProxyCredentialsDialog</name>
@@ -2225,6 +2319,18 @@ Copiez le programme d’installation sur un disque local</translation>
<source>Ready to Update</source>
<translation>Prêt pour la mise à jour</translation>
</message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation>Créer un programme d’installation hors ligne</translation>
+ </message>
+ <message>
+ <source>Ready to Create Offline Installer</source>
+ <translation>Prêt pour la création du programme d’installation hors ligne</translation>
+ </message>
+ <message>
+ <source>All required information is now available to create an offline installer for selected components.</source>
+ <translation>La création du programme d’installation hors ligne pour les composants sélectionnés est maintenant prête.</translation>
+ </message>
</context>
<context>
<name>QInstaller::RegisterFileTypeOperation</name>
@@ -2281,7 +2387,7 @@ Copiez le programme d’installation sur un disque local</translation>
<context>
<name>QInstaller::RestartPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>Exécution de l’assistant d’installation de %1</translation>
</message>
</context>
@@ -2561,7 +2667,7 @@ Ou acceptez l’élévation des droits d’accès si un message vous y invite.</
</message>
<message>
<source>Categories</source>
- <translation type="unfinished">Sélectionner les catégories</translation>
+ <translation>Catégories</translation>
</message>
</context>
<context>
@@ -2718,6 +2824,10 @@ Ou acceptez l’élévation des droits d’accès si un message vous y invite.</
<source>Clear cache</source>
<translation>Vider le cache</translation>
</message>
+ <message>
+ <source>Clearing cache...</source>
+ <translation>Vidage du cache...</translation>
+ </message>
</context>
<context>
<name>UpdateOperation</name>
@@ -2780,7 +2890,7 @@ Ou acceptez l’élévation des droits d’accès si un message vous y invite.</
</message>
<message>
<source>Information</source>
- <translation type="unfinished">Informations sur les composants</translation>
+ <translation>Informations</translation>
</message>
</context>
<context>
@@ -2986,6 +3096,10 @@ Ou acceptez l’élévation des droits d’accès si un message vous y invite.</
<source>Cannot synchronize invalidated cache.</source>
<translation>Impossible de synchroniser le cache invalidé.</translation>
</message>
+ <message>
+ <source>Unknown register mode selected!</source>
+ <translation>Le mode de registre sélectionné est inconnu !</translation>
+ </message>
</context>
<context>
<name>TabController</name>
diff --git a/src/sdk/translations/ifw_hr.ts b/src/sdk/translations/ifw_hr.ts
index d2a88f62d..d219b17f6 100644
--- a/src/sdk/translations/ifw_hr.ts
+++ b/src/sdk/translations/ifw_hr.ts
@@ -202,11 +202,11 @@
</message>
<message>
<source>Select All</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">Odaberi sve</translation>
</message>
<message>
<source>Deselect All</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">dznači sav odabir</translation>
</message>
<message>
<source>The server&apos;s URL that contains a valid repository.</source>
@@ -232,6 +232,10 @@
<source>Clear cache</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Clearing cache...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QObject</name>
@@ -410,6 +414,10 @@
<source>Invalid content in &quot;%1&quot;.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>This may be solved by restarting the application after clearing the cache from:</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>BinaryLayout</name>
@@ -470,18 +478,6 @@
<translation>Komponente nemaju podređenih u modusu aktualiziranja.</translation>
</message>
<message>
- <source>Cannot open the requested UI file &quot;%1&quot;: %2</source>
- <translation>Nije moguće otvoriti traženu UI datoteku &quot;%1&quot;: %2</translation>
- </message>
- <message>
- <source>Cannot load the requested UI file &quot;%1&quot;: %2</source>
- <translation>Nije moguće učitati traženu UI datoteku &quot;%1&quot;: %2</translation>
- </message>
- <message>
- <source>Cannot open the requested license file &quot;%1&quot;: %2</source>
- <translation>Nije moguće otvoriti traženu licencnu datoteku &quot;%1&quot;: %2</translation>
- </message>
- <message>
<source>Error</source>
<translation>Greška</translation>
</message>
@@ -501,6 +497,30 @@
<source>There was an error loading the selected component. This component cannot be installed.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Cannot open the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Nije moguće otvoriti traženu UI datoteku &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot load the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Nije moguće učitati traženu UI datoteku &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot open the requested license file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Nije moguće otvoriti traženu licencnu datoteku &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
</context>
<context>
<name>QInstaller::ComponentModel</name>
@@ -826,6 +846,10 @@ Greška prilikom učitavanja %2</translation>
<source>Total: </source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Retry count (%1) exceeded</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::Downloader</name>
@@ -1031,6 +1055,18 @@ Greška prilikom učitavanja %2</translation>
<source>Cannot find missing dependency &quot;%1&quot; for &quot;%2&quot;.</source>
<translation>Nije moguće naći nedostajuću ovisnost &quot;%1&quot; za &quot;%2&quot;.</translation>
</message>
+ <message>
+ <source>Components selected by alias &quot;%1&quot;:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Recursion detected, component alias &quot;%1&quot; already added.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Impossible dependency resolution detected. Forced install component &quot;%1&quot; would be uninstalled because its dependency &quot;%2&quot; is marked for uninstallation with reason: &quot;%3&quot;.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::InstallIconsOperation</name>
@@ -1190,10 +1226,6 @@ Greška prilikom učitavanja %2</translation>
<source>Can not write license file &quot;%1&quot;.</source>
<translation>Nije moguće zapisati licencnu datoteku &quot;%1&quot;.</translation>
</message>
- <message>
- <source>No license files found to delete.</source>
- <translation>Nema licencnih datoteka za brisanje.</translation>
- </message>
</context>
<context>
<name>QInstaller::LineReplaceOperation</name>
@@ -1249,14 +1281,6 @@ Greška prilikom učitavanja %2</translation>
<translation>Ustanovljena je neusklađenost kontrolnog zbroja za &quot;%1&quot;.</translation>
</message>
<message>
- <source>Retrieving meta information from remote repository... %1/%2 </source>
- <translation>Dohvaćanje meta informacija s udaljenih spremišta … %1/%2 </translation>
- </message>
- <message>
- <source>Retrieving meta information from remote repository... </source>
- <translation>Dohvaćanje meta informacija s udaljenih spremišta … </translation>
- </message>
- <message>
<source>Error while extracting archive &quot;%1&quot;: %2</source>
<translation>Greška prilikom raspakiravanja arhive &quot;%1&quot;: %2</translation>
</message>
@@ -1288,6 +1312,26 @@ Greška prilikom učitavanja %2</translation>
<source>Clearing the cache directory and restarting the application may solve this.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Unknown exception during updating cache.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot open extracted file &quot;%1&quot; for reading: %2</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot open file &quot;%1&quot; for writing: %2</source>
+ <translation type="unfinished">Nije moguće otvoriti datoteku &quot;%1&quot; za zapisivanje: %2</translation>
+ </message>
+ <message>
+ <source>Retrieving information from remote repositories...</source>
+ <translation>Dohvaćanje informacija s udaljenih spremišta …</translation>
+ </message>
+ <message>
+ <source>Retrieving meta information from remote repository...</source>
+ <translation>Dohvaćanje meta informacija s udaljenih spremišta …</translation>
+ </message>
</context>
<context>
<name>QInstaller::FileTaskObserver</name>
@@ -1473,10 +1517,6 @@ Ne preporučujemo instalirati u ovu mapu, jer instaliranje možda neće uspjeti.
<translation type="unfinished"></translation>
</message>
<message>
- <source>Running processes found.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
<source>Cannot elevate access rights while running from command line. Please restart the application as administrator.</source>
<translation type="unfinished"></translation>
</message>
@@ -1544,6 +1584,22 @@ Ne preporučujemo instalirati u ovu mapu, jer instaliranje možda neće uspjeti.
<source>Not enough disk space to store temporary files! %1 are available, while the minimum required is %2. You may select another location for the temporary files by modifying the local cache path from the installer settings.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Cannot resolve components to uninstall.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot select alias %1. There was a problem loading this alias, so it is marked unstable and cannot be selected.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot select %1. Alias is marked virtual, meaning it cannot be selected manually.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Created installer will use %1 of disk space.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCorePrivate</name>
@@ -1750,10 +1806,6 @@ Ne preporučujemo instalirati u ovu mapu, jer instaliranje možda neće uspjeti.
<translation>Nije moguće pronaći meta podatke: %1</translation>
</message>
<message>
- <source>Cannot add temporary update source information.</source>
- <translation>Nije moguće dodati privremene podatke izvora nadogradnje.</translation>
- </message>
- <message>
<source>Cannot find any update source information.</source>
<translation>Nije moguće naći bilo koje podatke izvora nadogradnje.</translation>
</message>
@@ -1814,6 +1866,18 @@ Ne preporučujemo instalirati u ovu mapu, jer instaliranje možda neće uspjeti.
<source>Loading component scripts...</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Alias declares name that conflicts with an existing component &quot;%1&quot;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unresolved component aliases</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cyclic dependency between aliases &quot;%1&quot; and &quot;%2&quot; detected.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerGui</name>
@@ -1871,8 +1935,8 @@ Kopiraj program za instaliranje na računalo</translation>
<context>
<name>QInstaller::IntroductionPage</name>
<message>
- <source>Setup - %1</source>
- <translation>Postavljanje – %1</translation>
+ <source>Welcome</source>
+ <translation type="unfinished"></translation>
</message>
<message>
<source>Welcome to the %1 Setup.</source>
@@ -1903,10 +1967,6 @@ Kopiraj program za instaliranje na računalo</translation>
<translation>Nema dostupnih nadogradnja.</translation>
</message>
<message>
- <source> Only local package management available.</source>
- <translation> Dostupno je samo lokalno upravljanje paketima.</translation>
- </message>
- <message>
<source>&amp;Quit</source>
<translation type="unfinished"></translation>
</message>
@@ -1978,10 +2038,6 @@ Kopiraj program za instaliranje na računalo</translation>
<translation type="unfinished"></translation>
</message>
<message>
- <source>&amp;Browse QBSP files</source>
- <translation>&amp;Pretraži QBSP datoteke</translation>
- </message>
- <message>
<source>Select a Qt Board Support Package file to install additional content that is not directly available from the online repositories.</source>
<translation type="unfinished"></translation>
</message>
@@ -2010,41 +2066,41 @@ Kopiraj program za instaliranje na računalo</translation>
<translation>Odaberi komponente koje želiš deinstalirati.</translation>
</message>
<message>
- <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source>
- <translation>Odaberi komponente koje želiš instalirati. Odznači instalirane komponente, kako bi se deinstalirale. Već instalirane komponente neće biti aktualizirane.</translation>
+ <source>Select the components to install. Deselect installed components to uninstall them.&lt;br&gt;Any components already installed will not be updated.</source>
+ <translation>Odaberi komponente koje želiš instalirati. Odznači instalirane komponente, kako bi se deinstalirale.&lt;br&gt;Već instalirane komponente neće biti aktualizirane.</translation>
</message>
<message>
<source>Mandatory components need to be updated first before you can select other components to update.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Alt+A</source>
- <comment>Select default components</comment>
- <translation type="unfinished">Alt+A</translation>
+ <source>Filter the enabled repository categories</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Alt+R</source>
- <comment>Reset to already installed components</comment>
- <translation type="unfinished">Alt+R</translation>
+ <source>Search</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Alt+S</source>
- <comment>Select all components</comment>
- <translation type="unfinished">Alt+S</translation>
+ <source>Create Offline Installer</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Alt+D</source>
- <comment>Deselect all components</comment>
- <translation type="unfinished">Alt+D</translation>
+ <source>Create offline installer from selected components, instead of installing now.</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Filter the enabled repository categories</source>
- <translation type="unfinished"></translation>
+ <source>Browse &amp;QBSP files</source>
+ <translation>&amp;Pretraži QBSP datoteke</translation>
</message>
<message>
- <source>Search</source>
+ <source>Select</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">Greška</translation>
+ </message>
</context>
<context>
<name>QInstaller::TargetDirectoryPage</name>
@@ -2127,6 +2183,18 @@ Kopiraj program za instaliranje na računalo</translation>
<source>All required information is now available to begin updating your installation.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Ready to Create Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>All required information is now available to create an offline installer for selected components.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::PerformInstallationPage</name>
@@ -2166,11 +2234,23 @@ Kopiraj program za instaliranje na računalo</translation>
<source>Uninstalling</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>&amp;Create Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer for %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::FinishedPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>Dovršavanje čarobnjaka %1</translation>
</message>
<message>
@@ -2178,7 +2258,7 @@ Kopiraj program za instaliranje na računalo</translation>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Click %1 to exit the %2 Wizard.</source>
+ <source>Click %1 to exit the %2 Setup.</source>
<translation>Klikni %1 za izlaženje iz čarobnjaka %2.</translation>
</message>
<message>
@@ -2197,7 +2277,7 @@ Kopiraj program za instaliranje na računalo</translation>
<context>
<name>QInstaller::RestartPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>Dovršavanje čarobnjaka postavaka %1</translation>
</message>
</context>
@@ -2514,6 +2594,10 @@ or accept the elevation of access rights if being asked.</source>
<source>Try again</source>
<translation>Pokušaj ponovo</translation>
</message>
+ <message>
+ <source>Cannot download %1. Cannot create directory for &quot;%2&quot;</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>Job</name>
@@ -2786,10 +2870,6 @@ or accept the elevation of access rights if being asked.</source>
<translation>Nije moguće čitati &quot;%1&quot;</translation>
</message>
<message>
- <source>Parse error in %1 at %2, %3: %4</source>
- <translation>Greška u obradi u %1 na %2, %3: %4</translation>
- </message>
- <message>
<source>Root element %1 unexpected, should be &quot;Updates&quot;.</source>
<translation>Neočekivani Root element %1, mora biti &quot;Updates&quot;.</translation>
</message>
@@ -3016,6 +3096,10 @@ or accept the elevation of access rights if being asked.</source>
<source>Cannot synchronize invalidated cache.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Unknown register mode selected!</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>TabController</name>
diff --git a/src/sdk/translations/ifw_hu.ts b/src/sdk/translations/ifw_hu.ts
index a66e0725c..cd247fd8b 100644
--- a/src/sdk/translations/ifw_hu.ts
+++ b/src/sdk/translations/ifw_hu.ts
@@ -136,6 +136,18 @@
<source>Cannot find missing dependency &quot;%1&quot; for &quot;%2&quot;.</source>
<translation>Nem található hiányzó &quot;%1&quot; függőség &quot;%2&quot; számára. </translation>
</message>
+ <message>
+ <source>Components selected by alias &quot;%1&quot;:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Recursion detected, component alias &quot;%1&quot; already added.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Impossible dependency resolution detected. Forced install component &quot;%1&quot; would be uninstalled because its dependency &quot;%2&quot; is marked for uninstallation with reason: &quot;%3&quot;.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>Job</name>
@@ -302,6 +314,10 @@
<source>Try again</source>
<translation>Próbálja újra</translation>
</message>
+ <message>
+ <source>Cannot download %1. Cannot create directory for &quot;%2&quot;</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>KDUpdater::LocalFileDownloader</name>
@@ -484,10 +500,6 @@
<translation>&quot;%1&quot; olvasása nem sikerült</translation>
</message>
<message>
- <source>Parse error in %1 at %2, %3: %4</source>
- <translation>Elemzési hiba %1-ben itt: %2, %3: %4</translation>
- </message>
- <message>
<source>Root element %1 unexpected, should be &quot;Updates&quot;.</source>
<translation>%1 gyökér elem váratlan, &apos;Updates&apos; kell, hogy legyen.</translation>
</message>
@@ -739,6 +751,10 @@
<source>The specified module could not be found.</source>
<translation>A megadott modul nem található.</translation>
</message>
+ <message>
+ <source>This may be solved by restarting the application after clearing the cache from:</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::Component</name>
@@ -747,18 +763,6 @@
<translation>A komponenseknek nem lehetnek gyermekei frissítés módban. </translation>
</message>
<message>
- <source>Cannot open the requested UI file &quot;%1&quot;: %2</source>
- <translation>Nem tudja megnyitni a kért &quot;%1&quot; UI fájlt: %2</translation>
- </message>
- <message>
- <source>Cannot load the requested UI file &quot;%1&quot;: %2</source>
- <translation>Nem tudja betölteni a kért &quot;%1&quot; UI fájlt: %2</translation>
- </message>
- <message>
- <source>Cannot open the requested license file &quot;%1&quot;: %2</source>
- <translation>Nem lehet megnyitni a kért &quot;%1&quot; licencfájlt: %2</translation>
- </message>
- <message>
<source>Error</source>
<translation>Hiba</translation>
</message>
@@ -778,6 +782,30 @@
<source>There was an error loading the selected component. This component cannot be installed.</source>
<translation>Hiba történt a kiválasztott komponens betöltésekor. Ez az komponens nem telepíthető.</translation>
</message>
+ <message>
+ <source>Cannot open the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Nem tudja megnyitni a kért &quot;%1&quot; UI fájlt: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot load the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Nem tudja betölteni a kért &quot;%1&quot; UI fájlt: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot open the requested license file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Nem lehet megnyitni a kért &quot;%1&quot; licencfájlt: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
</context>
<context>
<name>QInstaller::ComponentModel</name>
@@ -857,10 +885,6 @@
<translation>Minden komponens kijelölésének a megszüntetése a fa nézetben.</translation>
</message>
<message>
- <source>&amp;Browse QBSP files</source>
- <translation>QBSP fájlok böngészése</translation>
- </message>
- <message>
<source>Select a Qt Board Support Package file to install additional content that is not directly available from the online repositories.</source>
<translation>Qt Board támogatási csomagfájl kiválasztása a további tartalom telepítéséhez, amely közvetlenül nem érhető el az online tárolókból.</translation>
</message>
@@ -893,8 +917,8 @@
<translation>Kérem válassza ki az eltávolítani kívánt komponenseket.</translation>
</message>
<message>
- <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source>
- <translation>Válassza ki a telepítendő összetevőket. Törölje a telepített összetevők kijelölését az eltávolításhoz. A már telepített összetevők nem frissülnek.</translation>
+ <source>Select the components to install. Deselect installed components to uninstall them.&lt;br&gt;Any components already installed will not be updated.</source>
+ <translation>Válassza ki a telepítendő összetevőket. Törölje a telepített összetevők kijelölését az eltávolításhoz.&lt;br&gt;A már telepített összetevők nem frissülnek.</translation>
</message>
<message>
<source>Mandatory components need to be updated first before you can select other components to update.</source>
@@ -904,6 +928,26 @@
<source>Search</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Create offline installer from selected components, instead of installing now.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Browse &amp;QBSP files</source>
+ <translation>QBSP fájlok böngészése</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">Hiba</translation>
+ </message>
</context>
<context>
<name>QInstaller::ComponentSelectionPagePrivate</name>
@@ -1193,6 +1237,10 @@ Hiba %2 betöltése közben</translation>
<source>Cannot find component for %1.</source>
<translation>Nem található komponens %1 számára.</translation>
</message>
+ <message>
+ <source>Retry count (%1) exceeded</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::Downloader</name>
@@ -1364,7 +1412,7 @@ Hiba %2 betöltése közben</translation>
<context>
<name>QInstaller::FinishedPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>%1 varázsló befejezése</translation>
</message>
<message>
@@ -1372,7 +1420,7 @@ Hiba %2 betöltése közben</translation>
<translation>Befejezett</translation>
</message>
<message>
- <source>Click %1 to exit the %2 Wizard.</source>
+ <source>Click %1 to exit the %2 Setup.</source>
<translation>Kattintson %1 gombra %2 varázslóból való kilépéshez.</translation>
</message>
<message>
@@ -1433,8 +1481,8 @@ Hiba %2 betöltése közben</translation>
<context>
<name>QInstaller::IntroductionPage</name>
<message>
- <source>Setup - %1</source>
- <translation>Beállítás - %1</translation>
+ <source>Welcome</source>
+ <translation type="unfinished"></translation>
</message>
<message>
<source>Welcome to the %1 Setup.</source>
@@ -1465,10 +1513,6 @@ Hiba %2 betöltése közben</translation>
<translation>Nincs elérhető frissítés.</translation>
</message>
<message>
- <source> Only local package management available.</source>
- <translation>Csak helyi csomagkezelés áll rendelkezésre.</translation>
- </message>
- <message>
<source>There is an important update available. Please select &apos;%1&apos; first</source>
<translation>Egy fontos frissítés áll rendelkezésre. Kérjük, válassza előbb &apos;%1&apos; -t</translation>
</message>
@@ -1519,10 +1563,6 @@ Hiba %2 betöltése közben</translation>
<source>Can not write license file &quot;%1&quot;.</source>
<translation>Nem lehet írni &quot;%1&quot; licencfájlt.</translation>
</message>
- <message>
- <source>No license files found to delete.</source>
- <translation>Nem található törlendő licencfájl.</translation>
- </message>
</context>
<context>
<name>QInstaller::LineReplaceOperation</name>
@@ -1582,14 +1622,6 @@ Hiba %2 betöltése közben</translation>
<translation>Ellenőrző összeg eltérést észlelt &quot;%1&quot; fájlnál.</translation>
</message>
<message>
- <source>Retrieving meta information from remote repository... %1/%2 </source>
- <translation>Metainformációk lekérése távoli tárolóból... %1/ %2</translation>
- </message>
- <message>
- <source>Retrieving meta information from remote repository... </source>
- <translation>Metainformációk lekérése távoli tárolóból...</translation>
- </message>
- <message>
<source>Cannot open file &quot;%1&quot; for reading: %2</source>
<translation>Nem sikerült megnyitni &quot;%1&quot; fájlt olvasásra: %2</translation>
</message>
@@ -1615,6 +1647,26 @@ Hiba %2 betöltése közben</translation>
<source>Clearing the cache directory and restarting the application may solve this.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Unknown exception during updating cache.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot open extracted file &quot;%1&quot; for reading: %2</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot open file &quot;%1&quot; for writing: %2</source>
+ <translation type="unfinished">Nem sikerült megnyitni &quot;%1&quot; fájlt írásra: %2</translation>
+ </message>
+ <message>
+ <source>Retrieving information from remote repositories...</source>
+ <translation>Információk lekérése távoli tárolóból...</translation>
+ </message>
+ <message>
+ <source>Retrieving meta information from remote repository...</source>
+ <translation>Metainformációk lekérése távoli tárolóból...</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCore</name>
@@ -1765,10 +1817,6 @@ Kívánja folytatni?</translation>
<translation>%1 telepítése nem sikerült. A komponens virtuális.</translation>
</message>
<message>
- <source>Running processes found.</source>
- <translation>Futó folyamatok találhatók.</translation>
- </message>
- <message>
<source>Cannot elevate access rights while running from command line. Please restart the application as administrator.</source>
<translation>A parancssorból történő futtatás során nem növelhetők a hozzáférési jogok. Indítsa újra az alkalmazást rendszergazdaként.</translation>
</message>
@@ -1816,6 +1864,22 @@ Kívánja folytatni?</translation>
<source>Not enough disk space to store temporary files! %1 are available, while the minimum required is %2. You may select another location for the temporary files by modifying the local cache path from the installer settings.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Cannot resolve components to uninstall.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot select alias %1. There was a problem loading this alias, so it is marked unstable and cannot be selected.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot select %1. Alias is marked virtual, meaning it cannot be selected manually.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Created installer will use %1 of disk space.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCorePrivate</name>
@@ -2042,10 +2106,6 @@ Kívánja folytatni?</translation>
<translation>Nem sikerült lekérni metaadatokat: %1</translation>
</message>
<message>
- <source>Cannot add temporary update source information.</source>
- <translation>Nem adhatók hozzá ideiglenes frissítési forrásadatok.</translation>
- </message>
- <message>
<source>Cannot find any update source information.</source>
<translation>Nem található frissítési forrás információ.</translation>
</message>
@@ -2085,6 +2145,18 @@ Kívánja folytatni?</translation>
<source>Loading component scripts...</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Alias declares name that conflicts with an existing component &quot;%1&quot;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unresolved component aliases</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cyclic dependency between aliases &quot;%1&quot; and &quot;%2&quot; detected.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerGui</name>
@@ -2188,6 +2260,18 @@ Másolja a telepítőt egy helyi meghajtóra</translation>
<source>Uninstalling</source>
<translation>Eltávolítás</translation>
</message>
+ <message>
+ <source>&amp;Create Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer for %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::ProxyCredentialsDialog</name>
@@ -2269,6 +2353,18 @@ Másolja a telepítőt egy helyi meghajtóra</translation>
<source>Ready to Update</source>
<translation>Frissítésre kész</translation>
</message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Ready to Create Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>All required information is now available to create an offline installer for selected components.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::RegisterFileTypeOperation</name>
@@ -2325,7 +2421,7 @@ Másolja a telepítőt egy helyi meghajtóra</translation>
<context>
<name>QInstaller::RestartPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>%1 telepítő varázsló befejezése</translation>
</message>
</context>
@@ -2760,6 +2856,10 @@ a megfelelő jogokkal rendelkező felhasználóként, majd kattintson az OK gomb
<source>Clear cache</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Clearing cache...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UpdateOperation</name>
@@ -2966,6 +3066,10 @@ a megfelelő jogokkal rendelkező felhasználóként, majd kattintson az OK gomb
<source>Cannot synchronize invalidated cache.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Unknown register mode selected!</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>TabController</name>
diff --git a/src/sdk/translations/ifw_it.ts b/src/sdk/translations/ifw_it.ts
index 2b9c749f1..5f08dc1a7 100644
--- a/src/sdk/translations/ifw_it.ts
+++ b/src/sdk/translations/ifw_it.ts
@@ -136,6 +136,18 @@
<source>Cannot find missing dependency &quot;%1&quot; for &quot;%2&quot;.</source>
<translation>Impossibile trovare la dipendenza mancante &quot;%1&quot; per &quot;%2&quot;.</translation>
</message>
+ <message>
+ <source>Components selected by alias &quot;%1&quot;:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Recursion detected, component alias &quot;%1&quot; already added.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Impossible dependency resolution detected. Forced install component &quot;%1&quot; would be uninstalled because its dependency &quot;%2&quot; is marked for uninstallation with reason: &quot;%3&quot;.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>Job</name>
@@ -306,6 +318,10 @@
<source>Try again</source>
<translation>Riprova</translation>
</message>
+ <message>
+ <source>Cannot download %1. Cannot create directory for &quot;%2&quot;</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>KDUpdater::LocalFileDownloader</name>
@@ -489,10 +505,6 @@
<translation>Impossibile leggere &quot;%1&quot;</translation>
</message>
<message>
- <source>Parse error in %1 at %2, %3: %4</source>
- <translation>Errore di analisi in %1 a %2, %3: %4</translation>
- </message>
- <message>
<source>Root element %1 unexpected, should be &quot;Updates&quot;.</source>
<translation>Elemento radice %1 imprevisto, dovrebbe essere &quot;Updates&quot;.</translation>
</message>
@@ -744,6 +756,10 @@
<source>Invalid content in &quot;%1&quot;.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>This may be solved by restarting the application after clearing the cache from:</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::Component</name>
@@ -752,18 +768,6 @@
<translation>I componenti non possono avere figli in modalità updater.</translation>
</message>
<message>
- <source>Cannot open the requested UI file &quot;%1&quot;: %2</source>
- <translation>Impossibile aprire il file di interfaccia utente richiesto &quot;%1&quot;: %2</translation>
- </message>
- <message>
- <source>Cannot load the requested UI file &quot;%1&quot;: %2</source>
- <translation>Impossibile caricare il file di interfaccia utente richiesto &quot;%1&quot;: %2</translation>
- </message>
- <message>
- <source>Cannot open the requested license file &quot;%1&quot;: %2</source>
- <translation>Impossibile aprire il file di licenza richiesto &quot;%1&quot;: %2</translation>
- </message>
- <message>
<source>Error</source>
<translation>Errore</translation>
</message>
@@ -783,6 +787,30 @@
<source>There was an error loading the selected component. This component cannot be installed.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Cannot open the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Impossibile aprire il file di interfaccia utente richiesto &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot load the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Impossibile caricare il file di interfaccia utente richiesto &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot open the requested license file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Impossibile aprire il file di licenza richiesto &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
</context>
<context>
<name>QInstaller::ComponentModel</name>
@@ -862,10 +890,6 @@
<translation type="unfinished"></translation>
</message>
<message>
- <source>&amp;Browse QBSP files</source>
- <translation>&amp;Sfoglia file QBSP</translation>
- </message>
- <message>
<source>Select a Qt Board Support Package file to install additional content that is not directly available from the online repositories.</source>
<translation type="unfinished"></translation>
</message>
@@ -894,41 +918,41 @@
<translation>Selezionare i componenti che si desidera disinstallare.</translation>
</message>
<message>
- <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source>
- <translation>Selezionare i componenti da installare. Deselezionare i componenti installati per disinstallarli. I componenti già installati non verranno aggiornati.</translation>
+ <source>Select the components to install. Deselect installed components to uninstall them.&lt;br&gt;Any components already installed will not be updated.</source>
+ <translation>Selezionare i componenti da installare. Deselezionare i componenti installati per disinstallarli.&lt;br&gt;I componenti già installati non verranno aggiornati.</translation>
</message>
<message>
<source>Mandatory components need to be updated first before you can select other components to update.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Alt+A</source>
- <comment>Select default components</comment>
- <translation type="unfinished">Alt+A</translation>
+ <source>Filter the enabled repository categories</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Alt+R</source>
- <comment>Reset to already installed components</comment>
- <translation type="unfinished">Alt+F</translation>
+ <source>Search</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Alt+S</source>
- <comment>Select all components</comment>
- <translation type="unfinished">Alt+S</translation>
+ <source>Create Offline Installer</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Alt+D</source>
- <comment>Deselect all components</comment>
- <translation type="unfinished">Alt+D</translation>
+ <source>Create offline installer from selected components, instead of installing now.</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Filter the enabled repository categories</source>
- <translation type="unfinished"></translation>
+ <source>Browse &amp;QBSP files</source>
+ <translation>&amp;Sfoglia file QBSP</translation>
</message>
<message>
- <source>Search</source>
+ <source>Select</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">Errore</translation>
+ </message>
</context>
<context>
<name>QInstaller::ConsumeOutputOperation</name>
@@ -1207,6 +1231,10 @@ Errore durante il caricamento di %2</translation>
<source>Total: </source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Retry count (%1) exceeded</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::Downloader</name>
@@ -1344,7 +1372,7 @@ Errore durante il caricamento di %2</translation>
<context>
<name>QInstaller::FinishedPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>Completamento della procedura guidata %1</translation>
</message>
<message>
@@ -1352,7 +1380,7 @@ Errore durante il caricamento di %2</translation>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Click %1 to exit the %2 Wizard.</source>
+ <source>Click %1 to exit the %2 Setup.</source>
<translation>Fare clic su %1 per uscire dalla procedura guidata %2.</translation>
</message>
<message>
@@ -1413,8 +1441,8 @@ Errore durante il caricamento di %2</translation>
<context>
<name>QInstaller::IntroductionPage</name>
<message>
- <source>Setup - %1</source>
- <translation>Installazione - %1</translation>
+ <source>Welcome</source>
+ <translation type="unfinished"></translation>
</message>
<message>
<source>Welcome to the %1 Setup.</source>
@@ -1445,10 +1473,6 @@ Errore durante il caricamento di %2</translation>
<translation>Nessun aggiornamento disponibile.</translation>
</message>
<message>
- <source> Only local package management available.</source>
- <translation> Disponibile solo gestione pacchetto locale.</translation>
- </message>
- <message>
<source>&amp;Quit</source>
<translation>Esci</translation>
</message>
@@ -1499,10 +1523,6 @@ Errore durante il caricamento di %2</translation>
<source>Can not write license file &quot;%1&quot;.</source>
<translation>Impossibile scrivere il file di licenza &quot;%1&quot;.</translation>
</message>
- <message>
- <source>No license files found to delete.</source>
- <translation>Nessun file di licenza da eliminare trovato.</translation>
- </message>
</context>
<context>
<name>QInstaller::LineReplaceOperation</name>
@@ -1558,14 +1578,6 @@ Errore durante il caricamento di %2</translation>
<translation>Rilevata mancata corrispondenza checksum per &quot;%1&quot;.</translation>
</message>
<message>
- <source>Retrieving meta information from remote repository... %1/%2 </source>
- <translation>Recupero delle informazioni sui metadati dal repository remoto in corso... %1/%2 </translation>
- </message>
- <message>
- <source>Retrieving meta information from remote repository... </source>
- <translation>Recupero delle informazioni sui metadati dal repository remoto in corso... </translation>
- </message>
- <message>
<source>Error while extracting archive &quot;%1&quot;: %2</source>
<translation>Errore durante l&apos;estrazione dell&apos;archivio &quot;%1&quot;: %2</translation>
</message>
@@ -1596,6 +1608,26 @@ Errore durante il caricamento di %2</translation>
<source>Clearing the cache directory and restarting the application may solve this.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Unknown exception during updating cache.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot open extracted file &quot;%1&quot; for reading: %2</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot open file &quot;%1&quot; for writing: %2</source>
+ <translation type="unfinished">Impossibile aprire il file &quot;%1&quot; per la scrittura: %2</translation>
+ </message>
+ <message>
+ <source>Retrieving information from remote repositories...</source>
+ <translation>Recupero di informazioni da repository remoti in corso...</translation>
+ </message>
+ <message>
+ <source>Retrieving meta information from remote repository...</source>
+ <translation>Recupero delle informazioni sui metadati dal repository remoto in corso...</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCore</name>
@@ -1726,10 +1758,6 @@ Continuare?</translation>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Running processes found.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
<source>Cannot elevate access rights while running from command line. Please restart the application as administrator.</source>
<translation type="unfinished"></translation>
</message>
@@ -1797,6 +1825,22 @@ Continuare?</translation>
<source>Not enough disk space to store temporary files! %1 are available, while the minimum required is %2. You may select another location for the temporary files by modifying the local cache path from the installer settings.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Cannot resolve components to uninstall.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot select alias %1. There was a problem loading this alias, so it is marked unstable and cannot be selected.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot select %1. Alias is marked virtual, meaning it cannot be selected manually.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Created installer will use %1 of disk space.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCorePrivate</name>
@@ -2003,10 +2047,6 @@ Continuare?</translation>
<translation>Impossibile recuperare le meta informazioni: %1</translation>
</message>
<message>
- <source>Cannot add temporary update source information.</source>
- <translation>Impossibile aggiungere informazioni sull&apos;origine di aggiornamento temporanea.</translation>
- </message>
- <message>
<source>Cannot find any update source information.</source>
<translation>Impossibile trovare informazioni sull&apos;origine di aggiornamento.</translation>
</message>
@@ -2067,6 +2107,18 @@ Continuare?</translation>
<source>Loading component scripts...</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Alias declares name that conflicts with an existing component &quot;%1&quot;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unresolved component aliases</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cyclic dependency between aliases &quot;%1&quot; and &quot;%2&quot; detected.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerGui</name>
@@ -2170,6 +2222,18 @@ Copiare il programma di installazione in un&apos;unità locale</translation>
<source>Uninstalling</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>&amp;Create Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer for %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::ProxyCredentialsDialog</name>
@@ -2244,6 +2308,18 @@ Copiare il programma di installazione in un&apos;unità locale</translation>
<source>Ready to Update</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Ready to Create Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>All required information is now available to create an offline installer for selected components.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::RegisterFileTypeOperation</name>
@@ -2300,7 +2376,7 @@ Copiare il programma di installazione in un&apos;unità locale</translation>
<context>
<name>QInstaller::RestartPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>Completamento dell&apos;installazione guidata di %1</translation>
</message>
</context>
@@ -2702,11 +2778,11 @@ or accept the elevation of access rights if being asked.</source>
</message>
<message>
<source>Select All</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">Seleziona tutto</translation>
</message>
<message>
<source>Deselect All</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">Deseleziona tutto</translation>
</message>
<message>
<source>The server&apos;s URL that contains a valid repository.</source>
@@ -2732,6 +2808,10 @@ or accept the elevation of access rights if being asked.</source>
<source>Clear cache</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Clearing cache...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UpdateOperation</name>
@@ -3000,6 +3080,10 @@ or accept the elevation of access rights if being asked.</source>
<source>Cannot synchronize invalidated cache.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Unknown register mode selected!</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>TabController</name>
diff --git a/src/sdk/translations/ifw_ja.ts b/src/sdk/translations/ifw_ja.ts
index 341c9680e..5152944d3 100644
--- a/src/sdk/translations/ifw_ja.ts
+++ b/src/sdk/translations/ifw_ja.ts
@@ -16,11 +16,11 @@
<name>BinaryContent</name>
<message>
<source>Cannot seek to %1 to read the operation data.</source>
- <translation>操作データを読み取るための %1 のシークができません。</translation>
+ <translation>操作データを読み取るための %1 とうファイルポジションに移動できません。</translation>
</message>
<message>
<source>Cannot seek to %1 to read the resource collection block.</source>
- <translation>リソース コレクション ブロックを読み取るための %1 のシークができません。</translation>
+ <translation>リソース コレクション ブロックを読み取るため%1 とうファイルポジションに移動できません。</translation>
</message>
<message>
<source>Cannot open meta resource %1.</source>
@@ -31,11 +31,11 @@
<name>BinaryLayout</name>
<message>
<source>Cannot seek to %1 to read the embedded meta data count.</source>
- <translation>埋め込みメタ データ数を読み取るための %1 のシークができません。</translation>
+ <translation>埋め込みメタ データ数を読み取るため%1 とうファイルポジションに移動できません。</translation>
</message>
<message>
<source>Cannot seek to %1 to read the resource collection segment.</source>
- <translation>リソース コレクション セグメントを読み取るための %1 のシークができません。</translation>
+ <translation>リソース コレクション セグメントを読み取るため %1 とうファイルポジションに移動できません。</translation>
</message>
<message>
<source>Unexpected mismatch of meta resources. Read %1, expected: %2.</source>
@@ -136,12 +136,24 @@
<source>Cannot find missing dependency &quot;%1&quot; for &quot;%2&quot;.</source>
<translation>&quot;%2&quot; の欠落した依存関係 &quot;%1&quot; が見つかりません。</translation>
</message>
+ <message>
+ <source>Impossible dependency resolution detected. Forced install component &quot;%1&quot; would be uninstalled because its dependency &quot;%2&quot; is marked for uninstallation with reason: &quot;%3&quot;.</source>
+ <translation>不可能な依存関係が検出されました。強制にインストールされる&quot;%1&quot;コンポーネントは、&quot;%1&quot;に依存する &quot;%2&quot;がアンインストールの対象ですので、アンインストールされます。&quot;%2&quot;のアンインストレーション理由は: &quot;%3&quot;。</translation>
+ </message>
+ <message>
+ <source>Components selected by alias &quot;%1&quot;:</source>
+ <translation>エイリアス &quot;%1&quot; によって選択されたコンポーネント:</translation>
+ </message>
+ <message>
+ <source>Recursion detected, component alias &quot;%1&quot; already added.</source>
+ <translation>再帰が検出されました。コンポーネント エイリアス &quot;%1&quot; がすでに追加されています。</translation>
+ </message>
</context>
<context>
<name>Job</name>
<message>
<source>Canceled</source>
- <translation>キャンセル</translation>
+ <translation>キャンセルされました</translation>
</message>
</context>
<context>
@@ -209,7 +221,7 @@
<name>KDUpdater::FileDownloader</name>
<message>
<source>Download finished.</source>
- <translation>ダウンロードが終了しました。</translation>
+ <translation>ダウンロードが完了しました。</translation>
</message>
<message>
<source>Cryptographic hashes do not match.</source>
@@ -284,7 +296,7 @@
</message>
<message>
<source>Secure Connection Failed</source>
- <translation>セキュリティで保護された接続に失敗しました</translation>
+ <translation>セキュアな接続が失敗しました</translation>
</message>
<message>
<source>There was an error during connection to: %1.</source>
@@ -292,7 +304,7 @@
</message>
<message>
<source>This could be a problem with the server&apos;s configuration, or it could be someone trying to impersonate the server.</source>
- <translation>サーバーの構成に問題があるか、誰かがサーバーを偽装しようとした可能性があります。</translation>
+ <translation>サーバーの構成に問題があるか、誰かがサーバーを偽装しようとしている可能性があります。</translation>
</message>
<message>
<source>If you have connected to this server successfully in the past or trust this server, the error may be temporary and you can try again.</source>
@@ -302,6 +314,10 @@
<source>Try again</source>
<translation>再試行</translation>
</message>
+ <message>
+ <source>Cannot download %1. Cannot create directory for &quot;%2&quot;</source>
+ <translation>%1をダウンロードできません。&quot;%2&quot;のためディレクトリを作成することができません。</translation>
+ </message>
</context>
<context>
<name>KDUpdater::LocalFileDownloader</name>
@@ -421,11 +437,11 @@
</message>
<message>
<source>%1 cannot be paused</source>
- <translation>%1 を解析できません</translation>
+ <translation>%1 を一時停止できません</translation>
</message>
<message>
<source>Cannot pause task %1</source>
- <translation>タスク %1 を解析できません</translation>
+ <translation>タスク&#x3000;%1 を一時停止できません</translation>
</message>
<message>
<source>Cannot resume task %1</source>
@@ -484,10 +500,6 @@
<translation>&quot;%1&quot; を読み取れません</translation>
</message>
<message>
- <source>Parse error in %1 at %2, %3: %4</source>
- <translation>%2、%3 で %1 のエラーを解析します: %4</translation>
- </message>
- <message>
<source>Root element %1 unexpected, should be &quot;Updates&quot;.</source>
<translation>ルート エレメント %1 は予期しないものです。&quot;Updates&quot; でなければなりません。</translation>
</message>
@@ -739,6 +751,10 @@
<source>Invalid content in &quot;%1&quot;.</source>
<translation>&quot;%1&quot; に無効なコンテンツがあります。</translation>
</message>
+ <message>
+ <source>This may be solved by restarting the application after clearing the cache from:</source>
+ <translation>以下のキャッシュを削除した上でアプリケーションを再起動することで問題が解決することもあります。</translation>
+ </message>
</context>
<context>
<name>QInstaller::Component</name>
@@ -747,18 +763,6 @@
<translation>コンポーネントは、アップデーター モードで子を持つことができません。</translation>
</message>
<message>
- <source>Cannot open the requested UI file &quot;%1&quot;: %2</source>
- <translation>要求された UI ファイル &quot;%1&quot; を開けません: %2</translation>
- </message>
- <message>
- <source>Cannot load the requested UI file &quot;%1&quot;: %2</source>
- <translation>要求された UI ファイル &quot;%1&quot; を読み込めません: %2</translation>
- </message>
- <message>
- <source>Cannot open the requested license file &quot;%1&quot;: %2</source>
- <translation>要求されたライセンス ファイル &quot;%1&quot; を開けません: %2</translation>
- </message>
- <message>
<source>Error</source>
<translation>エラー</translation>
</message>
@@ -778,6 +782,30 @@
<source>There was an error loading the selected component. This component cannot be installed.</source>
<translation>選択したコンポーネントの読み込み中にエラーが発生しました。このコンポーネントをインストールできません。</translation>
</message>
+ <message>
+ <source>Cannot open the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>要求された UI ファイル &quot;%1&quot; を開けません: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot load the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>要求された UI ファイル &quot;%1&quot; を読み込めません: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot open the requested license file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>要求されたライセンス ファイル &quot;%1&quot; を開けません: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
</context>
<context>
<name>QInstaller::ComponentModel</name>
@@ -857,10 +885,6 @@
<translation>ツリー表示ですべてのコンポーネントの選択を解除します。</translation>
</message>
<message>
- <source>&amp;Browse QBSP files</source>
- <translation>QBSP ファイルの参照 (&amp;B)</translation>
- </message>
- <message>
<source>Select a Qt Board Support Package file to install additional content that is not directly available from the online repositories.</source>
<translation>Qt Board Support Packageファイルを選択し、オンラインリポジトリから直接取得できない追加のコンテンツをインストールします。</translation>
</message>
@@ -893,7 +917,7 @@
<translation>アンインストールするコンポーネントを選択してください。</translation>
</message>
<message>
- <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source>
+ <source>Select the components to install. Deselect installed components to uninstall them.&lt;br&gt;Any components already installed will not be updated.</source>
<translation>インストールするコンポーネントを選択します。 コンポーネントをアンインストールするには、インストール済みのコンポーネントを選択解除します。 すでにインストールされているコンポーネントは更新されません。</translation>
</message>
<message>
@@ -904,6 +928,26 @@
<source>Search</source>
<translation>検索</translation>
</message>
+ <message>
+ <source>Browse &amp;QBSP files</source>
+ <translation>QBSPファイルを検索</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>選択</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>エラー</translation>
+ </message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation>オフラインインストーラーの作成</translation>
+ </message>
+ <message>
+ <source>Create offline installer from selected components, instead of installing now.</source>
+ <translation>今すぐインストールするのではなく、選択したコンポーネントでオフライン インストーラーを作成します。</translation>
+ </message>
</context>
<context>
<name>QInstaller::ConsumeOutputOperation</name>
@@ -1172,11 +1216,15 @@ Error while loading %2</source>
</message>
<message>
<source>Archive: </source>
- <translation type="unfinished"></translation>
+ <translation>アーカイブ</translation>
</message>
<message>
<source>Total: </source>
- <translation type="unfinished"></translation>
+ <translation>合計</translation>
+ </message>
+ <message>
+ <source>Retry count (%1) exceeded</source>
+ <translation>再試行回数 (%1) を超えました</translation>
</message>
</context>
<context>
@@ -1311,7 +1359,7 @@ Error while loading %2</source>
<context>
<name>QInstaller::FinishedPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>%1 ウィザードを完了しています</translation>
</message>
<message>
@@ -1319,7 +1367,7 @@ Error while loading %2</source>
<translation>終了</translation>
</message>
<message>
- <source>Click %1 to exit the %2 Wizard.</source>
+ <source>Click %1 to exit the %2 Setup.</source>
<translation>%2 ウィザードを終了するには、%1 をクリックします。</translation>
</message>
<message>
@@ -1380,8 +1428,8 @@ Error while loading %2</source>
<context>
<name>QInstaller::IntroductionPage</name>
<message>
- <source>Setup - %1</source>
- <translation>設定 - %1</translation>
+ <source>Welcome</source>
+ <translation>ようこそ</translation>
</message>
<message>
<source>Welcome to the %1 Setup.</source>
@@ -1412,16 +1460,12 @@ Error while loading %2</source>
<translation>利用できる更新はありません。</translation>
</message>
<message>
- <source> Only local package management available.</source>
- <translation>ローカル パッケージ管理のみ利用可能です。</translation>
- </message>
- <message>
<source>&amp;Quit</source>
<translation>中止</translation>
</message>
<message>
<source>There is an important update available. Please select &apos;%1&apos; first</source>
- <translation type="unfinished"></translation>
+ <translation>重要な更新が見つかりました。まず&apos;%1&apos; を選択してください</translation>
</message>
</context>
<context>
@@ -1466,10 +1510,6 @@ Error while loading %2</source>
<source>Can not write license file &quot;%1&quot;.</source>
<translation>ライセンス ファイル &quot;%1&quot; に書き込めません</translation>
</message>
- <message>
- <source>No license files found to delete.</source>
- <translation>削除対象のライセンス ファイルが見つかりません。</translation>
- </message>
</context>
<context>
<name>QInstaller::LineReplaceOperation</name>
@@ -1529,14 +1569,6 @@ Error while loading %2</source>
<translation>&quot;%1&quot; でチェックサムの不一致が検出されました。</translation>
</message>
<message>
- <source>Retrieving meta information from remote repository... %1/%2 </source>
- <translation>リモート リポジトリからメタ情報を取得しています... %1/%2 </translation>
- </message>
- <message>
- <source>Retrieving meta information from remote repository... </source>
- <translation>リモート リポジトリからメタ情報を取得しています... </translation>
- </message>
- <message>
<source>Error while extracting archive &quot;%1&quot;: %2</source>
<translation>アーカイブ &quot;%1&quot; の抽出中にエラーが発生しました: %2</translation>
</message>
@@ -1562,6 +1594,26 @@ Error while loading %2</source>
<source>Clearing the cache directory and restarting the application may solve this.</source>
<translation>キャッシュディレクトリを空にしてアプリケーションを再起動すると、この問題が解決する場合があります。</translation>
</message>
+ <message>
+ <source>Unknown exception during updating cache.</source>
+ <translation>キャッシュの更新中に不明な例外が発生しました。</translation>
+ </message>
+ <message>
+ <source>Cannot open extracted file &quot;%1&quot; for reading: %2</source>
+ <translation>読み取り用の、解凍されたファイル &quot;%1&quot; を開けません:%2</translation>
+ </message>
+ <message>
+ <source>Cannot open file &quot;%1&quot; for writing: %2</source>
+ <translation>書き込み用の、ファイル &quot;%1&quot; を開けません:%2</translation>
+ </message>
+ <message>
+ <source>Retrieving information from remote repositories...</source>
+ <translation>リモート リポジトリから情報を取得しています...</translation>
+ </message>
+ <message>
+ <source>Retrieving meta information from remote repository...</source>
+ <translation>リモート リポジトリからメタ情報を取得しています... </translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCore</name>
@@ -1700,10 +1752,6 @@ Do you want to continue?</source>
<translation>%1 をインストールできません。コンポーネントが見つかりません。</translation>
</message>
<message>
- <source>Running processes found.</source>
- <translation>実行中のプロセスが見つかりました。</translation>
- </message>
- <message>
<source>Cannot elevate access rights while running from command line. Please restart the application as administrator.</source>
<translation>コマンドラインから実行しているときはアクセス権限を昇格できません。管理者としてアプリケーションを再起動してください。</translation>
</message>
@@ -1749,7 +1797,7 @@ Do you want to continue?</source>
</message>
<message>
<source>The estimated installer size %1 would exceed the supported executable size limit of %2. The application may not be able to run.</source>
- <translation type="unfinished"></translation>
+ <translation>インストーラの推定サイズ %1 は、実行可能ファイルのサイズ制限 %2 を超えています。アプリケーションが実行できない場合があります。</translation>
</message>
<message>
<source>Components about to be removed:</source>
@@ -1763,6 +1811,22 @@ Do you want to continue?</source>
<source>Not enough disk space to store temporary files! %1 are available, while the minimum required is %2. You may select another location for the temporary files by modifying the local cache path from the installer settings.</source>
<translation>時ファイルを保存するのに十分なディスク容量がありません!&#x3000;%1 が利用可能ですが、必要な最小値は %2 です。 インストーラー設定からローカル キャッシュ パスを変更することにより、一時ファイルの別の場所を選択できます。</translation>
</message>
+ <message>
+ <source>Cannot resolve components to uninstall.</source>
+ <translation>アンインストール対象のコンポーネントを解決できません。</translation>
+ </message>
+ <message>
+ <source>Cannot select alias %1. There was a problem loading this alias, so it is marked unstable and cannot be selected.</source>
+ <translation>エイリアス %1 を選択できません。エイリアスのロード中に問題が発生したため、不安定と記され、選択できません。</translation>
+ </message>
+ <message>
+ <source>Cannot select %1. Alias is marked virtual, meaning it cannot be selected manually.</source>
+ <translation>%1を選択できません。エイリアスは仮想として記され、手動で選択できません。</translation>
+ </message>
+ <message>
+ <source>Created installer will use %1 of disk space.</source>
+ <translation>作成されるインストーラーはディスク容量の %1 を使用します。</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCorePrivate</name>
@@ -1991,10 +2055,6 @@ Do you want to continue?</source>
<translation>メタ情報を取得できません: %1</translation>
</message>
<message>
- <source>Cannot add temporary update source information.</source>
- <translation>一時的な更新ソース情報を追加できません。</translation>
- </message>
- <message>
<source>Cannot find any update source information.</source>
<translation>更新ソース情報が見つかりません。</translation>
</message>
@@ -2034,6 +2094,18 @@ Do you want to continue?</source>
<source>Loading component scripts...</source>
<translation>コンポーネント スクリプトを読み込んでいます...</translation>
</message>
+ <message>
+ <source>Alias declares name that conflicts with an existing component &quot;%1&quot;</source>
+ <translation>エイリアスの名前が既存のコンポーネント &quot;%1&quot;&#x3000;の名前と対立しまていす。</translation>
+ </message>
+ <message>
+ <source>Unresolved component aliases</source>
+ <translation>コンポーネントエイリアスが未解決です</translation>
+ </message>
+ <message>
+ <source>Cyclic dependency between aliases &quot;%1&quot; and &quot;%2&quot; detected.</source>
+ <translation>エイリアス &quot;%1&quot; と &quot;%2&quot;&#x3000;の間の循環依存関係が検出されました。</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerGui</name>
@@ -2137,6 +2209,18 @@ Please copy the installer to a local drive</source>
<source>Uninstalling</source>
<translation>アンインストールしています</translation>
</message>
+ <message>
+ <source>&amp;Create Offline Installer</source>
+ <translation>&amp;オフラインインストーラーを作成</translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer for %1</source>
+ <translation>%1 のオフラインインストーラーを作成しています</translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer</source>
+ <translation>オフラインインストーラーを作成しています</translation>
+ </message>
</context>
<context>
<name>QInstaller::ProxyCredentialsDialog</name>
@@ -2211,6 +2295,18 @@ Please copy the installer to a local drive</source>
<source>Ready to Update</source>
<translation>更新の準備ができました</translation>
</message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation>オフラインインストーラーを作成</translation>
+ </message>
+ <message>
+ <source>Ready to Create Offline Installer</source>
+ <translation>オフラインインストーラーの準備ができました</translation>
+ </message>
+ <message>
+ <source>All required information is now available to create an offline installer for selected components.</source>
+ <translation>選択したコンポーネントのオフラインインストーラーを作成するために準備が整っています</translation>
+ </message>
</context>
<context>
<name>QInstaller::RegisterFileTypeOperation</name>
@@ -2267,7 +2363,7 @@ Please copy the installer to a local drive</source>
<context>
<name>QInstaller::RestartPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>%1 設定ウィザードを完了しています</translation>
</message>
</context>
@@ -2545,7 +2641,7 @@ or accept the elevation of access rights if being asked.</source>
</message>
<message>
<source>Categories</source>
- <translation type="unfinished">カテゴリを選択</translation>
+ <translation>カテゴリを選択</translation>
</message>
</context>
<context>
@@ -2702,6 +2798,10 @@ or accept the elevation of access rights if being asked.</source>
<source>Clear cache</source>
<translation>キャッシュの消去</translation>
</message>
+ <message>
+ <source>Clearing cache...</source>
+ <translation>キャッシュを消去しています…</translation>
+ </message>
</context>
<context>
<name>UpdateOperation</name>
@@ -2762,7 +2862,7 @@ or accept the elevation of access rights if being asked.</source>
</message>
<message>
<source>Information</source>
- <translation type="unfinished">コンポーネント情報</translation>
+ <translation>コンポーネント情報</translation>
</message>
</context>
<context>
@@ -2799,7 +2899,7 @@ or accept the elevation of access rights if being asked.</source>
<name>QInstaller::ExtractArchiveOperation::Worker</name>
<message>
<source>Could not create handler object for archive &quot;%1&quot;: &quot;%2&quot;.</source>
- <translation type="unfinished"></translation>
+ <translation>アーカイブ &quot;%1&quot; のハンドラ オブジェクトを作成できませんでした: &quot;%2&quot;。</translation>
</message>
<message>
<source>Cannot open archive &quot;%1&quot; for reading: %2</source>
@@ -2968,6 +3068,10 @@ or accept the elevation of access rights if being asked.</source>
<source>Cannot synchronize invalidated cache.</source>
<translation>無効化されたキャッシュを同期できません。</translation>
</message>
+ <message>
+ <source>Unknown register mode selected!</source>
+ <translation>不明な登録モードが選択されました!</translation>
+ </message>
</context>
<context>
<name>TabController</name>
diff --git a/src/sdk/translations/ifw_ko.ts b/src/sdk/translations/ifw_ko.ts
index be96480d9..39bd1ff85 100644
--- a/src/sdk/translations/ifw_ko.ts
+++ b/src/sdk/translations/ifw_ko.ts
@@ -232,6 +232,10 @@
<source>Clear cache</source>
<translation>캐시 모두 삭제</translation>
</message>
+ <message>
+ <source>Clearing cache...</source>
+ <translation>캐시 삭제 중...</translation>
+ </message>
</context>
<context>
<name>QInstaller</name>
@@ -343,6 +347,10 @@
<source>The specified module could not be found.</source>
<translation>지정된 모듈을 찾을 수 없습니다.</translation>
</message>
+ <message>
+ <source>This may be solved by restarting the application after clearing the cache from:</source>
+ <translation>캐시를 삭제한 후에 애플리케이션을 재시작하면 해결될 수 있습니다.</translation>
+ </message>
</context>
<context>
<name>QObject</name>
@@ -470,18 +478,6 @@
<translation>업데이터 모드에서는 구성요소에 하위 요소가 있으면 안 됩니다.</translation>
</message>
<message>
- <source>Cannot open the requested UI file &quot;%1&quot;: %2</source>
- <translation>요청된 UI 파일(&quot;%1&quot;)을 열 수 없음: %2</translation>
- </message>
- <message>
- <source>Cannot load the requested UI file &quot;%1&quot;: %2</source>
- <translation>요청된 UI 파일(&quot;%1&quot;)을 로드할 수 없음: %2</translation>
- </message>
- <message>
- <source>Cannot open the requested license file &quot;%1&quot;: %2</source>
- <translation>요청된 라이선스 파일(&quot;%1&quot;)을 열 수 없음: %2</translation>
- </message>
- <message>
<source>Error</source>
<translation>오류</translation>
</message>
@@ -501,6 +497,30 @@
<source>There was an error loading the selected component. This component cannot be installed.</source>
<translation>선택한 구성요소를 로드하는 중에 오류가 발생했습니다. 이 구성요소를 설치할 수 없습니다.</translation>
</message>
+ <message>
+ <source>Cannot open the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>요청된 UI 파일(&quot;%1&quot;)을 열 수 없음: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot load the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>요청된 UI 파일(&quot;%1&quot;)을 로드할 수 없음: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot open the requested license file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>요청된 라이선스 파일(&quot;%1&quot;)을 열 수 없음: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
</context>
<context>
<name>QInstaller::ComponentModel</name>
@@ -580,10 +600,6 @@
<translation>트리 보기에서 모든 구성요소를 선택 해제합니다.</translation>
</message>
<message>
- <source>&amp;Browse QBSP files</source>
- <translation>QBSP 파일 탐색(&amp;B)</translation>
- </message>
- <message>
<source>Select a Qt Board Support Package file to install additional content that is not directly available from the online repositories.</source>
<translation>QBSP(Qt Board Support Package) 파일을 선택하여 온라인 저장소에서 직접 사용할 수 없는 추가 콘텐츠를 설치합니다.</translation>
</message>
@@ -616,7 +632,7 @@
<translation>설치 제거하려는 구성요소를 선택하십시오.</translation>
</message>
<message>
- <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source>
+ <source>Select the components to install. Deselect installed components to uninstall them.&lt;br&gt;Any components already installed will not be updated.</source>
<translation>설치할 구성요소를 선택하십시오. 설치 제거할 설치된 구성요소를 선택 해제하십시오. 이미 설치된 모든 구성요소는 업데이트되지 않습니다.</translation>
</message>
<message>
@@ -627,6 +643,26 @@
<source>Search</source>
<translation>검색</translation>
</message>
+ <message>
+ <source>Browse &amp;QBSP files</source>
+ <translation>QBSP 파일 탐색(&amp;Q)</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>선택</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>오류</translation>
+ </message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation>오프라인 설치 프로그램 생성합니다.</translation>
+ </message>
+ <message>
+ <source>Create offline installer from selected components, instead of installing now.</source>
+ <translation>지금 설치하지 않고 선택된 구성요소들로 부터 오프라인 설치 프로그램을 생성합니다.</translation>
+ </message>
</context>
<context>
<name>QInstaller::ComponentSelectionPagePrivate</name>
@@ -839,14 +875,6 @@
<translation>다운로드 오류</translation>
</message>
<message>
- <source>Hash verification while downloading failed. This is a temporary error, please retry.</source>
- <translation>다운로드 중에 해시를 검증하지 못했습니다. 일시적인 오류이니 다시 시도하십시오.</translation>
- </message>
- <message>
- <source>Cannot verify Hash</source>
- <translation>해시를 검증할 수 없음</translation>
- </message>
- <message>
<source>Cannot download archive %1: %2</source>
<translation>%1 아카이브를 다운로드할 수 없음: %2</translation>
</message>
@@ -916,6 +944,28 @@ Error while loading %2</source>
<source>Total: </source>
<translation>총계:</translation>
</message>
+ <message>
+ <source>Retry count (%1) exceeded</source>
+ <translation>재시도 회수(%1) 초과</translation>
+ </message>
+ <message>
+ <source>Hash verification while downloading failed. This is a temporary error, please retry.
+
+Expected: %1
+Downloaded: %2</source>
+ <translation>다운로드 중에 해시를 검증하지 못했습니다. 일시적인 오류이니 다시 시도하십시오.
+
+예상 해시값: %1
+다운로드 해시값: %2</translation>
+ </message>
+ <message>
+ <source>Cannot verify Hash
+Expected: %1
+Downloaded: %2</source>
+ <translation>해시를 검증할 수 없음
+예상 해시값: %1
+다운로드 해시값: %2</translation>
+ </message>
</context>
<context>
<name>QInstaller::Downloader</name>
@@ -1117,6 +1167,18 @@ Error while loading %2</source>
<source>Cannot find missing dependency &quot;%1&quot; for &quot;%2&quot;.</source>
<translation>&quot;%2&quot;에 대한 누락된 종속성 &quot;%1&quot;을(를) 찾을 수 없습니다.</translation>
</message>
+ <message>
+ <source>Impossible dependency resolution detected. Forced install component &quot;%1&quot; would be uninstalled because its dependency &quot;%2&quot; is marked for uninstallation with reason: &quot;%3&quot;.</source>
+ <translation>해결할 수 없는 종속성 문제가 발생. 설치된 구성 요소 &quot;%1&quot;이(가) 종속성 &quot;%2&quot;(으)로 설정되어 제거됩니다.</translation>
+ </message>
+ <message>
+ <source>Components selected by alias &quot;%1&quot;:</source>
+ <translation>별칭 &quot;%1&quot;으로 선택된 구성요소.</translation>
+ </message>
+ <message>
+ <source>Recursion detected, component alias &quot;%1&quot; already added.</source>
+ <translation>반복이 감지됨, 별칭 &quot;%1&quot;가 이미 추가됨.</translation>
+ </message>
</context>
<context>
<name>QInstaller::InstallIconsOperation</name>
@@ -1276,10 +1338,6 @@ Error while loading %2</source>
<source>Can not write license file &quot;%1&quot;.</source>
<translation>&quot;%1&quot; 라이선스 파일을 쓸 수 없습니다.</translation>
</message>
- <message>
- <source>No license files found to delete.</source>
- <translation>삭제할 라이선스 파일을 찾을 수 없습니다.</translation>
- </message>
</context>
<context>
<name>QInstaller::LineReplaceOperation</name>
@@ -1339,14 +1397,6 @@ Error while loading %2</source>
<translation>&quot;%1&quot;에 대한 체크섬 불일치가 감지되었습니다.</translation>
</message>
<message>
- <source>Retrieving meta information from remote repository... %1/%2 </source>
- <translation>원격 저장소에서 메타 정보 검색 중... %1/%2 </translation>
- </message>
- <message>
- <source>Retrieving meta information from remote repository... </source>
- <translation>원격 저장소에서 메타 정보 검색 중... </translation>
- </message>
- <message>
<source>Error while extracting archive &quot;%1&quot;: %2</source>
<translation>자료 보관소 &quot;%1&quot; 추출 중에 오류 발생: %2</translation>
</message>
@@ -1372,6 +1422,26 @@ Error while loading %2</source>
<source>Clearing the cache directory and restarting the application may solve this.</source>
<translation>캐시 디렉터리를 모두 삭제하고 애플리케이션을 다시 시작하면 문제를 해결할 수 있습니다.</translation>
</message>
+ <message>
+ <source>Unknown exception during updating cache.</source>
+ <translation>캐시 업데이트 도중 알수 없는 예외 발생</translation>
+ </message>
+ <message>
+ <source>Cannot open extracted file &quot;%1&quot; for reading: %2</source>
+ <translation>&quot;%1&quot; 파일을 읽기 위해 열 수 없음: %2</translation>
+ </message>
+ <message>
+ <source>Cannot open file &quot;%1&quot; for writing: %2</source>
+ <translation>&quot;%1&quot; 파일을 쓰기 위해 열 수 없음: %2</translation>
+ </message>
+ <message>
+ <source>Retrieving information from remote repositories...</source>
+ <translation>원격 저장소에서 정보를 검색하는 중...</translation>
+ </message>
+ <message>
+ <source>Retrieving meta information from remote repository...</source>
+ <translation>원격 저장소에서 메타 정보 검색 중...</translation>
+ </message>
</context>
<context>
<name>QInstaller::FileTaskObserver</name>
@@ -1569,10 +1639,6 @@ Do you want to continue?</source>
<translation>%1을(를) 설치할 수 없습니다. 가상 구성요소입니다.</translation>
</message>
<message>
- <source>Running processes found.</source>
- <translation>실행 중인 프로세스를 찾았습니다.</translation>
- </message>
- <message>
<source>Cannot elevate access rights while running from command line. Please restart the application as administrator.</source>
<translation>명령줄에서 실행할 때 접근 원한을 상승시킬 수 없습니다. 관리자로서 애플리케이션을 재시작하십시오.</translation>
</message>
@@ -1620,6 +1686,22 @@ Do you want to continue?</source>
<source>Not enough disk space to store temporary files! %1 are available, while the minimum required is %2. You may select another location for the temporary files by modifying the local cache path from the installer settings.</source>
<translation>디스크 공간이 부족하여 임시 파일을 저장할 수 없습니다. %1은(는) 사용 가능하지만 최소한 %2이(가) 필요합니다. 설치 프로그램 설정에서 로컬 캐시 경로를 수정하여 임시 파일의 다른 위치를 선택할 수 있습니다.</translation>
</message>
+ <message>
+ <source>Cannot resolve components to uninstall.</source>
+ <translation>구성 요소들의 설치 제거를 해결 할 수 없습니다.</translation>
+ </message>
+ <message>
+ <source>Cannot select alias %1. There was a problem loading this alias, so it is marked unstable and cannot be selected.</source>
+ <translation>별칭 %1을 선택할 수 없습니다. 이 명칭을 불러오는 데 문제가 발생해 불안정한 것으로 설정되며 선택할 수 없습니다.</translation>
+ </message>
+ <message>
+ <source>Cannot select %1. Alias is marked virtual, meaning it cannot be selected manually.</source>
+ <translation>%1을 선택할 수 없습니다. 명칭이 가상(virtual)로 설정되어 있으며 이는 수동으로 선택될 수 없습니다.</translation>
+ </message>
+ <message>
+ <source>Created installer will use %1 of disk space.</source>
+ <translation>생성된 설치 프로그램이 %1 디스크 공간을 사용할 것입니다.</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCorePrivate</name>
@@ -1848,10 +1930,6 @@ Do you want to continue?</source>
<translation>메타 정보를 검색할 수 없음: %1</translation>
</message>
<message>
- <source>Cannot add temporary update source information.</source>
- <translation>임시 업데이트 소스 정보를 추가할 수 없습니다.</translation>
- </message>
- <message>
<source>Cannot find any update source information.</source>
<translation>어떠한 업데이트 소스 정보도 추가할 수 없습니다.</translation>
</message>
@@ -1891,6 +1969,18 @@ Do you want to continue?</source>
<source>Loading component scripts...</source>
<translation>구성요소 스크립트를 불러오는 중...</translation>
</message>
+ <message>
+ <source>Alias declares name that conflicts with an existing component &quot;%1&quot;</source>
+ <translation>별칭이 존재하는 구성요소 &quot;%1&quot;와 충돌하는 이름을 정의합니다.</translation>
+ </message>
+ <message>
+ <source>Unresolved component aliases</source>
+ <translation>해결되지 않은 구성 요소 별칭들</translation>
+ </message>
+ <message>
+ <source>Cyclic dependency between aliases &quot;%1&quot; and &quot;%2&quot; detected.</source>
+ <translation>별칭들 &quot;%1&quot;와 &quot;%2&quot; 사이에 순환 의존성 발견됨.</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerGui</name>
@@ -1948,8 +2038,8 @@ Please copy the installer to a local drive</source>
<context>
<name>QInstaller::IntroductionPage</name>
<message>
- <source>Setup - %1</source>
- <translation>설정 - %1</translation>
+ <source>Welcome</source>
+ <translation>환영</translation>
</message>
<message>
<source>Welcome to the %1 Setup.</source>
@@ -1980,10 +2070,6 @@ Please copy the installer to a local drive</source>
<translation>사용 가능한 업데이트가 없습니다.</translation>
</message>
<message>
- <source> Only local package management available.</source>
- <translation> 로컬 패키지 관리만 가능합니다.</translation>
- </message>
- <message>
<source>&amp;Quit</source>
<translation>종료(&amp;Q)</translation>
</message>
@@ -2101,6 +2187,18 @@ Please copy the installer to a local drive</source>
<source>Ready to Update</source>
<translation>업데이트 준비 완료</translation>
</message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation>오프라인 설치 프로그램을 생성합니다.</translation>
+ </message>
+ <message>
+ <source>Ready to Create Offline Installer</source>
+ <translation>오프라인 설치 프로그램을 생성하기 위해 준비합니다.</translation>
+ </message>
+ <message>
+ <source>All required information is now available to create an offline installer for selected components.</source>
+ <translation>선택된 구성요소들에 대한 오프라인 설치 프로그램을 생성하기 위한 모든 필요한 정보가 사용 가능합니다</translation>
+ </message>
</context>
<context>
<name>QInstaller::PerformInstallationPage</name>
@@ -2140,11 +2238,23 @@ Please copy the installer to a local drive</source>
<source>Uninstalling</source>
<translation>설치 제거 중</translation>
</message>
+ <message>
+ <source>&amp;Create Offline Installer</source>
+ <translation>오프라인 설치 프로그램을 생성합니다.</translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer for %1</source>
+ <translation>%1에 대한 오프라인 설치 프로그램을 생성하는 중</translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer</source>
+ <translation>오프라인 설치 프로그램을 생성하는 중</translation>
+ </message>
</context>
<context>
<name>QInstaller::FinishedPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>%1 마법사 완료 중</translation>
</message>
<message>
@@ -2152,7 +2262,7 @@ Please copy the installer to a local drive</source>
<translation>완료됨</translation>
</message>
<message>
- <source>Click %1 to exit the %2 Wizard.</source>
+ <source>Click %1 to exit the %2 Setup.</source>
<translation>%2 마법사를 종료하려면 %1을(를) 클릭하십시오.</translation>
</message>
<message>
@@ -2171,7 +2281,7 @@ Please copy the installer to a local drive</source>
<context>
<name>QInstaller::RestartPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>%1 설정 마법사 완료 중</translation>
</message>
</context>
@@ -2490,6 +2600,10 @@ or accept the elevation of access rights if being asked.</source>
<source>Try again</source>
<translation>다시 시도하기</translation>
</message>
+ <message>
+ <source>Cannot download %1. Cannot create directory for &quot;%2&quot;</source>
+ <translation>%1을(를) 다운로드 할 수 없음. &quot;%2&quot;을(를) 위한 디렉터리를 생성할 수 없음.</translation>
+ </message>
</context>
<context>
<name>Job</name>
@@ -2760,10 +2874,6 @@ or accept the elevation of access rights if being asked.</source>
<translation>&quot;%1&quot;을(를) 읽을 수 없음</translation>
</message>
<message>
- <source>Parse error in %1 at %2, %3: %4</source>
- <translation>%2의 %1에서 파싱 오류 발생, %3: %4</translation>
- </message>
- <message>
<source>Root element %1 unexpected, should be &quot;Updates&quot;.</source>
<translation>%1 루트 요소는 예상하지 못했습니다. &apos;Updates&apos;여야 합니다.</translation>
</message>
@@ -2968,6 +3078,10 @@ or accept the elevation of access rights if being asked.</source>
<source>Cannot synchronize invalidated cache.</source>
<translation>무효화된 캐시를 동기화할 수 없습니다.</translation>
</message>
+ <message>
+ <source>Unknown register mode selected!</source>
+ <translation>알 수 없는 등록 방법이 사용됨!</translation>
+ </message>
</context>
<context>
<name>TabController</name>
diff --git a/src/sdk/translations/ifw_pl.ts b/src/sdk/translations/ifw_pl.ts
index 2b7a721fe..572ea5ddc 100644
--- a/src/sdk/translations/ifw_pl.ts
+++ b/src/sdk/translations/ifw_pl.ts
@@ -136,6 +136,18 @@
<source>Cannot find missing dependency &quot;%1&quot; for &quot;%2&quot;.</source>
<translation>Nie można znaleźć brakującej zależności &quot;%1&quot; dla &quot;%2&quot;.</translation>
</message>
+ <message>
+ <source>Components selected by alias &quot;%1&quot;:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Recursion detected, component alias &quot;%1&quot; already added.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Impossible dependency resolution detected. Forced install component &quot;%1&quot; would be uninstalled because its dependency &quot;%2&quot; is marked for uninstallation with reason: &quot;%3&quot;.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>Job</name>
@@ -310,6 +322,10 @@
<source>Try again</source>
<translation>Spróbuj ponownie</translation>
</message>
+ <message>
+ <source>Cannot download %1. Cannot create directory for &quot;%2&quot;</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>KDUpdater::LocalFileDownloader</name>
@@ -494,10 +510,6 @@
<translation>Nie można odczytać &quot;%1&quot;</translation>
</message>
<message>
- <source>Parse error in %1 at %2, %3: %4</source>
- <translation>Błąd analizy w %1 przy %2, %3: %4</translation>
- </message>
- <message>
<source>Root element %1 unexpected, should be &quot;Updates&quot;.</source>
<translation>Nieoczekiwany element główny %1, powinno być &quot;Aktualizacje&quot;.</translation>
</message>
@@ -749,6 +761,10 @@
<source>Invalid content in &quot;%1&quot;.</source>
<translation>Nieprawidłowa zawartość w &quot;%1&quot;.</translation>
</message>
+ <message>
+ <source>This may be solved by restarting the application after clearing the cache from:</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::Component</name>
@@ -757,18 +773,6 @@
<translation>Elementy nie mogą mieć elementów podrzędnych w trybie programu aktualizującego.</translation>
</message>
<message>
- <source>Cannot open the requested UI file &quot;%1&quot;: %2</source>
- <translation>Nie można otworzyć żądanego pliku interfejsu użytkownika &quot;%1&quot;: %2</translation>
- </message>
- <message>
- <source>Cannot load the requested UI file &quot;%1&quot;: %2</source>
- <translation>Nie można wczytać żądanego pliku interfejsu użytkownika &quot;%1&quot;: %2</translation>
- </message>
- <message>
- <source>Cannot open the requested license file &quot;%1&quot;: %2</source>
- <translation>Nie można otworzyć żądanego pliku licencji &quot;%1&quot;: %2</translation>
- </message>
- <message>
<source>Error</source>
<translation>Błąd</translation>
</message>
@@ -788,6 +792,30 @@
<source>There was an error loading the selected component. This component cannot be installed.</source>
<translation>Podczas ładowania wybranego komponentu wystąpił błąd. Nie można zainstalować tego składnika.</translation>
</message>
+ <message>
+ <source>Cannot open the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Nie można otworzyć żądanego pliku interfejsu użytkownika &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot load the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Nie można wczytać żądanego pliku interfejsu użytkownika &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot open the requested license file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Nie można otworzyć żądanego pliku licencji &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
</context>
<context>
<name>QInstaller::ComponentModel</name>
@@ -867,10 +895,6 @@
<translation>Odznacz wszystkie komponenty.</translation>
</message>
<message>
- <source>&amp;Browse QBSP files</source>
- <translation>&amp;Znajdź pliki QBSP</translation>
- </message>
- <message>
<source>Select a Qt Board Support Package file to install additional content that is not directly available from the online repositories.</source>
<translation>Wybierz plik Qt Board Support Package, aby zainstalować dodatkową zawartość, która nie jest bezpośrednio dostępna w repozytoriach online.</translation>
</message>
@@ -899,40 +923,40 @@
<translation>Wybierz elementy, które chcesz odinstalować.</translation>
</message>
<message>
- <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source>
- <translation>Wybierz elementy do zainstalowania. Anuluj zaznaczenie zainstalowanych elementów, aby je dezinstalować. Elementy, które są już zainstalowane, nie zostaną zaktualizowane.</translation>
+ <source>Select the components to install. Deselect installed components to uninstall them.&lt;br&gt;Any components already installed will not be updated.</source>
+ <translation>Wybierz elementy do zainstalowania. Anuluj zaznaczenie zainstalowanych elementów, aby je dezinstalować.&lt;br&gt;Elementy, które są już zainstalowane, nie zostaną zaktualizowane.</translation>
</message>
<message>
<source>Mandatory components need to be updated first before you can select other components to update.</source>
<translation>Wymagane komponenty muszą zostać zaktualizowane, zanim będzie można wybrać inne komponenty do aktualizacji</translation>
</message>
<message>
- <source>Alt+A</source>
- <comment>Select default components</comment>
- <translation>Alt+A</translation>
+ <source>Filter the enabled repository categories</source>
+ <translation>Filtruj włączone kategorie repozytorium</translation>
</message>
<message>
- <source>Alt+R</source>
- <comment>Reset to already installed components</comment>
- <translation>Alt+R</translation>
+ <source>Search</source>
+ <translation>Szukaj</translation>
</message>
<message>
- <source>Alt+S</source>
- <comment>Select all components</comment>
- <translation>Alt+S</translation>
+ <source>Create Offline Installer</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Alt+D</source>
- <comment>Deselect all components</comment>
- <translation>Alt+D</translation>
+ <source>Create offline installer from selected components, instead of installing now.</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <source>Filter the enabled repository categories</source>
- <translation>Filtruj włączone kategorie repozytorium</translation>
+ <source>Browse &amp;QBSP files</source>
+ <translation>&amp;Znajdź pliki QBSP</translation>
</message>
<message>
- <source>Search</source>
- <translation>Szukaj</translation>
+ <source>Select</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">Błąd</translation>
</message>
</context>
<context>
@@ -1216,6 +1240,10 @@ Błąd podczas wczytywania %2</translation>
<source>Total: </source>
<translation>Razem: </translation>
</message>
+ <message>
+ <source>Retry count (%1) exceeded</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::Downloader</name>
@@ -1357,7 +1385,7 @@ Błąd podczas wczytywania %2</translation>
<context>
<name>QInstaller::FinishedPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>Wykonywanie Kreatora %1</translation>
</message>
<message>
@@ -1365,7 +1393,7 @@ Błąd podczas wczytywania %2</translation>
<translation>Zakończone</translation>
</message>
<message>
- <source>Click %1 to exit the %2 Wizard.</source>
+ <source>Click %1 to exit the %2 Setup.</source>
<translation>Kliknij pozycję %1, aby zamknąć Kreator %2.</translation>
</message>
<message>
@@ -1426,8 +1454,8 @@ Błąd podczas wczytywania %2</translation>
<context>
<name>QInstaller::IntroductionPage</name>
<message>
- <source>Setup - %1</source>
- <translation>Konfiguracja - %1</translation>
+ <source>Welcome</source>
+ <translation type="unfinished"></translation>
</message>
<message>
<source>Welcome to the %1 Setup.</source>
@@ -1458,10 +1486,6 @@ Błąd podczas wczytywania %2</translation>
<translation>Brak dostępnych aktualizacji.</translation>
</message>
<message>
- <source> Only local package management available.</source>
- <translation> Dostępne jedynie lokalne zarządzanie pakietami.</translation>
- </message>
- <message>
<source>&amp;Quit</source>
<translation>Zakończ</translation>
</message>
@@ -1512,10 +1536,6 @@ Błąd podczas wczytywania %2</translation>
<source>Can not write license file &quot;%1&quot;.</source>
<translation>Nie można zapisać pliku licencji: &quot;%1&quot;.</translation>
</message>
- <message>
- <source>No license files found to delete.</source>
- <translation>Nie znaleziono plików licencji do usunięcia.</translation>
- </message>
</context>
<context>
<name>QInstaller::LineReplaceOperation</name>
@@ -1571,14 +1591,6 @@ Błąd podczas wczytywania %2</translation>
<translation>Wykryto niezgodność sumy kontrolnej dla &quot;%1&quot;.</translation>
</message>
<message>
- <source>Retrieving meta information from remote repository... %1/%2 </source>
- <translation>Pobieranie metainformacji z repozytorium zdalnego... %1/%2 </translation>
- </message>
- <message>
- <source>Retrieving meta information from remote repository... </source>
- <translation>Pobieranie metainformacji z repozytorium zdalnego... </translation>
- </message>
- <message>
<source>Error while extracting archive &quot;%1&quot;: %2</source>
<translation>Błąd podczas wyodrębniania archiwum &quot;%1&quot;: %2</translation>
</message>
@@ -1610,6 +1622,26 @@ Błąd podczas wczytywania %2</translation>
<source>Clearing the cache directory and restarting the application may solve this.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Unknown exception during updating cache.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot open extracted file &quot;%1&quot; for reading: %2</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot open file &quot;%1&quot; for writing: %2</source>
+ <translation type="unfinished">Nie można otworzyć pliku &quot;%1&quot; do zapisu: %2</translation>
+ </message>
+ <message>
+ <source>Retrieving information from remote repositories...</source>
+ <translation>Pobieranie informacji ze zdalnych repozytoriów...</translation>
+ </message>
+ <message>
+ <source>Retrieving meta information from remote repository...</source>
+ <translation>Pobieranie metainformacji z repozytorium zdalnego...</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCore</name>
@@ -1740,10 +1772,6 @@ Czy chcesz kontynuować?</translation>
<translation>Nie można zainstalować %1. Komponent nieznaleziony.</translation>
</message>
<message>
- <source>Running processes found.</source>
- <translation>Znaleziono uruchomione procesy.</translation>
- </message>
- <message>
<source>Cannot elevate access rights while running from command line. Please restart the application as administrator.</source>
<translation>Nie można podnieść praw dostępu podczas uruchamiania z wiersza poleceń. Uruchom ponownie aplikację jako administrator.</translation>
</message>
@@ -1811,6 +1839,22 @@ Czy chcesz kontynuować?</translation>
<source>Not enough disk space to store temporary files! %1 are available, while the minimum required is %2. You may select another location for the temporary files by modifying the local cache path from the installer settings.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Cannot resolve components to uninstall.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot select alias %1. There was a problem loading this alias, so it is marked unstable and cannot be selected.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot select %1. Alias is marked virtual, meaning it cannot be selected manually.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Created installer will use %1 of disk space.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCorePrivate</name>
@@ -2017,10 +2061,6 @@ Czy chcesz kontynuować?</translation>
<translation>Nie można pobrać metainformacji: %1</translation>
</message>
<message>
- <source>Cannot add temporary update source information.</source>
- <translation>Nie można dodać informacji o tymczasowym źródle aktualizacji.</translation>
- </message>
- <message>
<source>Cannot find any update source information.</source>
<translation>Nie można znaleźć żadnych informacji o źródle aktualizacji.</translation>
</message>
@@ -2082,6 +2122,18 @@ Czy chcesz kontynuować?</translation>
<source>Loading component scripts...</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Alias declares name that conflicts with an existing component &quot;%1&quot;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unresolved component aliases</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cyclic dependency between aliases &quot;%1&quot; and &quot;%2&quot; detected.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerGui</name>
@@ -2185,6 +2237,18 @@ Please copy the installer to a local drive</source>
<source>Uninstalling</source>
<translation>Odinstalowywanie</translation>
</message>
+ <message>
+ <source>&amp;Create Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer for %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::ProxyCredentialsDialog</name>
@@ -2259,6 +2323,18 @@ Please copy the installer to a local drive</source>
<source>Ready to Update</source>
<translation>Gotowy do aktualizacji</translation>
</message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Ready to Create Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>All required information is now available to create an offline installer for selected components.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::RegisterFileTypeOperation</name>
@@ -2315,7 +2391,7 @@ Please copy the installer to a local drive</source>
<context>
<name>QInstaller::RestartPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>Wykonywanie Kreatora instalacji %1</translation>
</message>
</context>
@@ -2593,7 +2669,7 @@ or accept the elevation of access rights if being asked.</source>
</message>
<message>
<source>Categories</source>
- <translation type="unfinished">Wybierz kategorie</translation>
+ <translation>Kategorie</translation>
</message>
</context>
<context>
@@ -2750,6 +2826,10 @@ or accept the elevation of access rights if being asked.</source>
<source>Clear cache</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Clearing cache...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UpdateOperation</name>
@@ -2814,7 +2894,7 @@ or accept the elevation of access rights if being asked.</source>
</message>
<message>
<source>Information</source>
- <translation type="unfinished">Informacje o składnikach</translation>
+ <translation>Informacja</translation>
</message>
</context>
<context>
@@ -3020,6 +3100,10 @@ or accept the elevation of access rights if being asked.</source>
<source>Cannot synchronize invalidated cache.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Unknown register mode selected!</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>TabController</name>
diff --git a/src/sdk/translations/ifw_pt_BR.ts b/src/sdk/translations/ifw_pt_BR.ts
index 7f500067f..bae3a695c 100644
--- a/src/sdk/translations/ifw_pt_BR.ts
+++ b/src/sdk/translations/ifw_pt_BR.ts
@@ -232,6 +232,10 @@
<source>Clear cache</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Clearing cache...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QObject</name>
@@ -410,6 +414,10 @@
<source>Invalid content in &quot;%1&quot;.</source>
<translation>Conteúdo inválido em &quot;%1&quot;.</translation>
</message>
+ <message>
+ <source>This may be solved by restarting the application after clearing the cache from:</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>BinaryLayout</name>
@@ -470,18 +478,6 @@
<translation>Componentes não podem ter filhos no modo de atualização.</translation>
</message>
<message>
- <source>Cannot open the requested UI file &quot;%1&quot;: %2</source>
- <translation>Não é possível abrir o arquivo da interface do usuário solicitado &quot;%1&quot;: %2</translation>
- </message>
- <message>
- <source>Cannot load the requested UI file &quot;%1&quot;: %2</source>
- <translation>Não é possível carregar o arquivo da interface do usuário solicitado &quot;%1&quot;:%2</translation>
- </message>
- <message>
- <source>Cannot open the requested license file &quot;%1&quot;: %2</source>
- <translation>Não é possível abrir o arquivo de licença solicitado &quot;%1&quot;: %2</translation>
- </message>
- <message>
<source>Error</source>
<translation>Erro</translation>
</message>
@@ -501,6 +497,30 @@
<source>There was an error loading the selected component. This component cannot be installed.</source>
<translation>Ocorreu um erro a carregar o componente selecionado. Este componente não pode ser instalado.</translation>
</message>
+ <message>
+ <source>Cannot open the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Não é possível abrir o arquivo da interface do usuário solicitado &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot load the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Não é possível carregar o arquivo da interface do usuário solicitado &quot;%1&quot;:%2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot open the requested license file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Não é possível abrir o arquivo de licença solicitado &quot;%1&quot;: %2
+
+%3 &quot;%4&quot;</translation>
+ </message>
</context>
<context>
<name>QInstaller::ComponentModel</name>
@@ -822,6 +842,10 @@ Erro ao carregar %2</translation>
<source>Total: </source>
<translation>Total:</translation>
</message>
+ <message>
+ <source>Retry count (%1) exceeded</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::Downloader</name>
@@ -1002,6 +1026,18 @@ Erro ao carregar %2</translation>
<source>Cannot find missing dependency &quot;%1&quot; for &quot;%2&quot;.</source>
<translation>Não foi possível encontrar a dependência ausente &quot;%1&quot; para &quot;%2&quot;.</translation>
</message>
+ <message>
+ <source>Components selected by alias &quot;%1&quot;:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Recursion detected, component alias &quot;%1&quot; already added.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Impossible dependency resolution detected. Forced install component &quot;%1&quot; would be uninstalled because its dependency &quot;%2&quot; is marked for uninstallation with reason: &quot;%3&quot;.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::InstallIconsOperation</name>
@@ -1161,10 +1197,6 @@ Erro ao carregar %2</translation>
<source>Can not write license file &quot;%1&quot;.</source>
<translation>Não é possível gravar o arquivo de licença &quot;%1&quot;.</translation>
</message>
- <message>
- <source>No license files found to delete.</source>
- <translation>Nenhum arquivo de licença foi encontrado para ser excluído.</translation>
- </message>
</context>
<context>
<name>QInstaller::LineReplaceOperation</name>
@@ -1212,14 +1244,6 @@ Erro ao carregar %2</translation>
<translation>Incompatibilidade detectada na soma de verificação para &quot;%1&quot;.</translation>
</message>
<message>
- <source>Retrieving meta information from remote repository... %1/%2 </source>
- <translation>Recuperando metadados do repositório remoto...%1/%2 </translation>
- </message>
- <message>
- <source>Retrieving meta information from remote repository... </source>
- <translation>Recuperando metadados do repositório remoto... </translation>
- </message>
- <message>
<source>Failure to fetch repositories.</source>
<translation>Falha ao buscar repositórios.</translation>
</message>
@@ -1258,6 +1282,26 @@ Erro ao carregar %2</translation>
<source>Clearing the cache directory and restarting the application may solve this.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Unknown exception during updating cache.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot open extracted file &quot;%1&quot; for reading: %2</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot open file &quot;%1&quot; for writing: %2</source>
+ <translation type="unfinished">Não é possível abrir o arquivo &quot;%1&quot; para gravação: %2</translation>
+ </message>
+ <message>
+ <source>Retrieving information from remote repositories...</source>
+ <translation>Recuperando informações de repositórios remotos...</translation>
+ </message>
+ <message>
+ <source>Retrieving meta information from remote repository...</source>
+ <translation>Recuperando metadados do repositório remoto...</translation>
+ </message>
</context>
<context>
<name>QInstaller::FileTaskObserver</name>
@@ -1447,10 +1491,6 @@ Você quer continuar?</translation>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Running processes found.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
<source>Cannot elevate access rights while running from command line. Please restart the application as administrator.</source>
<translation type="unfinished"></translation>
</message>
@@ -1510,6 +1550,22 @@ Você quer continuar?</translation>
<source>Not enough disk space to store temporary files! %1 are available, while the minimum required is %2. You may select another location for the temporary files by modifying the local cache path from the installer settings.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Cannot resolve components to uninstall.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot select alias %1. There was a problem loading this alias, so it is marked unstable and cannot be selected.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot select %1. Alias is marked virtual, meaning it cannot be selected manually.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Created installer will use %1 of disk space.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCorePrivate</name>
@@ -1716,10 +1772,6 @@ Você quer continuar?</translation>
<translation>Não é possível recuperar metadados: %1</translation>
</message>
<message>
- <source>Cannot add temporary update source information.</source>
- <translation>Não é possível adicionar informações de fontes de atualização temporária.</translation>
- </message>
- <message>
<source>Cannot find any update source information.</source>
<translation>Não é possível encontrar informações de fonte de atualização.</translation>
</message>
@@ -1780,6 +1832,18 @@ Você quer continuar?</translation>
<source>Loading component scripts...</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Alias declares name that conflicts with an existing component &quot;%1&quot;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unresolved component aliases</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cyclic dependency between aliases &quot;%1&quot; and &quot;%2&quot; detected.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerGui</name>
@@ -1837,8 +1901,8 @@ Por favor, copie o instalador para uma unidade local</translation>
<context>
<name>QInstaller::IntroductionPage</name>
<message>
- <source>Setup - %1</source>
- <translation>%1 - Configuração</translation>
+ <source>Welcome</source>
+ <translation type="unfinished"></translation>
</message>
<message>
<source>Welcome to the %1 Setup.</source>
@@ -1869,10 +1933,6 @@ Por favor, copie o instalador para uma unidade local</translation>
<translation>Nenhuma atualização disponível.</translation>
</message>
<message>
- <source> Only local package management available.</source>
- <translation> Apenas gerenciamento de pacotes locais disponível.</translation>
- </message>
- <message>
<source>&amp;Quit</source>
<translation>Sair</translation>
</message>
@@ -1944,10 +2004,6 @@ Por favor, copie o instalador para uma unidade local</translation>
<translation type="unfinished"></translation>
</message>
<message>
- <source>&amp;Browse QBSP files</source>
- <translation>&amp;Procurar arquivos QBSP</translation>
- </message>
- <message>
<source>Select a Qt Board Support Package file to install additional content that is not directly available from the online repositories.</source>
<translation type="unfinished"></translation>
</message>
@@ -1976,41 +2032,41 @@ Por favor, copie o instalador para uma unidade local</translation>
<translation>Por favor, selecione os componentes que você deseja desinstalar.</translation>
</message>
<message>
- <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source>
- <translation>Selecione os componentes para instalar. Desmarque os componentes instalados para desinstalá-los. Quaisquer componentes já instalados não serão atualizados.</translation>
+ <source>Select the components to install. Deselect installed components to uninstall them.&lt;br&gt;Any components already installed will not be updated.</source>
+ <translation>Selecione os componentes para instalar. Desmarque os componentes instalados para desinstalá-los.&lt;br&gt;Quaisquer componentes já instalados não serão atualizados.</translation>
</message>
<message>
<source>Mandatory components need to be updated first before you can select other components to update.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Alt+A</source>
- <comment>Select default components</comment>
+ <source>Filter the enabled repository categories</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Alt+R</source>
- <comment>Reset to already installed components</comment>
+ <source>Search</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Alt+S</source>
- <comment>Select all components</comment>
+ <source>Create Offline Installer</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Alt+D</source>
- <comment>Deselect all components</comment>
+ <source>Create offline installer from selected components, instead of installing now.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Filter the enabled repository categories</source>
- <translation type="unfinished"></translation>
+ <source>Browse &amp;QBSP files</source>
+ <translation>&amp;Procurar arquivos QBSP</translation>
</message>
<message>
- <source>Search</source>
+ <source>Select</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished">Erro</translation>
+ </message>
</context>
<context>
<name>QInstaller::TargetDirectoryPage</name>
@@ -2093,6 +2149,18 @@ Por favor, copie o instalador para uma unidade local</translation>
<source>Ready to Update</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Ready to Create Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>All required information is now available to create an offline installer for selected components.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::PerformInstallationPage</name>
@@ -2132,11 +2200,23 @@ Por favor, copie o instalador para uma unidade local</translation>
<source>Uninstalling</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>&amp;Create Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer for %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QInstaller::FinishedPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>Concluindo o Assistente %1</translation>
</message>
<message>
@@ -2144,7 +2224,7 @@ Por favor, copie o instalador para uma unidade local</translation>
<translation type="unfinished"></translation>
</message>
<message>
- <source>Click %1 to exit the %2 Wizard.</source>
+ <source>Click %1 to exit the %2 Setup.</source>
<translation>Clique em %1 para sair do Assistente %2.</translation>
</message>
<message>
@@ -2163,7 +2243,7 @@ Por favor, copie o instalador para uma unidade local</translation>
<context>
<name>QInstaller::RestartPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>Concluindo o Assistente de Configuração %1</translation>
</message>
</context>
@@ -2288,7 +2368,7 @@ or accept the elevation of access rights if being asked.</source>
</message>
<message>
<source>Categories</source>
- <translation type="unfinished">Selecionar Categorias</translation>
+ <translation>Categorias</translation>
</message>
</context>
<context>
@@ -2479,6 +2559,10 @@ or accept the elevation of access rights if being asked.</source>
<source>Try again</source>
<translation>Tente novamente</translation>
</message>
+ <message>
+ <source>Cannot download %1. Cannot create directory for &quot;%2&quot;</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>Job</name>
@@ -2750,10 +2834,6 @@ or accept the elevation of access rights if being asked.</source>
<translation>Não é possível ler &quot;%1&quot;</translation>
</message>
<message>
- <source>Parse error in %1 at %2, %3: %4</source>
- <translation>Erro de análise em %1 em %2, %3: %4</translation>
- </message>
- <message>
<source>Root element %1 unexpected, should be &quot;Updates&quot;.</source>
<translation>Elemento raiz %1 inesperado. Deveria ser &apos;Updates&apos;.</translation>
</message>
@@ -2797,7 +2877,7 @@ or accept the elevation of access rights if being asked.</source>
</message>
<message>
<source>Information</source>
- <translation type="unfinished">Informação Componente.</translation>
+ <translation>Informação</translation>
</message>
</context>
<context>
@@ -3003,6 +3083,10 @@ or accept the elevation of access rights if being asked.</source>
<source>Cannot synchronize invalidated cache.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Unknown register mode selected!</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>TabController</name>
diff --git a/src/sdk/translations/ifw_pt.ts b/src/sdk/translations/ifw_pt_PT.ts
index 060f3ed30..3d4cf7c50 100644
--- a/src/sdk/translations/ifw_pt.ts
+++ b/src/sdk/translations/ifw_pt_PT.ts
@@ -232,6 +232,10 @@
<source>Clear cache</source>
<translation>Limpar cache</translation>
</message>
+ <message>
+ <source>Clearing cache...</source>
+ <translation>Limpando cache...</translation>
+ </message>
</context>
<context>
<name>QObject</name>
@@ -410,6 +414,10 @@
<source>Invalid content in &quot;%1&quot;.</source>
<translation>O conteúdo em &quot;%1&quot; é inválido.</translation>
</message>
+ <message>
+ <source>This may be solved by restarting the application after clearing the cache from:</source>
+ <translation>Esta situação pode ficar resolvida se reiniciar a aplicação após limpar a cache:</translation>
+ </message>
</context>
<context>
<name>BinaryLayout</name>
@@ -470,18 +478,6 @@
<translation>Em modo de atualização os componentes não podem descendentes.</translation>
</message>
<message>
- <source>Cannot open the requested UI file &quot;%1&quot;: %2</source>
- <translation>Ocorreu um erro a abrir o ficheiro da interface &quot;%1&quot;: %2</translation>
- </message>
- <message>
- <source>Cannot load the requested UI file &quot;%1&quot;: %2</source>
- <translation>Ocorreu um erro a carregar o ficheiro da interface do utilizador &quot;%1&quot;:%2</translation>
- </message>
- <message>
- <source>Cannot open the requested license file &quot;%1&quot;: %2</source>
- <translation>Ocorreu um erro a abrir o ficheiro de licença &quot;%1&quot;: %2</translation>
- </message>
- <message>
<source>Error</source>
<translation>Erro</translation>
</message>
@@ -501,6 +497,30 @@
<source>There was an error loading the selected component. This component cannot be installed.</source>
<translation>Ocorreu um erro ao carregar o componente selecionado. Este componente não pode ser instalado.</translation>
</message>
+ <message>
+ <source>Cannot open the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Ocorreu um erro a abrir o ficheiro da interface &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot load the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Ocorreu um erro a carregar o ficheiro da interface do utilizador &quot;%1&quot;:%2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot open the requested license file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Ocorreu um erro a abrir o ficheiro de licença &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
</context>
<context>
<name>QInstaller::ComponentModel</name>
@@ -822,6 +842,28 @@ Erro ao carregar %2</translation>
<source>Total: </source>
<translation>Total:</translation>
</message>
+ <message>
+ <source>Retry count (%1) exceeded</source>
+ <translation>Excedeu o número máximo de tentativas (%1).</translation>
+ </message>
+ <message>
+ <source>Hash verification while downloading failed. This is a temporary error, please retry.
+
+Expected: %1
+Downloaded: %2</source>
+ <translation>Falhou a verificação do código hash durante o download. Este é um erro temporário. Por favor, tente novamente.
+
+Previsto: %1
+Descarregado: %2</translation>
+ </message>
+ <message>
+ <source>Cannot verify Hash
+Expected: %1
+Downloaded: %2</source>
+ <translation>Não é possível verificar o código hash
+Previsto: %1
+Descarregado: %2</translation>
+ </message>
</context>
<context>
<name>QInstaller::Downloader</name>
@@ -996,12 +1038,24 @@ Erro ao carregar %2</translation>
</message>
<message>
<source>Recursion detected, component &quot;%1&quot; already added with reason: &quot;%2&quot;</source>
- <translation>Foi detectado um ciclo recursivo, componente &quot;%1&quot; já foi adicionado com o motivo: &quot;%2&quot;</translation>
+ <translation>Foi detectado um ciclo recursivo, o componente &quot;%1&quot; já foi adicionado devido a: &quot;%2&quot;</translation>
</message>
<message>
<source>Cannot find missing dependency &quot;%1&quot; for &quot;%2&quot;.</source>
<translation>Não foi possível encontrar a dependência &quot;%1&quot; para &quot;%2&quot;.</translation>
</message>
+ <message>
+ <source>Impossible dependency resolution detected. Forced install component &quot;%1&quot; would be uninstalled because its dependency &quot;%2&quot; is marked for uninstallation with reason: &quot;%3&quot;.</source>
+ <translation>Foi detetado uma dependência impossível de resolver. A instalação do componente &quot;%1&quot; teria de ser desinstalado devido à dependência &quot;%2&quot; que se encontra sinalizada para desinstalar por: &quot;%3&quot;.</translation>
+ </message>
+ <message>
+ <source>Components selected by alias &quot;%1&quot;:</source>
+ <translation>Componentes selecionados pelo &apos;alias&apos; &quot;%1&quot;:</translation>
+ </message>
+ <message>
+ <source>Recursion detected, component alias &quot;%1&quot; already added.</source>
+ <translation>Foi detectado um ciclo recursivo, o &apos;alias&apos; do componente &quot;%1&quot; já foi adicionado devido a: &quot;%2&quot;</translation>
+ </message>
</context>
<context>
<name>QInstaller::InstallIconsOperation</name>
@@ -1161,10 +1215,6 @@ Erro ao carregar %2</translation>
<source>Can not write license file &quot;%1&quot;.</source>
<translation>Não é possível guardar o ficheiro de licença &quot;%1&quot;.</translation>
</message>
- <message>
- <source>No license files found to delete.</source>
- <translation>Não foi encontrado ficheiro de licença para ser excluído.</translation>
- </message>
</context>
<context>
<name>QInstaller::LineReplaceOperation</name>
@@ -1216,14 +1266,6 @@ Erro ao carregar %2</translation>
<translation>Incompatibilidade detectada na verificação para &quot;%1&quot;.</translation>
</message>
<message>
- <source>Retrieving meta information from remote repository... %1/%2 </source>
- <translation>A obter metadados do repositório remoto...%1/%2 </translation>
- </message>
- <message>
- <source>Retrieving meta information from remote repository... </source>
- <translation>A obter metainformação do repositório remoto... </translation>
- </message>
- <message>
<source>Failure to fetch repositories.</source>
<translation>Ocorreu um erro ao obter repositórios.</translation>
</message>
@@ -1256,7 +1298,27 @@ Erro ao carregar %2</translation>
</message>
<message>
<source>Clearing the cache directory and restarting the application may solve this.</source>
- <translation>Limpar o diretório de cache e reiniciar o aplicativo pode resolver isso.</translation>
+ <translation>Limpar o diretório de cache e reiniciar o aplicativo pode resolver esta situação.</translation>
+ </message>
+ <message>
+ <source>Unknown exception during updating cache.</source>
+ <translation>Ocorreu um erro durante a actualização da cache.</translation>
+ </message>
+ <message>
+ <source>Cannot open extracted file &quot;%1&quot; for reading: %2</source>
+ <translation>Não foi possível abrir o ficheiro &quot;%1&quot; para leitura: %2</translation>
+ </message>
+ <message>
+ <source>Cannot open file &quot;%1&quot; for writing: %2</source>
+ <translation>Não foi possível abrir o ficheiro &quot;%1&quot; para escrita: %2</translation>
+ </message>
+ <message>
+ <source>Retrieving information from remote repositories...</source>
+ <translation>A obter informações de repositórios remotos...</translation>
+ </message>
+ <message>
+ <source>Retrieving meta information from remote repository...</source>
+ <translation>A obter metainformação do repositório remoto...</translation>
</message>
</context>
<context>
@@ -1447,10 +1509,6 @@ De certeza que deseja continuar?</translation>
<translation>Não é possível instalar %1. O componente não foi encontrado.</translation>
</message>
<message>
- <source>Running processes found.</source>
- <translation>Foram encontrados processos em execução.</translation>
- </message>
- <message>
<source>Cannot elevate access rights while running from command line. Please restart the application as administrator.</source>
<translation>Não foi possível obter os direitos de acesso necessários durante a execução na linha de comandos. Por favor, reinicie a aplicação com privilégios de administrador.</translation>
</message>
@@ -1510,6 +1568,22 @@ De certeza que deseja continuar?</translation>
<source>Not enough disk space to store temporary files! %1 are available, while the minimum required is %2. You may select another location for the temporary files by modifying the local cache path from the installer settings.</source>
<translation>Não há espaço em disco suficiente para armazenar arquivos temporários! %1 estão disponíveis, enquanto o mínimo necessário é %2. Você pode selecionar outro local para os arquivos temporários modificando o caminho do cache local nas configurações do instalador.</translation>
</message>
+ <message>
+ <source>Cannot resolve components to uninstall.</source>
+ <translation>Não foi possível resolver os componentes a serem desinstalados</translation>
+ </message>
+ <message>
+ <source>Cannot select alias %1. There was a problem loading this alias, so it is marked unstable and cannot be selected.</source>
+ <translation>O &apos;alias&apos; %1 não pode ser selecionado. Ocorreu um problema a carregar este &apos;alias&apos;, foi marcado com instável e não pode ser selecionado.</translation>
+ </message>
+ <message>
+ <source>Cannot select %1. Alias is marked virtual, meaning it cannot be selected manually.</source>
+ <translation>O &apos;alias&apos; %1 não pode ser selecionado. Este &apos;alias&apos; está categorizado como virtual, o que significa que não pode ser selecionado manualmente.</translation>
+ </message>
+ <message>
+ <source>Created installer will use %1 of disk space.</source>
+ <translation>O instalador criado irá utilizar %1 de espaco de disco.</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCorePrivate</name>
@@ -1683,11 +1757,11 @@ De certeza que deseja continuar?</translation>
</message>
<message>
<source>Offline generation completed successfully.</source>
- <translation>A geração offline foi concluída com sucesso.</translation>
+ <translation>A geração &apos;offline&apos; foi concluída com sucesso.</translation>
</message>
<message>
<source>Offline generation aborted!</source>
- <translation>A geração offline foi cancelada!</translation>
+ <translation>A geração &apos;offline&apos; foi cancelada!</translation>
</message>
<message>
<source>Installing component %1</source>
@@ -1738,10 +1812,6 @@ De certeza que deseja continuar?</translation>
<translation>Não é possível recuperar metadados: %1</translation>
</message>
<message>
- <source>Cannot add temporary update source information.</source>
- <translation>Não é possível adicionar informações de fontes de atualização temporária.</translation>
- </message>
- <message>
<source>Cannot find any update source information.</source>
<translation>Não é possível encontrar informações de fonte de atualização.</translation>
</message>
@@ -1781,6 +1851,18 @@ De certeza que deseja continuar?</translation>
<source>Loading component scripts...</source>
<translation>Carregando scripts de componentes...</translation>
</message>
+ <message>
+ <source>Alias declares name that conflicts with an existing component &quot;%1&quot;</source>
+ <translation>O &apos;alias&apos; declara um nome em conflito com um componente pré-existente &quot;%1&quot;</translation>
+ </message>
+ <message>
+ <source>Unresolved component aliases</source>
+ <translation>&apos;Alias&apos; dos componentes não resolvidos.</translation>
+ </message>
+ <message>
+ <source>Cyclic dependency between aliases &quot;%1&quot; and &quot;%2&quot; detected.</source>
+ <translation>Foi detetado um ciclo de dependência entre os alias &quot;%1&quot; e &quot;%2&quot;.</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerGui</name>
@@ -1838,8 +1920,8 @@ Por favor, copie o instalador para uma unidade de disco local</translation>
<context>
<name>QInstaller::IntroductionPage</name>
<message>
- <source>Setup - %1</source>
- <translation>%1 - Configuração</translation>
+ <source>Welcome</source>
+ <translation>Bem-vindo</translation>
</message>
<message>
<source>Welcome to the %1 Setup.</source>
@@ -1870,10 +1952,6 @@ Por favor, copie o instalador para uma unidade de disco local</translation>
<translation>Nenhuma atualização disponível.</translation>
</message>
<message>
- <source> Only local package management available.</source>
- <translation> Apenas gestãoo de pacotes locais disponível.</translation>
- </message>
- <message>
<source>&amp;Quit</source>
<translation>Sair</translation>
</message>
@@ -1945,10 +2023,6 @@ Por favor, copie o instalador para uma unidade de disco local</translation>
<translation>Desselecione todos os componentes na visualização em árvore.</translation>
</message>
<message>
- <source>&amp;Browse QBSP files</source>
- <translation>&amp;Procurar ficheiros QBSP</translation>
- </message>
- <message>
<source>Select a Qt Board Support Package file to install additional content that is not directly available from the online repositories.</source>
<translation>Selecione ficheiro &quot;Qt Board Support Package&quot; para instalar conteúdo adicional que não está disponível nos repositórios online.</translation>
</message>
@@ -1981,8 +2055,8 @@ Por favor, copie o instalador para uma unidade de disco local</translation>
<translation>Por favor, selecione os componentes que você deseja desinstalar.</translation>
</message>
<message>
- <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source>
- <translation>Selecione componentes para os instalar. Deselecione componentes instalados para desinstalá-los. Os componentes previamente instalados não serão atualizados.</translation>
+ <source>Select the components to install. Deselect installed components to uninstall them.&lt;br&gt;Any components already installed will not be updated.</source>
+ <translation>Selecione componentes para os instalar. Deselecione componentes instalados para desinstalá-los.&lt;br&gt;Os componentes previamente instalados não serão atualizados.</translation>
</message>
<message>
<source>Mandatory components need to be updated first before you can select other components to update.</source>
@@ -1992,6 +2066,26 @@ Por favor, copie o instalador para uma unidade de disco local</translation>
<source>Search</source>
<translation>Pesquisa</translation>
</message>
+ <message>
+ <source>Browse &amp;QBSP files</source>
+ <translation>Selecionar ficheiros do tipo &amp;QBSP</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Selecione</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Erro</translation>
+ </message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation>Criar um Instalador &apos;Offline&apos;</translation>
+ </message>
+ <message>
+ <source>Create offline installer from selected components, instead of installing now.</source>
+ <translation>Invés de instalar, criar um instalador &apos;Offline&apos; a partir dos componentes selecionados.</translation>
+ </message>
</context>
<context>
<name>QInstaller::TargetDirectoryPage</name>
@@ -2074,6 +2168,18 @@ Por favor, copie o instalador para uma unidade de disco local</translation>
<source>Ready to Update</source>
<translation>Pronto para atualizar</translation>
</message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation>Criar um Instalador &apos;Offline&apos;</translation>
+ </message>
+ <message>
+ <source>Ready to Create Offline Installer</source>
+ <translation>Pronto para criar um Instalador &apos;Offline&apos;</translation>
+ </message>
+ <message>
+ <source>All required information is now available to create an offline installer for selected components.</source>
+ <translation>O assistente de configuração está pronto para criar um instalador offline para os componentes selecionados.</translation>
+ </message>
</context>
<context>
<name>QInstaller::PerformInstallationPage</name>
@@ -2113,11 +2219,23 @@ Por favor, copie o instalador para uma unidade de disco local</translation>
<source>Uninstalling</source>
<translation>A desinstalar</translation>
</message>
+ <message>
+ <source>&amp;Create Offline Installer</source>
+ <translation>Criar um Instalador &apos;Offline&apos;</translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer for %1</source>
+ <translation>A criar um Instalador &apos;Offline&apos; para %1</translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer</source>
+ <translation>A criar um Instalador &apos;Offline&apos;</translation>
+ </message>
</context>
<context>
<name>QInstaller::FinishedPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>A concluir o Assistente %1</translation>
</message>
<message>
@@ -2125,7 +2243,7 @@ Por favor, copie o instalador para uma unidade de disco local</translation>
<translation>Concluído</translation>
</message>
<message>
- <source>Click %1 to exit the %2 Wizard.</source>
+ <source>Click %1 to exit the %2 Setup.</source>
<translation>Clique em %1 para fechar o Assistente %2.</translation>
</message>
<message>
@@ -2144,7 +2262,7 @@ Por favor, copie o instalador para uma unidade de disco local</translation>
<context>
<name>QInstaller::RestartPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>A concluir o Assistente de Configuração %1</translation>
</message>
</context>
@@ -2269,7 +2387,7 @@ Em alternativa, pode aceitar a alteração de permissões de acesso caso seja so
</message>
<message>
<source>Categories</source>
- <translation type="unfinished">Selecionar categorias</translation>
+ <translation>Categorias</translation>
</message>
</context>
<context>
@@ -2460,6 +2578,10 @@ Em alternativa, pode aceitar a alteração de permissões de acesso caso seja so
<source>Try again</source>
<translation>Tente novamente</translation>
</message>
+ <message>
+ <source>Cannot download %1. Cannot create directory for &quot;%2&quot;</source>
+ <translation>Não é possível fazer o descarregamento de %1. Não é possível criar o diretório &quot;%2&quot;</translation>
+ </message>
</context>
<context>
<name>Job</name>
@@ -2731,10 +2853,6 @@ Em alternativa, pode aceitar a alteração de permissões de acesso caso seja so
<translation>Não é possível ler &quot;%1&quot;</translation>
</message>
<message>
- <source>Parse error in %1 at %2, %3: %4</source>
- <translation>Ocorreu um erro a análisar %1 em %2, %3: %4</translation>
- </message>
- <message>
<source>Root element %1 unexpected, should be &quot;Updates&quot;.</source>
<translation>Não é esperado este elemento raiz %1. Deveria ser &apos;Updates&apos;.</translation>
</message>
@@ -2778,7 +2896,7 @@ Em alternativa, pode aceitar a alteração de permissões de acesso caso seja so
</message>
<message>
<source>Information</source>
- <translation type="unfinished">Informação do componente</translation>
+ <translation>Informação</translation>
</message>
</context>
<context>
@@ -2985,6 +3103,10 @@ Em alternativa, pode aceitar a alteração de permissões de acesso caso seja so
<source>Cannot synchronize invalidated cache.</source>
<translation>Não é possível sincronizar o cache invalidado.</translation>
</message>
+ <message>
+ <source>Unknown register mode selected!</source>
+ <translation>Foi selecionado um modo de registo desconhecido.</translation>
+ </message>
</context>
<context>
<name>TabController</name>
diff --git a/src/sdk/translations/ifw_ru.ts b/src/sdk/translations/ifw_ru.ts
index 75cdc532b..830c2bc82 100644
--- a/src/sdk/translations/ifw_ru.ts
+++ b/src/sdk/translations/ifw_ru.ts
@@ -136,6 +136,18 @@
<source>Cannot find missing dependency &quot;%1&quot; for &quot;%2&quot;.</source>
<translation>Не удалось найти компонент «%1», необходимый для «%2».</translation>
</message>
+ <message>
+ <source>Impossible dependency resolution detected. Forced install component &quot;%1&quot; would be uninstalled because its dependency &quot;%2&quot; is marked for uninstallation with reason: &quot;%3&quot;.</source>
+ <translation>Выявлено невозможное разрешение зависимостей. Принудительная установка компонента &quot;%1&quot; будет удалена, потому что зависимый &quot;%2&quot; помечен для удаления по причине: &quot;%3&quot;.</translation>
+ </message>
+ <message>
+ <source>Components selected by alias &quot;%1&quot;:</source>
+ <translation>Выбран компонент под именем &quot;%1&quot;:</translation>
+ </message>
+ <message>
+ <source>Recursion detected, component alias &quot;%1&quot; already added.</source>
+ <translation>Замечено повторение, компонент с именем &quot;%1&quot; уже выбран.</translation>
+ </message>
</context>
<context>
<name>Job</name>
@@ -310,6 +322,10 @@
<source>Cannot download %1. Cannot create file &quot;%2&quot;: %3</source>
<translation>Невозможно загрузить «%1». Не удалось создать «%2»: %3</translation>
</message>
+ <message>
+ <source>Cannot download %1. Cannot create directory for &quot;%2&quot;</source>
+ <translation>Невозможно загрузить %1. Невозможно создать каталог для &quot;%2&quot;</translation>
+ </message>
</context>
<context>
<name>KDUpdater::LocalFileDownloader</name>
@@ -494,10 +510,6 @@
<translation>Невозможно прочитать «%1»</translation>
</message>
<message>
- <source>Parse error in %1 at %2, %3: %4</source>
- <translation>Ошибка разбора XML в %1 в %2, %3: %4</translation>
- </message>
- <message>
<source>Root element %1 unexpected, should be &quot;Updates&quot;.</source>
<translation>Непредвиденный корневой элемент %1, требуется «Updates».</translation>
</message>
@@ -749,6 +761,10 @@
<source>Invalid content in &quot;%1&quot;.</source>
<translation>Недопустимые данные в «%1».</translation>
</message>
+ <message>
+ <source>This may be solved by restarting the application after clearing the cache from:</source>
+ <translation>Это может быть решено перезапуском приложения после очистки кэша:</translation>
+ </message>
</context>
<context>
<name>QInstaller::Component</name>
@@ -769,24 +785,36 @@
<translation>Информация об обновлении: </translation>
</message>
<message>
- <source>Cannot open the requested UI file &quot;%1&quot;: %2</source>
- <translation>Не удалось открыть запрошенный UI файл «%1»: %2</translation>
+ <source>Error: Operation %1 does not exist.</source>
+ <translation>Ошибка: операция %1 не существует.</translation>
</message>
<message>
- <source>Cannot load the requested UI file &quot;%1&quot;: %2</source>
- <translation>Не удалось загрузить запрошенный UI файл «%1»: %2</translation>
+ <source>There was an error loading the selected component. This component cannot be installed.</source>
+ <translation>Возникла ошибка при загрузке выбранного компонента. Установить его не получится.</translation>
</message>
<message>
- <source>Cannot open the requested license file &quot;%1&quot;: %2</source>
- <translation>Не удалось открыть запрошенный файл лицензии «%1»: %2</translation>
+ <source>Cannot open the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Не удалось открыть запрошенный UI файл «%1»: %2.
+
+%3 &quot;%4&quot;</translation>
</message>
<message>
- <source>Error: Operation %1 does not exist.</source>
- <translation>Ошибка: операция %1 не существует.</translation>
+ <source>Cannot load the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Не удалось загрузить запрошенный UI файл «%1»: %2.
+
+%3 &quot;%4&quot;</translation>
</message>
<message>
- <source>There was an error loading the selected component. This component cannot be installed.</source>
- <translation>Возникла ошибка при загрузке выбранного компонента. Установить его не получится.</translation>
+ <source>Cannot open the requested license file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>Не удалось открыть запрошенный файл лицензии «%1»: %2.
+
+%3 &quot;%4&quot;</translation>
</message>
</context>
<context>
@@ -867,10 +895,6 @@
<translation>Отмените выбор всех компонентов в древовидном представлении.</translation>
</message>
<message>
- <source>&amp;Browse QBSP files</source>
- <translation>&amp;Обзор файлов QBSP</translation>
- </message>
- <message>
<source>Select a Qt Board Support Package file to install additional content that is not directly available from the online repositories.</source>
<translation>Выберите файл инструментальных средств для разработки Qt Board Support Package, чтобы установить дополнительное содержимое, которое недоступно непосредственно из сетевых хранилищ.</translation>
</message>
@@ -895,8 +919,8 @@
<translation>Пожалуйста, выберите компоненты, которые вы хотите удалить.</translation>
</message>
<message>
- <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source>
- <translation>Выберите компоненты для установки. Для удаления уже установленных компонентов снимите отметки выбора. Уже установленные компоненты не будут обновлены.</translation>
+ <source>Select the components to install. Deselect installed components to uninstall them.&lt;br&gt;Any components already installed will not be updated.</source>
+ <translation>Выберите компоненты для установки. Для удаления уже установленных компонентов снимите отметки выбора.&lt;br&gt;Уже установленные компоненты не будут обновлены.</translation>
</message>
<message>
<source>Mandatory components need to be updated first before you can select other components to update.</source>
@@ -907,32 +931,32 @@
<translation>Открытие файла</translation>
</message>
<message>
- <source>Alt+A</source>
- <comment>Select default components</comment>
- <translation>Alt+A</translation>
+ <source>Filter the enabled repository categories</source>
+ <translation>Отфильтруйте категории включенного хранилища по выбору.</translation>
</message>
<message>
- <source>Alt+R</source>
- <comment>Reset to already installed components</comment>
- <translation>Alt+R</translation>
+ <source>Search</source>
+ <translation>Поиск</translation>
</message>
<message>
- <source>Alt+S</source>
- <comment>Select all components</comment>
- <translation>Alt+S</translation>
+ <source>Browse &amp;QBSP files</source>
+ <translation>Посмотреть &amp;QBSP файлы</translation>
</message>
<message>
- <source>Alt+D</source>
- <comment>Deselect all components</comment>
- <translation>Alt+D</translation>
+ <source>Select</source>
+ <translation>Выбрать</translation>
</message>
<message>
- <source>Filter the enabled repository categories</source>
- <translation>Отфильтруйте категории включенного хранилища по выбору.</translation>
+ <source>Error</source>
+ <translation>Ошибка</translation>
</message>
<message>
- <source>Search</source>
- <translation>Поиск</translation>
+ <source>Create Offline Installer</source>
+ <translation>Создать Автономный Установщик</translation>
+ </message>
+ <message>
+ <source>Create offline installer from selected components, instead of installing now.</source>
+ <translation>Создать автономный установщик из выбранных компонентов вместо установки сейчас.</translation>
</message>
</context>
<context>
@@ -947,7 +971,7 @@
</message>
<message>
<source>Information</source>
- <translation type="unfinished">Сведения о компонентах</translation>
+ <translation>Информация</translation>
</message>
</context>
<context>
@@ -1146,14 +1170,6 @@
<translation>Ошибка загрузки</translation>
</message>
<message>
- <source>Hash verification while downloading failed. This is a temporary error, please retry.</source>
- <translation>Не удалось проверить целостность хеша в процессе загрузки. Пожалуйста, повторите операцию.</translation>
- </message>
- <message>
- <source>Cannot verify Hash</source>
- <translation>Невозможно проверить хеш</translation>
- </message>
- <message>
<source>Cannot fetch archives: %1
Error while loading %2</source>
<translation>Невозможно получить архивы :%1
@@ -1231,6 +1247,28 @@ Error while loading %2</source>
<source>Total: </source>
<translation>Всего: </translation>
</message>
+ <message>
+ <source>Retry count (%1) exceeded</source>
+ <translation>Превышено количество (%1) повторов</translation>
+ </message>
+ <message>
+ <source>Hash verification while downloading failed. This is a temporary error, please retry.
+
+Expected: %1
+Downloaded: %2</source>
+ <translation>Не удалось проверить целостность хеша в процессе загрузки. Пожалуйста, повторите операцию.
+
+ожидалось: %1
+загружено: %2</translation>
+ </message>
+ <message>
+ <source>Cannot verify Hash
+Expected: %1
+Downloaded: %2</source>
+ <translation>Невозможно проверить хеш
+ожидалось: %1
+загружено: %2</translation>
+ </message>
</context>
<context>
<name>QInstaller::Downloader</name>
@@ -1395,7 +1433,7 @@ Error while loading %2</source>
<context>
<name>QInstaller::FinishedPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>Завершение установки %1</translation>
</message>
<message>
@@ -1415,7 +1453,7 @@ Error while loading %2</source>
<translation>Установка %1 не удалась.</translation>
</message>
<message>
- <source>Click %1 to exit the %2 Wizard.</source>
+ <source>Click %1 to exit the %2 Setup.</source>
<translation>Нажмите «%1» для выхода из мастера %2.</translation>
</message>
</context>
@@ -1464,8 +1502,8 @@ Error while loading %2</source>
<context>
<name>QInstaller::IntroductionPage</name>
<message>
- <source>Setup - %1</source>
- <translation>Установка - %1</translation>
+ <source>Welcome</source>
+ <translation>Добро пожаловать</translation>
</message>
<message>
<source>Welcome to the %1 Setup.</source>
@@ -1496,10 +1534,6 @@ Error while loading %2</source>
<translation>Нет доступных обновлений.</translation>
</message>
<message>
- <source> Only local package management available.</source>
- <translation> Доступно только локальное управление пакетами.</translation>
- </message>
- <message>
<source>&amp;Quit</source>
<translation>&amp;Выйти</translation>
</message>
@@ -1547,10 +1581,6 @@ Error while loading %2</source>
<translation>В операции «%1» необходимый объект установщика пуст.</translation>
</message>
<message>
- <source>No license files found to delete.</source>
- <translation>Невозможно удалить файл лицензии: файл не найден.</translation>
- </message>
- <message>
<source>Can not write license file &quot;%1&quot;.</source>
<translation>Не удалось записать файл лицензии «%1».</translation>
</message>
@@ -1597,14 +1627,6 @@ Error while loading %2</source>
<translation>Обнаружено несовпадение контрольной суммы у «%1».</translation>
</message>
<message>
- <source>Retrieving meta information from remote repository... %1/%2 </source>
- <translation>Получение метаданных из внешнего хранилища... %1/%2 </translation>
- </message>
- <message>
- <source>Retrieving meta information from remote repository... </source>
- <translation>Получение метаданных из внешнего хранилища... </translation>
- </message>
- <message>
<source>Failure to fetch repositories.</source>
<translation>Не удалось загрузить хранилища.</translation>
</message>
@@ -1648,6 +1670,26 @@ Error while loading %2</source>
<source>Clearing the cache directory and restarting the application may solve this.</source>
<translation>Очистка кэш-директории и перезапуск приложения может исправить это.</translation>
</message>
+ <message>
+ <source>Unknown exception during updating cache.</source>
+ <translation>Неизвестное исключение во время обновления кэша.</translation>
+ </message>
+ <message>
+ <source>Cannot open extracted file &quot;%1&quot; for reading: %2</source>
+ <translation>Невозможно открыть распакованный файл &quot;%1&quot; для чтения.</translation>
+ </message>
+ <message>
+ <source>Cannot open file &quot;%1&quot; for writing: %2</source>
+ <translation>Невозможно открыть файл &quot;%1&quot; для записи: %2</translation>
+ </message>
+ <message>
+ <source>Retrieving information from remote repositories...</source>
+ <translation>Получение информации из внешнего хранилища...</translation>
+ </message>
+ <message>
+ <source>Retrieving meta information from remote repository...</source>
+ <translation>Получение метаданных из внешнего хранилища...</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCore</name>
@@ -1758,10 +1800,6 @@ Do you want to continue?</source>
<translation>Не удалось установить %1. Компонент не найден.</translation>
</message>
<message>
- <source>Running processes found.</source>
- <translation>Обнаружены запущенные процессы.</translation>
- </message>
- <message>
<source>Cannot elevate access rights while running from command line. Please restart the application as administrator.</source>
<translation>Невозможно повысить уровень прав доступа при запуске из командной строки. Перезапустите приложение от имени администратора.</translation>
</message>
@@ -1849,6 +1887,22 @@ Do you want to continue?</source>
<source>Not enough disk space to store temporary files! %1 are available, while the minimum required is %2. You may select another location for the temporary files by modifying the local cache path from the installer settings.</source>
<translation>Недостаточно места на диске для хранения временных файлов! %1 доступно, минимально необходимо %2. Вы можете выбрать другое место для временных файлов, изменив путь к локальному кэшу в настройках установщика.</translation>
</message>
+ <message>
+ <source>Cannot resolve components to uninstall.</source>
+ <translation>Невозможно определить компоненты для удаления.</translation>
+ </message>
+ <message>
+ <source>Cannot select alias %1. There was a problem loading this alias, so it is marked unstable and cannot be selected.</source>
+ <translation>Невозможно выбрать псевдоним %1. Была проблема с загрузкой этого псевдонима, он был помечен нестабильным и не может быть выбран.</translation>
+ </message>
+ <message>
+ <source>Cannot select %1. Alias is marked virtual, meaning it cannot be selected manually.</source>
+ <translation>Невозможно выбрать %1. Псевдоним помечен как виртуальный и не может быть выбран вручную.</translation>
+ </message>
+ <message>
+ <source>Created installer will use %1 of disk space.</source>
+ <translation>Созданный установщик займет %1 дискового пространства.</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCorePrivate</name>
@@ -2038,10 +2092,6 @@ Do you want to continue?</source>
<translation>Невозможно загрузить метаданные: %1</translation>
</message>
<message>
- <source>Cannot add temporary update source information.</source>
- <translation>Невозможно добавить информацию о временном сервере обновления.</translation>
- </message>
- <message>
<source>Cannot find any update source information.</source>
<translation>Невозможно найти информацию об источниках обновления.</translation>
</message>
@@ -2119,6 +2169,18 @@ Do you want to continue?</source>
<source>Loading component scripts...</source>
<translation>Загрузка скриптов компонента...</translation>
</message>
+ <message>
+ <source>Alias declares name that conflicts with an existing component &quot;%1&quot;</source>
+ <translation>Псевдоним назван именем, которое конфликтует с существующим компонентом &quot;%1&quot;</translation>
+ </message>
+ <message>
+ <source>Unresolved component aliases</source>
+ <translation>Неразрешенные псевдонимы компонентов.</translation>
+ </message>
+ <message>
+ <source>Cyclic dependency between aliases &quot;%1&quot; and &quot;%2&quot; detected.</source>
+ <translation>Цикличная зависимость между псевдонимами &quot;%1&quot; и &quot;%2&quot; замечена.</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerGui</name>
@@ -2222,6 +2284,18 @@ Please copy the installer to a local drive</source>
<source>Uninstalling</source>
<translation>Удаление</translation>
</message>
+ <message>
+ <source>&amp;Create Offline Installer</source>
+ <translation>Создать Автономный Установщик.</translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer for %1</source>
+ <translation>Создание Автономного Установщика для %1</translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer</source>
+ <translation>Создание Автономного Установщика</translation>
+ </message>
</context>
<context>
<name>QInstaller::ProxyCredentialsDialog</name>
@@ -2296,6 +2370,18 @@ Please copy the installer to a local drive</source>
<source>Ready to Update</source>
<translation>Всё готово к обновлению</translation>
</message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation>Создать Автономный Установщик.</translation>
+ </message>
+ <message>
+ <source>Ready to Create Offline Installer</source>
+ <translation>Готов к установке Автономного Установщика.</translation>
+ </message>
+ <message>
+ <source>All required information is now available to create an offline installer for selected components.</source>
+ <translation>Вся необходимая информация доступна для создания автономного установщика для выбранных компонентов.</translation>
+ </message>
</context>
<context>
<name>QInstaller::RegisterFileTypeOperation</name>
@@ -2352,7 +2438,7 @@ Please copy the installer to a local drive</source>
<context>
<name>QInstaller::RestartPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>Завершение %1 мастера установки</translation>
</message>
</context>
@@ -2630,7 +2716,7 @@ or accept the elevation of access rights if being asked.</source>
</message>
<message>
<source>Categories</source>
- <translation type="unfinished">Выберите категории пакетов</translation>
+ <translation>Выберите категорию</translation>
</message>
</context>
<context>
@@ -2787,6 +2873,10 @@ or accept the elevation of access rights if being asked.</source>
<source>Clear cache</source>
<translation>Очистить кэш</translation>
</message>
+ <message>
+ <source>Clearing cache...</source>
+ <translation>Очистка кэша...</translation>
+ </message>
</context>
<context>
<name>UpdateOperation</name>
@@ -3019,6 +3109,10 @@ or accept the elevation of access rights if being asked.</source>
<source>Cannot synchronize invalidated cache.</source>
<translation>Не удается синхронизировать недействительный кеш.</translation>
</message>
+ <message>
+ <source>Unknown register mode selected!</source>
+ <translation>Выбран неизвестный режим регистра.</translation>
+ </message>
</context>
<context>
<name>TabController</name>
diff --git a/src/sdk/translations/ifw_zh_CN.ts b/src/sdk/translations/ifw_zh_CN.ts
index 337f99bda..7246914a1 100644
--- a/src/sdk/translations/ifw_zh_CN.ts
+++ b/src/sdk/translations/ifw_zh_CN.ts
@@ -136,6 +136,18 @@
<source>Cannot find missing dependency &quot;%1&quot; for &quot;%2&quot;.</source>
<translation>找不到“%2”的缺失依赖项“%1”。</translation>
</message>
+ <message>
+ <source>Impossible dependency resolution detected. Forced install component &quot;%1&quot; would be uninstalled because its dependency &quot;%2&quot; is marked for uninstallation with reason: &quot;%3&quot;.</source>
+ <translation>检测到无法解决的依赖关系。强制安装组件:“%1”将会被移除,因为它的依赖“%2”被标记为移除,原因:“%3”。</translation>
+ </message>
+ <message>
+ <source>Components selected by alias &quot;%1&quot;:</source>
+ <translation>通过别名“%1”选中的组件:</translation>
+ </message>
+ <message>
+ <source>Recursion detected, component alias &quot;%1&quot; already added.</source>
+ <translation>检测到递归,组件别名“%1”已添加。</translation>
+ </message>
</context>
<context>
<name>Job</name>
@@ -302,6 +314,10 @@
<source>Try again</source>
<translation>重试</translation>
</message>
+ <message>
+ <source>Cannot download %1. Cannot create directory for &quot;%2&quot;</source>
+ <translation>无法下载%1。无法为“%2”创建目录。</translation>
+ </message>
</context>
<context>
<name>KDUpdater::LocalFileDownloader</name>
@@ -484,10 +500,6 @@
<translation>无法读取“%1”</translation>
</message>
<message>
- <source>Parse error in %1 at %2, %3: %4</source>
- <translation>%1 中 %2、%3 的解析错误:%4</translation>
- </message>
- <message>
<source>Root element %1 unexpected, should be &quot;Updates&quot;.</source>
<translation>意外的根元素 %1,应为“Updates”。</translation>
</message>
@@ -739,6 +751,10 @@
<source>Invalid content in &quot;%1&quot;.</source>
<translation>“%1”中的内容无效。</translation>
</message>
+ <message>
+ <source>This may be solved by restarting the application after clearing the cache from:</source>
+ <translation>清空此处缓存之后重启应用程序也许可以解决问题:</translation>
+ </message>
</context>
<context>
<name>QInstaller::Component</name>
@@ -747,18 +763,6 @@
<translation>更新程序模式下组件不得包含子项。</translation>
</message>
<message>
- <source>Cannot open the requested UI file &quot;%1&quot;: %2</source>
- <translation>无法打开请求的 UI 文件“%1”:%2</translation>
- </message>
- <message>
- <source>Cannot load the requested UI file &quot;%1&quot;: %2</source>
- <translation>无法加载请求的 UI 文件“%1”:%2</translation>
- </message>
- <message>
- <source>Cannot open the requested license file &quot;%1&quot;: %2</source>
- <translation>无法打开请求的许可文件“%1”:%2</translation>
- </message>
- <message>
<source>Error</source>
<translation>错误</translation>
</message>
@@ -778,6 +782,30 @@
<source>There was an error loading the selected component. This component cannot be installed.</source>
<translation>加载选中组件的过程中出现错误。这个组件不会被安装。</translation>
</message>
+ <message>
+ <source>Cannot open the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>无法打开请求的 UI 文件“%1”:%2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot load the requested UI file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>无法加载请求的 UI 文件“%1”:%2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
+ <message>
+ <source>Cannot open the requested license file &quot;%1&quot;: %2.
+
+%3 &quot;%4&quot;</source>
+ <translation>无法打开请求的许可文件“%1”:%2.
+
+%3 &quot;%4&quot;</translation>
+ </message>
</context>
<context>
<name>QInstaller::ComponentModel</name>
@@ -857,10 +885,6 @@
<translation>在树视图中删除所有组件。</translation>
</message>
<message>
- <source>&amp;Browse QBSP files</source>
- <translation>浏览 QBSP 文件(&amp;B)</translation>
- </message>
- <message>
<source>Select a Qt Board Support Package file to install additional content that is not directly available from the online repositories.</source>
<translation>选择 Qt Board Support Package 文件以安装无法直接从在线存储库中获得的附加内容。</translation>
</message>
@@ -893,7 +917,7 @@
<translation>请选择要卸载的组件。</translation>
</message>
<message>
- <source>Select the components to install. Deselect installed components to uninstall them. Any components already installed will not be updated.</source>
+ <source>Select the components to install. Deselect installed components to uninstall them.&lt;br&gt;Any components already installed will not be updated.</source>
<translation>选择要安装的组件。 取消选择已安装组件以卸载它们。 所有已安装的组件均不会更新。</translation>
</message>
<message>
@@ -904,6 +928,26 @@
<source>Search</source>
<translation>搜索</translation>
</message>
+ <message>
+ <source>Browse &amp;QBSP files</source>
+ <translation>浏览&amp;QBSP文件</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>选择</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>错误</translation>
+ </message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation>创建离线安装程序</translation>
+ </message>
+ <message>
+ <source>Create offline installer from selected components, instead of installing now.</source>
+ <translation>根据选中组件创建离线安装程序,而不是现在就安装。</translation>
+ </message>
</context>
<context>
<name>QInstaller::ConsumeOutputOperation</name>
@@ -1101,14 +1145,6 @@
<translation>下载错误</translation>
</message>
<message>
- <source>Hash verification while downloading failed. This is a temporary error, please retry.</source>
- <translation>下载时的哈希验证失败。 此错误为临时错误,请重试。</translation>
- </message>
- <message>
- <source>Cannot verify Hash</source>
- <translation>无法验证哈希</translation>
- </message>
- <message>
<source>Cannot download archive %1: %2</source>
<translation>无法下载存档 %1:%2</translation>
</message>
@@ -1178,6 +1214,27 @@ Error while loading %2</source>
<source>Total: </source>
<translation>总计:</translation>
</message>
+ <message>
+ <source>Retry count (%1) exceeded</source>
+ <translation>超过重试次数(%1)</translation>
+ </message>
+ <message>
+ <source>Hash verification while downloading failed. This is a temporary error, please retry.
+
+Expected: %1
+Downloaded: %2</source>
+ <translation>下载时的哈希验证失败。 此错误为临时错误,请重试。
+预期的:%1
+已下载:%2</translation>
+ </message>
+ <message>
+ <source>Cannot verify Hash
+Expected: %1
+Downloaded: %2</source>
+ <translation>无法验证哈希
+预期的:%1
+已下载:%2</translation>
+ </message>
</context>
<context>
<name>QInstaller::Downloader</name>
@@ -1316,7 +1373,7 @@ Error while loading %2</source>
<context>
<name>QInstaller::FinishedPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>正在完成 %1 向导</translation>
</message>
<message>
@@ -1324,7 +1381,7 @@ Error while loading %2</source>
<translation>已完成</translation>
</message>
<message>
- <source>Click %1 to exit the %2 Wizard.</source>
+ <source>Click %1 to exit the %2 Setup.</source>
<translation>单击 %1 退出 %2 向导。</translation>
</message>
<message>
@@ -1385,8 +1442,8 @@ Error while loading %2</source>
<context>
<name>QInstaller::IntroductionPage</name>
<message>
- <source>Setup - %1</source>
- <translation>安装程序 - %1</translation>
+ <source>Welcome</source>
+ <translation>欢迎</translation>
</message>
<message>
<source>Welcome to the %1 Setup.</source>
@@ -1417,10 +1474,6 @@ Error while loading %2</source>
<translation>无可用更新。</translation>
</message>
<message>
- <source> Only local package management available.</source>
- <translation>仅本地软件包管理可用。</translation>
- </message>
- <message>
<source>&amp;Quit</source>
<translation>退出</translation>
</message>
@@ -1471,10 +1524,6 @@ Error while loading %2</source>
<source>Can not write license file &quot;%1&quot;.</source>
<translation>无法写入许可文件“%1”。</translation>
</message>
- <message>
- <source>No license files found to delete.</source>
- <translation>未找到要删除的许可文件。</translation>
- </message>
</context>
<context>
<name>QInstaller::LineReplaceOperation</name>
@@ -1534,14 +1583,6 @@ Error while loading %2</source>
<translation>检测到“%1”的校验和不匹配。</translation>
</message>
<message>
- <source>Retrieving meta information from remote repository... %1/%2 </source>
- <translation>正在从远程资料档案库中检索元信息... %1/%2 </translation>
- </message>
- <message>
- <source>Retrieving meta information from remote repository... </source>
- <translation>正在从远程资料档案库中检索元信息... </translation>
- </message>
- <message>
<source>Error while extracting archive &quot;%1&quot;: %2</source>
<translation>提取存档“%1”时出错:%2</translation>
</message>
@@ -1567,6 +1608,26 @@ Error while loading %2</source>
<source>Clearing the cache directory and restarting the application may solve this.</source>
<translation>正在清空缓存目录并且重启应用程序也许可以解决这个问题。</translation>
</message>
+ <message>
+ <source>Unknown exception during updating cache.</source>
+ <translation>更新缓存过程中的未知异常。</translation>
+ </message>
+ <message>
+ <source>Cannot open extracted file &quot;%1&quot; for reading: %2</source>
+ <translation>无法为了读取%2打开已经提取的文件”%1“</translation>
+ </message>
+ <message>
+ <source>Cannot open file &quot;%1&quot; for writing: %2</source>
+ <translation>无法为了写入%2打开文件“%1”</translation>
+ </message>
+ <message>
+ <source>Retrieving information from remote repositories...</source>
+ <translation>正在从远程存储库检索信息...</translation>
+ </message>
+ <message>
+ <source>Retrieving meta information from remote repository...</source>
+ <translation>正在从远程资料档案库中检索元信息...</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerCore</name>
@@ -1705,10 +1766,6 @@ Do you want to continue?</source>
<translation>无法安装 %1。未找到组件。</translation>
</message>
<message>
- <source>Running processes found.</source>
- <translation>已找到正在运行的进程。</translation>
- </message>
- <message>
<source>Cannot elevate access rights while running from command line. Please restart the application as administrator.</source>
<translation>请以管理员身份重新启动应用程序。</translation>
</message>
@@ -1766,7 +1823,23 @@ Do you want to continue?</source>
</message>
<message>
<source>Not enough disk space to store temporary files! %1 are available, while the minimum required is %2. You may select another location for the temporary files by modifying the local cache path from the installer settings.</source>
- <translation type="unfinished">没有足够的硬盘空间存储临时文件!有%1可用,但是最少需要%2。您可以通过修改安装程序设置中的本地缓存路径来为这些临时文件指定另外一个存储位置。</translation>
+ <translation>没有足够的硬盘空间存储临时文件!有%1可用,但是最少需要%2。您可以通过修改安装程序设置中的本地缓存路径来为这些临时文件指定另外一个存储位置。</translation>
+ </message>
+ <message>
+ <source>Cannot resolve components to uninstall.</source>
+ <translation>无法解析要移除的组件。</translation>
+ </message>
+ <message>
+ <source>Cannot select alias %1. There was a problem loading this alias, so it is marked unstable and cannot be selected.</source>
+ <translation>无法选择别名%1。加载这一别名时发生问题,所以它被标识为不稳定,并且无法被选中。</translation>
+ </message>
+ <message>
+ <source>Cannot select %1. Alias is marked virtual, meaning it cannot be selected manually.</source>
+ <translation>无法选择%1。别名被标记为虚拟,意味着它不能被手动选中。</translation>
+ </message>
+ <message>
+ <source>Created installer will use %1 of disk space.</source>
+ <translation>创建的安装程序将使用%1的磁盘空间。</translation>
</message>
</context>
<context>
@@ -1996,10 +2069,6 @@ Do you want to continue?</source>
<translation>无法检索元信息:%1</translation>
</message>
<message>
- <source>Cannot add temporary update source information.</source>
- <translation>无法添加临时更新源信息。</translation>
- </message>
- <message>
<source>Cannot find any update source information.</source>
<translation>找不到任何更新源信息。</translation>
</message>
@@ -2039,6 +2108,18 @@ Do you want to continue?</source>
<source>Loading component scripts...</source>
<translation>正在加载组件脚本……</translation>
</message>
+ <message>
+ <source>Alias declares name that conflicts with an existing component &quot;%1&quot;</source>
+ <translation>别名声明的名称与已经存在的组件“%1”冲突。</translation>
+ </message>
+ <message>
+ <source>Unresolved component aliases</source>
+ <translation>无法解析的组件别名</translation>
+ </message>
+ <message>
+ <source>Cyclic dependency between aliases &quot;%1&quot; and &quot;%2&quot; detected.</source>
+ <translation>检测到别名“%1”和“%2”之间的依赖项循环。</translation>
+ </message>
</context>
<context>
<name>QInstaller::PackageManagerGui</name>
@@ -2142,6 +2223,18 @@ Please copy the installer to a local drive</source>
<source>Uninstalling</source>
<translation>正在卸载</translation>
</message>
+ <message>
+ <source>&amp;Create Offline Installer</source>
+ <translation>创建离线安装程序(&amp;C)</translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer for %1</source>
+ <translation>正在为%1创建离线安装程序</translation>
+ </message>
+ <message>
+ <source>Creating Offline Installer</source>
+ <translation>正在创建离线安装程序</translation>
+ </message>
</context>
<context>
<name>QInstaller::ProxyCredentialsDialog</name>
@@ -2216,6 +2309,18 @@ Please copy the installer to a local drive</source>
<source>Ready to Update</source>
<translation>准备更新</translation>
</message>
+ <message>
+ <source>Create Offline Installer</source>
+ <translation>创建离线安装程序</translation>
+ </message>
+ <message>
+ <source>Ready to Create Offline Installer</source>
+ <translation>准备创建离线安装程序</translation>
+ </message>
+ <message>
+ <source>All required information is now available to create an offline installer for selected components.</source>
+ <translation>为所选组件创建离线安装程序的所需信息都已经准备好。</translation>
+ </message>
</context>
<context>
<name>QInstaller::RegisterFileTypeOperation</name>
@@ -2272,7 +2377,7 @@ Please copy the installer to a local drive</source>
<context>
<name>QInstaller::RestartPage</name>
<message>
- <source>Completing the %1 Setup</source>
+ <source>Finished the %1 Setup</source>
<translation>正在完成 %1 安装向导</translation>
</message>
</context>
@@ -2550,7 +2655,7 @@ or accept the elevation of access rights if being asked.</source>
</message>
<message>
<source>Categories</source>
- <translation type="unfinished">选择类别</translation>
+ <translation>类别</translation>
</message>
</context>
<context>
@@ -2707,6 +2812,10 @@ or accept the elevation of access rights if being asked.</source>
<source>Clear cache</source>
<translation>清空缓存</translation>
</message>
+ <message>
+ <source>Clearing cache...</source>
+ <translation>正在清空缓存...</translation>
+ </message>
</context>
<context>
<name>UpdateOperation</name>
@@ -2767,7 +2876,7 @@ or accept the elevation of access rights if being asked.</source>
</message>
<message>
<source>Information</source>
- <translation type="unfinished">组件信息</translation>
+ <translation>组件信息</translation>
</message>
</context>
<context>
@@ -2973,6 +3082,10 @@ or accept the elevation of access rights if being asked.</source>
<source>Cannot synchronize invalidated cache.</source>
<translation>无法同步失效的缓存。</translation>
</message>
+ <message>
+ <source>Unknown register mode selected!</source>
+ <translation>未知的注册模式被选中!</translation>
+ </message>
</context>
<context>
<name>TabController</name>
diff --git a/tests/auto/installer/appendfileoperation/tst_appendfileoperation.cpp b/tests/auto/installer/appendfileoperation/tst_appendfileoperation.cpp
index 9eb1e2401..743e4c625 100644
--- a/tests/auto/installer/appendfileoperation/tst_appendfileoperation.cpp
+++ b/tests/auto/installer/appendfileoperation/tst_appendfileoperation.cpp
@@ -81,8 +81,7 @@ private slots:
QVERIFY(!op.performOperation());
QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments);
- QCOMPARE(op.errorString(), QString("Invalid arguments in AppendFile: "
- "0 arguments given, exactly 2 arguments expected."));
+ QCOMPARE(op.errorString(), QString("Invalid arguments in AppendFile: 0 arguments given, 2 to 4 arguments expected in the form: <filename> <text to apply> [UNDOOPERATION, \"\"]."));
op.setArguments(QStringList() << "" << "");
QTest::ignoreMessage(QtWarningMsg, "QFSFileEngine::open: No file name specified");
@@ -98,10 +97,14 @@ private slots:
QTest::addColumn<QString>("source");
QTest::addColumn<QString>("append");
QTest::addColumn<QString>("expected");
+ QTest::addColumn<bool>("overrideUndo");
QTest::newRow("newline") << "Line1\nLine2\nLine3\n" << "AppendedText"
- << "Line1\nLine2\nLine3\nAppendedText";
+ << "Line1\nLine2\nLine3\nAppendedText" << false;
QTest::newRow("no newline") << "Lorem ipsum " << "dolore sit amet"
- << "Lorem ipsum dolore sit amet";
+ << "Lorem ipsum dolore sit amet" << false;
+
+ QTest::newRow("no undo") << "Lorem ipsum " << "dolore sit amet"
+ << "Lorem ipsum dolore sit amet" << true;
}
void testAppendText()
@@ -109,6 +112,7 @@ private slots:
QFETCH(QString, source);
QFETCH(QString, append);
QFETCH(QString, expected);
+ QFETCH(bool, overrideUndo);
QFile file(m_testFilePath);
QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Text));
@@ -117,20 +121,29 @@ private slots:
stream << source << Qt::flush;
file.close();
- AppendFileOperation op;
- op.setArguments(QStringList() << m_testFilePath << append);
+ AppendFileOperation *op = new AppendFileOperation();
+ op->setArguments(QStringList() << m_testFilePath << append);
+ if (overrideUndo)
+ op->setArguments(op->arguments() << QLatin1String("UNDOOPERATION"));
- op.backup();
- QVERIFY(QFileInfo(op.value("backupOfFile").toString()).exists());
+ op->backup();
+ QVERIFY(QFileInfo(op->value("backupOfFile").toString()).exists());
- QVERIFY2(op.performOperation(), op.errorString().toLatin1());
+ QVERIFY2(op->performOperation(), op->errorString().toLatin1());
QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text));
QCOMPARE(stream.readAll(), expected);
file.close();
- QVERIFY2(op.undoOperation(), op.errorString().toLatin1());
+ QVERIFY2(op->undoOperation(), op->errorString().toLatin1());
QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text));
- QCOMPARE(stream.readAll(), source);
+ if (overrideUndo)
+ QCOMPARE(stream.readAll(), expected);
+ else
+ QCOMPARE(stream.readAll(), source);
+ QString backupFileName = op->value("backupOfFile").toString();
+ delete op;
+ QVERIFY(!QFileInfo::exists(backupFileName));
+
file.close();
QVERIFY(file.remove());
diff --git a/tests/auto/installer/binaryformat/tst_binaryformat.cpp b/tests/auto/installer/binaryformat/tst_binaryformat.cpp
index 7e0f5ed24..2fcad0b38 100644
--- a/tests/auto/installer/binaryformat/tst_binaryformat.cpp
+++ b/tests/auto/installer/binaryformat/tst_binaryformat.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2021 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -26,6 +26,8 @@
**
**************************************************************************/
+#include "../shared/packagemanager.h"
+
#include <binarycontent.h>
#include <binaryformat.h>
#include <errors.h>
@@ -51,8 +53,8 @@ struct Layout : public QInstaller::BinaryLayout
class TestOperation : public KDUpdater::UpdateOperation
{
public:
- explicit TestOperation(const QString &name)
- : KDUpdater::UpdateOperation(nullptr)
+ explicit TestOperation(const QString &name, PackageManagerCore *core = nullptr)
+ : KDUpdater::UpdateOperation(core)
{ setName(name); }
virtual void backup() {}
@@ -392,6 +394,45 @@ private slots:
resource->close();
}
+ void testXmlDocumentParsing()
+ {
+ PackageManagerCore core;
+ core.setValue(scTargetDir, QLatin1String("relocatable_targetdir"));
+
+ TestOperation op(QLatin1String("Operation 3"), &core);
+ QStringList stringListValue = (QStringList() << QLatin1String("list_value1") << QLatin1String("list_value2"));
+ op.setValue(QLatin1String("string_list"), stringListValue);
+
+ const QString stringValue = core.value(scTargetDir) + QLatin1String(", string_value1");
+ op.setValue(QLatin1String("string"), stringValue);
+
+ QVariantMap map;
+ map.insert(QLatin1String("key1"), 1);
+ map.insert(QLatin1String("key2"), QLatin1String("map_value2"));
+ op.setValue(QLatin1String("variant_map"), map);
+
+ QDomDocument document = op.toXml();
+ QVERIFY2(document.toString().contains(QLatin1String("@RELOCATABLE_PATH@")),
+ "TargetDir not replaced with @RELOCATABLE_PATH@");
+
+ op.fromXml(document); // Resets the operation values from written QDomDocuments
+
+ QCOMPARE(op.value(QLatin1String("string_list")), stringListValue);
+ QVERIFY2(!op.value(QLatin1String("string")).toString().contains(QLatin1String("@RELOCATABLE_PATH@")),
+ "@RELOCATABLE@ not replaced with TargetDir");
+ QCOMPARE(op.value(QLatin1String("variant_map")), map);
+
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ QCOMPARE(op.value(QLatin1String("string_list")).metaType().id(), QMetaType::QStringList);
+ QCOMPARE(op.value(QLatin1String("string")).metaType().id(), QMetaType::QString);
+ QCOMPARE(op.value(QLatin1String("variant_map")).metaType().id(), QMetaType::QVariantMap);
+#else
+ QCOMPARE(op.value(QLatin1String("string_list")).type(), QMetaType::QStringList);
+ QCOMPARE(op.value(QLatin1String("string")).type(), QMetaType::QString);
+ QCOMPARE(op.value(QLatin1String("variant_map")).type(), QMetaType::QVariantMap);
+#endif
+ }
+
void cleanupTestCase()
{
m_manager.clear();
diff --git a/tests/auto/installer/clientserver/BLACKLIST b/tests/auto/installer/clientserver/BLACKLIST
deleted file mode 100644
index a328d26e7..000000000
--- a/tests/auto/installer/clientserver/BLACKLIST
+++ /dev/null
@@ -1,2 +0,0 @@
-[testQProcessWrapper]
-rhel-7.6 ci
diff --git a/tests/auto/installer/clientserver/tst_clientserver.cpp b/tests/auto/installer/clientserver/tst_clientserver.cpp
index 5aa40a5a3..7b3e65c4a 100644
--- a/tests/auto/installer/clientserver/tst_clientserver.cpp
+++ b/tests/auto/installer/clientserver/tst_clientserver.cpp
@@ -369,7 +369,6 @@ private slots:
QCOMPARE(settings.contains("key"), false);
const QDateTime dateTime = QDateTime::currentDateTimeUtc();
- QCOMPARE(settings.iniCodec(), nullptr);
// The wrapper does not support this method, but assume:
// QCOMPARE(wrapper.iniCodec(), QTextCodec::codecForName("UTF-8"));
wrapper.setValue("dateTime", dateTime);
@@ -468,6 +467,9 @@ private slots:
void testQProcessWrapper()
{
+ #ifdef Q_OS_LINUX
+ QSKIP("This test failes in CI redhat");
+ #endif
RemoteServer server;
QString socketName = QUuid::createUuid().toString();
server.init(socketName, QLatin1String("SomeKey"), Protocol::Mode::Production);
diff --git a/tests/auto/installer/commandlineinstall/tst_commandlineinstall.cpp b/tests/auto/installer/commandlineinstall/tst_commandlineinstall.cpp
index a986234c8..4dfadbad6 100644
--- a/tests/auto/installer/commandlineinstall/tst_commandlineinstall.cpp
+++ b/tests/auto/installer/commandlineinstall/tst_commandlineinstall.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -34,9 +34,7 @@
#include <QLoggingCategory>
#include <QTest>
#include <QRegularExpression>
-
-#include <iostream>
-#include <sstream>
+#include <QSignalSpy>
using namespace QInstaller;
@@ -51,15 +49,12 @@ public:
void ignoreAvailablePackagesMissingMessages()
{
QTest::ignoreMessage(QtDebugMsg, QRegularExpression("Searching packages with regular expression:"));
- QTest::ignoreMessage(QtDebugMsg, "Fetching latest update information...");
- QTest::ignoreMessage(QtDebugMsg, "Loading component scripts...");
QTest::ignoreMessage(QtDebugMsg, "No matching packages found.");
}
void ignoreInstallPackageFailsMessages(const QRegularExpression &regExp)
{
QTest::ignoreMessage(QtDebugMsg, "Fetching latest update information...");
- QTest::ignoreMessage(QtDebugMsg, "Loading component scripts...");
QTest::ignoreMessage(QtDebugMsg, regExp);
}
@@ -73,7 +68,7 @@ private slots:
(m_installDir, ":///data/repository"));
auto func = &PackageManagerCore::listAvailablePackages;
- verifyListPackagesMessage(core.get(), QLatin1String("<?xml version=\"1.0\"?>\n"
+ VerifyInstaller::verifyListPackagesMessage(core.get(), QLatin1String("<?xml version=\"1.0\"?>\n"
"<availablepackages>\n"
" <package name=\"AB\" displayname=\"AB\" version=\"1.0.2-1\"/>\n"
" <package name=\"A\" displayname=\"A\" version=\"1.0.2-1\"/>\n"
@@ -81,29 +76,29 @@ private slots:
" <package name=\"C\" displayname=\"C\" version=\"1.0.0-1\"/>\n"
"</availablepackages>\n"), func, QLatin1String("."), QHash<QString, QString>());
- verifyListPackagesMessage(core.get(), QLatin1String("<?xml version=\"1.0\"?>\n"
+ VerifyInstaller::verifyListPackagesMessage(core.get(), QLatin1String("<?xml version=\"1.0\"?>\n"
"<availablepackages>\n"
" <package name=\"AB\" displayname=\"AB\" version=\"1.0.2-1\"/>\n"
" <package name=\"A\" displayname=\"A\" version=\"1.0.2-1\"/>\n"
"</availablepackages>\n"), func, QLatin1String("A"), QHash<QString, QString>());
- verifyListPackagesMessage(core.get(), QLatin1String("<?xml version=\"1.0\"?>\n"
+ VerifyInstaller::verifyListPackagesMessage(core.get(), QLatin1String("<?xml version=\"1.0\"?>\n"
"<availablepackages>\n"
" <package name=\"AB\" displayname=\"AB\" version=\"1.0.2-1\"/>\n"
" <package name=\"A\" displayname=\"A\" version=\"1.0.2-1\"/>\n"
"</availablepackages>\n"), func, QLatin1String("A.*"), QHash<QString, QString>());
- verifyListPackagesMessage(core.get(), QLatin1String("<?xml version=\"1.0\"?>\n"
+ VerifyInstaller::verifyListPackagesMessage(core.get(), QLatin1String("<?xml version=\"1.0\"?>\n"
"<availablepackages>\n"
" <package name=\"B\" displayname=\"B\" version=\"1.0.0-1\"/>\n"
"</availablepackages>\n"), func, QLatin1String("^B"), QHash<QString, QString>());
- verifyListPackagesMessage(core.get(), QLatin1String("<?xml version=\"1.0\"?>\n"
+ VerifyInstaller::verifyListPackagesMessage(core.get(), QLatin1String("<?xml version=\"1.0\"?>\n"
"<availablepackages>\n"
" <package name=\"B\" displayname=\"B\" version=\"1.0.0-1\"/>\n"
"</availablepackages>\n"), func, QLatin1String("^B.*"), QHash<QString, QString>());
- verifyListPackagesMessage(core.get(), QLatin1String("<?xml version=\"1.0\"?>\n"
+ VerifyInstaller::verifyListPackagesMessage(core.get(), QLatin1String("<?xml version=\"1.0\"?>\n"
"<availablepackages>\n"
" <package name=\"C\" displayname=\"C\" version=\"1.0.0-1\"/>\n"
"</availablepackages>\n"), func, QLatin1String("^C"), QHash<QString, QString>());
@@ -113,7 +108,7 @@ private slots:
{ "Version", "1.0.2" },
{ "DisplayName", "A" }
};
- verifyListPackagesMessage(core.get(), QLatin1String("<?xml version=\"1.0\"?>\n"
+ VerifyInstaller::verifyListPackagesMessage(core.get(), QLatin1String("<?xml version=\"1.0\"?>\n"
"<availablepackages>\n"
" <package name=\"AB\" displayname=\"AB\" version=\"1.0.2-1\"/>\n"
" <package name=\"A\" displayname=\"A\" version=\"1.0.2-1\"/>\n"
@@ -121,7 +116,7 @@ private slots:
searchHash.clear();
searchHash.insert("Default", "false");
- verifyListPackagesMessage(core.get(), QLatin1String("<?xml version=\"1.0\"?>\n"
+ VerifyInstaller::verifyListPackagesMessage(core.get(), QLatin1String("<?xml version=\"1.0\"?>\n"
"<availablepackages>\n"
" <package name=\"B\" displayname=\"B\" version=\"1.0.0-1\"/>\n"
"</availablepackages>\n"), func, QString(), searchHash);
@@ -164,8 +159,6 @@ private slots:
QCOMPARE(PackageManagerCore::Canceled, core->installSelectedComponentsSilently(QStringList()
<< QLatin1String("B.subcomponent")));
- ignoreInstallPackageFailsMessages(QRegularExpression("Cannot install MissingComponent. "
- "Component not found.\n"));
QCOMPARE(PackageManagerCore::Canceled, core->installSelectedComponentsSilently(QStringList()
<< QLatin1String("MissingComponent")));
QCOMPARE(PackageManagerCore::Canceled, core->status());
@@ -176,8 +169,6 @@ private slots:
QString loggingRules = (QLatin1String("ifw.installer.installog = true\n"));
PackageManagerCore core;
core.setPackageManager();
- QString appFilePath = QCoreApplication::applicationFilePath();
- core.setAllowedRunningProcesses(QStringList() << appFilePath);
QLoggingCategory::setFilterRules(loggingRules);
QVERIFY(QFile::copy(":/data/componentsFromInstallPackagesRepository.xml", m_installDir + "/components.xml"));
@@ -216,13 +207,13 @@ private slots:
core.setValue(scTargetDir, testDirectory);
- verifyListPackagesMessage(&core, QLatin1String("<?xml version=\"1.0\"?>\n"
+ VerifyInstaller::verifyListPackagesMessage(&core, QLatin1String("<?xml version=\"1.0\"?>\n"
"<localpackages>\n"
" <package name=\"A\" displayname=\"A Title\" version=\"1.0.2-1\"/>\n"
" <package name=\"B\" displayname=\"B Title\" version=\"1.0.0-1\"/>\n"
"</localpackages>\n"), func, QString());
- verifyListPackagesMessage(&core, QLatin1String("<?xml version=\"1.0\"?>\n"
+ VerifyInstaller::verifyListPackagesMessage(&core, QLatin1String("<?xml version=\"1.0\"?>\n"
"<localpackages>\n"
" <package name=\"A\" displayname=\"A Title\" version=\"1.0.2-1\"/>\n"
"</localpackages>\n"), func, QLatin1String("A"));
@@ -231,6 +222,57 @@ private slots:
QVERIFY(dir.removeRecursively());
}
+ void testCategoryInstall_data()
+ {
+ QTest::addColumn<QString>("repository");
+ QTest::addColumn<QStringList>("installComponents");
+ QTest::addColumn<PackageManagerCore::Status>("status");
+
+
+ QTest::newRow("Category installation")
+ << ":///data/installPackagesRepository"
+ << (QStringList() << "componentE")
+ << PackageManagerCore::Success;
+ }
+
+ void testCategoryInstall()
+ {
+ QFETCH(QString, repository);
+ QFETCH(QStringList, installComponents);
+ QFETCH(PackageManagerCore::Status, status);
+
+
+ QString loggingRules = (QLatin1String("ifw.* = true\n"));
+ QLoggingCategory::setFilterRules(loggingRules);
+ QScopedPointer<PackageManagerCore> core(PackageManager::getPackageManagerWithInit
+ (m_installDir));
+
+ RepositoryCategory category;
+ category.setEnabled(false);
+ category.setDisplayName(QLatin1String("category"));
+
+ Repository repo = Repository::fromUserInput(repository);
+ category.addRepository(repo);
+
+ QSet<RepositoryCategory> categories;
+ categories.insert(category);
+
+ core->settings().addRepositoryCategories(categories);
+
+ QSignalSpy spy(core.data(), &PackageManagerCore::statusChanged);
+ QCOMPARE(core->installSelectedComponentsSilently(QStringList() << installComponents), status);
+
+ QList<int> statusArguments;
+
+ for (qsizetype i = 0; i < spy.size(); ++i) {
+ QList<QVariant> tempList = spy.at(i);
+ statusArguments << tempList.at(0).toInt();
+ }
+
+ QVERIFY(statusArguments.contains(PackageManagerCore::NoPackagesFound));
+ QVERIFY(statusArguments.contains(PackageManagerCore::Success));
+ }
+
void testInstall_data()
{
QTest::addColumn<QString>("repository");
@@ -762,21 +804,6 @@ private slots:
}
private:
- template <typename Func, typename... Args>
- void verifyListPackagesMessage(PackageManagerCore *core, const QString &message,
- Func func, Args... args)
- {
- std::ostringstream stream;
- std::streambuf *buf = std::cout.rdbuf();
- std::cout.rdbuf(stream.rdbuf());
-
- (core->*func)(std::forward<Args>(args)...);
-
- std::cout.rdbuf(buf);
- QVERIFY(stream && stream.str() == message.toStdString());
- }
-
-private:
QString m_installDir;
};
diff --git a/tests/auto/installer/componentalias/componentalias.pro b/tests/auto/installer/componentalias/componentalias.pro
new file mode 100644
index 000000000..efbc0268f
--- /dev/null
+++ b/tests/auto/installer/componentalias/componentalias.pro
@@ -0,0 +1,8 @@
+include(../../qttest.pri)
+
+QT -= gui
+QT += testlib
+
+SOURCES = tst_componentalias.cpp
+
+RESOURCES += settings.qrc
diff --git a/tests/auto/installer/componentalias/data/aliases-optional.xml b/tests/auto/installer/componentalias/data/aliases-optional.xml
new file mode 100644
index 000000000..bc16013b7
--- /dev/null
+++ b/tests/auto/installer/componentalias/data/aliases-optional.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Aliases>
+ <Alias>
+ <Name>set-A</Name>
+ <DisplayName>Installation A (optional component requirement)</DisplayName>
+ <Description>Installs component A</Description>
+ <Version>2.0.0</Version>
+ <Virtual>false</Virtual>
+ <RequiredComponents>A</RequiredComponents>
+ <OptionalComponents>component-nonexistent,B</OptionalComponents>
+ </Alias>
+ <Alias>
+ <Name>set-full</Name>
+ <DisplayName>Full installation (optional alias requirement)</DisplayName>
+ <Description>Installs all components</Description>
+ <Version>2.0.0</Version>
+ <Virtual>false</Virtual>
+ <OptionalAliases>set-A,set-nonexistent</OptionalAliases>
+ </Alias>
+ <Alias>
+ <Name>set-optional-broken</Name>
+ <DisplayName>Optionally requires broken alias</DisplayName>
+ <Description>Optionally requires broken alias</Description>
+ <Version>2.0.0</Version>
+ <Virtual>false</Virtual>
+ <OptionalAliases>set-broken</OptionalAliases>
+ </Alias>
+ <Alias>
+ <Name>set-broken</Name>
+ <DisplayName>Requires non-existent alias</DisplayName>
+ <Description>Requires non-existent alias</Description>
+ <Version>2.0.0</Version>
+ <Virtual>false</Virtual>
+ <RequiredAliases>set-nonexistent</RequiredAliases>
+ </Alias>
+</Aliases>
diff --git a/tests/auto/installer/componentalias/data/aliases-priority.xml b/tests/auto/installer/componentalias/data/aliases-priority.xml
new file mode 100644
index 000000000..f90d006b2
--- /dev/null
+++ b/tests/auto/installer/componentalias/data/aliases-priority.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Aliases>
+ <Alias>
+ <Name>set-A</Name>
+ <DisplayName>Installation A (priority)</DisplayName>
+ <Description>Installs component A</Description>
+ <Version>1.0.0</Version>
+ <Virtual>false</Virtual>
+ <RequiredComponents>A</RequiredComponents>
+ </Alias>
+ <Alias>
+ <Name>set-B</Name>
+ <DisplayName>Virtual installation B (priority)</DisplayName>
+ <Description>Installs component B</Description>
+ <Version>1.0.0</Version>
+ <Virtual>true</Virtual>
+ <RequiredComponents>B</RequiredComponents>
+ </Alias>
+ <Alias>
+ <Name>set-D</Name>
+ <DisplayName>Installation D (Unstable) (priority)</DisplayName>
+ <Description>Installs missing component D</Description>
+ <Version>1.0.0</Version>
+ <Virtual>false</Virtual>
+ <RequiredComponents>D</RequiredComponents>
+ </Alias>
+ <Alias>
+ <Name>set-full</Name>
+ <DisplayName>Full installation (priority)</DisplayName>
+ <Description>Installs all components</Description>
+ <Version>1.0.0</Version>
+ <Virtual>false</Virtual>
+ <RequiredAliases>set-A,set-B</RequiredAliases>
+ <RequiredComponents>C</RequiredComponents>
+ </Alias>
+</Aliases>
diff --git a/tests/auto/installer/componentalias/data/aliases-versions.xml b/tests/auto/installer/componentalias/data/aliases-versions.xml
new file mode 100644
index 000000000..993e14673
--- /dev/null
+++ b/tests/auto/installer/componentalias/data/aliases-versions.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Aliases>
+ <Alias>
+ <Name>set-A</Name>
+ <DisplayName>Installation A (updated)</DisplayName>
+ <Description>Installs component A</Description>
+ <Version>2.0.0</Version>
+ <Virtual>false</Virtual>
+ <RequiredComponents>A</RequiredComponents>
+ </Alias>
+ <Alias>
+ <Name>set-B</Name>
+ <DisplayName>Virtual installation B (updated)</DisplayName>
+ <Description>Installs component B</Description>
+ <Version>1.1.0</Version>
+ <Virtual>true</Virtual>
+ <RequiredComponents>B</RequiredComponents>
+ </Alias>
+ <Alias>
+ <Name>set-D</Name>
+ <DisplayName>Installation D (Unstable) (updated)</DisplayName>
+ <Description>Installs missing component D</Description>
+ <Version>1.2.0</Version>
+ <Virtual>false</Virtual>
+ <RequiredComponents>D</RequiredComponents>
+ </Alias>
+ <Alias>
+ <Name>set-full</Name>
+ <DisplayName>Full installation (updated)</DisplayName>
+ <Description>Installs all components</Description>
+ <Version>3.0.0</Version>
+ <Virtual>false</Virtual>
+ <RequiredAliases>set-A,set-B</RequiredAliases>
+ <RequiredComponents>C</RequiredComponents>
+ </Alias>
+</Aliases>
diff --git a/tests/auto/installer/componentalias/data/aliases.json b/tests/auto/installer/componentalias/data/aliases.json
new file mode 100644
index 000000000..4c78e20d2
--- /dev/null
+++ b/tests/auto/installer/componentalias/data/aliases.json
@@ -0,0 +1,38 @@
+{
+ "alias-packages": [
+ {
+ "Description": "Installs component A",
+ "DisplayName": "Installation A (JSON)",
+ "Name": "set-A-json",
+ "RequiredComponents": [
+ "A"
+ ],
+ "Version": "1.0.0",
+ "Virtual": false
+ },
+ {
+ "Description": "Installs component B",
+ "DisplayName": "Virtual installation B (JSON)",
+ "Name": "set-B-json",
+ "RequiredComponents": [
+ "B"
+ ],
+ "Version": "1.0.0",
+ "Virtual": true
+ },
+ {
+ "Description": "Installs all components",
+ "DisplayName": "Full installation (JSON)",
+ "Name": "set-full-json",
+ "RequiredAliases": [
+ "set-A-json",
+ "set-B-json"
+ ],
+ "RequiredComponents": [
+ "C"
+ ],
+ "Version": "1.0.0",
+ "Virtual": false
+ }
+ ]
+}
diff --git a/tests/auto/installer/componentalias/data/repository/Updates.xml b/tests/auto/installer/componentalias/data/repository/Updates.xml
new file mode 100644
index 000000000..e128590dc
--- /dev/null
+++ b/tests/auto/installer/componentalias/data/repository/Updates.xml
@@ -0,0 +1,43 @@
+<Updates>
+ <ApplicationName>{AnyApplication}</ApplicationName>
+ <ApplicationVersion>1.0.0</ApplicationVersion>
+ <Checksum>true</Checksum>
+ <PackageUpdate>
+ <Name>A</Name>
+ <DisplayName>A</DisplayName>
+ <Description>Example component A</Description>
+ <Version>1.0.2-1</Version>
+ <ReleaseDate>2015-01-01</ReleaseDate>
+ <Default>false</Default>
+ </PackageUpdate>
+ <PackageUpdate>
+ <Name>B</Name>
+ <DisplayName>B</DisplayName>
+ <Description>Example component B</Description>
+ <Version>1.0.0-1</Version>
+ <ReleaseDate>2015-01-01</ReleaseDate>
+ <Default>false</Default>
+ </PackageUpdate>
+ <PackageUpdate>
+ <Name>C</Name>
+ <DisplayName>C</DisplayName>
+ <Description>Example component C</Description>
+ <Version>1.0.0-1</Version>
+ <ReleaseDate>2015-01-01</ReleaseDate>
+ <Default>false</Default>
+ </PackageUpdate>
+ <PackageUpdate>
+ <Name>C.subcomponent</Name>
+ <DisplayName>Subcomponent of C</DisplayName>
+ <Description>Example subcomponent</Description>
+ <Version>1.0.0-1</Version>
+ <ReleaseDate>2015-01-01</ReleaseDate>
+ </PackageUpdate>
+ <PackageUpdate>
+ <Name>C.subcomponent.subcomponent</Name>
+ <DisplayName>Subcomponent of subcomponent component</DisplayName>
+ <Description>Example subcomponent of subcomponent</Description>
+ <Version>1.0.0-1</Version>
+ <ReleaseDate>2015-01-01</ReleaseDate>
+ </PackageUpdate>
+</Updates>
diff --git a/tests/auto/installer/componentalias/metadata/installer-config/aliases.xml b/tests/auto/installer/componentalias/metadata/installer-config/aliases.xml
new file mode 100644
index 000000000..278ae918b
--- /dev/null
+++ b/tests/auto/installer/componentalias/metadata/installer-config/aliases.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Aliases>
+ <Alias>
+ <Name>set-A</Name>
+ <DisplayName>Installation A</DisplayName>
+ <Description>Installs component A</Description>
+ <Version>1.0.0</Version>
+ <Virtual>false</Virtual>
+ <RequiredComponents>A</RequiredComponents>
+ </Alias>
+ <Alias>
+ <Name>set-B</Name>
+ <DisplayName>Virtual installation B</DisplayName>
+ <Description>Installs component B</Description>
+ <Version>1.0.0</Version>
+ <Virtual>true</Virtual>
+ <RequiredComponents>B</RequiredComponents>
+ </Alias>
+ <Alias>
+ <Name>set-D</Name>
+ <DisplayName>Installation D (Unstable)</DisplayName>
+ <Description>Installs missing component D</Description>
+ <Version>1.0.0</Version>
+ <Virtual>false</Virtual>
+ <RequiredComponents>D</RequiredComponents>
+ </Alias>
+ <Alias>
+ <Name>set-E</Name>
+ <DisplayName>Installation E (Requires unstable)</DisplayName>
+ <Description>Installs set E</Description>
+ <Version>1.0.0</Version>
+ <Virtual>false</Virtual>
+ <RequiredAliases>set-D</RequiredAliases>
+ </Alias>
+ <Alias>
+ <Name>set-F</Name>
+ <DisplayName>Installation F (Requires alias that refers another unstable)</DisplayName>
+ <Description>Installs set F</Description>
+ <Version>1.0.0</Version>
+ <Virtual>false</Virtual>
+ <RequiredAliases>set-E</RequiredAliases>
+ </Alias>
+ <Alias>
+ <Name>set-full</Name>
+ <DisplayName>Full installation</DisplayName>
+ <Description>Installs all components</Description>
+ <Version>1.0.0</Version>
+ <Virtual>false</Virtual>
+ <RequiredAliases>set-A,set-B</RequiredAliases>
+ <RequiredComponents>C</RequiredComponents>
+ </Alias>
+</Aliases>
diff --git a/tests/auto/installer/componentalias/metadata/installer-config/config.xml b/tests/auto/installer/componentalias/metadata/installer-config/config.xml
new file mode 100644
index 000000000..9e2b5af55
--- /dev/null
+++ b/tests/auto/installer/componentalias/metadata/installer-config/config.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Installer>
+ <Name>test</Name>
+ <Version>1.0.0</Version>
+ <AliasDefinitionsFile>aliases.xml</AliasDefinitionsFile>
+</Installer>
diff --git a/tests/auto/installer/componentalias/settings.qrc b/tests/auto/installer/componentalias/settings.qrc
new file mode 100644
index 000000000..771586edd
--- /dev/null
+++ b/tests/auto/installer/componentalias/settings.qrc
@@ -0,0 +1,11 @@
+<RCC>
+ <qresource prefix="/">
+ <file>data/repository/Updates.xml</file>
+ <file>data/aliases.json</file>
+ <file>data/aliases-priority.xml</file>
+ <file>data/aliases-versions.xml</file>
+ <file>data/aliases-optional.xml</file>
+ <file>metadata/installer-config/config.xml</file>
+ <file>metadata/installer-config/aliases.xml</file>
+ </qresource>
+</RCC>
diff --git a/tests/auto/installer/componentalias/tst_componentalias.cpp b/tests/auto/installer/componentalias/tst_componentalias.cpp
new file mode 100644
index 000000000..f6742af1f
--- /dev/null
+++ b/tests/auto/installer/componentalias/tst_componentalias.cpp
@@ -0,0 +1,269 @@
+/**************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#include "../shared/packagemanager.h"
+#include "../shared/verifyinstaller.h"
+
+#include <packagemanagercore.h>
+#include <componentalias.h>
+
+#include <QTest>
+#include <QLoggingCategory>
+
+using namespace QInstaller;
+
+class tst_ComponentAlias : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void init()
+ {
+ m_installDir = QInstaller::generateTemporaryFileName();
+ QVERIFY(QDir().mkpath(m_installDir));
+ }
+
+ void cleanup()
+ {
+ QDir dir(m_installDir);
+ QVERIFY(dir.removeRecursively());
+ }
+
+ void testSearchAlias()
+ {
+ QString loggingRules = (QLatin1String("ifw.* = false\n"));
+
+ QLoggingCategory::setFilterRules(loggingRules);
+ QScopedPointer<PackageManagerCore> core(PackageManager::getPackageManager
+ (m_installDir, ":///data/repository"));
+
+ core->setCommandLineInstance(true);
+
+ auto listMethod = &PackageManagerCore::listAvailableAliases;
+
+ VerifyInstaller::verifyListPackagesMessage(core.get(), QLatin1String("\n"
+ "Name: set-A\n"
+ "Display name: Installation A\n"
+ "Description: Installs component A\n"
+ "Version: 1.0.0\n"
+ "Components: A\n"
+ "Required aliases: \n"
+ "Optional components: \n"
+ "Optional aliases: \n"
+ "========================================\n"
+ "Name: set-full\n"
+ "Display name: Full installation\n"
+ "Description: Installs all components\n"
+ "Version: 1.0.0\n"
+ "Components: C\n"
+ "Required aliases: set-A,set-B\n"
+ "Optional components: \n"
+ "Optional aliases: \n"), listMethod, QString());
+
+ VerifyInstaller::verifyListPackagesMessage(core.get(), QLatin1String("\n"
+ "Name: set-A\n"
+ "Display name: Installation A\n"
+ "Description: Installs component A\n"
+ "Version: 1.0.0\n"
+ "Components: A\n"
+ "Required aliases: \n"
+ "Optional components: \n"
+ "Optional aliases: \n"), listMethod, QLatin1String("A"));
+ }
+
+ void testAliasSourceWithPriority()
+ {
+ QString loggingRules = (QLatin1String("ifw.* = false\n"));
+
+ QLoggingCategory::setFilterRules(loggingRules);
+ QScopedPointer<PackageManagerCore> core(PackageManager::getPackageManager
+ (m_installDir, ":///data/repository"));
+
+ core->setCommandLineInstance(true);
+ core->addAliasSource(AliasSource(AliasSource::SourceFileFormat::Xml,
+ ":///data/aliases-priority.xml", 1));
+
+ auto listMethod = &PackageManagerCore::listAvailableAliases;
+
+ VerifyInstaller::verifyListPackagesMessage(core.get(), QLatin1String("\n"
+ "Name: set-A\n"
+ "Display name: Installation A (priority)\n"
+ "Description: Installs component A\n"
+ "Version: 1.0.0\n"
+ "Components: A\n"
+ "Required aliases: \n"
+ "Optional components: \n"
+ "Optional aliases: \n"
+ "========================================\n"
+ "Name: set-full\n"
+ "Display name: Full installation (priority)\n"
+ "Description: Installs all components\n"
+ "Version: 1.0.0\n"
+ "Components: C\n"
+ "Required aliases: set-A,set-B\n"
+ "Optional components: \n"
+ "Optional aliases: \n"), listMethod, QString());
+ }
+
+ void testAliasSourceWithVersionCompare()
+ {
+ QString loggingRules = (QLatin1String("ifw.* = false\n"));
+
+ QLoggingCategory::setFilterRules(loggingRules);
+ QScopedPointer<PackageManagerCore> core(PackageManager::getPackageManager
+ (m_installDir, ":///data/repository"));
+
+ core->setCommandLineInstance(true);
+ core->addAliasSource(AliasSource(AliasSource::SourceFileFormat::Xml,
+ ":///data/aliases-versions.xml", -1));
+
+ auto listMethod = &PackageManagerCore::listAvailableAliases;
+
+ VerifyInstaller::verifyListPackagesMessage(core.get(), QLatin1String("\n"
+ "Name: set-A\n"
+ "Display name: Installation A (updated)\n"
+ "Description: Installs component A\n"
+ "Version: 2.0.0\n"
+ "Components: A\n"
+ "Required aliases: \n"
+ "Optional components: \n"
+ "Optional aliases: \n"
+ "========================================\n"
+ "Name: set-full\n"
+ "Display name: Full installation (updated)\n"
+ "Description: Installs all components\n"
+ "Version: 3.0.0\n"
+ "Components: C\n"
+ "Required aliases: set-A,set-B\n"
+ "Optional components: \n"
+ "Optional aliases: \n"), listMethod, QString());
+ }
+
+ void testInstallAlias_data()
+ {
+ QTest::addColumn<AliasSource>("additionalSource");
+ QTest::addColumn<QStringList>("selectedAliases");
+ QTest::addColumn<PackageManagerCore::Status>("status");
+ QTest::addColumn<QStringList>("installedComponents");
+
+ QTest::newRow("Simple alias")
+ << AliasSource()
+ << (QStringList() << "set-A")
+ << PackageManagerCore::Success
+ << (QStringList() << "A");
+
+ QTest::newRow("Alias with dependencies")
+ << AliasSource()
+ << (QStringList() << "set-full")
+ << PackageManagerCore::Success
+ << (QStringList() << "A" << "B" << "C" << "C.subcomponent" << "C.subcomponent.subcomponent");
+
+ QTest::newRow("Alias with dependencies (JSON source)")
+ << AliasSource(AliasSource::SourceFileFormat::Json, ":///data/aliases.json", -1)
+ << (QStringList() << "set-full-json")
+ << PackageManagerCore::Success
+ << (QStringList() << "A" << "B" << "C" << "C.subcomponent" << "C.subcomponent.subcomponent");
+
+ QTest::newRow("Alias with optional components (existent and non-existent)")
+ << AliasSource(AliasSource::SourceFileFormat::Xml, ":///data/aliases-optional.xml", -1)
+ << (QStringList() << "set-A")
+ << PackageManagerCore::Success
+ << (QStringList() << "A" << "B");
+
+ QTest::newRow("Alias with optional aliases (existent and non-existent)")
+ << AliasSource(AliasSource::SourceFileFormat::Xml, ":///data/aliases-optional.xml", -1)
+ << (QStringList() << "set-full")
+ << PackageManagerCore::Success
+ << (QStringList() << "A" << "B");
+
+ QTest::newRow("Alias with optional broken alias (will not install)")
+ << AliasSource(AliasSource::SourceFileFormat::Xml, ":///data/aliases-optional.xml", -1)
+ << (QStringList() << "set-optional-broken")
+ << PackageManagerCore::Canceled
+ << QStringList();
+ }
+
+ void testInstallAlias()
+ {
+ QFETCH(AliasSource, additionalSource);
+ QFETCH(QStringList, selectedAliases);
+ QFETCH(PackageManagerCore::Status, status);
+ QFETCH(QStringList, installedComponents);
+
+ QScopedPointer<PackageManagerCore> core(PackageManager::getPackageManagerWithInit
+ (m_installDir, ":///data/repository"));
+
+ core->setCommandLineInstance(true);
+
+ if (!additionalSource.filename.isEmpty())
+ core->addAliasSource(additionalSource);
+
+ QCOMPARE(core->installSelectedComponentsSilently(selectedAliases), status);
+
+ for (const QString &component : installedComponents)
+ QVERIFY(core->componentByName(component)->isInstalled());
+ }
+
+ void testInstallAliasFails_data()
+ {
+ QTest::addColumn<QStringList>("selectedAliases");
+ QTest::addColumn<PackageManagerCore::Status>("status");
+
+ QTest::newRow("Virtual alias")
+ << (QStringList() << "set-B")
+ << PackageManagerCore::Canceled;
+
+ QTest::newRow("Unstable alias")
+ << (QStringList() << "set-D")
+ << PackageManagerCore::Canceled;
+
+ QTest::newRow("Nested reference to unstable alias")
+ << (QStringList() << "set-F")
+ << PackageManagerCore::Canceled;
+ }
+
+ void testInstallAliasFails()
+ {
+ QFETCH(QStringList, selectedAliases);
+ QFETCH(PackageManagerCore::Status, status);
+
+ QScopedPointer<PackageManagerCore> core(PackageManager::getPackageManagerWithInit
+ (m_installDir, ":///data/repository"));
+
+ core->setCommandLineInstance(true);
+
+ QCOMPARE(status, core->installSelectedComponentsSilently(selectedAliases));
+ }
+
+private:
+ QString m_installDir;
+};
+
+QTEST_GUILESS_MAIN(tst_ComponentAlias)
+
+#include "tst_componentalias.moc"
diff --git a/tests/auto/installer/componentmodel/tst_componentmodel.cpp b/tests/auto/installer/componentmodel/tst_componentmodel.cpp
index 6bf78d88d..276292233 100644
--- a/tests/auto/installer/componentmodel/tst_componentmodel.cpp
+++ b/tests/auto/installer/componentmodel/tst_componentmodel.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2021 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -373,7 +373,11 @@ private slots:
{
QStringList localesToTest = { "en_US", "ru_RU", "de_DE", "fr_FR" };
foreach (const QString &localeToTest, localesToTest) {
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ QLocale::setDefault(QLocale(localeToTest));
+#else
QLocale::setDefault(localeToTest);
+#endif
QString expectedName = rootComponentDisplayNames.contains(localeToTest.toLower())
? rootComponentDisplayNames[localeToTest.toLower()]
: rootComponentDisplayNames[QString()];
diff --git a/tests/auto/installer/copyoperationtest/tst_copyoperationtest.cpp b/tests/auto/installer/copyoperationtest/tst_copyoperationtest.cpp
index d41853eee..692fd86d9 100644
--- a/tests/auto/installer/copyoperationtest/tst_copyoperationtest.cpp
+++ b/tests/auto/installer/copyoperationtest/tst_copyoperationtest.cpp
@@ -87,37 +87,48 @@ private slots:
QVERIFY(!op.performOperation());
QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments);
- QCOMPARE(op.errorString(), QString("Invalid arguments in Copy: "
- "0 arguments given, exactly 2 arguments expected."));
-
+ QCOMPARE(op.errorString(), QString("Invalid arguments in Copy: 0 arguments given, "
+ "2 to 4 arguments expected in the form: <source filename> <destination filename> [UNDOOPERATION, \"\"]."));
}
void testCopySomething_data()
{
- QTest::addColumn<QString>("source");
- QTest::addColumn<QString>("destination");
- QTest::newRow("full path syntax") << qApp->applicationFilePath() << m_testDestinationFilePath;
- QTest::newRow("short destination syntax") << qApp->applicationFilePath() << m_testDestinationPath;
- QTest::newRow("short destination syntax with ending separator") << qApp->applicationFilePath()
- << m_testDestinationPath + QDir::separator();
+ QTest::addColumn<QString>("source");
+ QTest::addColumn<QString>("destination");
+ QTest::addColumn<bool>("overrideUndo");
+ QTest::newRow("full path syntax") << qApp->applicationFilePath() << m_testDestinationFilePath << false;
+ QTest::newRow("short destination syntax") << qApp->applicationFilePath() << m_testDestinationPath << false;
+ QTest::newRow("short destination syntax with ending separator") << qApp->applicationFilePath()
+ << m_testDestinationPath + QDir::separator() << false;
+ QTest::newRow("override undo") << qApp->applicationFilePath() << m_testDestinationFilePath << true;
}
void testCopySomething()
{
QFETCH(QString, source);
QFETCH(QString, destination);
+ QFETCH(bool, overrideUndo);
- QVERIFY2(QFileInfo(source).exists(), QString("Source file \"%1\" does not exist.").arg(source).toLatin1());
- CopyOperation op;
- op.setArguments(QStringList() << source << destination);
- op.backup();
- QVERIFY2(op.performOperation(), op.errorString().toLatin1());
+ QVERIFY2(QFileInfo::exists(source), QString("Source file \"%1\" does not exist.").arg(source).toLatin1());
+ CopyOperation *op = new CopyOperation();
+ op->setArguments(QStringList() << source << destination);
+ if (overrideUndo)
+ op->setArguments(op->arguments() << QLatin1String("UNDOOPERATION"));
+ op->backup();
+ QVERIFY2(op->performOperation(), op->errorString().toLatin1());
- QVERIFY2(QFileInfo(m_testDestinationFilePath).exists(), QString("Copying from \"%1\" to \"%2\" was "
+ QVERIFY2(QFileInfo::exists(m_testDestinationFilePath), QString("Copying from \"%1\" to \"%2\" was "
"not working: '%3' does not exist").arg(source, destination, m_testDestinationFilePath).toLatin1());
- QVERIFY2(op.undoOperation(), op.errorString().toLatin1());
- QVERIFY2(!QFileInfo(m_testDestinationFilePath).exists(), QString("Undo of copying from \"%1\" to "
- "\"%2\" was not working.").toLatin1());
+ QVERIFY2(op->undoOperation(), op->errorString().toLatin1());
+ if (!overrideUndo) {
+ QVERIFY2(!QFileInfo::exists(m_testDestinationFilePath), QString("Undo of copying from \"%1\" to "
+ "\"%2\" was not working.").toLatin1());
+ } else {
+ QVERIFY(QFileInfo::exists(m_testDestinationFilePath));
+ }
+ QString backupFileName = op->value("backupOfExistingDestination").toString();
+ delete op;
+ QVERIFY(!QFileInfo::exists(backupFileName));
}
void testCopyIfDestinationExist_data()
diff --git a/tests/auto/installer/createoffline/tst_createoffline.cpp b/tests/auto/installer/createoffline/tst_createoffline.cpp
index 123f37a5b..607f9b7cc 100644
--- a/tests/auto/installer/createoffline/tst_createoffline.cpp
+++ b/tests/auto/installer/createoffline/tst_createoffline.cpp
@@ -93,7 +93,7 @@ private slots:
<< PackageManagerCore::Canceled;
QTest::newRow("Invalid repository")
<< ":///data/repository-invalid" << "a.dummy.component"
- << PackageManagerCore::Failure;
+ << PackageManagerCore::Canceled;
}
void testCreateOfflineInstaller()
@@ -136,13 +136,13 @@ private slots:
<< true << PackageManagerCore::Canceled;
QTest::newRow("Disallow unstable | Missing dependency with selected component")
<< ":///data/repository-missingdependency" << "example.with.unstable.dependency"
- << false << PackageManagerCore::Failure;
+ << false << PackageManagerCore::Canceled;
QTest::newRow("Allow unstable | Missing dependency with other component")
<< ":///data/repository-missingdependency" << "example.without.unstable.dependency"
<< true << PackageManagerCore::Success;
QTest::newRow("Disallow unstable | Missing dependency with other component")
<< ":///data/repository-missingdependency" << "example.without.unstable.dependency"
- << false << PackageManagerCore::Failure;
+ << false << PackageManagerCore::Canceled;
}
void testCreateOfflineWithUnstableComponent()
diff --git a/tests/auto/installer/createshortcutoperation/tst_createshortcutoperation.cpp b/tests/auto/installer/createshortcutoperation/tst_createshortcutoperation.cpp
index 67856a74c..a08567d64 100644
--- a/tests/auto/installer/createshortcutoperation/tst_createshortcutoperation.cpp
+++ b/tests/auto/installer/createshortcutoperation/tst_createshortcutoperation.cpp
@@ -56,7 +56,6 @@ private:
QList<OperationBlob> (), QString(), QString(), Protocol::DefaultAuthorizationKey,
Protocol::Mode::Production, QHash<QString, QString>(), true));
- core->setAllowedRunningProcesses(QStringList() << QCoreApplication::applicationFilePath());
core->disableWriteMaintenanceTool();
core->setAutoConfirmCommand();
QSet<Repository> repoList;
diff --git a/tests/auto/installer/deleteoperation/tst_deleteoperation.cpp b/tests/auto/installer/deleteoperation/tst_deleteoperation.cpp
index 807d03498..43ea52407 100644
--- a/tests/auto/installer/deleteoperation/tst_deleteoperation.cpp
+++ b/tests/auto/installer/deleteoperation/tst_deleteoperation.cpp
@@ -75,8 +75,7 @@ private slots:
QVERIFY(!op.performOperation());
QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments);
- QCOMPARE(op.errorString(), QString("Invalid arguments in Delete: "
- "0 arguments given, exactly 1 arguments expected."));
+ QCOMPARE(op.errorString(), QString("Invalid arguments in Delete: 0 arguments given, 1 to 3 arguments expected in the form: <file to remove> [UNDOOPERATION, \"\"]."));
op.setArguments(QStringList() << "");
QTest::ignoreMessage(QtWarningMsg, "QFile::copy: Empty or null file name");
@@ -92,13 +91,16 @@ private slots:
void testDeleteRestore_data()
{
QTest::addColumn<QString>("path");
- QTest::newRow("relative") << "test";
- QTest::newRow("absolute") << qApp->applicationDirPath() + QDir::toNativeSeparators("/test");
+ QTest::addColumn<bool>("overrideUndo");
+ QTest::newRow("relative") << "test" << false;
+ QTest::newRow("absolute") << qApp->applicationDirPath() + QDir::toNativeSeparators("/test") << false;
+ QTest::newRow("no undo") << "test" << true;
}
void testDeleteRestore()
{
QFETCH(QString, path);
+ QFETCH(bool, overrideUndo);
QByteArray testString("Generated by QTest\n");
QFile testFile(path);
@@ -107,23 +109,32 @@ private slots:
out << testString;
testFile.close();
- QVERIFY(QFileInfo(path).exists());
+ QVERIFY(QFileInfo::exists(path));
QByteArray testFileHash = QInstaller::calculateHash(path, QCryptographicHash::Sha1);
- DeleteOperation op;
- op.setArguments(QStringList() << path);
-
- op.backup();
- QVERIFY(QFileInfo(op.value("backupOfExistingFile").toString()).exists());
-
- QVERIFY2(op.performOperation(), op.errorString().toLatin1());
- QVERIFY(!QFileInfo(path).exists());
-
- QVERIFY2(op.undoOperation(), op.errorString().toLatin1());
- QByteArray restoredFileHash = QInstaller::calculateHash(path, QCryptographicHash::Sha1);
- QVERIFY(testFileHash == restoredFileHash);
-
- QVERIFY(QFile(path).remove());
+ DeleteOperation *op = new DeleteOperation();
+ op->setArguments(QStringList() << path);
+ if (overrideUndo)
+ op->setArguments(op->arguments() << QLatin1String("UNDOOPERATION"));
+
+ op->backup();
+ QVERIFY(QFileInfo::exists(op->value("backupOfExistingFile").toString()));
+
+ QVERIFY2(op->performOperation(), op->errorString().toLatin1());
+ QVERIFY(!QFileInfo::exists(path));
+
+ QVERIFY2(op->undoOperation(), op->errorString().toLatin1());
+ if (!overrideUndo) {
+ QByteArray restoredFileHash = QInstaller::calculateHash(path, QCryptographicHash::Sha1);
+ QVERIFY(testFileHash == restoredFileHash);
+ } else {
+ QVERIFY(!QFileInfo::exists(path));
+ }
+
+ QString backupFileName = op->value("backupOfExistingFile").toString();
+ delete op;
+ QVERIFY(!QFileInfo::exists(backupFileName));
+ QCOMPARE(QFile(path).remove(), !overrideUndo);
}
void testDeleteFromScript()
diff --git a/tests/auto/installer/installer.pro b/tests/auto/installer/installer.pro
index ff070d143..b2eb57790 100644
--- a/tests/auto/installer/installer.pro
+++ b/tests/auto/installer/installer.pro
@@ -15,6 +15,7 @@ SUBDIRS += \
scriptengine \
consumeoutputoperationtest \
mkdiroperationtest \
+ rmdiroperationtest \
copyoperationtest \
solver \
binaryformat \
@@ -29,6 +30,7 @@ SUBDIRS += \
linereplaceoperation \
metadatajob \
appendfileoperation \
+ prependfileoperation \
simplemovefileoperation \
deleteoperation \
copydirectoryoperation \
@@ -43,7 +45,8 @@ SUBDIRS += \
contentshaupdate \
componentreplace \
metadatacache \
- contentsha1check
+ contentsha1check \
+ componentalias
CONFIG(libarchive) {
SUBDIRS += libarchivearchive
diff --git a/tests/auto/installer/messageboxhandler/tst_messageboxhandler.cpp b/tests/auto/installer/messageboxhandler/tst_messageboxhandler.cpp
index d7ef0df90..5db79cc55 100644
--- a/tests/auto/installer/messageboxhandler/tst_messageboxhandler.cpp
+++ b/tests/auto/installer/messageboxhandler/tst_messageboxhandler.cpp
@@ -95,7 +95,6 @@ private slots:
core = new PackageManagerCore(BinaryContent::MagicInstallerMarker, QList<OperationBlob> (),
QString(), QString(), Protocol::DefaultAuthorizationKey, Protocol::Mode::Production,
QHash<QString, QString>(), true);
- core->setAllowedRunningProcesses(QStringList() << QCoreApplication::applicationFilePath());
core->disableWriteMaintenanceTool();
core->setAutoConfirmCommand();
m_installDir = QInstaller::generateTemporaryFileName();
@@ -196,7 +195,7 @@ private slots:
setRepository(":///data/missingarchive");
core->autoAcceptMessageBoxes();
core->installSelectedComponentsSilently(QStringList () << "C");
- QCOMPARE(PackageManagerCore::Canceled, core->status());
+ QCOMPARE(PackageManagerCore::Failure, core->status()); // Fails after retrying
}
void messageBoxFromScriptDefaultAnswer()
diff --git a/tests/auto/installer/metadatacache/data/existing-cache/manifest.json b/tests/auto/installer/metadatacache/data/existing-cache/manifest.json
index 0ef247e8e..7f30e0fc0 100644
--- a/tests/auto/installer/metadatacache/data/existing-cache/manifest.json
+++ b/tests/auto/installer/metadatacache/data/existing-cache/manifest.json
@@ -3,5 +3,5 @@
"placeholder_sha1"
],
"type": "Metadata",
- "version": "1.0.0"
+ "version": "1.2.0"
}
diff --git a/tests/auto/installer/metadatacache/tst_metadatacache.cpp b/tests/auto/installer/metadatacache/tst_metadatacache.cpp
index f3ab1b98e..ce97de9da 100644
--- a/tests/auto/installer/metadatacache/tst_metadatacache.cpp
+++ b/tests/auto/installer/metadatacache/tst_metadatacache.cpp
@@ -30,7 +30,7 @@
#include <errors.h>
#include <fileutils.h>
-#include <genericdatacache.h>
+#include <metadatacache.h>
#include <metadata.h>
#include <repository.h>
@@ -43,6 +43,9 @@
#include <QObject>
#include <QTest>
+#define QUOTE_(x) #x
+#define QUOTE(x) QUOTE_(x)
+
using namespace QInstaller;
static const QByteArray scPlaceholderSha1("placeholder_sha1");
@@ -141,7 +144,7 @@ private slots:
void testRegisterItemToEmptyCache()
{
- GenericDataCache<Metadata> cache(m_cachePath, "Metadata", "1.0.0");
+ MetadataCache cache(m_cachePath);
Metadata *metadata = new Metadata(":/data/local-temp-repository/");
QVERIFY(cache.registerItem(metadata));
@@ -160,7 +163,7 @@ private slots:
{
copyExistingCacheFromResourceTree();
- GenericDataCache<Metadata> cache(m_cachePath, "Metadata", "1.0.0");
+ MetadataCache cache(m_cachePath);
Metadata *metadata = new Metadata(":/data/local-temp-repository/");
QVERIFY(itemsFromManifest(m_cachePath + "/manifest.json").contains(QLatin1String(m_oldMetadataItemChecksum)));
@@ -180,7 +183,7 @@ private slots:
void testRegisterItemFails()
{
// 1. Test fail due to invalidated cache
- GenericDataCache<Metadata> cache;
+ MetadataCache cache;
Metadata *metadata = new Metadata(":/data/local-temp-repository/");
QVERIFY(!cache.registerItem(metadata));
@@ -192,7 +195,7 @@ private slots:
// 2. Test fail due to null metadata
cache.setPath(m_cachePath);
cache.setType("Metadata");
- cache.setVersion("1.0.0");
+ cache.setVersion(QUOTE(IFW_CACHE_FORMAT_VERSION));
QVERIFY(cache.initialize());
QVERIFY(!cache.registerItem(metadata));
@@ -220,7 +223,7 @@ private slots:
{
copyExistingCacheFromResourceTree();
- GenericDataCache<Metadata> cache(m_cachePath, "Metadata", "1.0.0");
+ MetadataCache cache(m_cachePath);
Metadata *metadata = cache.itemByChecksum(m_oldMetadataItemChecksum);
QVERIFY(metadata);
QVERIFY(metadata->isValid());
@@ -234,7 +237,7 @@ private slots:
QTest::addColumn<QString>("type");
QTest::addColumn<QString>("version");
- QTest::newRow("Type mismatch") << "MyCacheableType" << "1.0.0";
+ QTest::newRow("Type mismatch") << "MyCacheableType" << QUOTE(IFW_CACHE_FORMAT_VERSION);
QTest::newRow("Version mismatch") << "Metadata" << "0.9.1";
}
@@ -245,7 +248,12 @@ private slots:
copyExistingCacheFromResourceTree();
- GenericDataCache<Metadata> cache(m_cachePath, type, version);
+ MetadataCache cache;
+ cache.setType(type);
+ cache.setVersion(version);
+ cache.setPath(m_cachePath);
+ QVERIFY(cache.initialize());
+
QVERIFY(cache.isValid());
QVERIFY(!cache.itemByChecksum(m_oldMetadataItemChecksum));
@@ -256,7 +264,7 @@ private slots:
void testInitializeCacheFails()
{
- GenericDataCache<Metadata> cache;
+ MetadataCache cache;
QVERIFY(!cache.initialize());
QCOMPARE(cache.errorString(), "Cannot initialize cache with empty path.");
}
@@ -265,7 +273,7 @@ private slots:
{
copyExistingCacheFromResourceTree();
- GenericDataCache<Metadata> cache(m_cachePath, "Metadata", "1.0.0");
+ MetadataCache cache(m_cachePath);
Metadata *metadata = cache.itemByChecksum(m_oldMetadataItemChecksum);
QVERIFY(metadata);
QVERIFY(metadata->isValid());
@@ -279,7 +287,7 @@ private slots:
{
copyExistingCacheFromResourceTree();
- GenericDataCache<Metadata> cache(m_cachePath, "Metadata", "1.0.0");
+ MetadataCache cache(m_cachePath);
QVERIFY(!cache.removeItem("12345"));
QCOMPARE(cache.errorString(), "Cannot remove item specified by checksum 12345: no such item exists.");
@@ -289,7 +297,7 @@ private slots:
void testRetrieveItemFromCache()
{
- GenericDataCache<Metadata> cache(m_cachePath, "Metadata", "1.0.0");
+ MetadataCache cache(m_cachePath);
Metadata *metadata = new Metadata(":/data/local-temp-repository/");
QVERIFY(cache.registerItem(metadata));
@@ -307,7 +315,7 @@ private slots:
void testRetrieveItemFails()
{
- GenericDataCache<Metadata> cache(m_cachePath, "Metadata", "1.0.0");
+ MetadataCache cache(m_cachePath);
Metadata *metadata = new Metadata(":/data/local-temp-repository/");
const QString metadataPath = metadata->path();
@@ -325,7 +333,7 @@ private slots:
{
copyExistingCacheFromResourceTree();
- GenericDataCache<Metadata> cache(m_cachePath, "Metadata", "1.0.0");
+ MetadataCache cache(m_cachePath);
Metadata *metadata = new Metadata(":/data/local-temp-repository/");
QVERIFY(cache.registerItem(metadata));
@@ -351,7 +359,7 @@ private slots:
void testClearCacheFails()
{
- GenericDataCache<Metadata> cache(m_cachePath, "Metadata", "1.0.0");
+ MetadataCache cache(m_cachePath);
Metadata *metadata = new Metadata(":/data/local-temp-repository/");
QVERIFY(cache.registerItem(metadata));
diff --git a/tests/auto/installer/mkdiroperationtest/tst_mkdiroperationtest.cpp b/tests/auto/installer/mkdiroperationtest/tst_mkdiroperationtest.cpp
index f52c27d0f..e41ba8049 100644
--- a/tests/auto/installer/mkdiroperationtest/tst_mkdiroperationtest.cpp
+++ b/tests/auto/installer/mkdiroperationtest/tst_mkdiroperationtest.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -60,32 +60,42 @@ private slots:
QVERIFY(!op.performOperation());
QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments);
- QCOMPARE(op.errorString(), QString("Invalid arguments in Mkdir: "
- "0 arguments given, exactly 1 arguments expected."));
-
+ QCOMPARE(op.errorString(), QString("Invalid arguments in Mkdir: 0 arguments given, 1 to 3 "
+ "arguments expected in the form: <file to remove> [UNDOOPERATION, \"\"]."));
}
void testCreateDirectory_data()
{
- QTest::addColumn<QString>("directory");
- QTest::newRow("/test") << "/test";
- QTest::newRow("/test/test") << "/test/test";
- QTest::newRow("/test/test/test") << "/test/test/test";
+ QTest::addColumn<QString>("directory");
+ QTest::addColumn<bool>("overrideUndo");
+ QTest::newRow("/test") << "/test" << false;
+ QTest::newRow("/test/test") << "/test/test" << false;
+ QTest::newRow("/test/test/test") << "/test/test/test" << false;
+ QTest::newRow("no undo") << "/test" << true;
}
void testCreateDirectory()
{
QFETCH(QString, directory);
+ QFETCH(bool, overrideUndo);
+
QString path = QDir::current().path() + QDir::toNativeSeparators(directory);
QVERIFY2(!QDir(path).exists(), path.toLatin1());
MkdirOperation op;
op.setArguments(QStringList() << path);
+ if (overrideUndo)
+ op.setArguments(op.arguments() << QLatin1String("UNDOOPERATION"));
op.backup();
QVERIFY2(op.performOperation(), op.errorString().toLatin1());
QVERIFY2(QDir(path).exists(), path.toLatin1());
QVERIFY2(op.undoOperation(), op.errorString().toLatin1());
- QVERIFY2(!QDir(path).exists(), path.toLatin1());
+ if (overrideUndo) {
+ QVERIFY2(QDir(path).exists(), path.toLatin1());
+ QVERIFY(QDir(path).removeRecursively());
+ } else {
+ QVERIFY2(!QDir(path).exists(), path.toLatin1());
+ }
}
void testCreateDirectory_customFile_data()
diff --git a/tests/auto/installer/moveoperation/tst_moveoperation.cpp b/tests/auto/installer/moveoperation/tst_moveoperation.cpp
index 136eb1e45..bb391efee 100644
--- a/tests/auto/installer/moveoperation/tst_moveoperation.cpp
+++ b/tests/auto/installer/moveoperation/tst_moveoperation.cpp
@@ -86,8 +86,8 @@ private slots:
QVERIFY(!op.performOperation());
QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments);
- QCOMPARE(op.errorString(), QString("Invalid arguments in Move: "
- "0 arguments given, exactly 2 arguments expected."));
+ QCOMPARE(op.errorString(), QString("Invalid arguments in Move: 0 arguments given, 2 to 4 arguments "
+ "expected in the form: <complete source file name> <complete destination file name> [UNDOOPERATION, \"\"]."));
}
void testMoveFile()
diff --git a/tests/auto/installer/packagemanagercore/tst_packagemanagercore.cpp b/tests/auto/installer/packagemanagercore/tst_packagemanagercore.cpp
index cc2e069ea..410bfb01c 100644
--- a/tests/auto/installer/packagemanagercore/tst_packagemanagercore.cpp
+++ b/tests/auto/installer/packagemanagercore/tst_packagemanagercore.cpp
@@ -287,52 +287,6 @@ private slots:
QVERIFY(QDir().rmdir(testDirectory));
}
- void testAllowRunningProcess()
- {
- #ifdef Q_OS_MACOS
- QSKIP("In macOS the app path and maintenancetool differ, not possible to test running processes.");
- #endif
- PackageManagerCore core;
- core.setPackageManager();
- const QString testDirectory = QInstaller::generateTemporaryFileName();
- QVERIFY(QDir().mkpath(testDirectory));
- core.setValue(scTargetDir, testDirectory);
-
- QString appFilePath = QCoreApplication::applicationFilePath();
- core.setAllowedRunningProcesses(QStringList() << appFilePath);
- const QString warningMessage = QString("Failure to read packages from ");
- const QRegularExpression re(warningMessage);
- QTest::ignoreMessage(QtWarningMsg, re);
- QTest::ignoreMessage(QtDebugMsg, "No updates available.");
-
- QCOMPARE(PackageManagerCore::Canceled, core.updateComponentsSilently(QStringList()));
- QVERIFY(QDir().rmdir(testDirectory));
- }
-
- void testDisallowRunningProcess()
- {
- #ifdef Q_OS_MACOS
- QSKIP("In macOS the app path and maintenancetool differ, not possible to test running processes.");
- #endif
- PackageManagerCore core;
- core.setPackageManager();
- const QString testDirectory = QInstaller::generateTemporaryFileName();
- QVERIFY(QDir().mkpath(testDirectory));
- core.setValue(scTargetDir, testDirectory);
-
- const QString warningMessageUp = QString("Unable to update components. Please stop these processes: ");
- const QRegularExpression reUp(warningMessageUp);
- QTest::ignoreMessage(QtWarningMsg, reUp);
- QVERIFY_EXCEPTION_THROWN(core.updateComponentsSilently(QStringList()), Error);
-
- const QString warningMessageRm = QString("Unable to remove components. Please stop these processes: ");
- const QRegularExpression reRm(warningMessageRm);
- QTest::ignoreMessage(QtWarningMsg, reRm);
- QVERIFY_EXCEPTION_THROWN(core.removeInstallationSilently(), Error);
-
- QVERIFY(QDir().rmdir(testDirectory));
- }
-
void testCoreDataValues()
{
QHash<QString, QString> userValues;
diff --git a/tests/auto/installer/prependfileoperation/data/repository/B/1.0.2-1content.7z b/tests/auto/installer/prependfileoperation/data/repository/B/1.0.2-1content.7z
new file mode 100644
index 000000000..543aab656
--- /dev/null
+++ b/tests/auto/installer/prependfileoperation/data/repository/B/1.0.2-1content.7z
Binary files differ
diff --git a/tests/auto/installer/prependfileoperation/data/repository/B/1.0.2-1meta.7z b/tests/auto/installer/prependfileoperation/data/repository/B/1.0.2-1meta.7z
new file mode 100644
index 000000000..a59f269e7
--- /dev/null
+++ b/tests/auto/installer/prependfileoperation/data/repository/B/1.0.2-1meta.7z
Binary files differ
diff --git a/tests/auto/installer/prependfileoperation/data/repository/Updates.xml b/tests/auto/installer/prependfileoperation/data/repository/Updates.xml
new file mode 100644
index 000000000..e61d2445f
--- /dev/null
+++ b/tests/auto/installer/prependfileoperation/data/repository/Updates.xml
@@ -0,0 +1,16 @@
+<Updates>
+ <ApplicationName>{AnyApplication}</ApplicationName>
+ <ApplicationVersion>1.0.0</ApplicationVersion>
+ <Checksum>false</Checksum>
+ <PackageUpdate>
+ <Name>B</Name>
+ <DisplayName>A</DisplayName>
+ <Description>Example component B</Description>
+ <Version>1.0.2-1</Version>
+ <ReleaseDate>2015-01-01</ReleaseDate>
+ <Default>true</Default>
+ <Script>script.qs</Script>
+ <SHA1>750eda14d867849aeb2f47d620f6e5f32134f375</SHA1>
+ <DownloadableArchives>content.7z</DownloadableArchives>
+ </PackageUpdate>
+</Updates>
diff --git a/tests/auto/installer/prependfileoperation/data/xmloperationrepository/C/1.0.0content.7z b/tests/auto/installer/prependfileoperation/data/xmloperationrepository/C/1.0.0content.7z
new file mode 100644
index 000000000..d936db354
--- /dev/null
+++ b/tests/auto/installer/prependfileoperation/data/xmloperationrepository/C/1.0.0content.7z
Binary files differ
diff --git a/tests/auto/installer/prependfileoperation/data/xmloperationrepository/Updates.xml b/tests/auto/installer/prependfileoperation/data/xmloperationrepository/Updates.xml
new file mode 100644
index 000000000..379fe865f
--- /dev/null
+++ b/tests/auto/installer/prependfileoperation/data/xmloperationrepository/Updates.xml
@@ -0,0 +1,20 @@
+<Updates>
+ <ApplicationName>{AnyApplication}</ApplicationName>
+ <ApplicationVersion>1.0.0</ApplicationVersion>
+ <PackageUpdate>
+ <Name>C</Name>
+ <DisplayName>C</DisplayName>
+ <Description>Example component C</Description>
+ <Version>1.0.0</Version>
+ <ReleaseDate>2020-01-01</ReleaseDate>
+ <Default>true</Default>
+ <UpdateFile CompressedSize="224" OS="Any" UncompressedSize="74"/>
+ <DownloadableArchives>content.7z</DownloadableArchives>
+ <Operations>
+ <Operation name="PrependFile">
+ <Argument>@TargetDir@/C.txt</Argument>
+ <Argument>Prepended text: </Argument>
+ </Operation>
+ </Operations>
+ </PackageUpdate>
+</Updates>
diff --git a/tests/auto/installer/prependfileoperation/prependfileoperation.pro b/tests/auto/installer/prependfileoperation/prependfileoperation.pro
new file mode 100644
index 000000000..5f68385fe
--- /dev/null
+++ b/tests/auto/installer/prependfileoperation/prependfileoperation.pro
@@ -0,0 +1,10 @@
+include(../../qttest.pri)
+
+QT -= gui
+QT += testlib
+
+SOURCES += tst_prependfileoperation.cpp
+
+RESOURCES += \
+ settings.qrc \
+ ../shared/config.qrc
diff --git a/tests/auto/installer/prependfileoperation/settings.qrc b/tests/auto/installer/prependfileoperation/settings.qrc
new file mode 100644
index 000000000..deaeb257f
--- /dev/null
+++ b/tests/auto/installer/prependfileoperation/settings.qrc
@@ -0,0 +1,9 @@
+<RCC>
+ <qresource prefix="/">
+ <file>data/repository/Updates.xml</file>
+ <file>data/repository/B/1.0.2-1content.7z</file>
+ <file>data/repository/B/1.0.2-1meta.7z</file>
+ <file>data/xmloperationrepository/Updates.xml</file>
+ <file>data/xmloperationrepository/C/1.0.0content.7z</file>
+ </qresource>
+</RCC>
diff --git a/tests/auto/installer/prependfileoperation/tst_prependfileoperation.cpp b/tests/auto/installer/prependfileoperation/tst_prependfileoperation.cpp
new file mode 100644
index 000000000..12f178cb4
--- /dev/null
+++ b/tests/auto/installer/prependfileoperation/tst_prependfileoperation.cpp
@@ -0,0 +1,180 @@
+/**************************************************************************
+**
+** Copyright (C) 2024 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+#include "../shared/packagemanager.h"
+
+#include <updateoperations.h>
+#include <packagemanagercore.h>
+
+#include <QFile>
+#include <QTest>
+
+using namespace KDUpdater;
+using namespace QInstaller;
+
+class tst_prependfileoperation : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase()
+ {
+ m_testFilePath = qApp->applicationDirPath() + QDir::toNativeSeparators("/test");
+ }
+
+ void testMissingArguments()
+ {
+ PrependFileOperation op;
+
+ QVERIFY(op.testOperation());
+ QVERIFY(!op.performOperation());
+
+ QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments);
+ QCOMPARE(op.errorString(), QString("Invalid arguments in PrependFile: 0 arguments given, 2 to 4 arguments expected in the form: <filename> <text to prepend> [UNDOOPERATION, \"\"]."));
+
+ op.setArguments(QStringList() << "" << "");
+ QTest::ignoreMessage(QtWarningMsg, "QFSFileEngine::open: No file name specified");
+ QVERIFY(!op.performOperation());
+
+ QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::UserDefinedError);
+ QCOMPARE(op.errorString(), QString("Cannot open file \"\" for reading: No file name specified"));
+ }
+
+ void testPrependText_data()
+ {
+ QTest::addColumn<QString>("source");
+ QTest::addColumn<QString>("prepend");
+ QTest::addColumn<QString>("expected");
+ QTest::addColumn<bool>("overrideUndo");
+ QTest::newRow("newline") << "Line1\nLine2\nLine3\n" << "PrependedText"
+ << "PrependedTextLine1\nLine2\nLine3\n" << false;
+ QTest::newRow("no newline") << "dolore sit amet" << "Lorem ipsum "
+ << "Lorem ipsum dolore sit amet" << false;
+
+ QTest::newRow("no undo")<< "dolore sit amet" << "Lorem ipsum "
+ << "Lorem ipsum dolore sit amet" << true;
+ }
+
+ void testPrependText()
+ {
+ QFETCH(QString, source);
+ QFETCH(QString, prepend);
+ QFETCH(QString, expected);
+ QFETCH(bool, overrideUndo);
+
+ QFile file(m_testFilePath);
+ QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Text));
+
+ QTextStream stream(&file);
+ stream << source << Qt::flush;
+ file.close();
+
+ PrependFileOperation *op = new PrependFileOperation();
+ op->setArguments(QStringList() << m_testFilePath << prepend);
+ if (overrideUndo)
+ op->setArguments(op->arguments() << QLatin1String("UNDOOPERATION"));
+
+ op->backup();
+ QVERIFY(QFileInfo(op->value("backupOfFile").toString()).exists());
+
+ QVERIFY2(op->performOperation(), op->errorString().toLatin1());
+ QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text));
+ QCOMPARE(stream.readAll(), expected);
+ file.close();
+
+ QVERIFY2(op->undoOperation(), op->errorString().toLatin1());
+ QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text));
+ if (overrideUndo)
+ QCOMPARE(stream.readAll(), expected);
+ else
+ QCOMPARE(stream.readAll(), source);
+ file.close();
+
+ QVERIFY(file.remove());
+
+ QString backupFileName = op->value("backupOfFile").toString();
+ delete op;
+ QVERIFY(!QFileInfo::exists(backupFileName));
+ }
+
+ void testPrependFromCLI_data()
+ {
+ QTest::addColumn<QString>("repository");
+ QTest::addColumn<QString>("fileName");
+ QTest::addColumn<QString>("componentName");
+ QTest::addColumn<QString>("expected");
+
+ QTest::newRow("operationFromScript")
+ << (":///data/repository")
+ << ("B.txt")
+ << ("B")
+ << ("Prepended text: lorem ipsum");
+
+ QTest::newRow("operationFromXML")
+ << (":///data/xmloperationrepository")
+ << ("C.txt")
+ << ("C")
+ << ("Prepended text: lorem ipsum");
+ }
+
+ void testPrependFromCLI()
+ {
+ QFETCH(QString, repository);
+ QFETCH(QString, fileName);
+ QFETCH(QString, componentName);
+ QFETCH(QString, expected);
+
+ QString installDir = QInstaller::generateTemporaryFileName();
+ QVERIFY(QDir().mkpath(installDir));
+ QScopedPointer<PackageManagerCore> core(PackageManager::getPackageManagerWithInit
+ (installDir, repository));
+ core->installSelectedComponentsSilently(QStringList() << componentName);
+
+ QFile file(installDir + QDir::separator() + fileName);
+ QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text));
+ QTextStream stream(&file);
+ QCOMPARE(stream.readAll(), expected);
+ file.close();
+
+ core->setPackageManager();
+ core->commitSessionOperations();
+ // We cannot check the file contents here as it will be deleted on
+ // undo Extract, but at least check that the uninstallation succeeds.
+ QCOMPARE(PackageManagerCore::Success, core->uninstallComponentsSilently
+ (QStringList()<< componentName));
+
+ QDir dir(installDir);
+ QVERIFY(dir.removeRecursively());
+ }
+
+private:
+ QString m_testFilePath;
+};
+
+QTEST_MAIN(tst_prependfileoperation)
+
+#include "tst_prependfileoperation.moc"
diff --git a/tests/auto/installer/repository/data/repository/A/1.0.2meta.7z b/tests/auto/installer/repository/data/repository/A/1.0.2meta.7z
new file mode 100644
index 000000000..6631280a7
--- /dev/null
+++ b/tests/auto/installer/repository/data/repository/A/1.0.2meta.7z
Binary files differ
diff --git a/tests/auto/installer/repository/data/repository/B/1.0.0meta.7z b/tests/auto/installer/repository/data/repository/B/1.0.0meta.7z
new file mode 100644
index 000000000..16f3a6c42
--- /dev/null
+++ b/tests/auto/installer/repository/data/repository/B/1.0.0meta.7z
Binary files differ
diff --git a/tests/auto/installer/repository/data/repository/C/1.0.0meta.7z b/tests/auto/installer/repository/data/repository/C/1.0.0meta.7z
new file mode 100644
index 000000000..37c8fffc4
--- /dev/null
+++ b/tests/auto/installer/repository/data/repository/C/1.0.0meta.7z
Binary files differ
diff --git a/tests/auto/installer/repository/data/repository/Updates.xml b/tests/auto/installer/repository/data/repository/Updates.xml
index 8ddea3938..f541882c5 100644
--- a/tests/auto/installer/repository/data/repository/Updates.xml
+++ b/tests/auto/installer/repository/data/repository/Updates.xml
@@ -8,7 +8,26 @@
<Description>Example component A</Description>
<Version>1.0.2</Version>
<ReleaseDate>2015-01-01</ReleaseDate>
- <Default>true</Default>
+ <Default>false</Default>
<DownloadableArchives>content.7z</DownloadableArchives>
+ <Script postLoad="true">script.qs</Script>
+ </PackageUpdate>
+ <PackageUpdate>
+ <Name>B</Name>
+ <DisplayName>B</DisplayName>
+ <Description>Example component B</Description>
+ <Version>1.0.0</Version>
+ <ReleaseDate>2015-01-01</ReleaseDate>
+ <Default>false</Default>
+ <Script>script.qs</Script>
+ </PackageUpdate>
+ <PackageUpdate>
+ <Name>C</Name>
+ <DisplayName>C</DisplayName>
+ <Description>Example component C</Description>
+ <Version>1.0.0</Version>
+ <ReleaseDate>2015-01-01</ReleaseDate>
+ <Default>false</Default>
+ <Script postLoad="false">script.qs</Script>
</PackageUpdate>
</Updates>
diff --git a/tests/auto/installer/repository/settings.qrc b/tests/auto/installer/repository/settings.qrc
index ff628b482..92db7e3e1 100644
--- a/tests/auto/installer/repository/settings.qrc
+++ b/tests/auto/installer/repository/settings.qrc
@@ -2,6 +2,9 @@
<qresource prefix="/">
<file>data/repository/Updates.xml</file>
<file>data/repository/A/1.0.2content.7z</file>
+ <file>data/repository/A/1.0.2meta.7z</file>
+ <file>data/repository/B/1.0.0meta.7z</file>
+ <file>data/repository/C/1.0.0meta.7z</file>
<file>data/compressedRepository/compressedRepository.7z</file>
</qresource>
</RCC>
diff --git a/tests/auto/installer/repository/tst_repository.cpp b/tests/auto/installer/repository/tst_repository.cpp
index db538ba5d..112098130 100644
--- a/tests/auto/installer/repository/tst_repository.cpp
+++ b/tests/auto/installer/repository/tst_repository.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2021 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -39,6 +39,8 @@
using namespace QInstaller;
+typedef QList<QPair<QString, QString>> SettingsPairList;
+
class tst_Repository : public QObject
{
Q_OBJECT
@@ -168,7 +170,7 @@ private slots:
categories.insert(category);
settings.setRepositoryCategories(categories);
- QHash<QString, QPair<Repository, Repository>> update;
+ QMultiHash<QString, QPair<Repository, Repository>> update;
// non-empty update
update.insert(QLatin1String("replace"), qMakePair(original, replacement));
@@ -210,6 +212,102 @@ private slots:
QVERIFY(dir.removeRecursively());
core->deleteLater();
}
+
+ void testPostLoadScriptFromRepository_data()
+ {
+ QTest::addColumn<QStringList>("installComponent");
+ QTest::addColumn<bool>("repositoryPostLoadSetting");
+ QTest::addColumn<SettingsPairList>("expectedSettingsBeforeInstall");
+ QTest::addColumn<SettingsPairList>("expectedSettingsAfterInstall");
+ QTest::addColumn<QStringList>("unexpectedSettings");
+
+ // component A has postLoad = true in component.xml
+ // component B has no postLoad attribute
+ // component C has postLoad = false in component.xml
+
+ SettingsPairList expectedSettingsListAfterInstall;
+ expectedSettingsListAfterInstall.append(QPair<QString, QString>("componentAKey", "componentAValue"));
+
+ SettingsPairList expectedSettingsListBeforeInstall;
+ expectedSettingsListBeforeInstall.append(QPair<QString, QString>("componentBKey", "componentBValue"));
+ expectedSettingsListBeforeInstall.append(QPair<QString, QString>("componentCKey", "componentCValue"));
+
+ QTest::newRow("noRepoPostLoadComponentA")
+ << (QStringList() << "A")
+ << false
+ << expectedSettingsListBeforeInstall
+ << expectedSettingsListAfterInstall
+ << (QStringList());
+
+ // Component B is installed so values from component A and component C should not be set
+ expectedSettingsListAfterInstall.clear();
+ expectedSettingsListAfterInstall.append(QPair<QString, QString>("componentBKey", "componentBValue"));
+ QTest::newRow("noRepoPostLoadComponentB")
+ << (QStringList() << "B")
+ << false
+ << expectedSettingsListBeforeInstall
+ << expectedSettingsListAfterInstall
+ << (QStringList() << "componentAValue" << "componentCValue");
+
+ // PostLoad is set to whole repository. Since only A is installed,
+ // values from component B and component C values are not set
+ expectedSettingsListBeforeInstall.clear();
+ expectedSettingsListAfterInstall.clear();
+ expectedSettingsListAfterInstall.append(QPair<QString, QString>("componentAKey", "componentAValue"));
+ QTest::newRow("repoPostLoadComponentA") << (QStringList() << "A")
+ << true
+ << expectedSettingsListBeforeInstall
+ << expectedSettingsListAfterInstall
+ << (QStringList() << "componentBValue" << "componentCValue");
+
+ // PostLoad is set to whole repository. Since only B is installed,
+ // values from component C and component A are not set.
+ expectedSettingsListAfterInstall.clear();
+ expectedSettingsListAfterInstall.append(QPair<QString, QString>("componentBKey", "componentBValue"));
+ QTest::newRow("repoPostLoadComponentB") << (QStringList() << "B")
+ << true
+ << expectedSettingsListBeforeInstall
+ << expectedSettingsListAfterInstall
+ << (QStringList() << "componentCValue" << "componentAValue");
+
+ // PostLoad is set to whole repository. Since component C has its postload = false,
+ // value is set to component C before install
+ expectedSettingsListBeforeInstall.clear();
+ expectedSettingsListAfterInstall.clear();
+ expectedSettingsListBeforeInstall.append(QPair<QString, QString>("componentCKey", "componentCValue"));
+ QTest::newRow("repoPostLoadComponentC") << (QStringList() << "C")
+ << true
+ << expectedSettingsListBeforeInstall
+ << expectedSettingsListAfterInstall
+ << (QStringList() << "componentAValue" << "componentBValue");
+ }
+
+ void testPostLoadScriptFromRepository()
+ {
+ QFETCH(QStringList, installComponent);
+ QFETCH(bool, repositoryPostLoadSetting);
+ QFETCH(SettingsPairList, expectedSettingsBeforeInstall);
+ QFETCH(SettingsPairList, expectedSettingsAfterInstall);
+ QFETCH(QStringList, unexpectedSettings);
+
+ QString installDir = QInstaller::generateTemporaryFileName();
+ QScopedPointer<PackageManagerCore> core(PackageManager::getPackageManagerWithInit(installDir));
+ QSet<Repository> repoList;
+ Repository repo = Repository::fromUserInput(":///data/repository");
+ repo.setPostLoadComponentScript(repositoryPostLoadSetting);
+ repoList.insert(repo);
+ core->settings().setDefaultRepositories(repoList);
+ QVERIFY(core->fetchRemotePackagesTree());
+
+ for (const QPair<QString, QString> settingValue : expectedSettingsBeforeInstall)
+ QCOMPARE(core->value(settingValue.first), settingValue.second);
+
+ core->installSelectedComponentsSilently(installComponent);
+ for (const QPair<QString, QString> settingValue : expectedSettingsAfterInstall)
+ QCOMPARE(core->value(settingValue.first), settingValue.second);
+ for (const QString unexpectedSetting : unexpectedSettings)
+ QVERIFY2(!core->containsValue(unexpectedSetting), "Core contains unexpected value");
+ }
};
QTEST_MAIN(tst_Repository)
diff --git a/tests/auto/installer/rmdiroperationtest/rmdiroperationtest.pro b/tests/auto/installer/rmdiroperationtest/rmdiroperationtest.pro
new file mode 100644
index 000000000..72e61ad80
--- /dev/null
+++ b/tests/auto/installer/rmdiroperationtest/rmdiroperationtest.pro
@@ -0,0 +1,6 @@
+include(../../qttest.pri)
+
+QT -= gui
+QT += testlib
+
+SOURCES = tst_rmdiroperationtest.cpp
diff --git a/tests/auto/installer/rmdiroperationtest/tst_rmdiroperationtest.cpp b/tests/auto/installer/rmdiroperationtest/tst_rmdiroperationtest.cpp
new file mode 100644
index 000000000..bfdd5921e
--- /dev/null
+++ b/tests/auto/installer/rmdiroperationtest/tst_rmdiroperationtest.cpp
@@ -0,0 +1,111 @@
+/**************************************************************************
+**
+** Copyright (C) 2024 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#include "init.h"
+#include "updateoperations.h"
+
+#include <QDir>
+#include <QObject>
+#include <QTest>
+#include <QFile>
+#include <QTextStream>
+
+using namespace KDUpdater;
+using namespace QInstaller;
+
+class tst_rmdiroperationtest : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase()
+ {
+ QInstaller::init();
+ QString path = QDir::current().path() + QDir::toNativeSeparators("/test");
+ if (QDir(path).exists()) {
+ QFAIL("Remove test folder first!");
+ }
+ }
+
+ void testMissingArguments()
+ {
+ RmdirOperation op;
+
+ QVERIFY(op.testOperation());
+ QVERIFY(!op.performOperation());
+
+ QCOMPARE(UpdateOperation::Error(op.error()), UpdateOperation::InvalidArguments);
+ QCOMPARE(op.errorString(), QLatin1String("Invalid arguments in Rmdir: 0 arguments given, 1 to 3 "
+ "arguments expected in the form: <file to remove> [UNDOOPERATION, \"\"]."));
+ }
+
+ void testRemoveDirectory_data()
+ {
+ QTest::addColumn<QString>("directory");
+ QTest::addColumn<bool>("overrideUndo");
+ QTest::newRow("/test") << "/test" << false;
+ QTest::newRow("/test/test") << "/test/test" << false;
+ QTest::newRow("/test/test/test") << "/test/test/test" << false;
+ QTest::newRow("no undo") << "/test/test/test/test" << true;
+ }
+
+ void testRemoveDirectory()
+ {
+ QFETCH(QString, directory);
+ QFETCH(bool, overrideUndo);
+
+ QString path = QDir::current().path() + QDir::toNativeSeparators(directory);
+ //Create first the directories utilizing MkdirOperation
+ MkdirOperation op;
+ op.setArguments(QStringList() << path);
+ op.setArguments(op.arguments() << QLatin1String("UNDOOPERATION"));
+ op.backup();
+ QVERIFY2(op.performOperation(), op.errorString().toLatin1());
+ QVERIFY2(QDir(path).exists(), path.toLatin1());
+
+ RmdirOperation rmOp;
+ rmOp.setArguments(QStringList() << path);
+ if (overrideUndo)
+ rmOp.setArguments(op.arguments() << QLatin1String("UNDOOPERATION"));
+ rmOp.backup();
+ rmOp.performOperation();
+ QVERIFY2(!QDir(path).exists(), path.toLatin1());
+
+ QVERIFY2(rmOp.undoOperation(), rmOp.errorString().toLatin1());
+ if (overrideUndo) {
+ QVERIFY2(!QDir(path).exists(), path.toLatin1());
+ } else {
+ QVERIFY2(QDir(path).exists(), path.toLatin1());
+ QVERIFY(QDir(path).removeRecursively());
+ }
+ }
+};
+
+QTEST_MAIN(tst_rmdiroperationtest)
+
+#include "tst_rmdiroperationtest.moc"
diff --git a/tests/auto/installer/scriptengine/tst_scriptengine.cpp b/tests/auto/installer/scriptengine/tst_scriptengine.cpp
index 6c55fe205..86017a229 100644
--- a/tests/auto/installer/scriptengine/tst_scriptengine.cpp
+++ b/tests/auto/installer/scriptengine/tst_scriptengine.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -221,13 +221,6 @@ private slots:
.hasProperty(QLatin1String("getExistingDirectory")), true);
QCOMPARE(global.property(QLatin1String("QFileDialog"))
.hasProperty(QLatin1String("getOpenFileName")), true);
-
- QCOMPARE(global.hasProperty(QLatin1String("InstallerProxy")), true);
- QCOMPARE(global.property(QLatin1String("InstallerProxy"))
- .hasProperty(QLatin1String("componentByName")), true);
- QCOMPARE(global.property(QLatin1String("InstallerProxy"))
- .hasProperty(QLatin1String("components")), true);
-
QCOMPARE(global.hasProperty(QLatin1String("QDesktopServices")), true);
QCOMPARE(global.property(QLatin1String("QDesktopServices"))
.hasProperty(QLatin1String("openUrl")), true);
@@ -249,6 +242,8 @@ private slots:
QJSValue sinfo = global.property(QLatin1String("systemInfo"));
QCOMPARE(sinfo.property(QLatin1String("currentCpuArchitecture")).toString(),
QSysInfo::currentCpuArchitecture());
+ QCOMPARE(sinfo.property(QLatin1String("buildCpuArchitecture")).toString(),
+ QSysInfo::buildCpuArchitecture());
QCOMPARE(sinfo.property(QLatin1String("kernelType")).toString(), QSysInfo::kernelType());
QCOMPARE(sinfo.property(QLatin1String("kernelVersion")).toString(),
QSysInfo::kernelVersion());
@@ -478,6 +473,7 @@ private slots:
QFETCH(bool, postLoad);
try {
setExpectedScriptOutput("checked: false");
+ TestGui testGui(&m_core);
m_component->loadUserInterfaces(QDir(":///data"), QStringList() << QLatin1String("form.ui"));
m_component->evaluateComponentScript(path, postLoad);
} catch (const Error &error) {
diff --git a/tests/auto/installer/settings/data/full_config.xml b/tests/auto/installer/settings/data/full_config.xml
index 304dd21f4..bccb6f7ca 100644
--- a/tests/auto/installer/settings/data/full_config.xml
+++ b/tests/auto/installer/settings/data/full_config.xml
@@ -37,6 +37,7 @@ File should contain all elements we allow in a config.xml
<DependsOnLocalInstallerBinary>true</DependsOnLocalInstallerBinary>
<AllowSpaceInPath>true</AllowSpaceInPath>
<AllowNonAsciiCharacters>true</AllowNonAsciiCharacters>
+ <AllowRepositoriesForOfflineInstaller>true</AllowRepositoriesForOfflineInstaller>
<DisableAuthorizationFallback>true</DisableAuthorizationFallback>
<DisableCommandLineInterface>true</DisableCommandLineInterface>
<RepositorySettingsPageVisible>false</RepositorySettingsPageVisible>
diff --git a/tests/auto/installer/settings/tst_settings.cpp b/tests/auto/installer/settings/tst_settings.cpp
index d120f5680..15dcc98a1 100644
--- a/tests/auto/installer/settings/tst_settings.cpp
+++ b/tests/auto/installer/settings/tst_settings.cpp
@@ -109,6 +109,7 @@ void tst_Settings::loadTutorialConfig()
QCOMPARE(settings.repositorySettingsPageVisible(), true);
QCOMPARE(settings.allowSpaceInPath(), true);
QCOMPARE(settings.allowNonAsciiCharacters(), false);
+ QCOMPARE(settings.allowRepositoriesForOfflineInstaller(), true);
QCOMPARE(settings.disableAuthorizationFallback(), false);
QCOMPARE(settings.disableCommandLineInterface(), false);
QCOMPARE(settings.createLocalRepository(), false);
diff --git a/tests/auto/installer/shared/packagemanager.h b/tests/auto/installer/shared/packagemanager.h
index a95dd4442..9948be00a 100644
--- a/tests/auto/installer/shared/packagemanager.h
+++ b/tests/auto/installer/shared/packagemanager.h
@@ -61,7 +61,6 @@ struct PackageManager
PackageManagerCore *core = new PackageManagerCore(BinaryContent::MagicInstallerMarker, QList<OperationBlob> ());
QString appFilePath = QCoreApplication::applicationFilePath();
- core->setAllowedRunningProcesses(QStringList() << appFilePath);
core->disableWriteMaintenanceTool();
core->setAutoConfirmCommand();
QSet<Repository> repoList;
diff --git a/tests/auto/installer/shared/verifyinstaller.h b/tests/auto/installer/shared/verifyinstaller.h
index 4d70c577b..e19d3fa0a 100644
--- a/tests/auto/installer/shared/verifyinstaller.h
+++ b/tests/auto/installer/shared/verifyinstaller.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -29,6 +29,8 @@
#ifndef VERIFYINSTALLER_H
#define VERIFYINSTALLER_H
+#include <packagemanagercore.h>
+
#include <QString>
#include <QStringList>
#include <QCryptographicHash>
@@ -36,6 +38,9 @@
#include <QDir>
#include <QtTest/QTest>
+#include <iostream>
+#include <sstream>
+
struct VerifyInstaller
{
static void verifyInstallerResources(const QString &installDir, const QString &componentName, const QString &fileName)
@@ -114,5 +119,21 @@ struct VerifyInstaller
}
}
}
+
+ template <typename Func, typename... Args>
+ static void verifyListPackagesMessage(QInstaller::PackageManagerCore *core, const QString &message,
+ Func func, Args... args)
+ {
+ std::ostringstream stream;
+ std::streambuf *buf = std::cout.rdbuf();
+ std::cout.rdbuf(stream.rdbuf());
+
+ (core->*func)(std::forward<Args>(args)...);
+
+ std::cout.rdbuf(buf);
+ QVERIFY(stream && stream.tellp() == message.size());
+ for (const QString &line : message.split(QLatin1String("\n")))
+ QVERIFY(stream.str().find(line.toStdString()) != std::string::npos);
+ }
};
#endif
diff --git a/tests/auto/installer/solver/tst_solver.cpp b/tests/auto/installer/solver/tst_solver.cpp
index 85fb387e2..4548af3f1 100644
--- a/tests/auto/installer/solver/tst_solver.cpp
+++ b/tests/auto/installer/solver/tst_solver.cpp
@@ -48,7 +48,7 @@ public:
Data() {}
explicit Data(const QString &data)
: m_data(data) {}
- inline uint qHash(const Data &test);
+ inline hashValue qHash(const Data &test);
QString data() const { return m_data; }
bool operator==(const Data &rhs) const { return m_data == rhs.m_data; }
const Data &operator=(const Data &rhs) { if (this != &rhs) { m_data = rhs.m_data; } return *this; }
@@ -56,7 +56,7 @@ public:
private:
QString m_data;
};
-inline uint qHash(const Data &data)
+inline hashValue qHash(const Data &data)
{
return qHash(data.data());
}
diff --git a/tools/devtool/devtool.pro b/tools/devtool/devtool.pro
index def7066af..9a13ae0b8 100644
--- a/tools/devtool/devtool.pro
+++ b/tools/devtool/devtool.pro
@@ -10,6 +10,9 @@ CONFIG -= import_plugins
CONFIG += console
DESTDIR = $$IFW_APP_PATH
+!macos:QTPLUGIN += qopensslbackend
+macos:QTPLUGIN += qsecuretransportbackend
+
HEADERS += operationrunner.h \
binaryreplace.h \
binarydump.h
diff --git a/tools/repogen/repogen.pro b/tools/repogen/repogen.pro
index 73f1eafe5..2740167fc 100644
--- a/tools/repogen/repogen.pro
+++ b/tools/repogen/repogen.pro
@@ -12,6 +12,9 @@ CONFIG -= import_plugins
CONFIG += console
DESTDIR = $$IFW_APP_PATH
+!macos:QTPLUGIN += qopensslbackend
+macos:QTPLUGIN += qsecuretransportbackend
+
SOURCES += repogen.cpp
macx:include(../../no_app_bundle.pri)